From 893ad50b9cce75842a6593411003efaec63aacbd Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 19 Oct 2016 22:43:05 +1100 Subject: [PATCH 01/76] Updated schema.rb --- db/schema.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/schema.rb b/db/schema.rb index 5ce855fe08f..21fd8494ccc 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -832,7 +832,7 @@ ActiveRecord::Schema.define(version: 20161017095000) do t.integer "builds_access_level" t.datetime "created_at" t.datetime "updated_at" - t.integer "repository_access_level", default: 20, null: false + t.integer "repository_access_level", default: 20, null: false end add_index "project_features", ["project_id"], name: "index_project_features_on_project_id", using: :btree From ccdaa8abc8ef6033148b6a0151d5d13e4df8a9d4 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Thu, 20 Oct 2016 15:44:10 +1100 Subject: [PATCH 02/76] Add hover to trash icon in notes --- app/views/projects/notes/_note.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index 73fe6a715fa..ab719e38904 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -57,7 +57,7 @@ = link_to '#', title: 'Edit comment', class: 'note-action-button js-note-edit' do = icon('pencil', class: 'link-highlight') = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button hidden-xs js-note-delete danger' do - = icon('trash-o') + = icon('trash-o', class: 'danger-highlight') .note-body{class: note_editable ? 'js-task-list-container' : ''} .note-text.md = preserve do From 5b2200777231367cb402898af4f31cef2e63b1a1 Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Fri, 14 Oct 2016 10:57:10 -0500 Subject: [PATCH 03/76] Smaller min-width for MR pipeline table --- app/assets/stylesheets/pages/pipelines.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index 247339648fa..dfaf1ab732d 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -643,6 +643,10 @@ &.pipelines { + .ci-table { + min-width: 900px; + } + .content-list.pipelines { overflow: auto; } From 16fffa9061f72971f37ef13ed0656712e20084f4 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 18 Oct 2016 17:03:36 +0100 Subject: [PATCH 04/76] Fixed height of issue board blank state --- app/assets/stylesheets/pages/boards.scss | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index 6e81c12aa55..d8fabbdcebe 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -1,4 +1,3 @@ -lex [v-cloak] { display: none; } @@ -132,7 +131,7 @@ lex } .board-blank-state { - height: 100%; + height: calc(100% - 49px); padding: $gl-padding; background-color: #fff; } From f488b9f765346d9f7e918c31cb5bd07717b5989a Mon Sep 17 00:00:00 2001 From: Callum Dryden Date: Thu, 6 Oct 2016 15:19:27 +0000 Subject: [PATCH 05/76] Differentiate the expire from leave event At the moment we cannot see weather a user left a project due to their membership expiring of if they themselves opted to leave the project. This adds a new event type that allows us to make this differentiation. Note that is not really feasable to go back and reliably fix up the previous events. As a result the events for previous expire removals will remain the same however events of this nature going forward will be correctly represented. --- CHANGELOG.md | 1 + app/models/concerns/expirable.rb | 6 ++- app/models/event.rb | 9 +++- app/models/members/project_member.rb | 6 ++- app/services/event_create_service.rb | 4 ++ features/dashboard/dashboard.feature | 13 ------ features/steps/dashboard/dashboard.rb | 27 ------------ lib/event_filter.rb | 11 ++++- .../project_member_activity_index_spec.rb | 41 +++++++++++++++++++ spec/models/concerns/expirable_spec.rb | 31 ++++++++++++++ spec/models/event_spec.rb | 27 ++++++++++++ spec/models/members/project_member_spec.rb | 11 +++++ spec/services/event_create_service_spec.rb | 19 +++++++++ 13 files changed, 161 insertions(+), 45 deletions(-) create mode 100644 spec/features/dashboard/project_member_activity_index_spec.rb create mode 100644 spec/models/concerns/expirable_spec.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b018fc0d57..8cb848c3957 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) + - Adds user project membership expired event to clarify why user was removed (Callum Dryden) ## 8.13.0 (2016-10-22) diff --git a/app/models/concerns/expirable.rb b/app/models/concerns/expirable.rb index be93435453b..b66ba08dc59 100644 --- a/app/models/concerns/expirable.rb +++ b/app/models/concerns/expirable.rb @@ -5,11 +5,15 @@ module Expirable scope :expired, -> { where('expires_at <= ?', Time.current) } end + def expired? + expires? && expires_at <= Time.current + end + def expires? expires_at.present? end def expires_soon? - expires_at < 7.days.from_now + expires? && expires_at < 7.days.from_now end end diff --git a/app/models/event.rb b/app/models/event.rb index 0764cb8cabd..3993b35f96d 100644 --- a/app/models/event.rb +++ b/app/models/event.rb @@ -12,6 +12,7 @@ class Event < ActiveRecord::Base JOINED = 8 # User joined project LEFT = 9 # User left project DESTROYED = 10 + EXPIRED = 11 # User left project due to expiry RESET_PROJECT_ACTIVITY_INTERVAL = 1.hour @@ -115,6 +116,10 @@ class Event < ActiveRecord::Base action == LEFT end + def expired? + action == EXPIRED + end + def destroyed? action == DESTROYED end @@ -124,7 +129,7 @@ class Event < ActiveRecord::Base end def membership_changed? - joined? || left? + joined? || left? || expired? end def created_project? @@ -184,6 +189,8 @@ class Event < ActiveRecord::Base 'joined' elsif left? 'left' + elsif expired? + 'removed due to membership expiration from' elsif destroyed? 'destroyed' elsif commented? diff --git a/app/models/members/project_member.rb b/app/models/members/project_member.rb index 125f26369d7..e4880973117 100644 --- a/app/models/members/project_member.rb +++ b/app/models/members/project_member.rb @@ -121,7 +121,11 @@ class ProjectMember < Member end def post_destroy_hook - event_service.leave_project(self.project, self.user) + if expired? + event_service.expired_leave_project(self.project, self.user) + else + event_service.leave_project(self.project, self.user) + end super end diff --git a/app/services/event_create_service.rb b/app/services/event_create_service.rb index 07fc77001a5..e24cc66e0fe 100644 --- a/app/services/event_create_service.rb +++ b/app/services/event_create_service.rb @@ -62,6 +62,10 @@ class EventCreateService create_event(project, current_user, Event::LEFT) end + def expired_leave_project(project, current_user) + create_event(project, current_user, Event::EXPIRED) + end + def create_project(project, current_user) create_event(project, current_user, Event::CREATED) end diff --git a/features/dashboard/dashboard.feature b/features/dashboard/dashboard.feature index 1f4c9020731..b1d5e4a7acb 100644 --- a/features/dashboard/dashboard.feature +++ b/features/dashboard/dashboard.feature @@ -31,19 +31,6 @@ Feature: Dashboard And I click "Create Merge Request" link Then I see prefilled new Merge Request page - @javascript - Scenario: I should see User joined Project event - Given user with name "John Doe" joined project "Shop" - When I visit dashboard activity page - Then I should see "John Doe joined project Shop" event - - @javascript - Scenario: I should see User left Project event - Given user with name "John Doe" joined project "Shop" - And user with name "John Doe" left project "Shop" - When I visit dashboard activity page - Then I should see "John Doe left project Shop" event - @javascript Scenario: Sorting Issues Given I visit dashboard issues page diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb index a7d61bc28e0..b2bec369e0f 100644 --- a/features/steps/dashboard/dashboard.rb +++ b/features/steps/dashboard/dashboard.rb @@ -33,33 +33,6 @@ class Spinach::Features::Dashboard < Spinach::FeatureSteps expect(find("input#merge_request_target_branch").value).to eq "master" end - step 'user with name "John Doe" joined project "Shop"' do - user = create(:user, { name: "John Doe" }) - project.team << [user, :master] - Event.create( - project: project, - author_id: user.id, - action: Event::JOINED - ) - end - - step 'I should see "John Doe joined project Shop" event' do - expect(page).to have_content "John Doe joined project #{project.name_with_namespace}" - end - - step 'user with name "John Doe" left project "Shop"' do - user = User.find_by(name: "John Doe") - Event.create( - project: project, - author_id: user.id, - action: Event::LEFT - ) - end - - step 'I should see "John Doe left project Shop" event' do - expect(page).to have_content "John Doe left project #{project.name_with_namespace}" - end - step 'I have group with projects' do @group = create(:group) @project = create(:project, namespace: @group) diff --git a/lib/event_filter.rb b/lib/event_filter.rb index 96e70e37e8f..21f6a9a762b 100644 --- a/lib/event_filter.rb +++ b/lib/event_filter.rb @@ -45,9 +45,16 @@ class EventFilter when EventFilter.comments actions = [Event::COMMENTED] when EventFilter.team - actions = [Event::JOINED, Event::LEFT] + actions = [Event::JOINED, Event::LEFT, Event::EXPIRED] when EventFilter.all - actions = [Event::PUSHED, Event::MERGED, Event::COMMENTED, Event::JOINED, Event::LEFT] + actions = [ + Event::PUSHED, + Event::MERGED, + Event::COMMENTED, + Event::JOINED, + Event::LEFT, + Event::EXPIRED + ] end events.where(action: actions) diff --git a/spec/features/dashboard/project_member_activity_index_spec.rb b/spec/features/dashboard/project_member_activity_index_spec.rb new file mode 100644 index 00000000000..ba77093a6d4 --- /dev/null +++ b/spec/features/dashboard/project_member_activity_index_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +feature 'Project member activity', feature: true, js: true do + include WaitForAjax + + let(:user) { create(:user) } + let(:project) { create(:empty_project, :public, name: 'x', namespace: user.namespace) } + + before do + project.team << [user, :master] + end + + def visit_activities_and_wait_with_event(event_type) + Event.create(project: project, author_id: user.id, action: event_type) + visit activity_namespace_project_path(project.namespace.path, project.path) + wait_for_ajax + end + + subject { page.find(".event-title").text } + + context 'when a user joins the project' do + before { visit_activities_and_wait_with_event(Event::JOINED) } + + it { is_expected.to eq("#{user.name} joined project") } + end + + context 'when a user leaves the project' do + before { visit_activities_and_wait_with_event(Event::LEFT) } + + it { is_expected.to eq("#{user.name} left project") } + end + + context 'when a users membership expires for the project' do + before { visit_activities_and_wait_with_event(Event::EXPIRED) } + + it "presents the correct message" do + message = "#{user.name} removed due to membership expiration from project" + is_expected.to eq(message) + end + end +end diff --git a/spec/models/concerns/expirable_spec.rb b/spec/models/concerns/expirable_spec.rb new file mode 100644 index 00000000000..f7b436f32e6 --- /dev/null +++ b/spec/models/concerns/expirable_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe Expirable do + describe 'ProjectMember' do + let(:no_expire) { create(:project_member) } + let(:expire_later) { create(:project_member, expires_at: Time.current + 6.days) } + let(:expired) { create(:project_member, expires_at: Time.current - 6.days) } + + describe '.expired' do + it { expect(ProjectMember.expired).to match_array([expired]) } + end + + describe '#expired?' do + it { expect(no_expire.expired?).to eq(false) } + it { expect(expire_later.expired?).to eq(false) } + it { expect(expired.expired?).to eq(true) } + end + + describe '#expires?' do + it { expect(no_expire.expires?).to eq(false) } + it { expect(expire_later.expires?).to eq(true) } + it { expect(expired.expires?).to eq(true) } + end + + describe '#expires_soon?' do + it { expect(no_expire.expires_soon?).to eq(false) } + it { expect(expire_later.expires_soon?).to eq(true) } + it { expect(expired.expires_soon?).to eq(true) } + end + end +end diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 733b79079ed..aca49be2942 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -40,6 +40,33 @@ describe Event, models: true do end end + describe '#membership_changed?' do + context "created" do + subject { build(:event, action: Event::CREATED).membership_changed? } + it { is_expected.to be_falsey } + end + + context "updated" do + subject { build(:event, action: Event::UPDATED).membership_changed? } + it { is_expected.to be_falsey } + end + + context "expired" do + subject { build(:event, action: Event::EXPIRED).membership_changed? } + it { is_expected.to be_truthy } + end + + context "left" do + subject { build(:event, action: Event::LEFT).membership_changed? } + it { is_expected.to be_truthy } + end + + context "joined" do + subject { build(:event, action: Event::JOINED).membership_changed? } + it { is_expected.to be_truthy } + end + end + describe '#note?' do subject { Event.new(project: target.project, target: target) } diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb index d85a1c1e3b2..b2fe96e2e02 100644 --- a/spec/models/members/project_member_spec.rb +++ b/spec/models/members/project_member_spec.rb @@ -54,6 +54,17 @@ describe ProjectMember, models: true do master_todos end + it "creates an expired event when left due to expiry" do + expired = create(:project_member, project: project, expires_at: Time.now - 6.days) + expired.destroy + expect(Event.first.action).to eq(Event::EXPIRED) + end + + it "creates a left event when left due to leave" do + master.destroy + expect(Event.first.action).to eq(Event::LEFT) + end + it "destroys itself and delete associated todos" do expect(owner.user.todos.size).to eq(2) expect(master.user.todos.size).to eq(3) diff --git a/spec/services/event_create_service_spec.rb b/spec/services/event_create_service_spec.rb index 16a9956fe7f..b7dc99ed887 100644 --- a/spec/services/event_create_service_spec.rb +++ b/spec/services/event_create_service_spec.rb @@ -110,4 +110,23 @@ describe EventCreateService, services: true do end end end + + describe 'Project' do + let(:user) { create :user } + let(:project) { create(:empty_project) } + + describe '#join_project' do + subject { service.join_project(project, user) } + + it { is_expected.to be_truthy } + it { expect { subject }.to change { Event.count }.from(0).to(1) } + end + + describe '#expired_leave_project' do + subject { service.expired_leave_project(project, user) } + + it { is_expected.to be_truthy } + it { expect { subject }.to change { Event.count }.from(0).to(1) } + end + end end From 7077162af28b589c00bed5603cc4f18653cc5678 Mon Sep 17 00:00:00 2001 From: Paco Guzman Date: Wed, 19 Oct 2016 21:58:12 +0200 Subject: [PATCH 06/76] Simpler arguments passed to named_route on toggle_award_url helper method --- CHANGELOG.md | 1 + app/helpers/award_emoji_helper.rb | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8cb848c3957..dfde2cc81e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) - Adds user project membership expired event to clarify why user was removed (Callum Dryden) + - Simpler arguments passed to named_route on toggle_award_url helper method ## 8.13.0 (2016-10-22) diff --git a/app/helpers/award_emoji_helper.rb b/app/helpers/award_emoji_helper.rb index 592ffe7b89f..167b09e678f 100644 --- a/app/helpers/award_emoji_helper.rb +++ b/app/helpers/award_emoji_helper.rb @@ -3,8 +3,8 @@ module AwardEmojiHelper return url_for([:toggle_award_emoji, awardable]) unless @project if awardable.is_a?(Note) - # We render a list of notes very frequently and calling the specific method is a lot faster than the generic one (6.5x) - toggle_award_emoji_namespace_project_note_url(namespace_id: @project.namespace, project_id: @project, id: awardable.id) + # We render a list of notes very frequently and calling the specific method is a lot faster than the generic one (4.5x) + toggle_award_emoji_namespace_project_note_url(@project.namespace, @project, awardable.id) else url_for([:toggle_award_emoji, @project.namespace.becomes(Namespace), @project, awardable]) end From 6278ee5ab0c4c48d3c8a12ade85c263fefb935d2 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Thu, 20 Oct 2016 08:57:23 +0900 Subject: [PATCH 07/76] Fix a broken table in Project API doc --- CHANGELOG.md | 1 + doc/api/projects.md | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfde2cc81e5..399a7f65267 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,6 +135,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Delete dynamic environments - Fix buggy iOS tooltip layering behavior. - Make guests unable to view MRs on private projects + - Fix broken Project API docs (Takuya Noguchi) ## 8.12.7 diff --git a/doc/api/projects.md b/doc/api/projects.md index b7791b4748a..77d6bd6b5c2 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1333,8 +1333,8 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | -| `query` (required) - A string contained in the project name -| `per_page` (optional) - number of projects to return per page -| `page` (optional) - the page to retrieve -| `order_by` (optional) - Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields +| `query` | string | yes | A string contained in the project name | +| `per_page` | integer | no | number of projects to return per page | +| `page` | integer | no | the page to retrieve | +| `order_by` | string | no | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields | | `sort` | string | no | Return requests sorted in `asc` or `desc` order | From 6fd561d282098e71a523cf1b73396b440ef13e63 Mon Sep 17 00:00:00 2001 From: Takuya Noguchi Date: Thu, 20 Oct 2016 08:58:35 +0900 Subject: [PATCH 08/76] Remove pagination description from individual doc --- doc/api/projects.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/doc/api/projects.md b/doc/api/projects.md index 77d6bd6b5c2..b69db90e70d 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1334,7 +1334,5 @@ Parameters: | Attribute | Type | Required | Description | | --------- | ---- | -------- | ----------- | | `query` | string | yes | A string contained in the project name | -| `per_page` | integer | no | number of projects to return per page | -| `page` | integer | no | the page to retrieve | | `order_by` | string | no | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields | | `sort` | string | no | Return requests sorted in `asc` or `desc` order | From 7a184617199fa01c040857ed3a5d2a071944760a Mon Sep 17 00:00:00 2001 From: Valery Sizov Date: Wed, 19 Oct 2016 19:43:04 +0300 Subject: [PATCH 09/76] Refactoring find_commits functionality --- app/controllers/projects/commits_controller.rb | 2 +- app/models/repository.rb | 9 ++++++--- lib/gitlab/project_search_results.rb | 6 +----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb index a52c614b259..c2e7bf1ffec 100644 --- a/app/controllers/projects/commits_controller.rb +++ b/app/controllers/projects/commits_controller.rb @@ -13,7 +13,7 @@ class Projects::CommitsController < Projects::ApplicationController @commits = if search.present? - @repository.find_commits_by_message(search, @ref, @path, @limit, @offset).compact + @repository.find_commits_by_message(search, @ref, @path, @limit, @offset) else @repository.commits(@ref, path: @path, limit: @limit, offset: @offset) end diff --git a/app/models/repository.rb b/app/models/repository.rb index 72e473871fa..1b7f20a2134 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -109,6 +109,10 @@ class Repository end def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset = 0) + unless exists? && has_visible_content? && query.present? + return [] + end + ref ||= root_ref args = %W( @@ -117,9 +121,8 @@ class Repository ) args = args.concat(%W(-- #{path})) if path.present? - git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp) - commits = git_log_results.map { |c| commit(c) } - commits + git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines + git_log_results.map { |c| commit(c.chomp) }.compact end def find_branch(name, fresh_repo: true) diff --git a/lib/gitlab/project_search_results.rb b/lib/gitlab/project_search_results.rb index 5b9cfaeb2f8..24733435a5a 100644 --- a/lib/gitlab/project_search_results.rb +++ b/lib/gitlab/project_search_results.rb @@ -73,11 +73,7 @@ module Gitlab end def commits - if project.empty_repo? || query.blank? - [] - else - project.repository.find_commits_by_message(query).compact - end + project.repository.find_commits_by_message(query) end def project_ids_relation From 17ae807ae3e03fcc67f557c4ad7d5c6e0502065e Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Fri, 14 Oct 2016 19:38:41 -0300 Subject: [PATCH 10/76] Create project feature when project is created --- CHANGELOG.md | 1 + app/models/project.rb | 7 +---- ...5_generate_project_feature_for_projects.rb | 28 +++++++++++++++++++ db/schema.rb | 2 +- spec/models/project_spec.rb | 14 ++++++++-- 5 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20161019213545_generate_project_feature_for_projects.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 399a7f65267..670404e4fce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun) - Cancelled pipelines could be retried. !6927 - Updating verbiage on git basics to be more intuitive + - Fix project_feature record not generated on project creation - Clarify documentation for Runners API (Gennady Trafimenkov) - The instrumentation for Banzai::Renderer has been restored - Change user & group landing page routing from /u/:username to /:username diff --git a/app/models/project.rb b/app/models/project.rb index 653c38322c5..6685baab699 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -32,8 +32,8 @@ class Project < ActiveRecord::Base default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled } after_create :ensure_dir_exist + after_create :create_project_feature, unless: :project_feature after_save :ensure_dir_exist, if: :namespace_id_changed? - after_initialize :setup_project_feature # set last_activity_at to the same as created_at after_create :set_last_activity_at @@ -1310,11 +1310,6 @@ class Project < ActiveRecord::Base "projects/#{id}/pushes_since_gc" end - # Prevents the creation of project_feature record for every project - def setup_project_feature - build_project_feature unless project_feature - end - def default_branch_protected? current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_FULL || current_application_settings.default_branch_protection == Gitlab::Access::PROTECTION_DEV_CAN_MERGE diff --git a/db/migrate/20161019213545_generate_project_feature_for_projects.rb b/db/migrate/20161019213545_generate_project_feature_for_projects.rb new file mode 100644 index 00000000000..4554e14b0df --- /dev/null +++ b/db/migrate/20161019213545_generate_project_feature_for_projects.rb @@ -0,0 +1,28 @@ +class GenerateProjectFeatureForProjects < ActiveRecord::Migration + DOWNTIME = true + + DOWNTIME_REASON = <<-HEREDOC + Application was eager loading project_feature for all projects generating an extra query + everytime a project was fetched. We removed that behavior to avoid the extra query, this migration + makes sure all projects have a project_feature record associated. + HEREDOC + + def up + # Generate enabled values for each project feature 20, 20, 20, 20, 20 + # All features are enabled by default + enabled_values = [ProjectFeature::ENABLED] * 5 + + execute <<-EOF.strip_heredoc + INSERT INTO project_features + (project_id, merge_requests_access_level, builds_access_level, + issues_access_level, snippets_access_level, wiki_access_level) + (SELECT projects.id, #{enabled_values.join(',')} FROM projects LEFT OUTER JOIN project_features + ON project_features.project_id = projects.id + WHERE project_features.id IS NULL) + EOF + end + + def down + "Not needed" + end +end diff --git a/db/schema.rb b/db/schema.rb index f777ed39378..f5c01511195 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: 20161018024550) do +ActiveRecord::Schema.define(version: 20161019213545) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index e6d98e25d0b..f4dda1ee558 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -67,6 +67,14 @@ describe Project, models: true do it { is_expected.to have_many(:notification_settings).dependent(:destroy) } it { is_expected.to have_many(:forks).through(:forked_project_links) } + context 'after create' do + it "creates project feature" do + project = FactoryGirl.build(:project) + + expect { project.save }.to change{ project.project_feature.present? }.from(false).to(true) + end + end + describe '#members & #requesters' do let(:project) { create(:project, :public) } let(:requester) { create(:user) } @@ -531,9 +539,9 @@ describe Project, models: true do end describe '#has_wiki?' do - let(:no_wiki_project) { build(:project, wiki_enabled: false, has_external_wiki: false) } - let(:wiki_enabled_project) { build(:project) } - let(:external_wiki_project) { build(:project, has_external_wiki: true) } + let(:no_wiki_project) { create(:project, wiki_access_level: ProjectFeature::DISABLED, has_external_wiki: false) } + let(:wiki_enabled_project) { create(:project) } + let(:external_wiki_project) { create(:project, has_external_wiki: true) } it 'returns true if project is wiki enabled or has external wiki' do expect(wiki_enabled_project).to have_wiki From 89408aed1f32d760a879c9e26563b956f498793d Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Thu, 20 Oct 2016 12:10:27 +0200 Subject: [PATCH 11/76] Make label API spec independent of order --- spec/requests/api/labels_spec.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/requests/api/labels_spec.rb b/spec/requests/api/labels_spec.rb index 1da9988978b..867bc615b97 100644 --- a/spec/requests/api/labels_spec.rb +++ b/spec/requests/api/labels_spec.rb @@ -22,8 +22,7 @@ describe API::API, api: true do expect(response).to have_http_status(200) expect(json_response).to be_an Array expect(json_response.size).to eq(2) - expect(json_response.first['name']).to eq(group_label.name) - expect(json_response.second['name']).to eq(label1.name) + expect(json_response.map { |l| l['name'] }).to match_array([group_label.name, label1.name]) end end From ae0a9336f106b14a7abc39e5a32fe8491dd9b544 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 20 Oct 2016 10:27:30 +0100 Subject: [PATCH 12/76] Removed code from project members controller This code was meant to be added to another branch as an expirement, but instead was commited to wrong branch --- .../projects/project_members_controller.rb | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/app/controllers/projects/project_members_controller.rb b/app/controllers/projects/project_members_controller.rb index 37a86ed0523..2a07d154853 100644 --- a/app/controllers/projects/project_members_controller.rb +++ b/app/controllers/projects/project_members_controller.rb @@ -32,21 +32,6 @@ class Projects::ProjectMembersController < Projects::ApplicationController current_user: current_user ) - if params[:group_ids].present? - group_ids = params[:group_ids].split(',') - groups = Group.where(id: group_ids) - - groups.each do |group| - next unless can?(current_user, :read_group, group) - - project.project_group_links.create( - group: group, - group_access: params[:access_level], - expires_at: params[:expires_at] - ) - end - end - redirect_to namespace_project_project_members_path(@project.namespace, @project) end From 583b79a46875b14405061f3036cf041c44241c62 Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Thu, 20 Oct 2016 12:59:39 +0200 Subject: [PATCH 13/76] Restrict ProjectCacheWorker jobs to one per 15 min This ensures ProjectCacheWorker jobs for a given project are performed at most once per 15 minutes. This should reduce disk load a bit in cases where there are multiple pushes happening (which should schedule multiple ProjectCacheWorker jobs). --- CHANGELOG.md | 3 +- app/workers/project_cache_worker.rb | 27 ++++++++++++++++ spec/workers/project_cache_worker_spec.rb | 38 +++++++++++++++++------ 3 files changed, 57 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 670404e4fce..98cffab8c03 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) - Adds user project membership expired event to clarify why user was removed (Callum Dryden) - - Simpler arguments passed to named_route on toggle_award_url helper method + - Simpler arguments passed to named_route on toggle_award_url helper method ## 8.13.0 (2016-10-22) @@ -36,6 +36,7 @@ Please view this file on the master branch, on stable branches it's out of date. - AbstractReferenceFilter caches project_refs on RequestStore when active - Replaced the check sign to arrow in the show build view. !6501 - Add a /wip slash command to toggle the Work In Progress status of a merge request. !6259 (tbalthazar) + - ProjectCacheWorker updates caches at most once per 15 minutes per project - Fix Error 500 when viewing old merge requests with bad diff data - Create a new /templates namespace for the /licenses, /gitignores and /gitlab_ci_ymls API endpoints. !5717 (tbalthazar) - Speed-up group milestones show page diff --git a/app/workers/project_cache_worker.rb b/app/workers/project_cache_worker.rb index ccefd0f71a0..0d524e88dc3 100644 --- a/app/workers/project_cache_worker.rb +++ b/app/workers/project_cache_worker.rb @@ -1,9 +1,30 @@ +# Worker for updating any project specific caches. +# +# This worker runs at most once every 15 minutes per project. This is to ensure +# that multiple instances of jobs for this worker don't hammer the underlying +# storage engine as much. class ProjectCacheWorker include Sidekiq::Worker sidekiq_options queue: :default + LEASE_TIMEOUT = 15.minutes.to_i + def perform(project_id) + if try_obtain_lease_for(project_id) + Rails.logger. + info("Obtained ProjectCacheWorker lease for project #{project_id}") + else + Rails.logger. + info("Could not obtain ProjectCacheWorker lease for project #{project_id}") + + return + end + + update_caches(project_id) + end + + def update_caches(project_id) project = Project.find(project_id) return unless project.repository.exists? @@ -15,4 +36,10 @@ class ProjectCacheWorker project.repository.build_cache end end + + def try_obtain_lease_for(project_id) + Gitlab::ExclusiveLease. + new("project_cache_worker:#{project_id}", timeout: LEASE_TIMEOUT). + try_obtain + end end diff --git a/spec/workers/project_cache_worker_spec.rb b/spec/workers/project_cache_worker_spec.rb index 5785a6a06ff..f5b60b90d11 100644 --- a/spec/workers/project_cache_worker_spec.rb +++ b/spec/workers/project_cache_worker_spec.rb @@ -6,21 +6,39 @@ describe ProjectCacheWorker do subject { described_class.new } describe '#perform' do - it 'updates project cache data' do - expect_any_instance_of(Repository).to receive(:size) - expect_any_instance_of(Repository).to receive(:commit_count) + context 'when an exclusive lease can be obtained' do + before do + allow(subject).to receive(:try_obtain_lease_for).with(project.id). + and_return(true) + end - expect_any_instance_of(Project).to receive(:update_repository_size) - expect_any_instance_of(Project).to receive(:update_commit_count) + it 'updates project cache data' do + expect_any_instance_of(Repository).to receive(:size) + expect_any_instance_of(Repository).to receive(:commit_count) - subject.perform(project.id) + expect_any_instance_of(Project).to receive(:update_repository_size) + expect_any_instance_of(Project).to receive(:update_commit_count) + + subject.perform(project.id) + end + + it 'handles missing repository data' do + expect_any_instance_of(Repository).to receive(:exists?).and_return(false) + expect_any_instance_of(Repository).not_to receive(:size) + + subject.perform(project.id) + end end - it 'handles missing repository data' do - expect_any_instance_of(Repository).to receive(:exists?).and_return(false) - expect_any_instance_of(Repository).not_to receive(:size) + context 'when an exclusive lease can not be obtained' do + it 'does nothing' do + allow(subject).to receive(:try_obtain_lease_for).with(project.id). + and_return(false) - subject.perform(project.id) + expect(subject).not_to receive(:update_caches) + + subject.perform(project.id) + end end end end From bd3548c19e00cfadbc5d2c122b968090a160afbc Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Thu, 13 Oct 2016 13:58:31 -0500 Subject: [PATCH 14/76] Change input order on Sign In form for better tabbing. This *unreverts* 8751491b, which was mistakenly reverted in !6328. It also changes the implementation of the original commit to work with the new login styling and markup. cc: @ClemMakesApps --- app/assets/stylesheets/pages/login.scss | 17 +++++++++++++++++ app/views/devise/sessions/_new_base.html.haml | 4 ++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/pages/login.scss b/app/assets/stylesheets/pages/login.scss index e6d9be5185d..bdb13bee178 100644 --- a/app/assets/stylesheets/pages/login.scss +++ b/app/assets/stylesheets/pages/login.scss @@ -53,6 +53,7 @@ margin: 0 0 10px; } + .login-footer { margin-top: 10px; @@ -246,3 +247,19 @@ padding: 65px; // height of footer + bottom padding of email confirmation link } } + +// For sign in pane only, to improve tab order, the following removes the submit button from +// normal document flow and pins it to the bottom of the form. For context, see !6867 & !6928 + +.login-box { + .new_user { + position: relative; + padding-bottom: 35px; + } + + .move-submit-down { + position: absolute; + width: 100%; + bottom: 0; + } +} diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml index a96b579c593..525e7d99d71 100644 --- a/app/views/devise/sessions/_new_base.html.haml +++ b/app/views/devise/sessions/_new_base.html.haml @@ -5,6 +5,8 @@ %div.form-group = f.label :password = f.password_field :password, class: "form-control bottom", required: true, title: "This field is required." + %div.submit-container.move-submit-down + = f.submit "Sign in", class: "btn btn-save" - if devise_mapping.rememberable? .remember-me.checkbox %label{for: "user_remember_me"} @@ -12,5 +14,3 @@ %span Remember me .pull-right = link_to "Forgot your password?", new_password_path(resource_name) - %div.submit-container - = f.submit "Sign in", class: "btn btn-save" From a2f64619af8da5c5b09ead7554e5613368f80dae Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Sun, 18 Sep 2016 17:20:40 +0100 Subject: [PATCH 15/76] Added tooltip with jobs full name to build items in graph Added status to build tooltip and removed status icon tooltip Added Pipelines class to force tooltips ontop of the dropdown, we cannot do this with data attributes because dropdown toggle is already set Corrected dispatcher invocation --- app/assets/javascripts/pipelines.js.es6 | 11 +++++++++++ app/helpers/ci_status_helper.rb | 4 ++-- app/views/projects/commit/_pipeline_stage.html.haml | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js.es6 index a7624de6089..dd320c52e44 100644 --- a/app/assets/javascripts/pipelines.js.es6 +++ b/app/assets/javascripts/pipelines.js.es6 @@ -4,6 +4,17 @@ constructor() { $(document).off('click', '.toggle-pipeline-btn').on('click', '.toggle-pipeline-btn', this.toggleGraph); this.addMarginToBuildColumns(); + this.initGroupedPipelineTooltips(); + } + + initGroupedPipelineTooltips() { + $('.dropdown-menu-toggle', $('.grouped-pipeline-dropdown').parent()).each(function() { + const $this = $(this); + $this.tooltip({ + title: $this.data('tooltip-title'), + placement: 'bottom' + }); + }); } toggleGraph() { diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index b7f48630bd4..0e727f3dcf0 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -71,10 +71,10 @@ module CiStatusHelper Ci::Runner.shared.blank? end - def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '', container: 'body') + def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '', container: 'body', show_tooltip: true) klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}" title = "#{type.titleize}: #{ci_label_for_status(status)}" - data = { toggle: 'tooltip', placement: tooltip_placement, container: container } + data = { toggle: 'tooltip', placement: tooltip_placement, container: container } if show_tooltip if path link_to ci_icon_for_status(status), path, diff --git a/app/views/projects/commit/_pipeline_stage.html.haml b/app/views/projects/commit/_pipeline_stage.html.haml index 289aa5178b1..993fc89d23d 100644 --- a/app/views/projects/commit/_pipeline_stage.html.haml +++ b/app/views/projects/commit/_pipeline_stage.html.haml @@ -5,7 +5,7 @@ - is_playable = status.playable? && can?(current_user, :update_build, @project) %li.build{ class: ("playable" if is_playable) } .curve - .build-content + .build-content{ { data: { toggle: 'tooltip', title: "#{group_name} - #{status.status}", placement: 'bottom' } } } = render "projects/#{status.to_partial_path}_pipeline", subject: status - else %li.build From 33f3c3792abe2cbf1b68c0ce3414edb8e199be1e Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Fri, 7 Oct 2016 19:30:34 +0100 Subject: [PATCH 16/76] Added dyanmic position adjustment Added tooltips for dropdown items Reverted pretty much everything in favour of a DOM approach Simplified JS --- app/assets/javascripts/pipelines.js.es6 | 11 ----------- app/assets/stylesheets/pages/pipelines.scss | 14 ++++++++++---- app/helpers/ci_status_helper.rb | 4 ++-- .../projects/ci/builds/_build_pipeline.html.haml | 4 ++-- .../projects/commit/_pipeline_stage.html.haml | 2 +- .../commit/_pipeline_status_group.html.haml | 2 +- .../_generic_commit_status_pipeline.html.haml | 13 +++++++------ 7 files changed, 23 insertions(+), 27 deletions(-) diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js.es6 index dd320c52e44..a7624de6089 100644 --- a/app/assets/javascripts/pipelines.js.es6 +++ b/app/assets/javascripts/pipelines.js.es6 @@ -4,17 +4,6 @@ constructor() { $(document).off('click', '.toggle-pipeline-btn').on('click', '.toggle-pipeline-btn', this.toggleGraph); this.addMarginToBuildColumns(); - this.initGroupedPipelineTooltips(); - } - - initGroupedPipelineTooltips() { - $('.dropdown-menu-toggle', $('.grouped-pipeline-dropdown').parent()).each(function() { - const $this = $(this); - $this.tooltip({ - title: $this.data('tooltip-title'), - placement: 'bottom' - }); - }); } toggleGraph() { diff --git a/app/assets/stylesheets/pages/pipelines.scss b/app/assets/stylesheets/pages/pipelines.scss index dfaf1ab732d..5b8dc7f8c40 100644 --- a/app/assets/stylesheets/pages/pipelines.scss +++ b/app/assets/stylesheets/pages/pipelines.scss @@ -369,10 +369,6 @@ &:hover { background-color: $gray-lighter; - - .dropdown-menu-toggle { - background-color: transparent; - } } &.playable { @@ -402,6 +398,15 @@ } } + .tooltip { + white-space: nowrap; + + .tooltip-inner { + overflow: hidden; + text-overflow: ellipsis; + } + } + .ci-status-text { width: 135px; white-space: nowrap; @@ -419,6 +424,7 @@ } .dropdown-menu-toggle { + background-color: transparent; border: none; width: auto; padding: 0; diff --git a/app/helpers/ci_status_helper.rb b/app/helpers/ci_status_helper.rb index 0e727f3dcf0..b7f48630bd4 100644 --- a/app/helpers/ci_status_helper.rb +++ b/app/helpers/ci_status_helper.rb @@ -71,10 +71,10 @@ module CiStatusHelper Ci::Runner.shared.blank? end - def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '', container: 'body', show_tooltip: true) + def render_status_with_link(type, status, path = nil, tooltip_placement: 'auto left', cssclass: '', container: 'body') klass = "ci-status-link ci-status-icon-#{status.dasherize} #{cssclass}" title = "#{type.titleize}: #{ci_label_for_status(status)}" - data = { toggle: 'tooltip', placement: tooltip_placement, container: container } if show_tooltip + data = { toggle: 'tooltip', placement: tooltip_placement, container: container } if path link_to ci_icon_for_status(status), path, diff --git a/app/views/projects/ci/builds/_build_pipeline.html.haml b/app/views/projects/ci/builds/_build_pipeline.html.haml index 017d3ff6af2..55965172d3f 100644 --- a/app/views/projects/ci/builds/_build_pipeline.html.haml +++ b/app/views/projects/ci/builds/_build_pipeline.html.haml @@ -1,10 +1,10 @@ - is_playable = subject.playable? && can?(current_user, :update_build, @project) - if is_playable - = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, title: 'Play' do + = link_to play_namespace_project_build_path(subject.project.namespace, subject.project, subject, return_to: request.original_url), method: :post, data: { toggle: 'tooltip', title: "#{subject.name} - play", container: '.pipeline-graph', placement: 'bottom' } do = render_status_with_link('build', 'play') .ci-status-text= subject.name - elsif can?(current_user, :read_build, @project) - = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject) do + = link_to namespace_project_build_path(subject.project.namespace, subject.project, subject), data: { toggle: 'tooltip', title: "#{subject.name} - #{subject.status}", container: '.pipeline-graph', placement: 'bottom' } do %span.ci-status-icon = render_status_with_link('build', subject.status) .ci-status-text= subject.name diff --git a/app/views/projects/commit/_pipeline_stage.html.haml b/app/views/projects/commit/_pipeline_stage.html.haml index 993fc89d23d..289aa5178b1 100644 --- a/app/views/projects/commit/_pipeline_stage.html.haml +++ b/app/views/projects/commit/_pipeline_stage.html.haml @@ -5,7 +5,7 @@ - is_playable = status.playable? && can?(current_user, :update_build, @project) %li.build{ class: ("playable" if is_playable) } .curve - .build-content{ { data: { toggle: 'tooltip', title: "#{group_name} - #{status.status}", placement: 'bottom' } } } + .build-content = render "projects/#{status.to_partial_path}_pipeline", subject: status - else %li.build diff --git a/app/views/projects/commit/_pipeline_status_group.html.haml b/app/views/projects/commit/_pipeline_status_group.html.haml index 5d0d5ba0262..f2d71fa6989 100644 --- a/app/views/projects/commit/_pipeline_status_group.html.haml +++ b/app/views/projects/commit/_pipeline_status_group.html.haml @@ -1,5 +1,5 @@ - group_status = CommitStatus.where(id: subject).status -%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown' } } +%button.dropdown-menu-toggle.has-tooltip{ type: 'button', data: { toggle: 'dropdown', title: "#{name} - #{group_status}" } } %span.ci-status-icon = render_status_with_link('build', group_status) %span.ci-status-text diff --git a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml index 0a66d60accc..c45b73e4225 100644 --- a/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml +++ b/app/views/projects/generic_commit_statuses/_generic_commit_status_pipeline.html.haml @@ -1,9 +1,10 @@ -- if subject.target_url - = link_to subject.target_url do +%a{ data: { toggle: 'tooltip', title: "#{subject.name} - #{subject.status}", container: '.pipeline-graph', placement: 'bottom' } } + - if subject.target_url + = link_to subject.target_url do + %span.ci-status-icon + = render_status_with_link('commit status', subject.status) + %span.ci-status-text= subject.name + - else %span.ci-status-icon = render_status_with_link('commit status', subject.status) %span.ci-status-text= subject.name -- else - %span.ci-status-icon - = render_status_with_link('commit status', subject.status) - %span.ci-status-text= subject.name From b6c859974307b71a82544cb137196b1bcd7ef7ef Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 19 Oct 2016 16:53:12 +0100 Subject: [PATCH 17/76] Revert "Add #closed_without_source_project?" This reverts commit 31c37c6c38258684fc92e0d91119c33872e39034. See #23341 --- app/models/merge_request.rb | 10 ++---- .../projects/merge_requests/_show.html.haml | 31 ++++++++---------- spec/models/merge_request_spec.rb | 32 ------------------- 3 files changed, 16 insertions(+), 57 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 0cc0b3c2a0e..d32bc9f882f 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -333,11 +333,7 @@ class MergeRequest < ActiveRecord::Base end def closed_without_fork? - closed? && forked_source_project_missing? - end - - def closed_without_source_project? - closed? && !source_project + closed? && (forked_source_project_missing? || !source_project) end def forked_source_project_missing? @@ -348,9 +344,7 @@ class MergeRequest < ActiveRecord::Base end def reopenable? - return false if closed_without_fork? || closed_without_source_project? || merged? - - closed? + source_branch_exists? && closed? end def ensure_merge_request_diff diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index cd98aaf8d75..fe90383b00f 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -26,19 +26,17 @@ %ul.dropdown-menu.dropdown-menu-align-right %li= link_to "Email Patches", merge_request_path(@merge_request, format: :patch) %li= link_to "Plain Diff", merge_request_path(@merge_request, format: :diff) - - unless @merge_request.closed_without_fork? - .normal - %span Request to merge - %span.label-branch= source_branch_with_namespace(@merge_request) - %span into - %span.label-branch - = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch) - - if @merge_request.open? && @merge_request.diverged_from_target_branch? - %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) + .normal + %span Request to merge + %span.label-branch= source_branch_with_namespace(@merge_request) + %span into + %span.label-branch + = link_to @merge_request.target_branch, namespace_project_commits_path(@project.namespace, @project, @merge_request.target_branch) + - if @merge_request.open? && @merge_request.diverged_from_target_branch? + %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) - - unless @merge_request.closed_without_source_project? - = render "projects/merge_requests/show/how_to_merge" - = render "projects/merge_requests/widget/show.html.haml" + = render "projects/merge_requests/show/how_to_merge" + = render "projects/merge_requests/widget/show.html.haml" - if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user) .light.prepend-top-default.append-bottom-default @@ -52,11 +50,10 @@ = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do Discussion %span.badge= @merge_request.mr_and_commit_notes.user.count - - unless @merge_request.closed_without_source_project? - %li.commits-tab - = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do - Commits - %span.badge= @commits_count + %li.commits-tab + = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do + Commits + %span.badge= @commits_count - if @pipeline %li.pipelines-tab = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 6db5e7f7d80..ee003a9d18f 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1274,38 +1274,6 @@ describe MergeRequest, models: true do end end - describe '#closed_without_source_project?' do - let(:project) { create(:project) } - let(:user) { create(:user) } - let(:fork_project) { create(:project, forked_from_project: project, namespace: user.namespace) } - let(:destroy_service) { Projects::DestroyService.new(fork_project, user) } - - context 'when the merge request is closed' do - let(:closed_merge_request) do - create(:closed_merge_request, - source_project: fork_project, - target_project: project) - end - - it 'returns false if the source project exists' do - expect(closed_merge_request.closed_without_source_project?).to be_falsey - end - - it 'returns true if the source project does not exist' do - destroy_service.execute - closed_merge_request.reload - - expect(closed_merge_request.closed_without_source_project?).to be_truthy - end - end - - context 'when the merge request is open' do - it 'returns false' do - expect(subject.closed_without_source_project?).to be_falsey - end - end - end - describe '#reopenable?' do context 'when the merge request is closed' do it 'returns true' do From f00ee5c2ed9a0812b6337e52814756c560c879c8 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 19 Oct 2016 17:13:04 +0100 Subject: [PATCH 18/76] Fix the merge request view when source projects or branches are removed --- .../projects/merge_requests_controller.rb | 2 +- app/helpers/merge_requests_helper.rb | 10 +++++++--- app/models/merge_request.rb | 15 ++++++--------- app/views/projects/merge_requests/_show.html.haml | 13 ++++++++----- .../merge_requests/created_from_fork_spec.rb | 14 ++++++++++++++ 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 0f593d1a936..55ea31e48a0 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -554,7 +554,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController def define_pipelines_vars @pipelines = @merge_request.all_pipelines - if @pipelines.any? + if @pipelines.present? @pipeline = @pipelines.first @statuses = @pipeline.statuses.relevant end diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb index 249cb44e9d5..a6659ea2fd1 100644 --- a/app/helpers/merge_requests_helper.rb +++ b/app/helpers/merge_requests_helper.rb @@ -86,11 +86,15 @@ module MergeRequestsHelper end def source_branch_with_namespace(merge_request) - branch = link_to(merge_request.source_branch, namespace_project_commits_path(merge_request.source_project.namespace, merge_request.source_project, merge_request.source_branch)) + namespace = merge_request.source_project_namespace + branch = merge_request.source_branch + + if merge_request.source_branch_exists? + namespace = link_to(namespace, project_path(merge_request.source_project)) + branch = link_to(branch, namespace_project_commits_path(merge_request.source_project.namespace, merge_request.source_project, merge_request.source_branch)) + end if merge_request.for_fork? - namespace = link_to(merge_request.source_project_namespace, - project_path(merge_request.source_project)) namespace + ":" + branch else branch diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index d32bc9f882f..45fa8af60e5 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -333,7 +333,7 @@ class MergeRequest < ActiveRecord::Base end def closed_without_fork? - closed? && (forked_source_project_missing? || !source_project) + closed? && forked_source_project_missing? end def forked_source_project_missing? @@ -344,7 +344,7 @@ class MergeRequest < ActiveRecord::Base end def reopenable? - source_branch_exists? && closed? + closed? && !source_project_missing? && source_branch_exists? end def ensure_merge_request_diff @@ -656,7 +656,7 @@ class MergeRequest < ActiveRecord::Base end def has_ci? - source_project.ci_service && commits.any? + source_project.try(:ci_service) && commits.any? end def branch_missing? @@ -688,12 +688,9 @@ class MergeRequest < ActiveRecord::Base @environments ||= begin - environments = source_project.environments_for( - source_branch, diff_head_commit) - environments += target_project.environments_for( - target_branch, diff_head_commit, with_tags: true) - - environments.uniq + envs = target_project.environments_for(target_branch, diff_head_commit, with_tags: true) + envs.concat(source_project.environments_for(source_branch, diff_head_commit)) if source_project + envs.uniq end end diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index fe90383b00f..0e19d224fcd 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -35,7 +35,9 @@ - if @merge_request.open? && @merge_request.diverged_from_target_branch? %span (#{pluralize(@merge_request.diverged_commits_count, 'commit')} behind) - = render "projects/merge_requests/show/how_to_merge" + - if @merge_request.source_branch_exists? + = render "projects/merge_requests/show/how_to_merge" + = render "projects/merge_requests/widget/show.html.haml" - if @merge_request.source_branch_exists? && @merge_request.mergeable? && @merge_request.can_be_merged_by?(current_user) @@ -50,10 +52,11 @@ = link_to namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#notes', action: 'notes', toggle: 'tab' } do Discussion %span.badge= @merge_request.mr_and_commit_notes.user.count - %li.commits-tab - = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do - Commits - %span.badge= @commits_count + - if @merge_request.source_project + %li.commits-tab + = link_to commits_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: 'div#commits', action: 'commits', toggle: 'tab' } do + Commits + %span.badge= @commits_count - if @pipeline %li.pipelines-tab = link_to pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), data: { target: '#pipelines', action: 'pipelines', toggle: 'tab' } do diff --git a/spec/features/merge_requests/created_from_fork_spec.rb b/spec/features/merge_requests/created_from_fork_spec.rb index a506624b30d..cfc1244429f 100644 --- a/spec/features/merge_requests/created_from_fork_spec.rb +++ b/spec/features/merge_requests/created_from_fork_spec.rb @@ -25,6 +25,20 @@ feature 'Merge request created from fork' do expect(page).to have_content 'Test merge request' end + context 'source project is deleted' do + background do + MergeRequests::MergeService.new(project, user).execute(merge_request) + fork_project.destroy! + end + + scenario 'user can access merge request' do + visit_merge_request(merge_request) + + expect(page).to have_content 'Test merge request' + expect(page).to have_content "(removed):#{merge_request.source_branch}" + end + end + context 'pipeline present in source project' do include WaitForAjax From f118d2fc7394cbbd71a8c97e0c186581c045fb47 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 19 Oct 2016 17:48:30 +0100 Subject: [PATCH 19/76] Fix two CI endpoints for MRs where the source project is deleted --- app/controllers/projects/merge_requests_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 55ea31e48a0..2ee53f7ceda 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -398,7 +398,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController status ||= "preparing" else - ci_service = @merge_request.source_project.ci_service + ci_service = @merge_request.source_project.try(:ci_service) status = ci_service.commit_status(merge_request.diff_head_sha, merge_request.source_branch) if ci_service if ci_service.respond_to?(:commit_coverage) From 51fbb9bfa90f293447cf3f338bdc0a189b601d0e Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 19 Oct 2016 19:33:51 +0100 Subject: [PATCH 20/76] Rename forked_source_project_missing? to source_project_missing? --- app/models/merge_request.rb | 6 +++--- spec/models/merge_request_spec.rb | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 45fa8af60e5..c476a3bb14e 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -326,17 +326,17 @@ class MergeRequest < ActiveRecord::Base def validate_fork return true unless target_project && source_project return true if target_project == source_project - return true unless forked_source_project_missing? + return true unless source_project_missing? errors.add :validate_fork, 'Source project is not a fork of the target project' end def closed_without_fork? - closed? && forked_source_project_missing? + closed? && source_project_missing? end - def forked_source_project_missing? + def source_project_missing? return false unless for_fork? return true unless source_project diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index ee003a9d18f..6e5137602aa 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1198,7 +1198,7 @@ describe MergeRequest, models: true do end end - describe "#forked_source_project_missing?" do + describe "#source_project_missing?" do let(:project) { create(:project) } let(:fork_project) { create(:project, forked_from_project: project) } let(:user) { create(:user) } @@ -1211,13 +1211,13 @@ describe MergeRequest, models: true do target_project: project) end - it { expect(merge_request.forked_source_project_missing?).to be_falsey } + it { expect(merge_request.source_project_missing?).to be_falsey } end context "when the source project is the same as the target project" do let(:merge_request) { create(:merge_request, source_project: project) } - it { expect(merge_request.forked_source_project_missing?).to be_falsey } + it { expect(merge_request.source_project_missing?).to be_falsey } end context "when the fork does not exist" do @@ -1231,7 +1231,7 @@ describe MergeRequest, models: true do unlink_project.execute merge_request.reload - expect(merge_request.forked_source_project_missing?).to be_truthy + expect(merge_request.source_project_missing?).to be_truthy end end end From 25447b46c6adf62a0aafc0da38d456ef80e489f3 Mon Sep 17 00:00:00 2001 From: Nick Thomas Date: Wed, 19 Oct 2016 18:09:33 +0100 Subject: [PATCH 21/76] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98cffab8c03..4f163f323e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Please view this file on the master branch, on stable branches it's out of date. - ProjectCacheWorker updates caches at most once per 15 minutes per project - Fix Error 500 when viewing old merge requests with bad diff data - Create a new /templates namespace for the /licenses, /gitignores and /gitlab_ci_ymls API endpoints. !5717 (tbalthazar) + - Fix viewing merged MRs when the source project has been removed !6991 - Speed-up group milestones show page - Fix inconsistent options dropdown caret on mobile viewports (ClemMakesApps) - Extract project#update_merge_requests and SystemHooks to its own worker from GitPushService From 3ab461dc64d8cadd61a67e632fde309fb887d1e8 Mon Sep 17 00:00:00 2001 From: Airat Shigapov Date: Thu, 15 Sep 2016 18:45:22 +0300 Subject: [PATCH 22/76] Render hipchat notification descriptions as HTML instead of raw markdown --- .../project_services/hipchat_service.rb | 9 +++------ .../project_services/hipchat_service_spec.rb | 20 +++++++++---------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index afebd3b6a12..98f0312d84e 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -144,8 +144,7 @@ class HipchatService < Service message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" if description - description = format_body(description) - message << description + message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(description)) end message @@ -167,8 +166,7 @@ class HipchatService < Service "#{project_link}: #{title}" if description - description = format_body(description) - message << description + message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(description)) end message @@ -219,8 +217,7 @@ class HipchatService < Service message << title if note - note = format_body(note) - message << note + message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(note)) end message diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 26dd95bdfec..90066f01f6f 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -117,7 +117,7 @@ describe HipchatService, models: true do end context 'issue events' do - let(:issue) { create(:issue, title: 'Awesome issue', description: 'please fix') } + 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') } @@ -135,12 +135,12 @@ describe HipchatService, models: true do "issue ##{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome issue" \ - "
please fix
") + "

please fix

\n
") 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_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') } @@ -159,7 +159,7 @@ describe HipchatService, models: true do "merge request !#{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome merge request" \ - "
please fix
") + "

please fix

\n
") end end @@ -190,7 +190,7 @@ describe HipchatService, models: true do "commit #{commit_id} in " \ "#{project_name}: " \ "#{title}" \ - "
a comment on a commit
") + "

a comment on a commit

\n
") end end @@ -203,7 +203,7 @@ describe HipchatService, models: true do let(:merge_request_note) do create(:note_on_merge_request, noteable: merge_request, project: project, - note: "merge request note") + note: "merge request **note**") end it "calls Hipchat API for merge request comment events" do @@ -222,7 +222,7 @@ describe HipchatService, models: true do "merge request !#{merge_id} in " \ "#{project_name}: " \ "#{title}" \ - "
merge request note
") + "

merge request note

\n
") end end @@ -230,7 +230,7 @@ describe HipchatService, models: true do let(:issue) { create(:issue, project: project) } let(:issue_note) do create(:note_on_issue, noteable: issue, project: project, - note: "issue note") + note: "issue **note**") end it "calls Hipchat API for issue comment events" do @@ -247,7 +247,7 @@ describe HipchatService, models: true do "issue ##{issue_id} in " \ "#{project_name}: " \ "#{title}" \ - "
issue note
") + "

issue note

\n
") end end @@ -275,7 +275,7 @@ describe HipchatService, models: true do "snippet ##{snippet_id} in " \ "#{project_name}: " \ "#{title}" \ - "
snippet note
") + "

snippet note

\n
") end end end From 0090116d87585ab6e433ba7c04198271848c43c0 Mon Sep 17 00:00:00 2001 From: David Eisner Date: Tue, 4 Oct 2016 12:28:42 +0100 Subject: [PATCH 23/76] Full Banzai rendering for HipChat notifications --- app/models/project_services/hipchat_service.rb | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 98f0312d84e..f4edbbbceb2 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -121,14 +121,6 @@ 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) user_name = data[:user][:name] @@ -144,7 +136,7 @@ class HipchatService < Service message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" if description - message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(description)) + message << Banzai.render(note, project: project) end message @@ -166,7 +158,7 @@ class HipchatService < Service "#{project_link}: #{title}" if description - message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(description)) + message << Banzai.render(note, project: project) end message @@ -217,7 +209,7 @@ class HipchatService < Service message << title if note - message << format_body(Banzai::Filter::MarkdownFilter.renderer.render(note)) + message << Banzai.render(note, project: project) end message From ad28b3989dece0d3495e08cf545708caf9642cfc Mon Sep 17 00:00:00 2001 From: David Eisner Date: Tue, 4 Oct 2016 12:38:31 +0100 Subject: [PATCH 24/76] Also render commit titles in HipChat notifications --- app/models/project_services/hipchat_service.rb | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index f4edbbbceb2..7d70452a70b 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -88,6 +88,10 @@ class HipchatService < Service end end + def render_line(text) + Banzai.render(text.lines.first.chomp, project: project, pipeline: :single_line) if text + end + def create_push_message(push) ref_type = Gitlab::Git.tag_ref?(push[:ref]) ? 'tag' : 'branch' ref = Gitlab::Git.ref_name(push[:ref]) @@ -110,7 +114,7 @@ class HipchatService < Service message << "(Compare changes)" push[:commits].take(MAX_COMMITS).each do |commit| - message << "
- #{commit[:message].lines.first} (#{commit[:id][0..5]})" + message << "
- #{render_line(commit[:message])} (#{commit[:id][0..5]})" end if push[:commits].count > MAX_COMMITS @@ -126,7 +130,7 @@ class HipchatService < Service obj_attr = data[:object_attributes] obj_attr = HashWithIndifferentAccess.new(obj_attr) - title = obj_attr[:title] + title = render_line(obj_attr[:title]) state = obj_attr[:state] issue_iid = obj_attr[:iid] issue_url = obj_attr[:url] @@ -150,7 +154,7 @@ class HipchatService < Service merge_request_id = obj_attr[:iid] state = obj_attr[:state] description = obj_attr[:description] - title = obj_attr[:title] + title = render_line(obj_attr[:title]) merge_request_url = "#{project_url}/merge_requests/#{merge_request_id}" merge_request_link = "merge request !#{merge_request_id}" @@ -165,7 +169,7 @@ class HipchatService < Service end def format_title(title) - "" + title.lines.first.chomp + "" + "#{render_line(title)}" end def create_note_message(data) From 59b2770a035489db9995b8638792ed5c92242035 Mon Sep 17 00:00:00 2001 From: David Eisner Date: Tue, 4 Oct 2016 16:23:16 +0100 Subject: [PATCH 25/76] Absolute URLs for Banzai HTML for HipChat Using "pipeline: :email" gets "only_path: false" into the context to produce full URLs instead of /namespace/project/... --- .../project_services/hipchat_service.rb | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 7d70452a70b..9d52a1423b7 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -89,7 +89,7 @@ class HipchatService < Service end def render_line(text) - Banzai.render(text.lines.first.chomp, project: project, pipeline: :single_line) if text + markdown(text.lines.first.chomp, pipeline: :single_line) if text end def create_push_message(push) @@ -125,6 +125,20 @@ class HipchatService < Service message end + def markdown(text, context = {}) + if text + context = ({ + project: project, + pipeline: :email + }).merge(context) + + html = Banzai.render(text, context) + html = Banzai.post_process(html, context) + else + "" + end + end + def create_issue_message(data) user_name = data[:user][:name] @@ -139,9 +153,7 @@ class HipchatService < Service issue_link = "issue ##{issue_iid}" message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" - if description - message << Banzai.render(note, project: project) - end + message << markdown(description) message end @@ -161,9 +173,7 @@ class HipchatService < Service message = "#{user_name} #{state} #{merge_request_link} in " \ "#{project_link}: #{title}" - if description - message << Banzai.render(note, project: project) - end + message << markdown(description) message end @@ -180,11 +190,13 @@ class HipchatService < Service note = obj_attr[:note] note_url = obj_attr[:url] noteable_type = obj_attr[:noteable_type] + commit_id = nil case noteable_type when "Commit" commit_attr = HashWithIndifferentAccess.new(data[:commit]) - subject_desc = commit_attr[:id] + commit_id = commit_attr[:id] + subject_desc = commit_id subject_desc = Commit.truncate_sha(subject_desc) subject_type = "commit" title = format_title(commit_attr[:message]) @@ -212,9 +224,7 @@ class HipchatService < Service message = "#{user_name} commented on #{subject_html} in #{project_link}: " message << title - if note - message << Banzai.render(note, project: project) - end + message << markdown(note, ref: commit_id) message end From 73f13526d6ef3da1289074e2503bf2764b41b137 Mon Sep 17 00:00:00 2001 From: David Eisner Date: Tue, 4 Oct 2016 16:25:45 +0100 Subject: [PATCH 26/76] Ensure absolute URLs for single lines from Banzai for HipChat "pipeline: :single_line" leaves the protocol/host part out of the URLs and caches them that way. To avoid giving those out to HipChat, markdown is always rendered with "pipeline: :email" first. There must be a better way to do this, but I can't see how to avoid the link caching. --- app/models/project_services/hipchat_service.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 9d52a1423b7..ce4a2a96015 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -125,12 +125,16 @@ class HipchatService < Service message end - def markdown(text, context = {}) + def markdown(text, options = {}) if text - context = ({ + context = { project: project, pipeline: :email - }).merge(context) + } + + Banzai.render(text, context) + + context.merge!(options) html = Banzai.render(text, context) html = Banzai.post_process(html, context) From 551c74edf75e3fa89ea57a45b217a3a34f8c2fc1 Mon Sep 17 00:00:00 2001 From: David Eisner Date: Tue, 4 Oct 2016 16:27:40 +0100 Subject: [PATCH 27/76] Clean up Banzai HTML for HipChat The `class` and `data-*` attributes are meaningless in HipChat, and it would probably be better to limit the tags, too. For example, we could avoid block-level elements in `render_line`. --- app/models/project_services/hipchat_service.rb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index ce4a2a96015..8988a7b905e 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -1,4 +1,6 @@ class HipchatService < Service + include ActionView::Helpers::SanitizeHelper + MAX_COMMITS = 3 prop_accessor :token, :room, :server, :notify, :color, :api_version @@ -138,6 +140,7 @@ class HipchatService < Service html = Banzai.render(text, context) html = Banzai.post_process(html, context) + sanitize html, attributes: %w(href title alt) else "" end From f6a97e6c0bf4d0f699ded24983c6be1ca4b5d6cc Mon Sep 17 00:00:00 2001 From: David Eisner Date: Wed, 5 Oct 2016 13:38:08 +0100 Subject: [PATCH 28/76] Tests for markdown HipChat notifications --- spec/models/project_services/hipchat_service_spec.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 90066f01f6f..1029b6d2459 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -135,7 +135,7 @@ describe HipchatService, models: true do "issue ##{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome issue" \ - "

please fix

\n
") + "

please fix

") end end @@ -159,7 +159,7 @@ describe HipchatService, models: true do "merge request !#{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome merge request" \ - "

please fix

\n
") + "

please fix

") end end @@ -190,7 +190,7 @@ describe HipchatService, models: true do "commit #{commit_id} in " \ "#{project_name}: " \ "#{title}" \ - "

a comment on a commit

\n
") + "

a comment on a commit

") end end @@ -222,7 +222,7 @@ describe HipchatService, models: true do "merge request !#{merge_id} in " \ "#{project_name}: " \ "#{title}" \ - "

merge request note

\n
") + "

merge request note

") end end @@ -247,7 +247,7 @@ describe HipchatService, models: true do "issue ##{issue_id} in " \ "#{project_name}: " \ "#{title}" \ - "

issue note

\n
") + "

issue note

") end end @@ -275,7 +275,7 @@ describe HipchatService, models: true do "snippet ##{snippet_id} in " \ "#{project_name}: " \ "#{title}" \ - "

snippet note

\n
") + "

snippet note

") end end end From 1c7807925aaa3efcc85275273cf65c574985dd61 Mon Sep 17 00:00:00 2001 From: Airat Shigapov Date: Wed, 12 Oct 2016 09:51:02 +0300 Subject: [PATCH 29/76] Use guard clause instead of if-else statement --- .../project_services/hipchat_service.rb | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index 8988a7b905e..e7a77070b9f 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -128,22 +128,21 @@ class HipchatService < Service end def markdown(text, options = {}) - if text - context = { - project: project, - pipeline: :email - } + return "" unless text - Banzai.render(text, context) + context = { + project: project, + pipeline: :email + } - context.merge!(options) + Banzai.render(text, context) - html = Banzai.render(text, context) - html = Banzai.post_process(html, context) - sanitize html, attributes: %w(href title alt) - else - "" - end + context.merge!(options) + + html = Banzai.render(text, context) + html = Banzai.post_process(html, context) + + sanitize html, attributes: %w(href title alt) end def create_issue_message(data) From 5d608ceb4f433a0d3f196a2a5cb11cf6a535baf2 Mon Sep 17 00:00:00 2001 From: Airat Shigapov Date: Wed, 19 Oct 2016 22:51:15 +0300 Subject: [PATCH 30/76] Return truncation for notification descriptions, fix minor bugs with rendering --- app/models/project_services/hipchat_service.rb | 17 +++++++++++------ .../project_services/hipchat_service_spec.rb | 12 ++++++------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/app/models/project_services/hipchat_service.rb b/app/models/project_services/hipchat_service.rb index e7a77070b9f..660a8ae3421 100644 --- a/app/models/project_services/hipchat_service.rb +++ b/app/models/project_services/hipchat_service.rb @@ -2,6 +2,11 @@ class HipchatService < Service include ActionView::Helpers::SanitizeHelper MAX_COMMITS = 3 + HIPCHAT_ALLOWED_TAGS = %w[ + a b i strong em br img pre code + table th tr td caption colgroup col thead tbody tfoot + ul ol li dl dt dd + ] prop_accessor :token, :room, :server, :notify, :color, :api_version boolean_accessor :notify_only_broken_builds @@ -139,10 +144,10 @@ class HipchatService < Service context.merge!(options) - html = Banzai.render(text, context) - html = Banzai.post_process(html, context) + html = Banzai.post_process(Banzai.render(text, context), context) + sanitized_html = sanitize(html, tags: HIPCHAT_ALLOWED_TAGS, attributes: %w[href title alt]) - sanitize html, attributes: %w(href title alt) + sanitized_html.truncate(200, separator: ' ', omission: '...') end def create_issue_message(data) @@ -159,7 +164,7 @@ class HipchatService < Service issue_link = "issue ##{issue_iid}" message = "#{user_name} #{state} #{issue_link} in #{project_link}: #{title}" - message << markdown(description) + message << "
#{markdown(description)}
" message end @@ -179,7 +184,7 @@ class HipchatService < Service message = "#{user_name} #{state} #{merge_request_link} in " \ "#{project_link}: #{title}" - message << markdown(description) + message << "
#{markdown(description)}
" message end @@ -230,7 +235,7 @@ class HipchatService < Service message = "#{user_name} commented on #{subject_html} in #{project_link}: " message << title - message << markdown(note, ref: commit_id) + message << "
#{markdown(note, ref: commit_id)}
" message end diff --git a/spec/models/project_services/hipchat_service_spec.rb b/spec/models/project_services/hipchat_service_spec.rb index 1029b6d2459..2da3a9cb09f 100644 --- a/spec/models/project_services/hipchat_service_spec.rb +++ b/spec/models/project_services/hipchat_service_spec.rb @@ -135,7 +135,7 @@ describe HipchatService, models: true do "issue ##{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome issue" \ - "

please fix

") + "
please fix
") end end @@ -159,7 +159,7 @@ describe HipchatService, models: true do "merge request !#{obj_attr["iid"]} in " \ "#{project_name}: " \ "Awesome merge request" \ - "

please fix

") + "
please fix
") end end @@ -190,7 +190,7 @@ describe HipchatService, models: true do "commit #{commit_id} in " \ "#{project_name}: " \ "#{title}" \ - "

a comment on a commit

") + "
a comment on a commit
") end end @@ -222,7 +222,7 @@ describe HipchatService, models: true do "merge request !#{merge_id} in " \ "#{project_name}: " \ "#{title}" \ - "

merge request note

") + "
merge request note
") end end @@ -247,7 +247,7 @@ describe HipchatService, models: true do "issue ##{issue_id} in " \ "#{project_name}: " \ "#{title}" \ - "

issue note

") + "
issue note
") end end @@ -275,7 +275,7 @@ describe HipchatService, models: true do "snippet ##{snippet_id} in " \ "#{project_name}: " \ "#{title}" \ - "

snippet note

") + "
snippet note
") end end end From 435678d58828db76c3ef5f95643dac0e3ae979b3 Mon Sep 17 00:00:00 2001 From: Airat Shigapov Date: Thu, 20 Oct 2016 15:12:39 +0300 Subject: [PATCH 31/76] Add CHANGELOG.md entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4f163f323e6..0bfdf23b959 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) - Adds user project membership expired event to clarify why user was removed (Callum Dryden) + - Fix HipChat notifications rendering (airatshigapov, eisnerd) - Simpler arguments passed to named_route on toggle_award_url helper method ## 8.13.0 (2016-10-22) From ea704005c7bdca55e2782a2c24fe0c5e89cad179 Mon Sep 17 00:00:00 2001 From: Kamil Trzcinski Date: Wed, 19 Oct 2016 14:48:37 +0200 Subject: [PATCH 32/76] Update duration at the end of pipeline --- CHANGELOG.md | 1 + app/models/ci/pipeline.rb | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bfdf23b959..de24e08c52f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Add `/projects/visible` API endpoint (Ben Boeckel) - Fix centering of custom header logos (Ashley Dumaine) - Keep around commits only pipeline creation as pipeline data doesn't change over time + - Update duration at the end of pipeline - ExpireBuildArtifactsWorker query builds table without ordering enqueuing one job per build to cleanup - Add group level labels. (!6425) - Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun) diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index e84c91b417d..d5c1e03b461 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -59,9 +59,6 @@ module Ci before_transition any => [:success, :failed, :canceled] do |pipeline| pipeline.finished_at = Time.now - end - - before_transition do |pipeline| pipeline.update_duration end From 523ee4a5f4c28aab29310a742f4798bc77f20ccf Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Oct 2016 16:16:57 +0800 Subject: [PATCH 33/76] Preserve note_type and position for notes from emails Closes #23208 --- .../email/handler/create_note_handler.rb | 4 +++- spec/fixtures/emails/commands_in_reply.eml | 2 -- spec/fixtures/emails/commands_only_reply.eml | 2 -- .../email/handler/create_note_handler_spec.rb | 24 ++++++++++--------- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/lib/gitlab/email/handler/create_note_handler.rb b/lib/gitlab/email/handler/create_note_handler.rb index 06dae31cc27..447c7a6a6b9 100644 --- a/lib/gitlab/email/handler/create_note_handler.rb +++ b/lib/gitlab/email/handler/create_note_handler.rb @@ -46,7 +46,9 @@ module Gitlab noteable_type: sent_notification.noteable_type, noteable_id: sent_notification.noteable_id, commit_id: sent_notification.commit_id, - line_code: sent_notification.line_code + line_code: sent_notification.line_code, + position: sent_notification.position, + type: sent_notification.note_type ).execute end end diff --git a/spec/fixtures/emails/commands_in_reply.eml b/spec/fixtures/emails/commands_in_reply.eml index 06bf60ab734..712f6f797b4 100644 --- a/spec/fixtures/emails/commands_in_reply.eml +++ b/spec/fixtures/emails/commands_in_reply.eml @@ -23,8 +23,6 @@ Cool! /close /todo -/due tomorrow - On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta wrote: diff --git a/spec/fixtures/emails/commands_only_reply.eml b/spec/fixtures/emails/commands_only_reply.eml index aed64224b06..2d2e2f94290 100644 --- a/spec/fixtures/emails/commands_only_reply.eml +++ b/spec/fixtures/emails/commands_only_reply.eml @@ -21,8 +21,6 @@ X-Scanned-By: MIMEDefang 2.69 on IPv6:2001:470:1d:165::1 /close /todo -/due tomorrow - On Sun, Jun 9, 2013 at 1:39 PM, eviltrout via Discourse Meta wrote: diff --git a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb index 4909fed6b77..48660d1dd1b 100644 --- a/spec/lib/gitlab/email/handler/create_note_handler_spec.rb +++ b/spec/lib/gitlab/email/handler/create_note_handler_spec.rb @@ -12,10 +12,13 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do let(:email_raw) { fixture_file('emails/valid_reply.eml') } let(:project) { create(:project, :public) } - let(:noteable) { create(:issue, project: project) } let(:user) { create(:user) } + let(:note) { create(:diff_note_on_merge_request, project: project) } + let(:noteable) { note.noteable } - let!(:sent_notification) { SentNotification.record(noteable, user.id, mail_key) } + let!(:sent_notification) do + SentNotification.record_note(note, user.id, mail_key) + end context "when the recipient address doesn't include a mail key" do let(:email_raw) { fixture_file('emails/valid_reply.eml').gsub(mail_key, "") } @@ -82,7 +85,6 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do expect { receiver.execute }.to change { noteable.notes.count }.by(1) expect(noteable.reload).to be_closed - expect(noteable.due_date).to eq(Date.tomorrow) expect(TodoService.new.todo_exist?(noteable, user)).to be_truthy end end @@ -100,7 +102,6 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do expect { receiver.execute }.to change { noteable.notes.count }.by(1) expect(noteable.reload).to be_open - expect(noteable.due_date).to be_nil expect(TodoService.new.todo_exist?(noteable, user)).to be_falsy end end @@ -117,7 +118,6 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do expect { receiver.execute }.to change { noteable.notes.count }.by(2) expect(noteable.reload).to be_closed - expect(noteable.due_date).to eq(Date.tomorrow) expect(TodoService.new.todo_exist?(noteable, user)).to be_truthy end end @@ -138,10 +138,11 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do it "creates a comment" do expect { receiver.execute }.to change { noteable.notes.count }.by(1) - note = noteable.notes.last + new_note = noteable.notes.last - expect(note.author).to eq(sent_notification.recipient) - expect(note.note).to include("I could not disagree more.") + expect(new_note.author).to eq(sent_notification.recipient) + expect(new_note.position).to eq(note.position) + expect(new_note.note).to include("I could not disagree more.") end it "adds all attachments" do @@ -160,10 +161,11 @@ describe Gitlab::Email::Handler::CreateNoteHandler, lib: true do shared_examples 'an email that contains a mail key' do |header| it "fetches the mail key from the #{header} header and creates a comment" do expect { receiver.execute }.to change { noteable.notes.count }.by(1) - note = noteable.notes.last + new_note = noteable.notes.last - expect(note.author).to eq(sent_notification.recipient) - expect(note.note).to include('I could not disagree more.') + expect(new_note.author).to eq(sent_notification.recipient) + expect(new_note.position).to eq(note.position) + expect(new_note.note).to include('I could not disagree more.') end end From cbb65aae395821c596746d2b347fc3a7de1b3da8 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Oct 2016 16:24:37 +0800 Subject: [PATCH 34/76] Add CHANGELOG entry [ci skip] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index de24e08c52f..98d95e275e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ Please view this file on the master branch, on stable branches it's out of date. - Fix HipChat notifications rendering (airatshigapov, eisnerd) - Simpler arguments passed to named_route on toggle_award_url helper method + - Fix discussion thread from emails for merge requests. !7010 + ## 8.13.0 (2016-10-22) - Fix save button on project pipeline settings page. (!6955) From 25d00ea871a970fb82d79067d97c84fdcb5264c5 Mon Sep 17 00:00:00 2001 From: Lin Jen-Shin Date: Thu, 20 Oct 2016 20:47:21 +0800 Subject: [PATCH 35/76] We want to release this in 8.13.0 --- CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 98d95e275e2..73dc323e02c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,6 @@ Please view this file on the master branch, on stable branches it's out of date. - Fix HipChat notifications rendering (airatshigapov, eisnerd) - Simpler arguments passed to named_route on toggle_award_url helper method - - Fix discussion thread from emails for merge requests. !7010 - ## 8.13.0 (2016-10-22) - Fix save button on project pipeline settings page. (!6955) @@ -47,6 +45,7 @@ Please view this file on the master branch, on stable branches it's out of date. - Speed-up group milestones show page - Fix inconsistent options dropdown caret on mobile viewports (ClemMakesApps) - Extract project#update_merge_requests and SystemHooks to its own worker from GitPushService + - Fix discussion thread from emails for merge requests. !7010 - Don't include archived projects when creating group milestones. !4940 (Jeroen Jacobs) - Add tag shortcut from the Commit page. !6543 - Keep refs for each deployment From 8979567e439c624145ffef7ebc255b7936b5d05e Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Wed, 19 Oct 2016 14:49:09 +0200 Subject: [PATCH 36/76] Use deployment IID when saving refs --- app/models/deployment.rb | 2 +- app/models/environment.rb | 4 ++-- spec/controllers/projects/merge_requests_controller_spec.rb | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/models/deployment.rb b/app/models/deployment.rb index 1f8c5fb3d85..c843903877b 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -102,6 +102,6 @@ class Deployment < ActiveRecord::Base private def ref_path - File.join(environment.ref_path, 'deployments', id.to_s) + File.join(environment.ref_path, 'deployments', iid.to_s) end end diff --git a/app/models/environment.rb b/app/models/environment.rb index d575f1dc73a..73f415c0ef0 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -71,8 +71,8 @@ class Environment < ActiveRecord::Base return nil unless ref - deployment_id = ref.split('/').last - deployments.find(deployment_id) + deployment_iid = ref.split('/').last + deployments.find_by(iid: deployment_iid) end def ref_path diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index d6980471ea4..940d54f8686 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -913,7 +913,7 @@ describe Projects::MergeRequestsController do end describe 'GET ci_environments_status' do - context 'when the environment is from a forked project' do + context 'the environment is from a forked project' do let!(:forked) { create(:project) } let!(:environment) { create(:environment, project: forked) } let!(:deployment) { create(:deployment, environment: environment, sha: forked.commit.id, ref: 'master') } From 1cb75998992745216cb634537c281561559d1964 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Thu, 20 Oct 2016 14:21:40 +0200 Subject: [PATCH 37/76] Only create refs for new deployments This patch makes sure GitLab does not save the refs to the filesystem each time the deployment is updated. This will save some IO although I expect the impact to be minimal. --- app/models/deployment.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/deployment.rb b/app/models/deployment.rb index c843903877b..91d85c2279b 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -11,7 +11,7 @@ class Deployment < ActiveRecord::Base delegate :name, to: :environment, prefix: true - after_save :create_ref + after_create :create_ref def commit project.commit(sha) From 3974c2e9e18d80a9b5a49bd16ea3fc0d157dd919 Mon Sep 17 00:00:00 2001 From: Alfredo Sumaran Date: Fri, 14 Oct 2016 17:25:12 -0500 Subject: [PATCH 38/76] Create protected branches bundle --- .../protected_branch_access_dropdown.js.es6 | 0 .../{ => protected_branches}/protected_branch_create.js.es6 | 0 .../{ => protected_branches}/protected_branch_dropdown.js.es6 | 0 .../{ => protected_branches}/protected_branch_edit.js.es6 | 0 .../{ => protected_branches}/protected_branch_edit_list.js.es6 | 0 .../javascripts/protected_branches/protected_branches_bundle.js | 1 + app/views/projects/protected_branches/index.html.haml | 2 ++ config/application.rb | 1 + 8 files changed, 4 insertions(+) rename app/assets/javascripts/{ => protected_branches}/protected_branch_access_dropdown.js.es6 (100%) rename app/assets/javascripts/{ => protected_branches}/protected_branch_create.js.es6 (100%) rename app/assets/javascripts/{ => protected_branches}/protected_branch_dropdown.js.es6 (100%) rename app/assets/javascripts/{ => protected_branches}/protected_branch_edit.js.es6 (100%) rename app/assets/javascripts/{ => protected_branches}/protected_branch_edit_list.js.es6 (100%) create mode 100644 app/assets/javascripts/protected_branches/protected_branches_bundle.js diff --git a/app/assets/javascripts/protected_branch_access_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6 similarity index 100% rename from app/assets/javascripts/protected_branch_access_dropdown.js.es6 rename to app/assets/javascripts/protected_branches/protected_branch_access_dropdown.js.es6 diff --git a/app/assets/javascripts/protected_branch_create.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_create.js.es6 similarity index 100% rename from app/assets/javascripts/protected_branch_create.js.es6 rename to app/assets/javascripts/protected_branches/protected_branch_create.js.es6 diff --git a/app/assets/javascripts/protected_branch_dropdown.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6 similarity index 100% rename from app/assets/javascripts/protected_branch_dropdown.js.es6 rename to app/assets/javascripts/protected_branches/protected_branch_dropdown.js.es6 diff --git a/app/assets/javascripts/protected_branch_edit.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit.js.es6 similarity index 100% rename from app/assets/javascripts/protected_branch_edit.js.es6 rename to app/assets/javascripts/protected_branches/protected_branch_edit.js.es6 diff --git a/app/assets/javascripts/protected_branch_edit_list.js.es6 b/app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6 similarity index 100% rename from app/assets/javascripts/protected_branch_edit_list.js.es6 rename to app/assets/javascripts/protected_branches/protected_branch_edit_list.js.es6 diff --git a/app/assets/javascripts/protected_branches/protected_branches_bundle.js b/app/assets/javascripts/protected_branches/protected_branches_bundle.js new file mode 100644 index 00000000000..15b3affd469 --- /dev/null +++ b/app/assets/javascripts/protected_branches/protected_branches_bundle.js @@ -0,0 +1 @@ +/*= require_tree . */ diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 49dcc9a6ba4..42e9bdbd30e 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -1,4 +1,6 @@ - page_title "Protected branches" +- content_for :page_specific_javascripts do + = page_specific_javascript_tag('protected_branches/protected_branches_bundle.js') .row.prepend-top-default.append-bottom-default .col-lg-3 diff --git a/config/application.rb b/config/application.rb index 8a9c539cb43..f3337b00dc6 100644 --- a/config/application.rb +++ b/config/application.rb @@ -87,6 +87,7 @@ module Gitlab config.assets.precompile << "users/users_bundle.js" config.assets.precompile << "network/network_bundle.js" config.assets.precompile << "profile/profile_bundle.js" + config.assets.precompile << "protected_branches/protected_branches_bundle.js" config.assets.precompile << "diff_notes/diff_notes_bundle.js" config.assets.precompile << "boards/boards_bundle.js" config.assets.precompile << "merge_conflicts/merge_conflicts_bundle.js" From a2aa1abbc272b285dab12f03465f13e71fc91e15 Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 19 Oct 2016 15:35:38 +0200 Subject: [PATCH 39/76] Test GitLab project import for a user with only their default namespace. Refactor the spec file: - remove hardcoded record IDs - avoid top-level let if not used in all scenarios - prefer expect { ... }.to change { ... }.from(0).to(1) over checking that there are no records at the beginning of the test --- .../import_export/import_file_spec.rb | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/spec/features/projects/import_export/import_file_spec.rb b/spec/features/projects/import_export/import_file_spec.rb index f32834801a0..3015576f6f8 100644 --- a/spec/features/projects/import_export/import_file_spec.rb +++ b/spec/features/projects/import_export/import_file_spec.rb @@ -3,13 +3,8 @@ require 'spec_helper' feature 'Import/Export - project import integration test', feature: true, js: true do include Select2Helper - let(:admin) { create(:admin) } - let(:normal_user) { create(:user) } - let!(:namespace) { create(:namespace, name: "asd", owner: admin) } let(:file) { File.join(Rails.root, 'spec', 'features', 'projects', 'import_export', 'test_project_export.tar.gz') } let(:export_path) { "#{Dir::tmpdir}/import_file_spec" } - let(:project) { Project.last } - let(:project_hook) { Gitlab::Git::Hook.new('post-receive', project.repository.path) } background do allow_any_instance_of(Gitlab::ImportExport).to receive(:storage_path).and_return(export_path) @@ -19,41 +14,43 @@ feature 'Import/Export - project import integration test', feature: true, js: tr FileUtils.rm_rf(export_path, secure: true) end - context 'admin user' do + context 'when selecting the namespace' do + let(:user) { create(:admin) } + let!(:namespace) { create(:namespace, name: "asd", owner: user) } + before do - login_as(admin) + login_as(user) end scenario 'user imports an exported project successfully' do - expect(Project.all.count).to be_zero - visit new_project_path - select2('2', from: '#project_namespace_id') + select2(namespace.id, from: '#project_namespace_id') fill_in :project_path, with: 'test-project-path', visible: true click_link 'GitLab export' expect(page).to have_content('GitLab project export') - expect(URI.parse(current_url).query).to eq('namespace_id=2&path=test-project-path') + expect(URI.parse(current_url).query).to eq("namespace_id=#{namespace.id}&path=test-project-path") attach_file('file', file) - click_on 'Import project' # import starts + expect { click_on 'Import project' }.to change { Project.count }.from(0).to(1) + project = Project.last expect(project).not_to be_nil expect(project.issues).not_to be_empty expect(project.merge_requests).not_to be_empty - expect(project_hook).to exist - expect(wiki_exists?).to be true + expect(project_hook_exists?(project)).to be true + expect(wiki_exists?(project)).to be true expect(project.import_status).to eq('finished') end scenario 'invalid project' do - project = create(:project, namespace_id: 2) + project = create(:project, namespace: namespace) visit new_project_path - select2('2', from: '#project_namespace_id') + select2(namespace.id, from: '#project_namespace_id') fill_in :project_path, with: project.name, visible: true click_link 'GitLab export' @@ -66,11 +63,11 @@ feature 'Import/Export - project import integration test', feature: true, js: tr end scenario 'project with no name' do - create(:project, namespace_id: 2) + create(:project, namespace: namespace) visit new_project_path - select2('2', from: '#project_namespace_id') + select2(namespace.id, from: '#project_namespace_id') # click on disabled element find(:link, 'GitLab export').trigger('click') @@ -81,24 +78,30 @@ feature 'Import/Export - project import integration test', feature: true, js: tr end end - context 'normal user' do + context 'when limited to the default user namespace' do + let(:user) { create(:user) } before do - login_as(normal_user) + login_as(user) end - scenario 'non-admin user is allowed to import a project' do - expect(Project.all.count).to be_zero - + scenario 'passes correct namespace ID in the URL' do visit new_project_path fill_in :project_path, with: 'test-project-path', visible: true - expect(page).to have_content('GitLab export') + click_link 'GitLab export' + + expect(page).to have_content('GitLab project export') + expect(URI.parse(current_url).query).to eq("namespace_id=#{user.namespace.id}&path=test-project-path") end end - def wiki_exists? + def wiki_exists?(project) wiki = ProjectWiki.new(project) File.exist?(wiki.repository.path_to_repo) && !wiki.repository.empty? end + + def project_hook_exists?(project) + Gitlab::Git::Hook.new('post-receive', project.repository.path).exists? + end end From beddc37478113771785385a645fecf50f743d2ec Mon Sep 17 00:00:00 2001 From: Adam Niedzielski Date: Wed, 19 Oct 2016 20:42:35 +0200 Subject: [PATCH 40/76] Fix GitLab project import when a user has access only to their default namespace. Render a hidden field with namespace ID so it can be read by JavaScript and passed to "/import/gitlab_project/new" screen. --- app/views/projects/new.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index cc8cb134fb8..399ccf15b7f 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -27,6 +27,7 @@ - else .input-group-addon.static-namespace #{root_url}#{current_user.username}/ + = f.hidden_field :namespace_id, value: current_user.namespace_id .form-group.col-xs-12.col-sm-6.project-path = f.label :namespace_id, class: 'label-light' do %span From 1bdda800b6a18237921dd0cdec60c36c0fa0153f Mon Sep 17 00:00:00 2001 From: Douglas Barbosa Alexandre Date: Thu, 20 Oct 2016 14:15:39 -0200 Subject: [PATCH 41/76] [ci skip] Add a comment explaining validate_board_limit callback Callback associations are not common to see around. We want to make clear that the `before_add` callback uses the number before the addition, in this particular case 1. --- app/models/project.rb | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/models/project.rb b/app/models/project.rb index 6685baab699..af117f0acb0 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -1339,6 +1339,13 @@ class Project < ActiveRecord::Base shared_projects.any? end + # Similar to the normal callbacks that hook into the life cycle of an + # Active Record object, you can also define callbacks that get triggered + # when you add an object to an association collection. If any of these + # callbacks throw an exception, the object will not be added to the + # collection. Before you add a new board to the boards collection if you + # already have 1, 2, or n it will fail, but it if you have 0 that is lower + # than the number of permitted boards per project it won't fail. def validate_board_limit(board) raise BoardLimitExceeded, 'Number of permitted boards exceeded' if boards.size >= NUMBER_OF_PERMITTED_BOARDS end From 327ae90c6bcbbc3cc08895ece2f6cc641983a84c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Thu, 20 Oct 2016 18:51:03 +0200 Subject: [PATCH 42/76] Don't use Hash#slice since it's not supported in Ruby 2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- lib/api/commit_statuses.rb | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/lib/api/commit_statuses.rb b/lib/api/commit_statuses.rb index f282a3b9cd6..f54d4f06627 100644 --- a/lib/api/commit_statuses.rb +++ b/lib/api/commit_statuses.rb @@ -67,9 +67,14 @@ module API pipeline = @project.ensure_pipeline(ref, commit.sha, current_user) status = GenericCommitStatus.running_or_pending.find_or_initialize_by( - project: @project, pipeline: pipeline, - user: current_user, name: name, ref: ref) - status.attributes = declared(params).slice(:target_url, :description) + project: @project, + pipeline: pipeline, + user: current_user, + name: name, + ref: ref, + target_url: params[:target_url], + description: params[:description] + ) begin case params[:state].to_s From 813286e5ea6712039fd868310160eef8acb1c012 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 21 Oct 2016 08:39:37 +1100 Subject: [PATCH 43/76] Added item to CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 73dc323e02c..128f5dec039 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. ## 8.14.0 (2016-11-22) - Adds user project membership expired event to clarify why user was removed (Callum Dryden) - Fix HipChat notifications rendering (airatshigapov, eisnerd) + - Add hover to trash icon in notes !7008 (blackst0ne) - Simpler arguments passed to named_route on toggle_award_url helper method ## 8.13.0 (2016-10-22) From 905fdfba927dcfa32b99d649521a52445bc6838f Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 17 Feb 2017 07:03:42 +1100 Subject: [PATCH 44/76] Add merge request count to each issue on issues list --- .../images/icon-merge-request-unmerged.svg | 1 + app/assets/stylesheets/pages/issues.scss | 5 +++++ .../concerns/issuable_collections.rb | 20 +++++++++++++------ app/controllers/projects/issues_controller.rb | 2 +- .../projects/merge_requests_controller.rb | 2 +- app/models/concerns/issuable.rb | 4 ++-- app/models/merge_requests_closing_issues.rb | 8 ++++++++ .../shared/_issuable_meta_data.html.haml | 6 ++++++ .../unreleased/add_mr_info_to_issues_list.yml | 4 ++++ 9 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 app/assets/images/icon-merge-request-unmerged.svg create mode 100644 changelogs/unreleased/add_mr_info_to_issues_list.yml diff --git a/app/assets/images/icon-merge-request-unmerged.svg b/app/assets/images/icon-merge-request-unmerged.svg new file mode 100644 index 00000000000..c4d8e65122d --- /dev/null +++ b/app/assets/images/icon-merge-request-unmerged.svg @@ -0,0 +1 @@ + diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 80b0c9493d8..b595480561b 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -10,6 +10,11 @@ .issue-labels { display: inline-block; } + + .icon-merge-request-unmerged { + height: 13px; + margin-bottom: 3px; + } } } diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index a6e158ebae6..d7d781cbe72 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -9,24 +9,32 @@ module IssuableCollections private - def issuable_meta_data(issuable_collection) + def issuable_meta_data(issuable_collection, collection_type) # map has to be used here since using pluck or select will # throw an error when ordering issuables by priority which inserts # a new order into the collection. # We cannot use reorder to not mess up the paginated collection. - issuable_ids = issuable_collection.map(&:id) - issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) + issuable_ids = issuable_collection.map(&:id) + issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) issuable_votes_count = AwardEmoji.votes_for_collection(issuable_ids, @collection_type) + issuable_merge_requests_count = + if collection_type == 'Issue' + MergeRequestsClosingIssues.count_for_collection(issuable_ids) + else + [] + end issuable_ids.each_with_object({}) do |id, issuable_meta| downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? } - upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } - notes = issuable_note_count.find { |notes| notes.noteable_id == id } + upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } + notes = issuable_note_count.find { |notes| notes.noteable_id == id } + merge_requests = issuable_merge_requests_count.find { |mr| mr.issue_id == id } issuable_meta[id] = Issuable::IssuableMeta.new( upvotes.try(:count).to_i, downvotes.try(:count).to_i, - notes.try(:count).to_i + notes.try(:count).to_i, + merge_requests.try(:count).to_i ) end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 744a4af1c51..05056ad046a 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -26,7 +26,7 @@ class Projects::IssuesController < Projects::ApplicationController @collection_type = "Issue" @issues = issues_collection @issues = @issues.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) if @issues.out_of_range? && @issues.total_pages != 0 return redirect_to url_for(params.merge(page: @issues.total_pages)) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index c3e1760f168..8a7aeeaa96f 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -39,7 +39,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @collection_type = "MergeRequest" @merge_requests = merge_requests_collection @merge_requests = @merge_requests.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) if @merge_requests.out_of_range? && @merge_requests.total_pages != 0 return redirect_to url_for(params.merge(page: @merge_requests.total_pages)) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 5f53c48fc88..c9c6bd24d75 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -16,9 +16,9 @@ module Issuable include TimeTrackable # This object is used to gather issuable meta data for displaying - # upvotes, downvotes and notes count for issues and merge requests + # upvotes, downvotes, notes and closing merge requests count for issues and merge requests # lists avoiding n+1 queries and improving performance. - IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count) + IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count, :merge_requests_count) included do cache_markdown_field :title, pipeline: :single_line diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb index ab597c37947..1ecdfd1dfdb 100644 --- a/app/models/merge_requests_closing_issues.rb +++ b/app/models/merge_requests_closing_issues.rb @@ -4,4 +4,12 @@ class MergeRequestsClosingIssues < ActiveRecord::Base validates :merge_request_id, uniqueness: { scope: :issue_id }, presence: true validates :issue_id, presence: true + + class << self + def count_for_collection(ids) + select('issue_id', 'COUNT(*) as count'). + group(:issue_id). + where(issue_id: ids) + end + end end diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml index 1264e524d86..66310da5cd6 100644 --- a/app/views/shared/_issuable_meta_data.html.haml +++ b/app/views/shared/_issuable_meta_data.html.haml @@ -2,6 +2,12 @@ - issue_votes = @issuable_meta_data[issuable.id] - upvotes, downvotes = issue_votes.upvotes, issue_votes.downvotes - issuable_url = @collection_type == "Issue" ? issue_path(issuable, anchor: 'notes') : merge_request_path(issuable, anchor: 'notes') +- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count + +- if issuable_mr > 0 + %li + = image_tag('icon-merge-request-unmerged', class: 'icon-merge-request-unmerged') + = issuable_mr - if upvotes > 0 %li diff --git a/changelogs/unreleased/add_mr_info_to_issues_list.yml b/changelogs/unreleased/add_mr_info_to_issues_list.yml new file mode 100644 index 00000000000..8087aa6296c --- /dev/null +++ b/changelogs/unreleased/add_mr_info_to_issues_list.yml @@ -0,0 +1,4 @@ +--- +title: Add merge request count to each issue on issues list +merge_request: 9252 +author: blackst0ne From 204a0865e0e69d740abcaa85a689218140678a49 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 17 Feb 2017 07:09:24 +1100 Subject: [PATCH 45/76] Add merge request count to each issue on issues list --- .../images/icon-merge-request-unmerged.svg | 1 + app/assets/stylesheets/pages/issues.scss | 5 +++++ .../concerns/issuable_collections.rb | 20 +++++++++++++------ app/controllers/projects/issues_controller.rb | 2 +- .../projects/merge_requests_controller.rb | 2 +- app/models/concerns/issuable.rb | 4 ++-- app/models/merge_requests_closing_issues.rb | 8 ++++++++ .../shared/_issuable_meta_data.html.haml | 6 ++++++ .../unreleased/add_mr_info_to_issues_list.yml | 4 ++++ 9 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 app/assets/images/icon-merge-request-unmerged.svg create mode 100644 changelogs/unreleased/add_mr_info_to_issues_list.yml diff --git a/app/assets/images/icon-merge-request-unmerged.svg b/app/assets/images/icon-merge-request-unmerged.svg new file mode 100644 index 00000000000..c4d8e65122d --- /dev/null +++ b/app/assets/images/icon-merge-request-unmerged.svg @@ -0,0 +1 @@ + diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 80b0c9493d8..b595480561b 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -10,6 +10,11 @@ .issue-labels { display: inline-block; } + + .icon-merge-request-unmerged { + height: 13px; + margin-bottom: 3px; + } } } diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index a6e158ebae6..d7d781cbe72 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -9,24 +9,32 @@ module IssuableCollections private - def issuable_meta_data(issuable_collection) + def issuable_meta_data(issuable_collection, collection_type) # map has to be used here since using pluck or select will # throw an error when ordering issuables by priority which inserts # a new order into the collection. # We cannot use reorder to not mess up the paginated collection. - issuable_ids = issuable_collection.map(&:id) - issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) + issuable_ids = issuable_collection.map(&:id) + issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) issuable_votes_count = AwardEmoji.votes_for_collection(issuable_ids, @collection_type) + issuable_merge_requests_count = + if collection_type == 'Issue' + MergeRequestsClosingIssues.count_for_collection(issuable_ids) + else + [] + end issuable_ids.each_with_object({}) do |id, issuable_meta| downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? } - upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } - notes = issuable_note_count.find { |notes| notes.noteable_id == id } + upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } + notes = issuable_note_count.find { |notes| notes.noteable_id == id } + merge_requests = issuable_merge_requests_count.find { |mr| mr.issue_id == id } issuable_meta[id] = Issuable::IssuableMeta.new( upvotes.try(:count).to_i, downvotes.try(:count).to_i, - notes.try(:count).to_i + notes.try(:count).to_i, + merge_requests.try(:count).to_i ) end end diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 744a4af1c51..05056ad046a 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -26,7 +26,7 @@ class Projects::IssuesController < Projects::ApplicationController @collection_type = "Issue" @issues = issues_collection @issues = @issues.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) if @issues.out_of_range? && @issues.total_pages != 0 return redirect_to url_for(params.merge(page: @issues.total_pages)) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 63b5bcbb586..1d286ca62e5 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -39,7 +39,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @collection_type = "MergeRequest" @merge_requests = merge_requests_collection @merge_requests = @merge_requests.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) if @merge_requests.out_of_range? && @merge_requests.total_pages != 0 return redirect_to url_for(params.merge(page: @merge_requests.total_pages)) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 5f53c48fc88..c9c6bd24d75 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -16,9 +16,9 @@ module Issuable include TimeTrackable # This object is used to gather issuable meta data for displaying - # upvotes, downvotes and notes count for issues and merge requests + # upvotes, downvotes, notes and closing merge requests count for issues and merge requests # lists avoiding n+1 queries and improving performance. - IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count) + IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count, :merge_requests_count) included do cache_markdown_field :title, pipeline: :single_line diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb index ab597c37947..1ecdfd1dfdb 100644 --- a/app/models/merge_requests_closing_issues.rb +++ b/app/models/merge_requests_closing_issues.rb @@ -4,4 +4,12 @@ class MergeRequestsClosingIssues < ActiveRecord::Base validates :merge_request_id, uniqueness: { scope: :issue_id }, presence: true validates :issue_id, presence: true + + class << self + def count_for_collection(ids) + select('issue_id', 'COUNT(*) as count'). + group(:issue_id). + where(issue_id: ids) + end + end end diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml index 1264e524d86..66310da5cd6 100644 --- a/app/views/shared/_issuable_meta_data.html.haml +++ b/app/views/shared/_issuable_meta_data.html.haml @@ -2,6 +2,12 @@ - issue_votes = @issuable_meta_data[issuable.id] - upvotes, downvotes = issue_votes.upvotes, issue_votes.downvotes - issuable_url = @collection_type == "Issue" ? issue_path(issuable, anchor: 'notes') : merge_request_path(issuable, anchor: 'notes') +- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count + +- if issuable_mr > 0 + %li + = image_tag('icon-merge-request-unmerged', class: 'icon-merge-request-unmerged') + = issuable_mr - if upvotes > 0 %li diff --git a/changelogs/unreleased/add_mr_info_to_issues_list.yml b/changelogs/unreleased/add_mr_info_to_issues_list.yml new file mode 100644 index 00000000000..8087aa6296c --- /dev/null +++ b/changelogs/unreleased/add_mr_info_to_issues_list.yml @@ -0,0 +1,4 @@ +--- +title: Add merge request count to each issue on issues list +merge_request: 9252 +author: blackst0ne From ffd3583486f4772c8aec58b2750619d889d18d1b Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 17 Feb 2017 08:30:00 +1100 Subject: [PATCH 46/76] Added second parameter to @issuable_meta_data variables --- app/controllers/concerns/issues_action.rb | 2 +- app/controllers/concerns/merge_requests_action.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb index fb5edb34370..b17c138d5c7 100644 --- a/app/controllers/concerns/issues_action.rb +++ b/app/controllers/concerns/issues_action.rb @@ -10,7 +10,7 @@ module IssuesAction .page(params[:page]) @collection_type = "Issue" - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) respond_to do |format| format.html diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb index 6229759dcf1..d3c8e4888bc 100644 --- a/app/controllers/concerns/merge_requests_action.rb +++ b/app/controllers/concerns/merge_requests_action.rb @@ -9,7 +9,7 @@ module MergeRequestsAction .page(params[:page]) @collection_type = "MergeRequest" - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) end private From 27ffc2817554902c380a1101db7a0feb5816955f Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Fri, 17 Feb 2017 08:33:09 +1100 Subject: [PATCH 47/76] Add merge request count to each issue on issues list --- .../images/icon-merge-request-unmerged.svg | 1 + app/assets/stylesheets/pages/issues.scss | 5 +++++ .../concerns/issuable_collections.rb | 20 +++++++++++++------ app/controllers/concerns/issues_action.rb | 2 +- .../concerns/merge_requests_action.rb | 2 +- app/controllers/projects/issues_controller.rb | 2 +- .../projects/merge_requests_controller.rb | 2 +- app/models/concerns/issuable.rb | 4 ++-- app/models/merge_requests_closing_issues.rb | 8 ++++++++ .../shared/_issuable_meta_data.html.haml | 6 ++++++ .../unreleased/add_mr_info_to_issues_list.yml | 4 ++++ 11 files changed, 44 insertions(+), 12 deletions(-) create mode 100644 app/assets/images/icon-merge-request-unmerged.svg create mode 100644 changelogs/unreleased/add_mr_info_to_issues_list.yml diff --git a/app/assets/images/icon-merge-request-unmerged.svg b/app/assets/images/icon-merge-request-unmerged.svg new file mode 100644 index 00000000000..c4d8e65122d --- /dev/null +++ b/app/assets/images/icon-merge-request-unmerged.svg @@ -0,0 +1 @@ + diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss index 80b0c9493d8..b595480561b 100644 --- a/app/assets/stylesheets/pages/issues.scss +++ b/app/assets/stylesheets/pages/issues.scss @@ -10,6 +10,11 @@ .issue-labels { display: inline-block; } + + .icon-merge-request-unmerged { + height: 13px; + margin-bottom: 3px; + } } } diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index a6e158ebae6..d7d781cbe72 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -9,24 +9,32 @@ module IssuableCollections private - def issuable_meta_data(issuable_collection) + def issuable_meta_data(issuable_collection, collection_type) # map has to be used here since using pluck or select will # throw an error when ordering issuables by priority which inserts # a new order into the collection. # We cannot use reorder to not mess up the paginated collection. - issuable_ids = issuable_collection.map(&:id) - issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) + issuable_ids = issuable_collection.map(&:id) + issuable_note_count = Note.count_for_collection(issuable_ids, @collection_type) issuable_votes_count = AwardEmoji.votes_for_collection(issuable_ids, @collection_type) + issuable_merge_requests_count = + if collection_type == 'Issue' + MergeRequestsClosingIssues.count_for_collection(issuable_ids) + else + [] + end issuable_ids.each_with_object({}) do |id, issuable_meta| downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? } - upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } - notes = issuable_note_count.find { |notes| notes.noteable_id == id } + upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } + notes = issuable_note_count.find { |notes| notes.noteable_id == id } + merge_requests = issuable_merge_requests_count.find { |mr| mr.issue_id == id } issuable_meta[id] = Issuable::IssuableMeta.new( upvotes.try(:count).to_i, downvotes.try(:count).to_i, - notes.try(:count).to_i + notes.try(:count).to_i, + merge_requests.try(:count).to_i ) end end diff --git a/app/controllers/concerns/issues_action.rb b/app/controllers/concerns/issues_action.rb index fb5edb34370..b17c138d5c7 100644 --- a/app/controllers/concerns/issues_action.rb +++ b/app/controllers/concerns/issues_action.rb @@ -10,7 +10,7 @@ module IssuesAction .page(params[:page]) @collection_type = "Issue" - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) respond_to do |format| format.html diff --git a/app/controllers/concerns/merge_requests_action.rb b/app/controllers/concerns/merge_requests_action.rb index 6229759dcf1..d3c8e4888bc 100644 --- a/app/controllers/concerns/merge_requests_action.rb +++ b/app/controllers/concerns/merge_requests_action.rb @@ -9,7 +9,7 @@ module MergeRequestsAction .page(params[:page]) @collection_type = "MergeRequest" - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) end private diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index 744a4af1c51..05056ad046a 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -26,7 +26,7 @@ class Projects::IssuesController < Projects::ApplicationController @collection_type = "Issue" @issues = issues_collection @issues = @issues.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@issues) + @issuable_meta_data = issuable_meta_data(@issues, @collection_type) if @issues.out_of_range? && @issues.total_pages != 0 return redirect_to url_for(params.merge(page: @issues.total_pages)) diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb index 63b5bcbb586..1d286ca62e5 100644 --- a/app/controllers/projects/merge_requests_controller.rb +++ b/app/controllers/projects/merge_requests_controller.rb @@ -39,7 +39,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController @collection_type = "MergeRequest" @merge_requests = merge_requests_collection @merge_requests = @merge_requests.page(params[:page]) - @issuable_meta_data = issuable_meta_data(@merge_requests) + @issuable_meta_data = issuable_meta_data(@merge_requests, @collection_type) if @merge_requests.out_of_range? && @merge_requests.total_pages != 0 return redirect_to url_for(params.merge(page: @merge_requests.total_pages)) diff --git a/app/models/concerns/issuable.rb b/app/models/concerns/issuable.rb index 5f53c48fc88..c9c6bd24d75 100644 --- a/app/models/concerns/issuable.rb +++ b/app/models/concerns/issuable.rb @@ -16,9 +16,9 @@ module Issuable include TimeTrackable # This object is used to gather issuable meta data for displaying - # upvotes, downvotes and notes count for issues and merge requests + # upvotes, downvotes, notes and closing merge requests count for issues and merge requests # lists avoiding n+1 queries and improving performance. - IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count) + IssuableMeta = Struct.new(:upvotes, :downvotes, :notes_count, :merge_requests_count) included do cache_markdown_field :title, pipeline: :single_line diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb index ab597c37947..1ecdfd1dfdb 100644 --- a/app/models/merge_requests_closing_issues.rb +++ b/app/models/merge_requests_closing_issues.rb @@ -4,4 +4,12 @@ class MergeRequestsClosingIssues < ActiveRecord::Base validates :merge_request_id, uniqueness: { scope: :issue_id }, presence: true validates :issue_id, presence: true + + class << self + def count_for_collection(ids) + select('issue_id', 'COUNT(*) as count'). + group(:issue_id). + where(issue_id: ids) + end + end end diff --git a/app/views/shared/_issuable_meta_data.html.haml b/app/views/shared/_issuable_meta_data.html.haml index 1264e524d86..66310da5cd6 100644 --- a/app/views/shared/_issuable_meta_data.html.haml +++ b/app/views/shared/_issuable_meta_data.html.haml @@ -2,6 +2,12 @@ - issue_votes = @issuable_meta_data[issuable.id] - upvotes, downvotes = issue_votes.upvotes, issue_votes.downvotes - issuable_url = @collection_type == "Issue" ? issue_path(issuable, anchor: 'notes') : merge_request_path(issuable, anchor: 'notes') +- issuable_mr = @issuable_meta_data[issuable.id].merge_requests_count + +- if issuable_mr > 0 + %li + = image_tag('icon-merge-request-unmerged', class: 'icon-merge-request-unmerged') + = issuable_mr - if upvotes > 0 %li diff --git a/changelogs/unreleased/add_mr_info_to_issues_list.yml b/changelogs/unreleased/add_mr_info_to_issues_list.yml new file mode 100644 index 00000000000..8087aa6296c --- /dev/null +++ b/changelogs/unreleased/add_mr_info_to_issues_list.yml @@ -0,0 +1,4 @@ +--- +title: Add merge request count to each issue on issues list +merge_request: 9252 +author: blackst0ne From 32b59a1fa7f439cccbf0de29094c3fab3ec518a8 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 18 Feb 2017 11:47:56 +1100 Subject: [PATCH 48/76] Added specs --- spec/features/issuables/issuable_list_spec.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index e31bc40adc3..13ea9ce853c 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -30,6 +30,12 @@ describe 'issuable list', feature: true do end end + it "counts merge requests closing issues icons for each issue" do + visit_issuable_list(:issue) + + expect(first('.icon-merge-request-unmerged').find(:xpath, '..')).to have_content(1) + end + def visit_issuable_list(issuable_type) if issuable_type == :issue visit namespace_project_issues_path(project.namespace, project) @@ -42,6 +48,13 @@ describe 'issuable list', feature: true do 3.times do if issuable_type == :issue issuable = create(:issue, project: project, author: user) + merge_request = create(:merge_request, + title: FFaker::Lorem.sentence, + description: "Closes #{issuable.to_reference}", + source_project: project, + source_branch: FFaker::Name.name) + + MergeRequestsClosingIssues.create!(issue: issuable, merge_request: merge_request) else issuable = create(:merge_request, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) end From c21df05066a3a9351db649ebc3f00f4bee63cce8 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 18 Feb 2017 11:49:13 +1100 Subject: [PATCH 49/76] Remove empty line in note --- app/views/projects/notes/_note.html.haml | 1 - 1 file changed, 1 deletion(-) diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml index a68a09baf4f..1b08165c14c 100644 --- a/app/views/projects/notes/_note.html.haml +++ b/app/views/projects/notes/_note.html.haml @@ -63,7 +63,6 @@ = icon('pencil', class: 'link-highlight') = link_to namespace_project_note_path(note.project.namespace, note.project, note), title: 'Remove comment', method: :delete, data: { confirm: 'Are you sure you want to remove this comment?' }, remote: true, class: 'note-action-button js-note-delete danger' do = icon('trash-o', class: 'danger-highlight') - .note-body{ class: note_editable ? 'js-task-list-container' : '' } .note-text.md = preserve do From 24ba7585e6da5ee8881ff8b4db53558940cb0c23 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 18 Feb 2017 12:58:24 +1100 Subject: [PATCH 50/76] Fixed rubocop offenses --- spec/features/issuables/issuable_list_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 13ea9ce853c..ce4dca1175f 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -30,11 +30,11 @@ describe 'issuable list', feature: true do end end - it "counts merge requests closing issues icons for each issue" do - visit_issuable_list(:issue) + it "counts merge requests closing issues icons for each issue" do + visit_issuable_list(:issue) - expect(first('.icon-merge-request-unmerged').find(:xpath, '..')).to have_content(1) - end + expect(first('.icon-merge-request-unmerged').find(:xpath, '..')).to have_content(1) + end def visit_issuable_list(issuable_type) if issuable_type == :issue From b2f1c2b8be610695cf0523ae93524a1f53831c44 Mon Sep 17 00:00:00 2001 From: Rudi Kramer Date: Mon, 20 Feb 2017 11:14:40 +0000 Subject: [PATCH 51/76] Update two_factor_authentication.md by correcting FreeOTP link. --- doc/user/profile/account/two_factor_authentication.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/user/profile/account/two_factor_authentication.md b/doc/user/profile/account/two_factor_authentication.md index a23ad79ae1d..eaa39a0c4ea 100644 --- a/doc/user/profile/account/two_factor_authentication.md +++ b/doc/user/profile/account/two_factor_authentication.md @@ -213,5 +213,5 @@ your GitLab server's time is synchronized via a service like NTP. Otherwise, you may have cases where authorization always fails because of time differences. [Google Authenticator]: https://support.google.com/accounts/answer/1066447?hl=en -[FreeOTP]: https://fedorahosted.org/freeotp/ +[FreeOTP]: https://freeotp.github.io/ [YubiKey]: https://www.yubico.com/products/yubikey-hardware/ From 95ed01749e0ffe55a979acb246ca8e0ae663bffb Mon Sep 17 00:00:00 2001 From: Jan Christophersen Date: Sat, 11 Feb 2017 20:15:01 +0100 Subject: [PATCH 52/76] Add AsciiDoc snippet for CI/CD Badges This commit adds CI/CD Badges Snippets for AsciiDoc as requested in #26087. I've however run into an issue in highlighting the snippet, it seems as if AsciiDoc is currently not being highlighted properly (displayed as plaintext) Add testcase for to_asciidoc Update test case for Badges list --- app/views/projects/pipelines_settings/_badge.html.haml | 7 +++++++ .../unreleased/26087-asciidoc-cicd-badges-snippet.yml | 4 ++++ lib/gitlab/badge/metadata.rb | 4 ++++ spec/features/projects/badges/list_spec.rb | 6 ++++-- spec/lib/gitlab/badge/shared/metadata.rb | 10 ++++++++++ 5 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/26087-asciidoc-cicd-badges-snippet.yml diff --git a/app/views/projects/pipelines_settings/_badge.html.haml b/app/views/projects/pipelines_settings/_badge.html.haml index 22a3b884520..43bbd735059 100644 --- a/app/views/projects/pipelines_settings/_badge.html.haml +++ b/app/views/projects/pipelines_settings/_badge.html.haml @@ -25,3 +25,10 @@ HTML .col-md-10.code.js-syntax-highlight = highlight('.html', badge.to_html) + .row + %hr + .row + .col-md-2.text-center + AsciiDoc + .col-md-10.code.js-syntax-highlight + = highlight('.adoc', badge.to_asciidoc) diff --git a/changelogs/unreleased/26087-asciidoc-cicd-badges-snippet.yml b/changelogs/unreleased/26087-asciidoc-cicd-badges-snippet.yml new file mode 100644 index 00000000000..799c5277207 --- /dev/null +++ b/changelogs/unreleased/26087-asciidoc-cicd-badges-snippet.yml @@ -0,0 +1,4 @@ +--- +title: Added AsciiDoc Snippet to CI/CD Badges +merge_request: 9164 +author: Jan Christophersen diff --git a/lib/gitlab/badge/metadata.rb b/lib/gitlab/badge/metadata.rb index 548f85b78bb..4a049ef758d 100644 --- a/lib/gitlab/badge/metadata.rb +++ b/lib/gitlab/badge/metadata.rb @@ -20,6 +20,10 @@ module Gitlab "[![#{title}](#{image_url})](#{link_url})" end + def to_asciidoc + "image:#{image_url}[link=\"#{link_url}\",title=\"#{title}\"]" + end + def title raise NotImplementedError end diff --git a/spec/features/projects/badges/list_spec.rb b/spec/features/projects/badges/list_spec.rb index 67a4a5d1ab1..ae9db0c0d6e 100644 --- a/spec/features/projects/badges/list_spec.rb +++ b/spec/features/projects/badges/list_spec.rb @@ -14,7 +14,8 @@ feature 'list of badges' do expect(page).to have_content 'build status' expect(page).to have_content 'Markdown' expect(page).to have_content 'HTML' - expect(page).to have_css('.highlight', count: 2) + expect(page).to have_content 'AsciiDoc' + expect(page).to have_css('.highlight', count: 3) expect(page).to have_xpath("//img[@alt='build status']") page.within('.highlight', match: :first) do @@ -28,7 +29,8 @@ feature 'list of badges' do expect(page).to have_content 'coverage report' expect(page).to have_content 'Markdown' expect(page).to have_content 'HTML' - expect(page).to have_css('.highlight', count: 2) + expect(page).to have_content 'AsciiDoc' + expect(page).to have_css('.highlight', count: 3) expect(page).to have_xpath("//img[@alt='coverage report']") page.within('.highlight', match: :first) do diff --git a/spec/lib/gitlab/badge/shared/metadata.rb b/spec/lib/gitlab/badge/shared/metadata.rb index 0cf18514251..63c7ca5a915 100644 --- a/spec/lib/gitlab/badge/shared/metadata.rb +++ b/spec/lib/gitlab/badge/shared/metadata.rb @@ -18,4 +18,14 @@ shared_examples 'badge metadata' do it { is_expected.to include metadata.image_url } it { is_expected.to include metadata.link_url } end + + describe '#to_asciidoc' do + subject { metadata.to_asciidoc } + + it { is_expected.to include metadata.image_url } + it { is_expected.to include metadata.link_url } + it { is_expected.to include 'image:' } + it { is_expected.to include 'link=' } + it { is_expected.to include 'title=' } + end end From 2a12cbe6d6d5c7c78c6fac64e7d5a6af6742462a Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Tue, 21 Feb 2017 12:07:50 +1100 Subject: [PATCH 53/76] Improved specs --- spec/features/issuables/issuable_list_spec.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index ce4dca1175f..4ea801cd1ac 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -33,6 +33,7 @@ describe 'issuable list', feature: true do it "counts merge requests closing issues icons for each issue" do visit_issuable_list(:issue) + expect(page).to have_selector('.icon-merge-request-unmerged', count: 1) expect(first('.icon-merge-request-unmerged').find(:xpath, '..')).to have_content(1) end @@ -48,13 +49,6 @@ describe 'issuable list', feature: true do 3.times do if issuable_type == :issue issuable = create(:issue, project: project, author: user) - merge_request = create(:merge_request, - title: FFaker::Lorem.sentence, - description: "Closes #{issuable.to_reference}", - source_project: project, - source_branch: FFaker::Name.name) - - MergeRequestsClosingIssues.create!(issue: issuable, merge_request: merge_request) else issuable = create(:merge_request, title: FFaker::Lorem.sentence, source_project: project, source_branch: FFaker::Name.name) end @@ -65,6 +59,16 @@ describe 'issuable list', feature: true do create(:award_emoji, :downvote, awardable: issuable) create(:award_emoji, :upvote, awardable: issuable) + + if issuable_type == :issue + issue = Issue.reorder(:iid).first + merge_request = create(:merge_request, + title: FFaker::Lorem.sentence, + source_project: project, + source_branch: FFaker::Name.name) + + MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) if MergeRequestsClosingIssues.count.zero? + end end end end From 1eb72a71f54da310b2277e5890dce27c15e11036 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Tue, 21 Feb 2017 12:45:08 +1100 Subject: [PATCH 54/76] Refactored count_for_collection() for using pluck instead of select --- app/controllers/concerns/issuable_collections.rb | 4 ++-- app/models/merge_requests_closing_issues.rb | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/concerns/issuable_collections.rb b/app/controllers/concerns/issuable_collections.rb index d7d781cbe72..85ae4985e58 100644 --- a/app/controllers/concerns/issuable_collections.rb +++ b/app/controllers/concerns/issuable_collections.rb @@ -28,13 +28,13 @@ module IssuableCollections downvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.downvote? } upvotes = issuable_votes_count.find { |votes| votes.awardable_id == id && votes.upvote? } notes = issuable_note_count.find { |notes| notes.noteable_id == id } - merge_requests = issuable_merge_requests_count.find { |mr| mr.issue_id == id } + merge_requests = issuable_merge_requests_count.find { |mr| mr.first == id } issuable_meta[id] = Issuable::IssuableMeta.new( upvotes.try(:count).to_i, downvotes.try(:count).to_i, notes.try(:count).to_i, - merge_requests.try(:count).to_i + merge_requests.try(:last).to_i ) end end diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb index 1ecdfd1dfdb..97210900bd5 100644 --- a/app/models/merge_requests_closing_issues.rb +++ b/app/models/merge_requests_closing_issues.rb @@ -7,9 +7,9 @@ class MergeRequestsClosingIssues < ActiveRecord::Base class << self def count_for_collection(ids) - select('issue_id', 'COUNT(*) as count'). - group(:issue_id). - where(issue_id: ids) + group(:issue_id). + where(issue_id: ids). + pluck('issue_id', 'COUNT(*) as count') end end end From 63bd79f594272d98ce022685f26a47ce0afae9d4 Mon Sep 17 00:00:00 2001 From: "Z.J. van de Weg" Date: Tue, 21 Feb 2017 09:53:44 +0100 Subject: [PATCH 55/76] Chat slash commands show labels correctly --- .../unreleased/zj-fix-slash-command-labels.yml | 4 ++++ lib/gitlab/chat_commands/presenters/issue_base.rb | 2 +- .../chat_commands/presenters/issue_show_spec.rb | 15 +++++++++++++++ 3 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/zj-fix-slash-command-labels.yml diff --git a/changelogs/unreleased/zj-fix-slash-command-labels.yml b/changelogs/unreleased/zj-fix-slash-command-labels.yml new file mode 100644 index 00000000000..93b7194dd4e --- /dev/null +++ b/changelogs/unreleased/zj-fix-slash-command-labels.yml @@ -0,0 +1,4 @@ +--- +title: Chat slash commands show labels correctly +merge_request: +author: diff --git a/lib/gitlab/chat_commands/presenters/issue_base.rb b/lib/gitlab/chat_commands/presenters/issue_base.rb index a0058407fb2..054f7f4be0c 100644 --- a/lib/gitlab/chat_commands/presenters/issue_base.rb +++ b/lib/gitlab/chat_commands/presenters/issue_base.rb @@ -32,7 +32,7 @@ module Gitlab }, { title: "Labels", - value: @resource.labels.any? ? @resource.label_names : "_None_", + value: @resource.labels.any? ? @resource.label_names.join(', ') : "_None_", short: true } ] diff --git a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb index 5b678d31fce..3916fc704a4 100644 --- a/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb +++ b/spec/lib/gitlab/chat_commands/presenters/issue_show_spec.rb @@ -26,6 +26,21 @@ describe Gitlab::ChatCommands::Presenters::IssueShow do end end + context 'with labels' do + let(:label) { create(:label, project: project, title: 'mep') } + let(:label1) { create(:label, project: project, title: 'mop') } + + before do + issue.labels << [label, label1] + end + + it 'shows the labels' do + labels = attachment[:fields].find { |f| f[:title] == 'Labels' } + + expect(labels[:value]).to eq("mep, mop") + end + end + context 'confidential issue' do let(:issue) { create(:issue, project: project) } From 71270f80dd42e524a904a3c19f23217e8766e282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nov=C3=BD?= Date: Thu, 25 Aug 2016 21:56:32 +0000 Subject: [PATCH 56/76] UI: Allow a project variable to be set to an empty value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- app/views/projects/variables/_form.html.haml | 2 +- .../lnovy-gitlab-ce-empty-variables.yml | 4 ++ spec/features/variables_spec.rb | 44 ++++++++++++++++--- 3 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 changelogs/unreleased/lnovy-gitlab-ce-empty-variables.yml diff --git a/app/views/projects/variables/_form.html.haml b/app/views/projects/variables/_form.html.haml index a5bae83e0ce..1ae86d258af 100644 --- a/app/views/projects/variables/_form.html.haml +++ b/app/views/projects/variables/_form.html.haml @@ -6,5 +6,5 @@ = f.text_field :key, class: "form-control", placeholder: "PROJECT_VARIABLE", required: true .form-group = f.label :value, "Value", class: "label-light" - = f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE", required: true + = f.text_area :value, class: "form-control", placeholder: "PROJECT_VARIABLE" = f.submit btn_text, class: "btn btn-save" diff --git a/changelogs/unreleased/lnovy-gitlab-ce-empty-variables.yml b/changelogs/unreleased/lnovy-gitlab-ce-empty-variables.yml new file mode 100644 index 00000000000..bd5db5ac7af --- /dev/null +++ b/changelogs/unreleased/lnovy-gitlab-ce-empty-variables.yml @@ -0,0 +1,4 @@ +--- +title: 'UI: Allow a project variable to be set to an empty value' +merge_request: 6044 +author: Lukáš Nový diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb index 9a4bc027004..a07eba2f01e 100644 --- a/spec/features/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe 'Project variables', js: true do let(:user) { create(:user) } let(:project) { create(:project) } - let(:variable) { create(:ci_variable, key: 'test') } + let(:variable) { create(:ci_variable, key: 'test_key', value: 'test value') } before do login_as(user) @@ -16,16 +16,28 @@ describe 'Project variables', js: true do it 'shows list of variables' do page.within('.variables-table') do expect(page).to have_content(variable.key) + expect(page).to have_content(variable.value) end end it 'adds new variable' do - fill_in('variable_key', with: 'key') - fill_in('variable_value', with: 'key value') + fill_in('variable_key', with: 'new_key') + fill_in('variable_value', with: 'new value') click_button('Add new variable') page.within('.variables-table') do - expect(page).to have_content('key') + expect(page).to have_content('new_key') + expect(page).to have_content('new value') + end + end + + it 'adds empty variable' do + fill_in('variable_key', with: 'new_key') + fill_in('variable_value', with: '') + click_button('Add new variable') + + page.within('.variables-table') do + expect(page).to have_content('new_key') end end @@ -68,12 +80,30 @@ describe 'Project variables', js: true do end expect(page).to have_content('Update variable') - fill_in('variable_key', with: 'key') - fill_in('variable_value', with: 'key value') + fill_in('variable_key', with: 'new_key') + fill_in('variable_value', with: 'new value') click_button('Save variable') page.within('.variables-table') do - expect(page).to have_content('key') + expect(page).not_to have_content(variable.key) + expect(page).not_to have_content(variable.value) + expect(page).to have_content('new_key') + expect(page).to have_content('new value') + end + end + + it 'edits variable with empty value' do + page.within('.variables-table') do + find('.btn-variable-edit').click + end + + expect(page).to have_content('Update variable') + fill_in('variable_value', with: '') + click_button('Save variable') + + page.within('.variables-table') do + expect(page).to have_content(variable.key) + expect(page).not_to have_content(variable.value) end end end From 4f115a090a931c3999f6b51d9fa027165b96b618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Tue, 21 Feb 2017 18:48:22 +0100 Subject: [PATCH 57/76] Fix specs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Rémy Coutable --- spec/features/variables_spec.rb | 28 +++++++++++----------------- 1 file changed, 11 insertions(+), 17 deletions(-) diff --git a/spec/features/variables_spec.rb b/spec/features/variables_spec.rb index a07eba2f01e..a362d6fd3b6 100644 --- a/spec/features/variables_spec.rb +++ b/spec/features/variables_spec.rb @@ -16,18 +16,17 @@ describe 'Project variables', js: true do it 'shows list of variables' do page.within('.variables-table') do expect(page).to have_content(variable.key) - expect(page).to have_content(variable.value) end end it 'adds new variable' do - fill_in('variable_key', with: 'new_key') - fill_in('variable_value', with: 'new value') + fill_in('variable_key', with: 'key') + fill_in('variable_value', with: 'key value') click_button('Add new variable') + expect(page).to have_content('Variables were successfully updated.') page.within('.variables-table') do - expect(page).to have_content('new_key') - expect(page).to have_content('new value') + expect(page).to have_content('key') end end @@ -36,6 +35,7 @@ describe 'Project variables', js: true do fill_in('variable_value', with: '') click_button('Add new variable') + expect(page).to have_content('Variables were successfully updated.') page.within('.variables-table') do expect(page).to have_content('new_key') end @@ -80,16 +80,12 @@ describe 'Project variables', js: true do end expect(page).to have_content('Update variable') - fill_in('variable_key', with: 'new_key') - fill_in('variable_value', with: 'new value') + fill_in('variable_key', with: 'key') + fill_in('variable_value', with: 'key value') click_button('Save variable') - page.within('.variables-table') do - expect(page).not_to have_content(variable.key) - expect(page).not_to have_content(variable.value) - expect(page).to have_content('new_key') - expect(page).to have_content('new value') - end + expect(page).to have_content('Variable was successfully updated.') + expect(project.variables.first.value).to eq('key value') end it 'edits variable with empty value' do @@ -101,9 +97,7 @@ describe 'Project variables', js: true do fill_in('variable_value', with: '') click_button('Save variable') - page.within('.variables-table') do - expect(page).to have_content(variable.key) - expect(page).not_to have_content(variable.value) - end + expect(page).to have_content('Variable was successfully updated.') + expect(project.variables.first.value).to eq('') end end From 0b2fc0557f00753a552600da6e5c13d5617afaee Mon Sep 17 00:00:00 2001 From: Dmitriy Volkov Date: Sat, 11 Feb 2017 16:56:53 +0300 Subject: [PATCH 58/76] docs(ci/docker_build): Add example of variable use --- doc/ci/docker/using_docker_build.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/ci/docker/using_docker_build.md b/doc/ci/docker/using_docker_build.md index 28141cced3b..174fa8393e4 100644 --- a/doc/ci/docker/using_docker_build.md +++ b/doc/ci/docker/using_docker_build.md @@ -298,6 +298,30 @@ push to the Registry connected to your project. Its password is provided in the `$CI_BUILD_TOKEN` variable. This allows you to automate building and deployment of your Docker images. +You can also make use of [other variables](../variables/README.md) to avoid hardcoding: + +```yaml +services: + - docker:dind + +variables: + IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_BUILD_REF_NAME + +before_script: + - docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $CI_REGISTRY + +build: + stage: build + script: + - docker build -t $IMAGE_TAG . + - docker push $IMAGE_TAG +``` + +Here, `$CI_REGISTRY_IMAGE` would be resolved to the address of the registry tied +to this project, and `$CI_BUILD_REF_NAME` would be resolved to the branch or +tag name for this particular job. We also declare our own variable, `$IMAGE_TAG`, +combining the two to save us some typing in the `script` section. + Here's a more elaborate example that splits up the tasks into 4 pipeline stages, including two tests that run in parallel. The build is stored in the container registry and used by subsequent stages, downloading the image From 601b5adf5768b548a5810ffe890b38f7f4980d89 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 21 Feb 2017 19:34:03 +0000 Subject: [PATCH 59/76] Use a btn-group to group all action buttons --- .../components/environment_actions.js.es6 | 38 +++++++++---------- .../components/environment_item.js.es6 | 25 +++--------- .../stylesheets/pages/environments.scss | 18 ++++++++- 3 files changed, 42 insertions(+), 39 deletions(-) diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index c5a714d9673..978d4dd8b6b 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -15,29 +15,29 @@ module.exports = Vue.component('actions-component', { }, template: ` -
- + + {{action.name}} + + + + + +
`, }); diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 24fd58a301a..ad9d1d21a79 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -505,39 +505,26 @@ module.exports = Vue.component('environment-item', {
-
- + -
-
- -
-
- -
-
- -
-
- diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 181dcb7721f..f789ae1ccd3 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -35,7 +35,6 @@ display: table-cell; } - .environments-name, .environments-commit, .environments-actions { width: 20%; @@ -45,6 +44,7 @@ width: 10%; } + .environments-name, .environments-deploy, .environments-build { width: 15%; @@ -62,6 +62,22 @@ } } + .btn-group { + + > a { + color: $gl-text-color-secondary; + } + + svg path { + fill: $gl-text-color-secondary; + } + + .dropdown { + outline: none; + } + } + + .commit-title { margin: 0; } From 93e3cfec3abc7c0eed741ba94779bf014cd9bcb7 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 22 Feb 2017 08:52:49 +1100 Subject: [PATCH 60/76] Added space indentation in models/merge_requests_closing_issues.rb --- app/models/merge_requests_closing_issues.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/merge_requests_closing_issues.rb b/app/models/merge_requests_closing_issues.rb index 97210900bd5..daafb137be4 100644 --- a/app/models/merge_requests_closing_issues.rb +++ b/app/models/merge_requests_closing_issues.rb @@ -8,8 +8,8 @@ class MergeRequestsClosingIssues < ActiveRecord::Base class << self def count_for_collection(ids) group(:issue_id). - where(issue_id: ids). - pluck('issue_id', 'COUNT(*) as count') + where(issue_id: ids). + pluck('issue_id', 'COUNT(*) as count') end end end From 5cc838d325fb3fcdd7a86a43c67a442ce5feb3d9 Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 22 Feb 2017 09:00:03 +1100 Subject: [PATCH 61/76] Refactored specs --- spec/features/issuables/issuable_list_spec.rb | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 4ea801cd1ac..1fc1c20b8a3 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -60,15 +60,15 @@ describe 'issuable list', feature: true do create(:award_emoji, :downvote, awardable: issuable) create(:award_emoji, :upvote, awardable: issuable) - if issuable_type == :issue - issue = Issue.reorder(:iid).first - merge_request = create(:merge_request, - title: FFaker::Lorem.sentence, - source_project: project, - source_branch: FFaker::Name.name) + if issuable_type == :issue + issue = Issue.reorder(:iid).first + merge_request = create(:merge_request, + title: FFaker::Lorem.sentence, + source_project: project, + source_branch: FFaker::Name.name) - MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) if MergeRequestsClosingIssues.count.zero? - end + MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) if MergeRequestsClosingIssues.count.zero? + end end end end From 0494930d7a939297a071bb817ad0227da17dda1b Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Wed, 22 Feb 2017 09:08:20 +1100 Subject: [PATCH 62/76] Refactored specs --- spec/features/issuables/issuable_list_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/features/issuables/issuable_list_spec.rb b/spec/features/issuables/issuable_list_spec.rb index 1fc1c20b8a3..0bf7977fb02 100644 --- a/spec/features/issuables/issuable_list_spec.rb +++ b/spec/features/issuables/issuable_list_spec.rb @@ -59,6 +59,7 @@ describe 'issuable list', feature: true do create(:award_emoji, :downvote, awardable: issuable) create(:award_emoji, :upvote, awardable: issuable) + end if issuable_type == :issue issue = Issue.reorder(:iid).first @@ -67,8 +68,7 @@ describe 'issuable list', feature: true do source_project: project, source_branch: FFaker::Name.name) - MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) if MergeRequestsClosingIssues.count.zero? - end + MergeRequestsClosingIssues.create!(issue: issue, merge_request: merge_request) end end end From b8c88a839da9722f17bc7a851af2fae15e1ab1c5 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 22 Feb 2017 10:40:58 +0100 Subject: [PATCH 63/76] Grapfiy the CI::Triggers API --- lib/ci/api/triggers.rb | 43 ++++++++++----------------- spec/requests/ci/api/triggers_spec.rb | 3 +- 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/lib/ci/api/triggers.rb b/lib/ci/api/triggers.rb index 63b42113513..6e622601680 100644 --- a/lib/ci/api/triggers.rb +++ b/lib/ci/api/triggers.rb @@ -1,41 +1,30 @@ module Ci module API - # Build Trigger API class Triggers < Grape::API resource :projects do - # Trigger a GitLab CI project build - # - # Parameters: - # id (required) - The ID of a CI project - # ref (required) - The name of project's branch or tag - # token (required) - The uniq token of trigger - # Example Request: - # POST /projects/:id/ref/:ref/trigger + desc 'Trigger a GitLab CI project build' do + success Entities::TriggerRequest + end + params do + requires :id, type: Integer, desc: 'The ID of a CI project' + requires :ref, type: String, desc: "The name of project's branch or tag" + requires :token, type: String, desc: 'The unique token of the trigger' + optional :variables, type: Hash, desc: 'Optional build variables' + end post ":id/refs/:ref/trigger" do - required_attributes! [:token] - - project = Project.find_by(ci_id: params[:id].to_i) - trigger = Ci::Trigger.find_by_token(params[:token].to_s) + project = Project.find_by(ci_id: params[:id]) + trigger = Ci::Trigger.find_by_token(params[:token]) not_found! unless project && trigger unauthorized! unless trigger.project == project - # validate variables - variables = params[:variables] - if variables - unless variables.is_a?(Hash) - render_api_error!('variables needs to be a hash', 400) - end - - unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) } - render_api_error!('variables needs to be a map of key-valued strings', 400) - end - - # convert variables from Mash to Hash - variables = variables.to_h + # Validate variables + variables = params[:variables].to_h + unless variables.all? { |key, value| key.is_a?(String) && value.is_a?(String) } + render_api_error!('variables needs to be a map of key-valued strings', 400) end # create request and trigger builds - trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref].to_s, variables) + trigger_request = Ci::CreateTriggerRequestService.new.execute(project, trigger, params[:ref], variables) if trigger_request present trigger_request, with: Entities::TriggerRequest else diff --git a/spec/requests/ci/api/triggers_spec.rb b/spec/requests/ci/api/triggers_spec.rb index a30be767119..5321f8b134f 100644 --- a/spec/requests/ci/api/triggers_spec.rb +++ b/spec/requests/ci/api/triggers_spec.rb @@ -60,7 +60,8 @@ describe Ci::API::Triggers do it 'validates variables to be a hash' do post ci_api("/projects/#{project.ci_id}/refs/master/trigger"), options.merge(variables: 'value') expect(response).to have_http_status(400) - expect(json_response['message']).to eq('variables needs to be a hash') + + expect(json_response['error']).to eq('variables is invalid') end it 'validates variables needs to be a map of key-valued strings' do From f0766fdefaeadcc526d6a87e29b65f5bf7b26318 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Mon, 6 Feb 2017 20:15:25 +0100 Subject: [PATCH 64/76] extract pipeline mails layout --- .../images/mailers/gitlab_footer_logo.gif | Bin 0 -> 3654 bytes .../images/mailers/gitlab_header_logo.gif | Bin 0 -> 3040 bytes app/mailers/emails/pipelines.rb | 4 +- app/views/layouts/mailer.html.haml | 72 +++++ app/views/layouts/mailer.text.haml | 5 + .../notify/pipeline_failed_email.html.haml | 280 +++++++----------- .../notify/pipeline_failed_email.text.erb | 4 - .../notify/pipeline_success_email.html.haml | 230 +++++--------- .../notify/pipeline_success_email.text.erb | 4 - 9 files changed, 264 insertions(+), 335 deletions(-) create mode 100644 app/assets/images/mailers/gitlab_footer_logo.gif create mode 100644 app/assets/images/mailers/gitlab_header_logo.gif create mode 100644 app/views/layouts/mailer.html.haml create mode 100644 app/views/layouts/mailer.text.haml diff --git a/app/assets/images/mailers/gitlab_footer_logo.gif b/app/assets/images/mailers/gitlab_footer_logo.gif new file mode 100644 index 0000000000000000000000000000000000000000..3f4ef31947bc4a53d6b2d243d6e9f2c975c84b77 GIT binary patch literal 3654 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 z

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 +%html{ lang: "en" } + %head + %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }/ + %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }/ + %meta{ content: "IE=edge", "http-equiv" => "X-UA-Compatible" }/ + %title= message.subject + :css + /* CLIENT-SPECIFIC STYLES */ + body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } + table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; } + img { -ms-interpolation-mode: bicubic; } + + /* iOS BLUE LINKS */ + a[x-apple-data-detectors] { + color: inherit !important; + text-decoration: none !important; + font-size: inherit !important; + font-family: inherit !important; + font-weight: inherit !important; + line-height: inherit !important; + } + + /* ANDROID MARGIN HACK */ + body { margin:0 !important; } + div[style*="margin: 16px 0"] { margin:0 !important; } + + @media only screen and (max-width: 639px) { + body, #body { + min-width: 320px !important; + } + table.wrapper { + width: 100% !important; + min-width: 320px !important; + } + table.wrapper > tbody > tr > td { + border-left: 0 !important; + border-right: 0 !important; + border-radius: 0 !important; + padding-left: 10px !important; + padding-right: 10px !important; + } + } + %body{ style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;height:100%;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } + %table#body{ border: "0", cellpadding: "0", cellspacing: "0", style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;" } + %tbody + %tr.line + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }   + %tr.header + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } + %img{ alt: "GitLab", height: "50", src: image_url('mailers/gitlab_header_logo.gif'), width: "55" }/ + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } + %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#ffffff;text-align:left;padding:18px 25px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } + %table.content{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:separate;border-spacing:0;" } + %tbody + = yield + + %tr.footer + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } + %img{ alt: "GitLab", height: "33", src: image_url('mailers/gitlab_footer_logo.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/ + %div + %a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications + · + %a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help + %div + You're receiving this email because of your account on + = succeed "." do + %a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host diff --git a/app/views/layouts/mailer.text.haml b/app/views/layouts/mailer.text.haml new file mode 100644 index 00000000000..6a9c6ced9cc --- /dev/null +++ b/app/views/layouts/mailer.text.haml @@ -0,0 +1,5 @@ += yield + +You're receiving this email because of your account on #{Gitlab.config.gitlab.host}. +Manage all notifications: #{profile_notifications_url} +Help: #{help_url} diff --git a/app/views/notify/pipeline_failed_email.html.haml b/app/views/notify/pipeline_failed_email.html.haml index d9ebbaa2704..85a1aea3a61 100644 --- a/app/views/notify/pipeline_failed_email.html.haml +++ b/app/views/notify/pipeline_failed_email.html.haml @@ -1,179 +1,109 @@ - -%html{ lang: "en" } - %head - %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }/ - %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }/ - %meta{ content: "IE=edge", "http-equiv" => "X-UA-Compatible" }/ - %title= message.subject - :css - /* CLIENT-SPECIFIC STYLES */ - body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } - table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; } - img { -ms-interpolation-mode: bicubic; } - - /* iOS BLUE LINKS */ - a[x-apple-data-detectors] { - color: inherit !important; - text-decoration: none !important; - font-size: inherit !important; - font-family: inherit !important; - font-weight: inherit !important; - line-height: inherit !important; - } - - /* ANDROID MARGIN HACK */ - body { margin:0 !important; } - div[style*="margin: 16px 0"] { margin:0 !important; } - - @media only screen and (max-width: 639px) { - body, #body { - min-width: 320px !important; - } - table.wrapper { - width: 100% !important; - min-width: 320px !important; - } - table.wrapper > tbody > tr > td { - border-left: 0 !important; - border-right: 0 !important; - border-radius: 0 !important; - padding-left: 10px !important; - padding-right: 10px !important; - } - } - %body{ style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;height:100%;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } - %table#body{ border: "0", cellpadding: "0", cellspacing: "0", style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;" } +%tr.alert + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:10px;border-radius:3px;font-size:14px;line-height:1.3;text-align:center;overflow:hidden;background-color:#d22f57;color:#ffffff;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" } %tbody - %tr.line - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }   - %tr.header - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } - %img{ alt: "GitLab", height: "50", src: image_url('mailers/ci_pipeline_notif_v1/gitlab-logo.gif'), width: "55" }/ %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } - %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" } + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;padding-right:5px;" } + %img{ alt: "x", height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red-inverted.gif'), style: "display:block;", width: "13" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;" } + Your pipeline has failed. +%tr.spacer + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } +   +%tr.section + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } + %table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" } Project + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;" } + - namespace_name = @project.group ? @project.group.name : @project.namespace.owner.name + - namespace_url = @project.group ? group_url(@project.group) : user_url(@project.namespace.owner) + %a.muted{ href: namespace_url, style: "color:#333333;text-decoration:none;" } + = namespace_name + \/ + %a.muted{ href: project_url(@project), style: "color:#333333;text-decoration:none;" } + = @project.name + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Branch + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } %tbody %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#ffffff;text-align:left;padding:18px 25px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } - %table.content{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:separate;border-spacing:0;" } - %tbody - %tr.alert - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:10px;border-radius:3px;font-size:14px;line-height:1.3;text-align:center;overflow:hidden;background-color:#d22f57;color:#ffffff;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;padding-right:5px;" } - %img{ alt: "x", height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red-inverted.gif'), style: "display:block;", width: "13" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;" } - Your pipeline has failed. - %tr.spacer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } -   - %tr.section - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } - %table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" } Project - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;" } - - namespace_name = @project.group ? @project.group.name : @project.namespace.owner.name - - namespace_url = @project.group ? group_url(@project.group) : user_url(@project.namespace.owner) - %a.muted{ href: namespace_url, style: "color:#333333;text-decoration:none;" } - = namespace_name - \/ - %a.muted{ href: project_url(@project), style: "color:#333333;text-decoration:none;" } - = @project.name - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Branch - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-branch-gray.gif'), style: "display:block;", width: "13", alt: "Branch icon" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - %a.muted{ href: commits_url(@pipeline), style: "color:#333333;text-decoration:none;" } - = @pipeline.ref - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-commit-gray.gif'), style: "display:block;", width: "13", alt: "Commit icon" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - %a{ href: commit_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } - = @pipeline.short_sha - - if @merge_request - in - %a{ href: merge_request_url(@merge_request), style: "color:#3777b0;text-decoration:none;" } - = @merge_request.to_reference - .commit{ style: "color:#5c5c5c;font-weight:300;" } - = @pipeline.git_commit_message.truncate(50) - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Author - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - - commit = @pipeline.commit - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img.avatar{ height: "24", src: avatar_icon(commit.author || commit.author_email, 24), style: "display:block;border-radius:12px;margin:-2px 0;", width: "24", alt: "Avatar" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - - if commit.author - %a.muted{ href: user_url(commit.author), style: "color:#333333;text-decoration:none;" } - = commit.author.name - - else - %span - = commit.author_name - %tr.spacer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } -   - - failed = @pipeline.statuses.latest.failed - %tr.pre-section - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:400;line-height:1.4;padding:15px 0;" } - Pipeline - %a{ href: pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } - = "\##{@pipeline.id}" - had - = failed.size - failed - #{'build'.pluralize(failed.size)}. - %tr.warning - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #ededed;border-bottom:0;border-radius:3px 3px 0 0;overflow:hidden;background-color:#fdf4f6;color:#d22852;font-size:14px;line-height:1.4;text-align:center;padding:8px 15px;" } - Logs may contain sensitive data. Please consider before forwarding this email. - %tr.section - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;border-top:0;border-radius:0 0 3px 3px;" } - %table.builds{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:collapse;" } - %tbody - - failed.each do |build| - %tr.build-state - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#8c8c8c;font-weight:500;font-size:15px;vertical-align:middle;padding-right:5px;" } - %img{ alt: "x", height: "10", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red.gif'), style: "display:block;", width: "10" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#8c8c8c;font-weight:500;font-size:15px;vertical-align:middle;" } - = build.stage - %td{ align: "right", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" } - = render "notify/links/#{build.to_partial_path}", pipeline: @pipeline, build: build - %tr.build-log - - if build.has_trace? - %td{ colspan: "2", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 0 15px;" } - %pre{ style: "font-family:Monaco,'Lucida Console','Courier New',Courier,monospace;background-color:#fafafa;border-radius:3px;overflow:hidden;white-space:pre-wrap;word-break:break-all;font-size:13px;line-height:1.4;padding:12px;color:#333333;margin:0;" } - = build.trace_html(last_lines: 10).html_safe - - else - %td{ colspan: "2" } - %tr.footer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } - %img{ alt: "GitLab", height: "33", src: image_url('mailers/ci_pipeline_notif_v1/gitlab-logo-full-horizontal.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/ - %div - %a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications - · - %a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help - %div - You're receiving this email because of your account on - = succeed "." do - %a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-branch-gray.gif'), style: "display:block;", width: "13", alt: "Branch icon" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + %a.muted{ href: commits_url(@pipeline), style: "color:#333333;text-decoration:none;" } + = @pipeline.ref + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-commit-gray.gif'), style: "display:block;", width: "13", alt: "Commit icon" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + %a{ href: commit_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } + = @pipeline.short_sha + - if @merge_request + in + %a{ href: merge_request_url(@merge_request), style: "color:#3777b0;text-decoration:none;" } + = @merge_request.to_reference + .commit{ style: "color:#5c5c5c;font-weight:300;" } + = @pipeline.git_commit_message.truncate(50) + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Author + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } + %tbody + %tr + - commit = @pipeline.commit + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img.avatar{ height: "24", src: avatar_icon(commit.author || commit.author_email, 24), style: "display:block;border-radius:12px;margin:-2px 0;", width: "24", alt: "Avatar" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + - if commit.author + %a.muted{ href: user_url(commit.author), style: "color:#333333;text-decoration:none;" } + = commit.author.name + - else + %span + = commit.author_name +%tr.spacer + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } +   +- failed = @pipeline.statuses.latest.failed +%tr.pre-section + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:400;line-height:1.4;padding:15px 0;" } + Pipeline + %a{ href: pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } + = "\##{@pipeline.id}" + had + = failed.size + failed + #{'build'.pluralize(failed.size)}. +%tr.warning + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;border:1px solid #ededed;border-bottom:0;border-radius:3px 3px 0 0;overflow:hidden;background-color:#fdf4f6;color:#d22852;font-size:14px;line-height:1.4;text-align:center;padding:8px 15px;" } + Logs may contain sensitive data. Please consider before forwarding this email. +%tr.section + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;border-top:0;border-radius:0 0 3px 3px;" } + %table.builds{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:collapse;" } + %tbody + - failed.each do |build| + %tr.build-state + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#8c8c8c;font-weight:500;font-size:15px;vertical-align:middle;padding-right:5px;" } + %img{ alt: "x", height: "10", src: image_url('mailers/ci_pipeline_notif_v1/icon-x-red.gif'), style: "display:block;", width: "10" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#8c8c8c;font-weight:500;font-size:15px;vertical-align:middle;" } + = build.stage + %td{ align: "right", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:20px 0;color:#8c8c8c;font-weight:500;font-size:15px;" } + = render "notify/links/#{build.to_partial_path}", pipeline: @pipeline, build: build + %tr.build-log + - if build.has_trace? + %td{ colspan: "2", style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 0 15px;" } + %pre{ style: "font-family:Monaco,'Lucida Console','Courier New',Courier,monospace;background-color:#fafafa;border-radius:3px;overflow:hidden;white-space:pre-wrap;word-break:break-all;font-size:13px;line-height:1.4;padding:12px;color:#333333;margin:0;" } + = build.trace_html(last_lines: 10).html_safe + - else + %td{ colspan: "2" } diff --git a/app/views/notify/pipeline_failed_email.text.erb b/app/views/notify/pipeline_failed_email.text.erb index ab91c7ef350..520a2fc7d68 100644 --- a/app/views/notify/pipeline_failed_email.text.erb +++ b/app/views/notify/pipeline_failed_email.text.erb @@ -27,7 +27,3 @@ Trace: <%= build.trace_with_state(last_lines: 10)[:text] %> <% end -%> <% end -%> - -You're receiving this email because of your account on <%= Gitlab.config.gitlab.host %>. -Manage all notifications: <%= profile_notifications_url %> -Help: <%= help_url %> diff --git a/app/views/notify/pipeline_success_email.html.haml b/app/views/notify/pipeline_success_email.html.haml index 8add2e18206..19d4add06f5 100644 --- a/app/views/notify/pipeline_success_email.html.haml +++ b/app/views/notify/pipeline_success_email.html.haml @@ -1,154 +1,84 @@ - -%html{ lang: "en" } - %head - %meta{ content: "text/html; charset=UTF-8", "http-equiv" => "Content-Type" }/ - %meta{ content: "width=device-width, initial-scale=1", name: "viewport" }/ - %meta{ content: "IE=edge", "http-equiv" => "X-UA-Compatible" }/ - %title= message.subject - :css - /* CLIENT-SPECIFIC STYLES */ - body, table, td, a { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; } - table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; } - img { -ms-interpolation-mode: bicubic; } - - /* iOS BLUE LINKS */ - a[x-apple-data-detectors] { - color: inherit !important; - text-decoration: none !important; - font-size: inherit !important; - font-family: inherit !important; - font-weight: inherit !important; - line-height: inherit !important; - } - - /* ANDROID MARGIN HACK */ - body { margin:0 !important; } - div[style*="margin: 16px 0"] { margin:0 !important; } - - @media only screen and (max-width: 639px) { - body, #body { - min-width: 320px !important; - } - table.wrapper { - width: 100% !important; - min-width: 320px !important; - } - table.wrapper > tbody > tr > td { - border-left: 0 !important; - border-right: 0 !important; - border-radius: 0 !important; - padding-left: 10px !important; - padding-right: 10px !important; - } - } - %body{ style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;height:100%;font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } - %table#body{ border: "0", cellpadding: "0", cellspacing: "0", style: "background-color:#fafafa;margin:0;padding:0;text-align:center;min-width:640px;width:100%;" } +%tr.success + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:10px;border-radius:3px;font-size:14px;line-height:1.3;text-align:center;overflow:hidden;color:#ffffff;background-color:#31af64;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" } %tbody - %tr.line - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }   - %tr.header - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } - %img{ alt: "GitLab", height: "50", src: image_url('mailers/ci_pipeline_notif_v1/gitlab-logo.gif'), width: "55" }/ %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } - %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" } + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;padding-right:5px;" } + %img{ alt: "âś“", height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-check-green-inverted.gif'), style: "display:block;", width: "13" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;" } + Your pipeline has passed. +%tr.spacer + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } +   +%tr.section + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } + %table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" } Project + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;" } + - namespace_name = @project.group ? @project.group.name : @project.namespace.owner.name + - namespace_url = @project.group ? group_url(@project.group) : user_url(@project.namespace.owner) + %a.muted{ href: namespace_url, style: "color:#333333;text-decoration:none;" } + = namespace_name + \/ + %a.muted{ href: project_url(@project), style: "color:#333333;text-decoration:none;" } + = @project.name + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Branch + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } %tbody %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#ffffff;text-align:left;padding:18px 25px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } - %table.content{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;border-collapse:separate;border-spacing:0;" } - %tbody - %tr.success - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:10px;border-radius:3px;font-size:14px;line-height:1.3;text-align:center;overflow:hidden;color:#ffffff;background-color:#31af64;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;margin:0 auto;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;padding-right:5px;" } - %img{ alt: "âś“", height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-check-green-inverted.gif'), style: "display:block;", width: "13" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;vertical-align:middle;color:#ffffff;text-align:center;" } - Your pipeline has passed. - %tr.spacer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } -   - %tr.section - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:0 15px;border:1px solid #ededed;border-radius:3px;overflow:hidden;" } - %table.info{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:100%;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;" } Project - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;" } - - namespace_name = @project.group ? @project.group.name : @project.namespace.owner.name - - namespace_url = @project.group ? group_url(@project.group) : user_url(@project.namespace.owner) - %a.muted{ href: namespace_url, style: "color:#333333;text-decoration:none;" } - = namespace_name - \/ - %a.muted{ href: project_url(@project), style: "color:#333333;text-decoration:none;" } - = @project.name - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Branch - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-branch-gray.gif'), style: "display:block;", width: "13", alt: "Branch icon" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - %a.muted{ href: commits_url(@pipeline), style: "color:#333333;text-decoration:none;" } - = @pipeline.ref - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-commit-gray.gif'), style: "display:block;", width: "13", alt: "Commit icon" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - %a{ href: commit_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } - = @pipeline.short_sha - - if @merge_request - in - %a{ href: merge_request_url(@merge_request), style: "color:#3777b0;text-decoration:none;" } - = @merge_request.to_reference - .commit{ style: "color:#5c5c5c;font-weight:300;" } - = @pipeline.git_commit_message.truncate(50) - %tr - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Author - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } - %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } - %tbody - %tr - - commit = @pipeline.commit - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } - %img.avatar{ height: "24", src: avatar_icon(commit.author || commit.author_email, 24), style: "display:block;border-radius:12px;margin:-2px 0;", width: "24", alt: "Avatar" }/ - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } - - if commit.author - %a.muted{ href: user_url(commit.author), style: "color:#333333;text-decoration:none;" } - = commit.author.name - - else - %span - = commit.author_name - %tr.spacer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } -   - %tr.success-message - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:400;line-height:1.4;padding:15px 5px;text-align:center;" } - - build_count = @pipeline.statuses.latest.size - - stage_count = @pipeline.stages_count - Pipeline - %a{ href: pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } - = "\##{@pipeline.id}" - successfully completed - #{build_count} #{'build'.pluralize(build_count)} - in - #{stage_count} #{'stage'.pluralize(stage_count)}. - %tr.footer - %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } - %img{ alt: "GitLab", height: "33", src: image_url('mailers/ci_pipeline_notif_v1/gitlab-logo-full-horizontal.gif'), style: "display:block;margin:0 auto 1em;", width: "90" }/ - %div - %a{ href: profile_notifications_url, style: "color:#3777b0;text-decoration:none;" } Manage all notifications - · - %a{ href: help_url, style: "color:#3777b0;text-decoration:none;" } Help - %div - You're receiving this email because of your account on - = succeed "." do - %a{ href: root_url, style: "color:#3777b0;text-decoration:none;" }= Gitlab.config.gitlab.host + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-branch-gray.gif'), style: "display:block;", width: "13", alt: "Branch icon" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + %a.muted{ href: commits_url(@pipeline), style: "color:#333333;text-decoration:none;" } + = @pipeline.ref + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Commit + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } + %tbody + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img{ height: "13", src: image_url('mailers/ci_pipeline_notif_v1/icon-commit-gray.gif'), style: "display:block;", width: "13", alt: "Commit icon" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + %a{ href: commit_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } + = @pipeline.short_sha + - if @merge_request + in + %a{ href: merge_request_url(@merge_request), style: "color:#3777b0;text-decoration:none;" } + = @merge_request.to_reference + .commit{ style: "color:#5c5c5c;font-weight:300;" } + = @pipeline.git_commit_message.truncate(50) + %tr + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;border-top:1px solid #ededed;" } Author + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;color:#8c8c8c;font-weight:300;padding:14px 0;margin:0;color:#333333;font-weight:400;width:75%;padding-left:5px;border-top:1px solid #ededed;" } + %table.img{ border: "0", cellpadding: "0", cellspacing: "0", style: "border-collapse:collapse;" } + %tbody + %tr + - commit = @pipeline.commit + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;padding-right:5px;" } + %img.avatar{ height: "24", src: avatar_icon(commit.author || commit.author_email, 24), style: "display:block;border-radius:12px;margin:-2px 0;", width: "24", alt: "Avatar" }/ + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;font-size:15px;line-height:1.4;vertical-align:middle;" } + - if commit.author + %a.muted{ href: user_url(commit.author), style: "color:#333333;text-decoration:none;" } + = commit.author.name + - else + %span + = commit.author_name +%tr.spacer + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;height:18px;font-size:18px;line-height:18px;" } +   +%tr.success-message + %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;color:#333333;font-size:15px;font-weight:400;line-height:1.4;padding:15px 5px;text-align:center;" } + - build_count = @pipeline.statuses.latest.size + - stage_count = @pipeline.stages_count + Pipeline + %a{ href: pipeline_url(@pipeline), style: "color:#3777b0;text-decoration:none;" } + = "\##{@pipeline.id}" + successfully completed + #{build_count} #{'build'.pluralize(build_count)} + in + #{stage_count} #{'stage'.pluralize(stage_count)}. diff --git a/app/views/notify/pipeline_success_email.text.erb b/app/views/notify/pipeline_success_email.text.erb index 40e5e306426..0970a3a4e09 100644 --- a/app/views/notify/pipeline_success_email.text.erb +++ b/app/views/notify/pipeline_success_email.text.erb @@ -18,7 +18,3 @@ Commit Author: <%= commit.author_name %> <% build_count = @pipeline.statuses.latest.size -%> <% stage_count = @pipeline.stages_count -%> Pipeline #<%= @pipeline.id %> ( <%= pipeline_url(@pipeline) %> ) successfully completed <%= build_count %> <%= 'build'.pluralize(build_count) %> in <%= stage_count %> <%= 'stage'.pluralize(stage_count) %>. - -You're receiving this email because of your account on <%= Gitlab.config.gitlab.host %>. -Manage all notifications: <%= profile_notifications_url %> -Help: <%= help_url %> From 0df104a389438665df2c7248ae022cdbb767f838 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 7 Feb 2017 16:06:27 +0100 Subject: [PATCH 65/76] use custom brand logo in pipeline mails --- app/helpers/emails_helper.rb | 14 +++++++++++++ app/views/layouts/mailer.html.haml | 2 +- spec/helpers/emails_helper_spec.rb | 32 ++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index 2843ad96efa..3beddff9206 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -1,4 +1,6 @@ module EmailsHelper + include AppearancesHelper + # Google Actions # https://developers.google.com/gmail/markup/reference/go-to-action def email_action(url) @@ -49,4 +51,16 @@ module EmailsHelper msg = "This link is valid for #{password_reset_token_valid_time}. " msg << "After it expires, you can #{link_tag}." end + + def header_logo + if brand_item && brand_item.header_logo? + brand_header_logo + else + image_tag( + image_url('mailers/gitlab_header_logo.gif'), + size: "55x50", + alt: "GitLab" + ) + end + end end diff --git a/app/views/layouts/mailer.html.haml b/app/views/layouts/mailer.html.haml index 39133f8cdb3..53268cc22f8 100644 --- a/app/views/layouts/mailer.html.haml +++ b/app/views/layouts/mailer.html.haml @@ -48,7 +48,7 @@ %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;background-color:#6b4fbb;height:4px;font-size:4px;line-height:4px;" }   %tr.header %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;padding:25px 0;font-size:13px;line-height:1.6;color:#5c5c5c;" } - %img{ alt: "GitLab", height: "50", src: image_url('mailers/gitlab_header_logo.gif'), width: "55" }/ + = header_logo %tr %td{ style: "font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;" } %table.wrapper{ border: "0", cellpadding: "0", cellspacing: "0", style: "width:640px;margin:0 auto;border-collapse:separate;border-spacing:0;" } diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index 3223556e1d3..b9519e387eb 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -43,4 +43,36 @@ describe EmailsHelper do end end end + + describe '#header_logo' do + context 'there is a brand item with a logo' do + it 'returns the brand header logo' do + appearance = create :appearance, header_logo: fixture_file_upload( + Rails.root.join('spec/fixtures/dk.png') + ) + + expect(header_logo).to eq( + %{Dk} + ) + end + end + + context 'there is a brand item without a logo' do + it 'returns the default header logo' do + create :appearance, header_logo: nil + + expect(header_logo).to eq( + %{GitLab} + ) + end + end + + context 'there is no brand item' do + it 'returns the default header logo' do + expect(header_logo).to eq( + %{GitLab} + ) + end + end + end end From 84420c89d5fbf98a19fb831a4489e9d5441e18ad Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 7 Feb 2017 18:23:58 +0100 Subject: [PATCH 66/76] add documentation for custom brand logo in email --- doc/README.md | 1 + .../branded_page_and_email_header.md | 15 +++++++++++++++ .../appearance.png | Bin 0 -> 10253 bytes .../custom_brand_header.png | Bin 0 -> 10014 bytes .../custom_email_header.png | Bin 0 -> 37472 bytes 5 files changed, 16 insertions(+) create mode 100644 doc/customization/branded_page_and_email_header.md create mode 100644 doc/customization/branded_page_and_email_header/appearance.png create mode 100644 doc/customization/branded_page_and_email_header/custom_brand_header.png create mode 100644 doc/customization/branded_page_and_email_header/custom_email_header.png diff --git a/doc/README.md b/doc/README.md index 1943d656aa7..c082b91a6b1 100644 --- a/doc/README.md +++ b/doc/README.md @@ -50,6 +50,7 @@ - [System hooks](system_hooks/system_hooks.md) Notifications when users, projects and keys are changed. - [Update](update/README.md) Update guides to upgrade your installation. - [Welcome message](customization/welcome_message.md) Add a custom welcome message to the sign-in page. +- [Header logo](customization/branded_page_and_email_header.md) Change the logo on the overall page and email header. - [Reply by email](administration/reply_by_email.md) Allow users to comment on issues and merge requests by replying to notification emails. - [Migrate GitLab CI to CE/EE](migrate_ci_to_ce/README.md) Follow this guide to migrate your existing GitLab CI data to GitLab CE/EE. - [Git LFS configuration](workflow/lfs/lfs_administration.md) diff --git a/doc/customization/branded_page_and_email_header.md b/doc/customization/branded_page_and_email_header.md new file mode 100644 index 00000000000..9a0f0b382fa --- /dev/null +++ b/doc/customization/branded_page_and_email_header.md @@ -0,0 +1,15 @@ +# Changing the logo on the overall page and email header + +Navigate to the **Admin** area and go to the **Appearance** page. + +Upload the custom logo (**Header logo**) in the section **Navigation bar**. + +![appearance](branded_page_and_email_header/appearance.png) + +After saving the page, your GitLab navigation bar will contain the custom logo: + +![custom_brand_header](branded_page_and_email_header/custom_brand_header.png) + +The GitLab pipeline emails will also have the custom logo: + +![custom_email_header](branded_page_and_email_header/custom_email_header.png) diff --git a/doc/customization/branded_page_and_email_header/appearance.png b/doc/customization/branded_page_and_email_header/appearance.png new file mode 100644 index 0000000000000000000000000000000000000000..abbba6f9ac9facf1b58d2caf1c3aa09830cf0342 GIT binary patch literal 10253 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 literal 0 HcmV?d00001 diff --git a/doc/customization/branded_page_and_email_header/custom_brand_header.png b/doc/customization/branded_page_and_email_header/custom_brand_header.png new file mode 100644 index 0000000000000000000000000000000000000000..7390f8a5e4e82cf3a5fc9f8127e3d7a17f54d764 GIT binary patch literal 10014 zcmcI~cQ{*p*swl*N~={>R9ma1W-5xJcB@A1)(#OXA$Wu5dEWPXzw3Ix>;2<9mrKrl&iUQvUcY;u_m6ee8R)Om)6mc`XgpHU zr=d9mq@FvRrKSG&_2>9PLvw>hL*;>?&!^>7m}AO|=Qz*3EM-y~_;X98((sqisZI(q zXSHDWmi?ae^M81D%cfW4(i=W}^3LxPt;bxaGQhu(n|!+W z?rquK^71X4=}$|k4-@TPGHsr^|6(9X#c8Na@E8=tmybHO z!KS1Qn)rBlc%H}X4AHeo1$Hjw9aPVho@Zj(!x;+afPn%uBeKG<;a$~}#~6{0kim(! z-VTHgLKiz}EOU;l-h6b!whh9~!?Rt}Ze2d0L-#ZK21475LJXAP15xd!8!jNB4Uw)XHf~IzoP>WDRV{Pvm_I+5`J^+9Dv%)3d(c-e=+}xl%Veuex$9Z-x z_qDC3LrLA-QQj0!DvyVn{}o%pYuA-;bz1{C$`C^gd0=hNIBI<1|H9`~5`ZtFk9238 zDxTOXb%sqO7ZX+CO6kixOR6g058|Qcdb!RX%Xmbp6utSvlhy2Z{c$IDaF>@r&709Ijp4GvUizG+QKq(tl{8YW% z_n!}k`jS6Q`EL0t>~9Y6k^MMm$xw=k#u>c?hdTqn8d`6q2yfVk83}sP$WZmw3L$*`Yo<6oYvoX~1+lJ!scn zp@HO?np)S806!M?cc3R8RUpYbQzhLb5i>aSUf3r~uo%uq) z7a%NOW)UKQv4m0BllS)_!&PnQjHbA8ELZ{5L;dw!7W0l=ih*Ul{6&R~e7f?QOmy2I zN>tN@>x5#8a>Abd2>Wg`TJ1Oc9v)s6*J*D>Jwy`B}Zm^>k z)BO%pF;-`c?Cf0l)gB>Yu@rlvt&k~-T`B!uP2q32H#~DXM~PDFbX^fz7%GmXIov+zU;4BJ zgqzP|w59!&&5Y$UKi6EB;E*&Ly*u!J-Ae7NTaK+U^(wU2zcb8-_@g6QodsCD66rsK z!uOv|Gzl6`JO8s9m4KbL@s{)9$NiKc^LewA38j_&O$4A^ol$^psgikMAf}--eXvDa z&0PTEon;$Qc;|1G+TpkACZH%-9sK|)|M#rdK6$_KGwjZt&!>9SS0{5Rap>G;n*)vX zgB|m6%{G|R)BBlo@ovKe2W338OCpItV6tae9uz-x9S zH}kUAKj+P7M?ldy!_5J;i%w^Hq|9`E-CM>rgLE(oOhD14>Gld)lI_;ycZa|& zM+fPJn9iCz42hIr||1| z&0+v~!mSNQr=s$U+Z@$uGZtA}$p4n9MO!PU1rE|;;>|Zz9q2S;x~5inp!wqq5j(oO z?4%VlIC&AhO9n~Y=Dlh)#OL@4ZSLv|dhsI7vw61N-EVbhw{M+{?WwBNk%#l1kd-Q} zU{jY*#!QUY)IpQ@gx+qQ&_h-G=u96!R^`P2*7eY zoH`Pe&<>MOL|{=sac4_Ar0?if;MR_`VG^qF0A<-&H?w-0x))=LLoqxc5Yt1oJ0+FO z2EAv6o%0fOP0WfCUC%H){20t9kZL^UT9fKxiHy7qe70e?STYTHDTZxw)2fmKTMoB> zu>*OOP9erWxt~Ofy3VG$Mu-ys3a+GS%HJ4wuKs;p1XeEh60&B^_h2p~x{;CUQkABH zkek(Z>`bE$&dZ6FFUOI^Kg{suEydHpS|g5B=Qp|h(*gB6p}Y`oEtMUJchePEaz2ME z^qw=Tizb*|J`PNEy(x#QsjW}e5JNY`x5jZVuZj?1ODTm}gmfuWd+G*qwxm4ydrNoW zjN~)yZr{X|+sIYdSxnrqR?)UeNZ@4XxYHDlsCI1o=maVc&nb6n$%!)_6T@1%3i;0X zN)y*w-AfBJkipx~!mpX7SJ*tsZeoVHo?B+d7!<1ru#!u3oEb>G4sKgFYN*iwh(!EN z+DOyEkaV}uuhI&?_4d~B7L$YQ?r;okU-?NS8klR&$uYeJb``;V=6PbETfm)b)51&7 z#?APSwKyyy`kIK6?NxeOUd`;unZ*#y(2Q!~in1;;I9fkH3~rJ*IIpOf;OL9&WXU2_ z_#KcJ?R?$hvTT6r$fKzK%g+UUIJ@`**@K<%TI2KvK-fhfh0G6Q4yn=*pentTeN^}& zRNcU|Z#tpStz>Hc%~5cvSHv_Iz=54qPMsmz1N~I202hAvxZho;q4?hrlo$>&m}1z!?-G-Dttd zm4|sIzBjVS3YX?8J_|oY@tYmYLj)V$vQBa&$Wf3U*>wOLgK_Jl*HR~&{u4=e3iopH z#Si`+(zE|TFQp?UGKHbIdSvD7j(x7P#IlA zLW90*17_X$_iW?7t&o}JZj?U;?*?fZ{+(mkMvS4ZPCQu+9aTJW#0oDJ(@pTHIJdX6 zhxJ+^0yPfgwGOB0sc=kVEhe!0aMzQtL5}WWXJT5FKL@8-etjI2!Yl~ITCURC2S2$8 z5#ucp-pq&Yq}oL3!&P(6bgJ;DQ2!+_tLs(<7Anu082QXOcO9nq$5W#G4R;3W40o1b zB`E-`oT8G7N__<%_>W4u<7AP?t2o3P2GNQmEfy-(nuHwgH$?Z)F)@izo!TFj=l_1D zN;TRe;N4B( zuOKvY;=63+4mQw;6GJ{q0GY~`ZXNrZqr{WvIrhXZjx0^(dr900*T)I5g}_O=dAz7j z_k^0`MP8{V3Fq;mU$S(u?b(;gq`{`9^E(`uj$Z+r#a#^>>AHB9S{0lepD{PUfBXa7 z$38&*`48}_q{{?zIF9A>e1ASilf4-{oOYFG>W^#SL* zB(~o!ltoybO#S18%FlWlIr<$0x70M+`+Bh$LcC^9a?ru_bmo;SR}2MNs-ea-TS6@K zW~QcgLY4>46yGQ{?t%SP-G$dPb!88y4p-vUvSJq2;*>_3^d7A$p9p2%Ahz8)FOQ~o zpmJT}u9A{oCDl_1vY3T0XSpb9R{pxY3iH;a5>qBZ@z?~O2<4Sx2=v@nF*EYDX(B`I zYh%SwD$V=RbaJ=-aqKu;lb+gtVm~WH!%h`>11-MXn-4r3dLsSayi58tQndKXehf`E ztD49n#(!A6nN8z(p^0zvdN5`x0Se+i(aHUE;Hi3U@DvnWt8lfEm~u;O&xN%?apr+suZAuGu{Rxro(Cs9B9UeM&;B=xM+ZNY ze;OFtutGN0@_%z685TRMJQcDT#V^Bo; zz{kgrp7_U^s9gqTymhodRODPNOa*_vT^$^oGn(DRE~C-e=6|e!u-aTjZ95uD#vU`=?KjR|3kuDTOV6R->i8d*@EBDP!>aB2JT$ zq(s~*9Jh+CWHRjR&@5-&-eaw-omH)r0Czl*ziMc0pll9rh+)tGaQ%iW(%DGQD6GDP z`l<)<)6jfoN2WrrMd!trlAuoa9WMbf07=F#gV#6gyVAm5LIkrP+o{pTBx@$@&c)j5 zaSVU^>OIk!vACQ)<@@3ySO4p4B$>TT*RI@+*hEQhYqgArM5FHHYpF^s`a7oObDq{7 z_>r5Of@uPGvremPCy1sZuuTj3O)ccrh{fPkd#IynXmsiT%0OLn<05zXl5*~JqyyS^ zo>i6=C}O3YrI;Q-{j*|Dj%EW`7#sWO%c*z7gg6ykr48h3V+FBp8@Dxkc!1GNjoKQq zS@|$!IrRvu$d>`a;QfuHDweeve|PqwogH1WFwgTD-%?2>^Rk6=QRIMivf5omR^uUv zCsyVK4k}RyXpcwNqINSVnY=Gta|)hS2ec5jv^wVB=>~u;GmygIR>$dJwWON|OLkVx>(#e2Tdp%b*gMTQ7z%C<7jn(%57m%qmIQD zldK zA*^HGhQwd-`tC%JTO9qJeKI6hmx;i(?mB=1F;JE`-0_1v$GaPA92m7*oq zmS(k=j08PQb3)QE?y};{{rItjbV(wj4yxIQ2={$traM|reM`=q$HB;{5am$GIz!^f zM%%;<-=9g{UEMuhfH$yVn>W2!J>TTz*QB9@77`ztDhtU+A#!*W{_;Y)W;mX#4 ztmN=p)}X{rpNWV7=c^nsrVbQ^fCi|&ye2I>kVQ8#O5j<3{3nT(yjOGTWb|tL0vvnpsM(P(l`Twn*&$e9O4` znrvWnaM7B8iICm*EcU*OY%gB#LUpDhikA%afB8`xqKXcmvNK2q(~c2|rpG ztLWLYtoj2`AYDmpHrWg&hjT?MWeLo=JPOeYPdm)m4xqe?2E#pO+WfMoliZMC{{u!2 zQtJR8XPIqf+o!%wGI#CxPy^I=P2wS=faPHGd!m`yIciALW3LX+V@(;ED=FDLW35qs z!KI4O8-E$30W$9^5MyAh6>}f|p|X|OVIwx*#I;jdrU%QSFOxKE?6})m4 z-g6##dR*=9H9eF1;qvAnEs%|kI=`gsY+xWXC4l*3RA_(H(@+A5?)vxp(j|r^^?<3Z zuJ>moEhv6B^7D;2ZU7{%$BS8@%u1)Qw@9_256;xPMnb{5LoNgkKAv~pY4+FDK7U(m ztn7UB_;vrzfOt~^w#jjY@)}w+eO0~h6+~^wX=NBu+F$;h(3TgKFKwAc5(5Zu0TpoE zXT9!q)Z*Rzwn{zuG(ZyI{R96#IXl~`1JY+pBzS4Rv8zX$FcNU&L-j@?9l-DOd~Q~> zLs2gaclyt8(ua871|7h6`W+235LudYOOfVU4Q&!cPeGP`CjZeroP?|_oRk)%yr)d( zS>lD1ow4rbG!zWbF7V44PVtscD0Tl8Ynyemivs~roys{M+EHrXfW4sb(8Q5dPhE0_ zJpmVMt!tm%J``VQ4+KY>Ty$n1TVU_A<^jksMePNQ8Tm$6QFn27T^}X9M+|^wN%`Pn z-H~cgNc{E887Q+mJ4k0)UzyNuqK0Agm}_E{teA6KY9?rnxl&{re%t7F)E9?3G!xoS z*P1eOaqqsjuw?aJ1&hHVe!9bD)}z#(kulHZ4>;~kAn(uC z)ce`>FGVd#4xrJG_T6NQZc_lLVL>`^V0RYGJmvA`7h1bI8gWwiRX zL@x9%QJDSKuj@n-dw6oSBOoKJY&Xd*+YE+oS>rjURqfP%HzG#ThdVX@j|2M<=4y_k z;+%m8TxTi=*0e`F@K&`o1A*}Nt1zvu0LCxPHtwr1hjfJIjy4U={X?iZ7Af!cpgrV_ zh)*uOzTYbaFP<)IJQZZ&K9Jrq6e$v-wdz2pn`cxfDer#pS(#3^^uXUO)pgxHl$D+{ zaa?{w6LK%3nXW1MTnI}t;)&qhtgLoFym;ws-?fm;iX7H>GK!ZzB(ofz;?vbD;UNqj z>$6`Tllj7wu801}L=NCh7Uye^6R2kXP@$;GoP^aEQxqk4ud7zu9SzUP(kW30f*gpYaW`&)V}2OqNH-P%SOjSlrT zw2~DUT3fh9v^FY47hfYYcrhldsr!Zq_SFUajNU?@7B;)(w5K!D0NrZKw_!5nT4OJL z7QPZ7T$2eWLTy&~mh)w78^~DB7$_>Ia$!y$gb0Fo=Cd<&B;Er2JcD|s!`J_%9ys?? z*QLd30PmK)#%)>E)1FKp=>rfHnC_6eo`oO}aXI+6#VhAz<$HHN8Yu|-@NkS3P*TuS zyO#0Ic+K%SyxJH0XOw53u&@BW_;>O};mgthWsSITP(|*ALl1JGS(R{cH#WR&BmqL- zvC3GNUf`juwv1wTW-XOKvspKLRpZH+!ZQ(VNMeycbw3nKTfV1V&EhOEYZ>#s4xZ_6 z_!&)#4}KHW82RY&fRQ`o(El+j&^++4!D^VoW%%tVChvyoI14#?t!L^%O(%76` zfDBg7r3E_y6|(8()~EWDc1pQzmc*EMX17B=J1{1`$tDONza3)BqM%SXt88|@eLxne zhScUf5Ac{*UT9S%&pzog48cfRN^D->JO?+vZ-r*kxhjT86v5oRYf1kqHa>w>;x6G# zr@chsTvJX#J5xIUb8{9T_7lkr@1{NQz5}B(TE6VjGUKg_jDI<86Va#t(h4b$HfP+Q zHL&r}*n1&bAPcrM7!2qe2U=``R*`v|^EvGLa|{Xrb8X2G#VmEbhFm>*p?%e9zU9W7 z7DZq&koy4vK({%MfNwsUmIx(1d=ers<^#m^ATSD|s& zS(ajiiL5hnJl`roDSrvZ_@&9Fa22+YB#EZ`!WGd&E&n&qQ;UWfBfNNll?3ZyV^~eG zoY~%%+KkkikD}A!eLFSvx%x-7cMF>(o^ht84t>1l;_odnV;GDfj1^CiWjN7YP}GXU zyR-~uytp~a$SgL#x8w^H^!G{C%L z_5zag<<(VH!2VMVbHpg6KD()7|gZ1V4QLLMLew?nivjGvA$xbWiptF8@r@=SfXGtaVGsqp2I*;pkM zbd3+o0CzZY`I~R%e}?hr=H4~RU~*rK24%7U)vFeJoCWx;o`1LSmAUizb%uu1CjVSY zL=ES?OK}5&CHGc3s-AYnFJ}`*#9WM$2hETd1YcqgX#JzU4y{2)rvtQ#s@x<2ZIMF1 zTE65@wlg;SnYT<5lfF%Fu>oAHhf1KRR?__;t2G1-&8whiTFp8AvVk|U5zWMSv)F9D zqoQa2KA3GTHaVr?b2iCy&(1WX_d!d~=t`H9ZO@YO+LdvgcbNVtS6jWMALtKMmu#PL zx6h`FGu5@mJ2YmfF?zNZ0MxUC*r|o;^#~)(dX@X@ms#OU=((KpvK(oBHzg)_U=K~c z4&mLb;r_gzRGtjzk0lQ$xv11dCTU}0ZQfx3Y^g~+eZhNMDk=t9icz~d8urr9S2h93 zP?u!0RV!<^GD`iS_uR?s^YMtCli20sy zN2i51?z&Jh5^Qyp3>yc$tbEz2ay!#*VYQZO7U?L2Nh*6}sg{2;fm#nOzEX@eM9cJ4 z_|2^|Xb5qV9o765162Kk*56s)GcThTbDsZEo;~f!AG114Qq)4lb<|tb&g|p{W2U>j z=&OS~4nqB!ZsR@?`)Z|$AeVz4pBR5>BKbF~!bTi+^T*ywndpmKllQXNI!!8x0(6_- z+ij=Jn+Rr=lHjqHly$>kEzl_j=`vP-$G?l^v|+X89DiPS^}e<6jiNH6dIZ^s(}CPz zC0zYROOtK&ld)fbsR5xbK`=ETKHA5M0bZK1z-3|CU>hnaH6N`sYU6FDD{z6l|6sJ7 zb*&W5yt%lHs(w@a4l`~1Tdh>Vp(Ln2r+9km3dEtIg>LBo1JWTfXKp6{Sqw&ov8XDTsqi+F9z@8{-KIv8HqqPcanPF(8Gx~jG zTnEn_nsX}e`fJm@uw~f-P9#C@X{>ssd-*hc(pV)c518q)^0PaUpYaY*3W6uOsMqIHZbqdwSPYEAOIDIdij$e!FNwUUd#FqEv3fJnf zY3aoynSu@GuvN~zZFYW!0LjufrN_d6#JDX&nz46AGRTWgc?x)ho_j(H-Q4ad} zfpr}p-G<_xs$tEpaRzt`d8Bq)S8W4wVCt`1;(DA!0u<5plmg3bsa5Dfi?(@n!$FkkaEi((Wxu z%&B&@&H!D8@gSUG9;dop`J{Z5RMav$x+v#&CFH@XD88jGvd*Q?5BIk6`P4`YDZ7e< zQ?OlLeZY5Ipup@zvN!K(RmjS_-_IKWt6r9hDLxOMeAM7TZ7!C1;>-0We{QdI#X~{q zz_V~S*ph_Imz$#e&KpsHOQq!I{`Z(hchk2mz0&ux@qOpch*WU^L*Lc^u5nVSYf7x+ zu`d=IPJuL7RV4BlSW)Z0=nu_V1_WrLBx@SS5Og7WrujO_**dnWDfy}pE@7euklQn3 zaGg`Qt@|5ZOh;9&E?Ic#7RxzW;gTV?4@}X8m2yKGNN=m{J?eyO7Wfs@@jleX5R7$^ zy|l^YAO+UcH?zGvKXvs7yApUSWudaj6iGqC%w9h=EcC`+;Z1nr=X~R8!H99+1o`wg zQ?e&k!FHc)tU&$P0_JW;4D1{eyEZ@|-MLgE4->G1x^p!`Ui+Bo-hN!6AYY8c!<8I` z>Q+eiJCZ*pvxXI;4+~>J`wIDrX~&WIbOX2kFmGv2$eA3rIcu(qfBCexsCk^A2!Eqj-#ejOnJM{Ph`4W&_898w& z@ekhdj>7waYAsdl8PX#Yj}kmNM&Ey>9K3o?A)z&P<-qGl?nJkL@8+4$6%!!*<=s>N zbcEe_t(nIpXPvmY5x)EVf(#~yL)apk`?p;7K9ZSKD~ zY5%uv>tL2wQ4f&8mT#e>b(eul5C7@v|4)5)HGtB?jg5_3&!yoj-Ly}g=tJJ<7Z?uo zG_H23dmfe*P&@e(#e2Ba{u-R0<9Q{{hV%b)=Mm}YCP4Vo=3N@USTGQ)|7VA_ICb9e zIOFk16X?`n-eW<#XU`rWv~w4%xRl7JqtFTkdpJHzFIlr_>S>$a!PE0fH~$kI2n2c} zoS-j`Q2BmECr6)Jn%OVB0LHcdmI&n(OVF%h5s8owTBqCHHji0AOQT~r*T-EH)GEQJ z|G!LXj)yw`(@01s1cM78YyC3#cm7k$)I{Js`X=r8xG&vrhy;Vd$D^v_8JEaq<7UbK i)wt*w(f>(A^dY13LnFToKjibHyBeyxDkaKK-~0zHf1jTK literal 0 HcmV?d00001 diff --git a/doc/customization/branded_page_and_email_header/custom_email_header.png b/doc/customization/branded_page_and_email_header/custom_email_header.png new file mode 100644 index 0000000000000000000000000000000000000000..705698ef4a8ca046c47b1702a5a731753d63c7dd GIT binary patch literal 37472 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 Ivaf^x8xA~MP5=M^ literal 0 HcmV?d00001 From 26da2c45ac4071f7a33a34c89162709d5a1bc470 Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Tue, 7 Feb 2017 22:17:59 +0100 Subject: [PATCH 67/76] add changelog entry --- changelogs/unreleased/feature-brand-logo-in-emails.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/feature-brand-logo-in-emails.yml diff --git a/changelogs/unreleased/feature-brand-logo-in-emails.yml b/changelogs/unreleased/feature-brand-logo-in-emails.yml new file mode 100644 index 00000000000..a7674b9b25e --- /dev/null +++ b/changelogs/unreleased/feature-brand-logo-in-emails.yml @@ -0,0 +1,4 @@ +--- +title: Brand header logo for pipeline emails +merge_request: 9049 +author: Alexis Reigel From c1e94479bd565a3deebe7452f186815157082cbb Mon Sep 17 00:00:00 2001 From: Alexis Reigel Date: Fri, 17 Feb 2017 10:05:13 +0100 Subject: [PATCH 68/76] restrict height of the custom brand logo in emails --- app/helpers/emails_helper.rb | 5 ++++- spec/helpers/emails_helper_spec.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/helpers/emails_helper.rb b/app/helpers/emails_helper.rb index 3beddff9206..a6d9e37ac76 100644 --- a/app/helpers/emails_helper.rb +++ b/app/helpers/emails_helper.rb @@ -54,7 +54,10 @@ module EmailsHelper def header_logo if brand_item && brand_item.header_logo? - brand_header_logo + image_tag( + brand_item.header_logo, + style: 'height: 50px' + ) else image_tag( image_url('mailers/gitlab_header_logo.gif'), diff --git a/spec/helpers/emails_helper_spec.rb b/spec/helpers/emails_helper_spec.rb index b9519e387eb..cd112dbb2fb 100644 --- a/spec/helpers/emails_helper_spec.rb +++ b/spec/helpers/emails_helper_spec.rb @@ -52,7 +52,7 @@ describe EmailsHelper do ) expect(header_logo).to eq( - %{Dk} + %{Dk} ) end end From 87fe6a27dd4c17cf6b202de809faa821712a3e17 Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Wed, 22 Feb 2017 17:07:17 +0530 Subject: [PATCH 69/76] Document when current coverage configuration option was introduced * Introduced in v8.17 [skip ci] --- .../28524-gitlab-ci-yml-coverage-key-is-unknown.yml | 4 ++++ doc/ci/yaml/README.md | 4 ++++ 2 files changed, 8 insertions(+) create mode 100644 changelogs/unreleased/28524-gitlab-ci-yml-coverage-key-is-unknown.yml diff --git a/changelogs/unreleased/28524-gitlab-ci-yml-coverage-key-is-unknown.yml b/changelogs/unreleased/28524-gitlab-ci-yml-coverage-key-is-unknown.yml new file mode 100644 index 00000000000..eda5764c13e --- /dev/null +++ b/changelogs/unreleased/28524-gitlab-ci-yml-coverage-key-is-unknown.yml @@ -0,0 +1,4 @@ +--- +title: Document when current coverage configuration option was introduced +merge_request: 9443 +author: diff --git a/doc/ci/yaml/README.md b/doc/ci/yaml/README.md index a73598df812..dd3ba1283f8 100644 --- a/doc/ci/yaml/README.md +++ b/doc/ci/yaml/README.md @@ -1003,6 +1003,9 @@ job: ### coverage +**Notes:** +- [Introduced][ce-7447] in GitLab 8.17. + `coverage` allows you to configure how code coverage will be extracted from the job output. @@ -1361,3 +1364,4 @@ CI with various languages. [ce-6669]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6669 [variables]: ../variables/README.md [ce-7983]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7983 +[ce-7447]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7447 From d3425933dddf4e849199c06dd3ce00c212d0c6da Mon Sep 17 00:00:00 2001 From: Mark Fletcher Date: Tue, 21 Feb 2017 20:21:31 +0530 Subject: [PATCH 70/76] Add housekeeping endpoint for Projects API --- .../27032-add-a-house-keeping-api-call.yml | 4 ++ doc/api/projects.md | 14 ++++++ lib/api/projects.rb | 13 +++++ spec/requests/api/projects_spec.rb | 49 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 changelogs/unreleased/27032-add-a-house-keeping-api-call.yml diff --git a/changelogs/unreleased/27032-add-a-house-keeping-api-call.yml b/changelogs/unreleased/27032-add-a-house-keeping-api-call.yml new file mode 100644 index 00000000000..a9f70e339c0 --- /dev/null +++ b/changelogs/unreleased/27032-add-a-house-keeping-api-call.yml @@ -0,0 +1,4 @@ +--- +title: Add housekeeping endpoint for Projects API +merge_request: 9421 +author: diff --git a/doc/api/projects.md b/doc/api/projects.md index e9ef03a0c0c..872f570e0f6 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -1195,3 +1195,17 @@ Parameters: | `query` | string | yes | A string contained in the project name | | `order_by` | string | no | Return requests ordered by `id`, `name`, `created_at` or `last_activity_at` fields | | `sort` | string | no | Return requests sorted in `asc` or `desc` order | + +## Start the Housekeeping task for a Project + +>**Note:** This feature was introduced in GitLab 9.0 + +``` +POST /projects/:id/housekeeping +``` + +Parameters: + +| Attribute | Type | Required | Description | +| --------- | ---- | -------- | ----------- | +| `id` | integer/string | yes | The ID of the project or NAMESPACE/PROJECT_NAME | diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 366e5679edd..f1cb1b22143 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -374,6 +374,19 @@ module API present paginate(users), with: Entities::UserBasic end + + desc 'Start the housekeeping task for a project' do + detail 'This feature was introduced in GitLab 9.0.' + end + post ':id/housekeeping' do + authorize_admin_project + + begin + ::Projects::HousekeepingService.new(user_project).execute + rescue ::Projects::HousekeepingService::LeaseTaken => error + conflict!(error.message) + end + end end end end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 4e90aae9279..2f1181b2e8c 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1422,4 +1422,53 @@ describe API::Projects, api: true do end end end + + describe 'POST /projects/:id/housekeeping' do + let(:housekeeping) { Projects::HousekeepingService.new(project) } + + before do + allow(Projects::HousekeepingService).to receive(:new).with(project).and_return(housekeeping) + end + + context 'when authenticated as owner' do + it 'starts the housekeeping process' do + expect(housekeeping).to receive(:execute).once + + post api("/projects/#{project.id}/housekeeping", user) + + expect(response).to have_http_status(201) + end + + context 'when housekeeping lease is taken' do + it 'returns conflict' do + expect(housekeeping).to receive(:execute).once.and_raise(Projects::HousekeepingService::LeaseTaken) + + post api("/projects/#{project.id}/housekeeping", user) + + expect(response).to have_http_status(409) + expect(json_response['message']).to match(/Somebody already triggered housekeeping for this project/) + end + end + end + + context 'when authenticated as developer' do + before do + project_member2 + end + + it 'returns forbidden error' do + post api("/projects/#{project.id}/housekeeping", user3) + + expect(response).to have_http_status(403) + end + end + + context 'when unauthenticated' do + it 'returns authentication error' do + post api("/projects/#{project.id}/housekeeping") + + expect(response).to have_http_status(401) + end + end + end end From 3d013487cea47272ff40d3f9a4b02960d2c2591f Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Wed, 22 Feb 2017 11:03:04 +0100 Subject: [PATCH 71/76] Grapify the CI::Runners API --- lib/ci/api/runners.rb | 44 ++++++++++++++++++------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/lib/ci/api/runners.rb b/lib/ci/api/runners.rb index bcc82969eb3..2a611a67eaf 100644 --- a/lib/ci/api/runners.rb +++ b/lib/ci/api/runners.rb @@ -1,44 +1,36 @@ module Ci module API - # Runners API class Runners < Grape::API resource :runners do - # Delete runner - # Parameters: - # token (required) - The unique token of runner - # - # Example Request: - # GET /runners/delete + desc 'Delete a runner' + params do + requires :token, type: String, desc: 'The unique token of the runner' + end delete "delete" do - required_attributes! [:token] authenticate_runner! Ci::Runner.find_by_token(params[:token]).destroy end - # Register a new runner - # - # Note: This is an "internal" API called when setting up - # runners, so it is authenticated differently. - # - # Parameters: - # token (required) - The unique token of runner - # - # Example Request: - # POST /runners/register + desc 'Register a new runner' do + success Entities::Runner + end + params do + requires :token, type: String, desc: 'The unique token of the runner' + optional :description, type: String, desc: 'The description of the runner' + optional :tag_list, type: Array[String], desc: 'A list of tags the runner should run for' + optional :run_untagged, type: Boolean, desc: 'Flag if the runner should execute untagged jobs' + optional :locked, type: Boolean, desc: 'Lock this runner for this specific project' + end post "register" do - required_attributes! [:token] - - attributes = attributes_for_keys( - [:description, :tag_list, :run_untagged, :locked] - ) + runner_params = declared(params, include_missing: false) runner = if runner_registration_token_valid? # Create shared runner. Requires admin access - Ci::Runner.create(attributes.merge(is_shared: true)) - elsif project = Project.find_by(runners_token: params[:token]) + Ci::Runner.create(runner_params.merge(is_shared: true)) + elsif project = Project.find_by(runners_token: runner_params[:token]) # Create a specific runner for project. - project.runners.create(attributes) + project.runners.create(runner_params) end return forbidden! unless runner From 80033d8c326aa2b4c4e4ed7da7ab7e174af27451 Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 22 Feb 2017 11:33:23 -0300 Subject: [PATCH 72/76] Update CHANGELOG.md for 8.17.0 [ci skip] --- CHANGELOG.md | 180 ++++++++++++++++++ changelogs/unreleased/17662-rename-builds.yml | 4 - ...uire-from-request_profiler-initializer.yml | 4 - ...ect-better-blank-state-for-labels-view.yml | 4 - .../21518_recaptcha_spam_issues.yml | 4 - .../22007-unify-projects-search.yml | 4 - ...ing-a-branch-matching-a-wildcard-fails.yml | 4 - ...974-trigger-service-events-through-api.yml | 4 - ...-notify-automerge-user-of-failed-build.yml | 4 - .../23634-remove-project-grouping.yml | 4 - ...sable-storing-of-sensitive-information.yml | 4 - .../unreleased/24147-delete-env-button.yml | 4 - ...606-force-password-reset-on-next-login.yml | 4 - .../unreleased/24716-fix-ctrl-click-links.yml | 4 - ...5_refactor_merge_request_build_service.yml | 4 - ...o-search-by-commit-hash-within-project.yml | 4 - changelogs/unreleased/24923_nested_tasks.yml | 4 - ...w-doesn-t-show-organization-membership.yml | 4 - .../25312-search-input-cmd-click-issue.yml | 4 - ...0-remove-flash-warning-from-login-page.yml | 4 - .../25460-replace-word-users-with-members.yml | 4 - ...ipate-obstacles-to-removing-turbolinks.yml | 4 - ...-update-when-new-pipeline-is-triggered.yml | 4 - ...cons-to-svg-to-propperly-position-them.yml | 4 - ...25989-fix-rogue-scrollbars-on-comments.yml | 4 - .../unreleased/26059-segoe-ui-vertical.yml | 4 - .../unreleased/26068_tasklist_issue.yml | 4 - .../26117-sort-pipeline-for-commit.yml | 4 - ...and-minus-signs-as-part-of-line-number.yml | 4 - .../26445-accessible-piplelines-buttons.yml | 4 - .../unreleased/26447-fix-tab-list-order.yml | 4 - .../26468-fix-users-sort-in-admin-area.yml | 4 - .../26787-add-copy-icon-hover-state.yml | 4 - ...ible-when-there-are-no-lines-to-unfold.yml | 5 - .../26852-fix-slug-for-openshift.yml | 4 - ...move-hover-animation-from-row-elements.yml | 4 - .../26881-backup-fails-if-data-changes.yml | 4 - ...920-hover-cursor-on-pagination-element.yml | 4 - .../26947-build-status-self-link.yml | 4 - ...ipeline-status-icon-linking-in-widgets.yml | 4 - .../27013-regression-in-commit-title-bar.yml | 4 - .../27014-fix-pipeline-tooltip-wrapping.yml | 4 - ...21-line-numbers-now-in-copy-pasta-data.yml | 4 - ...update-builds-link-in-project-settings.yml | 4 - .../27240-make-progress-bars-consistent.yml | 4 - ...-mini-pipeline-graph-glitch-upon-hover.yml | 4 - .../27291-unify-mr-diff-file-buttons.yml | 4 - ...parator-line-in-edit-projects-settings.yml | 4 - ...-no-line-spacing-in-firefox-and-safari.yml | 4 - .../27352-search-label-filter-header.yml | 4 - ...95-reduce-group-activity-sql-queries-2.yml | 4 - ...7395-reduce-group-activity-sql-queries.yml | 4 - .../27484-environment-show-name.yml | 4 - .../unreleased/27488-fix-jwt-version.yml | 4 - .../27494-environment-list-column-headers.yml | 4 - ...avatar-border-flicker-mention-dropdown.yml | 4 - .../unreleased/27632_fix_mr_widget_url.yml | 4 - ...er-the-side-panel-in-the-merge-request.yml | 4 - .../unreleased/27656-doc-ci-enable-ci.yml | 4 - ...alization-graph-page-with-roboto-fonts.yml | 4 - .../27822-default-bulk-assign-labels.yml | 4 - ...it-comments-are-shared-across-projects.yml | 4 - ...elines-table-not-showing-commit-branch.yml | 4 - ...acter-is-part-of-an-autocompleted-text.yml | 4 - .../27922-cmd-click-todo-doesn-t-work.yml | 5 - ...925-fix-mr-stray-pipelines-api-request.yml | 4 - ...-merge-request-pipelines-displays-json.yml | 4 - .../27939-fix-current-build-arrow.yml | 4 - ...-list-on-profile-page-is-aligned-right.yml | 4 - ...-icon-and-text-in-merge-request-widget.yml | 4 - ...-mr-notification-use-pipeline-language.yml | 4 - changelogs/unreleased/27963-tooltips-jobs.yml | 4 - ...ranch-ref-switcher-input-filter-broken.yml | 4 - .../27987-skipped-pipeline-mr-graph.yml | 4 - .../27991-success-with-warnings-caret.yml | 4 - ...mprove-blockquote-formatting-on-emails.yml | 4 - .../unreleased/28032-tooltips-file-name.yml | 5 - ...-add-pagination-to-admin-abuse-reports.yml | 4 - ...x-notification-when-group-set-to-watch.yml | 4 - changelogs/unreleased/8-15-stable.yml | 4 - .../unreleased/8082-permalink-to-file.yml | 4 - changelogs/unreleased/9-0-api-changes.yml | 4 - ...ommand-for-target-merge-request-branch.yml | 4 - .../unreleased/add_project_update_hook.yml | 4 - .../api-remove-snippets-expires-at.yml | 4 - .../unreleased/babel-all-the-things.yml | 5 - ..._doing_offline_update_check-help_page-.yml | 4 - changelogs/unreleased/change_queue_weight.yml | 4 - .../clipboard-button-commit-sha.yml | 3 - .../contribution-calendar-scroll.yml | 4 - changelogs/unreleased/cop-gem-fetcher.yml | 4 - changelogs/unreleased/copy-as-md.yml | 4 - ...-autologin-on-email-confirmation-links.yml | 4 - changelogs/unreleased/display-project-id.yml | 4 - changelogs/unreleased/document-how-to-vue.yml | 4 - .../unreleased/dynamic-todos-fixture.yml | 4 - .../dz-nested-groups-improvements-2.yml | 4 - .../empty-selection-reply-shortcut.yml | 4 - .../unreleased/fe-commit-mr-pipelines.yml | 4 - ...success-warning-icons-in-stages-builds.yml | 4 - changelogs/unreleased/fix-27479.yml | 4 - .../unreleased/fix-api-mr-permissions.yml | 4 - .../unreleased/fix-ar-connection-leaks.yml | 4 - changelogs/unreleased/fix-ci-build-policy.yml | 4 - .../unreleased/fix-deleting-project-again.yml | 4 - changelogs/unreleased/fix-depr-warn.yml | 4 - ...ackwards-compatibility-coverage-ci-yml.yml | 4 - .../fix-guest-access-posting-to-notes.yml | 4 - .../unreleased/fix-import-encrypt-atts.yml | 4 - .../unreleased/fix-import-group-members.yml | 4 - .../fix-job-to-pipeline-renaming.yml | 4 - .../fix-references-header-parsing.yml | 5 - changelogs/unreleased/fix-scroll-test.yml | 4 - ...-users-deleting-public-deployment-keys.yml | 4 - .../fix_broken_diff_discussions.yml | 4 - ...g_message_in_admin_background_job_page.yml | 4 - .../unreleased/fwn-to-find-by-full-path.yml | 4 - ...tification_service_spec-to-make-it-DRY.yml | 4 - .../unreleased/git_to_html_redirection.yml | 4 - .../unreleased/go-go-gadget-webpack.yml | 4 - .../unreleased/group-label-sidebar-link.yml | 4 - .../unreleased/hardcode-title-system-note.yml | 4 - .../unreleased/improve-ci-example-php-doc.yml | 4 - .../improve-handleLocationHash-tests.yml | 4 - .../unreleased/issuable-sidebar-bug.yml | 4 - changelogs/unreleased/issue-20428.yml | 4 - .../issue-sidebar-empty-assignee.yml | 4 - changelogs/unreleased/issue_19262.yml | 4 - changelogs/unreleased/issue_23317.yml | 4 - changelogs/unreleased/issue_27211.yml | 4 - .../unreleased/jej-pages-picked-from-ee.yml | 4 - changelogs/unreleased/label-promotion.yml | 4 - .../unreleased/lfs-noauth-public-repo.yml | 4 - changelogs/unreleased/markdown-plantuml.yml | 4 - .../unreleased/merge-request-tabs-fixture.yml | 4 - ...linged-discussion-with-no-avatar-26854.yml | 4 - .../unreleased/mr-tabs-container-offset.yml | 4 - changelogs/unreleased/newline-eslint-rule.yml | 4 - .../no-sidebar-on-action-btn-click.yml | 4 - changelogs/unreleased/no_project_notes.yml | 4 - .../unreleased/pms-lowercase-system-notes.yml | 4 - ...redesign-searchbar-admin-project-26794.yml | 4 - ...irect-to-commit-when-only-commit-found.yml | 5 - changelogs/unreleased/relative-url-assets.yml | 4 - .../unreleased/remove-deploy-key-endpoint.yml | 4 - ...e-issue-and-mr-counts-from-labels-page.yml | 4 - changelogs/unreleased/route-map.yml | 4 - .../unreleased/rs-warden-blocked-users.yml | 4 - .../sh-add-index-to-ci-trigger-requests.yml | 4 - changelogs/unreleased/sh-add-labels-index.yml | 4 - changelogs/unreleased/slash-commands-typo.yml | 4 - .../small-screen-fullscreen-button.yml | 4 - .../snippets-search-performance.yml | 4 - .../tc-only-mr-button-if-allowed.yml | 4 - .../unreleased/terminal-max-session-time.yml | 4 - changelogs/unreleased/updated-pages-0-3-1.yml | 4 - changelogs/unreleased/upgrade-babel-v6.yml | 4 - changelogs/unreleased/upgrade-omniauth.yml | 4 - .../unreleased/upgrade-webpack-v2-2.yml | 4 - changelogs/unreleased/wip-mr-from-commits.yml | 4 - .../unreleased/zj-format-chat-messages.yml | 4 - .../zj-remove-deprecated-ci-service.yml | 4 - .../unreleased/zj-requeue-pending-delete.yml | 4 - 163 files changed, 180 insertions(+), 653 deletions(-) delete mode 100644 changelogs/unreleased/17662-rename-builds.yml delete mode 100644 changelogs/unreleased/20452-remove-require-from-request_profiler-initializer.yml delete mode 100644 changelogs/unreleased/20852-getting-started-project-better-blank-state-for-labels-view.yml delete mode 100644 changelogs/unreleased/21518_recaptcha_spam_issues.yml delete mode 100644 changelogs/unreleased/22007-unify-projects-search.yml delete mode 100644 changelogs/unreleased/22638-creating-a-branch-matching-a-wildcard-fails.yml delete mode 100644 changelogs/unreleased/22974-trigger-service-events-through-api.yml delete mode 100644 changelogs/unreleased/23524-notify-automerge-user-of-failed-build.yml delete mode 100644 changelogs/unreleased/23634-remove-project-grouping.yml delete mode 100644 changelogs/unreleased/23767-disable-storing-of-sensitive-information.yml delete mode 100644 changelogs/unreleased/24147-delete-env-button.yml delete mode 100644 changelogs/unreleased/24606-force-password-reset-on-next-login.yml delete mode 100644 changelogs/unreleased/24716-fix-ctrl-click-links.yml delete mode 100644 changelogs/unreleased/24795_refactor_merge_request_build_service.yml delete mode 100644 changelogs/unreleased/24833-Allow-to-search-by-commit-hash-within-project.yml delete mode 100644 changelogs/unreleased/24923_nested_tasks.yml delete mode 100644 changelogs/unreleased/25134-mobile-issue-view-doesn-t-show-organization-membership.yml delete mode 100644 changelogs/unreleased/25312-search-input-cmd-click-issue.yml delete mode 100644 changelogs/unreleased/25360-remove-flash-warning-from-login-page.yml delete mode 100644 changelogs/unreleased/25460-replace-word-users-with-members.yml delete mode 100644 changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml delete mode 100644 changelogs/unreleased/25811-pipeline-number-and-url-do-not-update-when-new-pipeline-is-triggered.yml delete mode 100644 changelogs/unreleased/25910-convert-manual-action-icons-to-svg-to-propperly-position-them.yml delete mode 100644 changelogs/unreleased/25989-fix-rogue-scrollbars-on-comments.yml delete mode 100644 changelogs/unreleased/26059-segoe-ui-vertical.yml delete mode 100644 changelogs/unreleased/26068_tasklist_issue.yml delete mode 100644 changelogs/unreleased/26117-sort-pipeline-for-commit.yml delete mode 100644 changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml delete mode 100644 changelogs/unreleased/26445-accessible-piplelines-buttons.yml delete mode 100644 changelogs/unreleased/26447-fix-tab-list-order.yml delete mode 100644 changelogs/unreleased/26468-fix-users-sort-in-admin-area.yml delete mode 100644 changelogs/unreleased/26787-add-copy-icon-hover-state.yml delete mode 100644 changelogs/unreleased/26824-diff-unfold-link-is-still-visible-when-there-are-no-lines-to-unfold.yml delete mode 100644 changelogs/unreleased/26852-fix-slug-for-openshift.yml delete mode 100644 changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml delete mode 100644 changelogs/unreleased/26881-backup-fails-if-data-changes.yml delete mode 100644 changelogs/unreleased/26920-hover-cursor-on-pagination-element.yml delete mode 100644 changelogs/unreleased/26947-build-status-self-link.yml delete mode 100644 changelogs/unreleased/26982-improve-pipeline-status-icon-linking-in-widgets.yml delete mode 100644 changelogs/unreleased/27013-regression-in-commit-title-bar.yml delete mode 100644 changelogs/unreleased/27014-fix-pipeline-tooltip-wrapping.yml delete mode 100644 changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml delete mode 100644 changelogs/unreleased/27178-update-builds-link-in-project-settings.yml delete mode 100644 changelogs/unreleased/27240-make-progress-bars-consistent.yml delete mode 100644 changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml delete mode 100644 changelogs/unreleased/27291-unify-mr-diff-file-buttons.yml delete mode 100644 changelogs/unreleased/27321-double-separator-line-in-edit-projects-settings.yml delete mode 100644 changelogs/unreleased/27332-mini-pipeline-graph-with-many-stages-has-no-line-spacing-in-firefox-and-safari.yml delete mode 100644 changelogs/unreleased/27352-search-label-filter-header.yml delete mode 100644 changelogs/unreleased/27395-reduce-group-activity-sql-queries-2.yml delete mode 100644 changelogs/unreleased/27395-reduce-group-activity-sql-queries.yml delete mode 100644 changelogs/unreleased/27484-environment-show-name.yml delete mode 100644 changelogs/unreleased/27488-fix-jwt-version.yml delete mode 100644 changelogs/unreleased/27494-environment-list-column-headers.yml delete mode 100644 changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml delete mode 100644 changelogs/unreleased/27632_fix_mr_widget_url.yml delete mode 100644 changelogs/unreleased/27639-emoji-panel-under-the-side-panel-in-the-merge-request.yml delete mode 100644 changelogs/unreleased/27656-doc-ci-enable-ci.yml delete mode 100644 changelogs/unreleased/27774-text-color-contrast-is-barely-readable-for-pipelines-visualization-graph-page-with-roboto-fonts.yml delete mode 100644 changelogs/unreleased/27822-default-bulk-assign-labels.yml delete mode 100644 changelogs/unreleased/27873-when-a-commit-appears-in-several-projects-commit-comments-are-shared-across-projects.yml delete mode 100644 changelogs/unreleased/27880-pipelines-table-not-showing-commit-branch.yml delete mode 100644 changelogs/unreleased/27883-autocomplete-seems-to-not-trigger-when-at-character-is-part-of-an-autocompleted-text.yml delete mode 100644 changelogs/unreleased/27922-cmd-click-todo-doesn-t-work.yml delete mode 100644 changelogs/unreleased/27925-fix-mr-stray-pipelines-api-request.yml delete mode 100644 changelogs/unreleased/27932-merge-request-pipelines-displays-json.yml delete mode 100644 changelogs/unreleased/27939-fix-current-build-arrow.yml delete mode 100644 changelogs/unreleased/27943-contribution-list-on-profile-page-is-aligned-right.yml delete mode 100644 changelogs/unreleased/27947-missing-margin-between-loading-icon-and-text-in-merge-request-widget.yml delete mode 100644 changelogs/unreleased/27955-mr-notification-use-pipeline-language.yml delete mode 100644 changelogs/unreleased/27963-tooltips-jobs.yml delete mode 100644 changelogs/unreleased/27966-branch-ref-switcher-input-filter-broken.yml delete mode 100644 changelogs/unreleased/27987-skipped-pipeline-mr-graph.yml delete mode 100644 changelogs/unreleased/27991-success-with-warnings-caret.yml delete mode 100644 changelogs/unreleased/28029-improve-blockquote-formatting-on-emails.yml delete mode 100644 changelogs/unreleased/28032-tooltips-file-name.yml delete mode 100644 changelogs/unreleased/28059-add-pagination-to-admin-abuse-reports.yml delete mode 100644 changelogs/unreleased/395-fix-notification-when-group-set-to-watch.yml delete mode 100644 changelogs/unreleased/8-15-stable.yml delete mode 100644 changelogs/unreleased/8082-permalink-to-file.yml delete mode 100644 changelogs/unreleased/9-0-api-changes.yml delete mode 100644 changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml delete mode 100644 changelogs/unreleased/add_project_update_hook.yml delete mode 100644 changelogs/unreleased/api-remove-snippets-expires-at.yml delete mode 100644 changelogs/unreleased/babel-all-the-things.yml delete mode 100644 changelogs/unreleased/broken_iamge_when_doing_offline_update_check-help_page-.yml delete mode 100644 changelogs/unreleased/change_queue_weight.yml delete mode 100644 changelogs/unreleased/clipboard-button-commit-sha.yml delete mode 100644 changelogs/unreleased/contribution-calendar-scroll.yml delete mode 100644 changelogs/unreleased/cop-gem-fetcher.yml delete mode 100644 changelogs/unreleased/copy-as-md.yml delete mode 100644 changelogs/unreleased/disable-autologin-on-email-confirmation-links.yml delete mode 100644 changelogs/unreleased/display-project-id.yml delete mode 100644 changelogs/unreleased/document-how-to-vue.yml delete mode 100644 changelogs/unreleased/dynamic-todos-fixture.yml delete mode 100644 changelogs/unreleased/dz-nested-groups-improvements-2.yml delete mode 100644 changelogs/unreleased/empty-selection-reply-shortcut.yml delete mode 100644 changelogs/unreleased/fe-commit-mr-pipelines.yml delete mode 100644 changelogs/unreleased/feature-success-warning-icons-in-stages-builds.yml delete mode 100644 changelogs/unreleased/fix-27479.yml delete mode 100644 changelogs/unreleased/fix-api-mr-permissions.yml delete mode 100644 changelogs/unreleased/fix-ar-connection-leaks.yml delete mode 100644 changelogs/unreleased/fix-ci-build-policy.yml delete mode 100644 changelogs/unreleased/fix-deleting-project-again.yml delete mode 100644 changelogs/unreleased/fix-depr-warn.yml delete mode 100644 changelogs/unreleased/fix-gb-backwards-compatibility-coverage-ci-yml.yml delete mode 100644 changelogs/unreleased/fix-guest-access-posting-to-notes.yml delete mode 100644 changelogs/unreleased/fix-import-encrypt-atts.yml delete mode 100644 changelogs/unreleased/fix-import-group-members.yml delete mode 100644 changelogs/unreleased/fix-job-to-pipeline-renaming.yml delete mode 100644 changelogs/unreleased/fix-references-header-parsing.yml delete mode 100644 changelogs/unreleased/fix-scroll-test.yml delete mode 100644 changelogs/unreleased/fix-users-deleting-public-deployment-keys.yml delete mode 100644 changelogs/unreleased/fix_broken_diff_discussions.yml delete mode 100644 changelogs/unreleased/fix_sidekiq_concurrency_warning_message_in_admin_background_job_page.yml delete mode 100644 changelogs/unreleased/fwn-to-find-by-full-path.yml delete mode 100644 changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml delete mode 100644 changelogs/unreleased/git_to_html_redirection.yml delete mode 100644 changelogs/unreleased/go-go-gadget-webpack.yml delete mode 100644 changelogs/unreleased/group-label-sidebar-link.yml delete mode 100644 changelogs/unreleased/hardcode-title-system-note.yml delete mode 100644 changelogs/unreleased/improve-ci-example-php-doc.yml delete mode 100644 changelogs/unreleased/improve-handleLocationHash-tests.yml delete mode 100644 changelogs/unreleased/issuable-sidebar-bug.yml delete mode 100644 changelogs/unreleased/issue-20428.yml delete mode 100644 changelogs/unreleased/issue-sidebar-empty-assignee.yml delete mode 100644 changelogs/unreleased/issue_19262.yml delete mode 100644 changelogs/unreleased/issue_23317.yml delete mode 100644 changelogs/unreleased/issue_27211.yml delete mode 100644 changelogs/unreleased/jej-pages-picked-from-ee.yml delete mode 100644 changelogs/unreleased/label-promotion.yml delete mode 100644 changelogs/unreleased/lfs-noauth-public-repo.yml delete mode 100644 changelogs/unreleased/markdown-plantuml.yml delete mode 100644 changelogs/unreleased/merge-request-tabs-fixture.yml delete mode 100644 changelogs/unreleased/misalinged-discussion-with-no-avatar-26854.yml delete mode 100644 changelogs/unreleased/mr-tabs-container-offset.yml delete mode 100644 changelogs/unreleased/newline-eslint-rule.yml delete mode 100644 changelogs/unreleased/no-sidebar-on-action-btn-click.yml delete mode 100644 changelogs/unreleased/no_project_notes.yml delete mode 100644 changelogs/unreleased/pms-lowercase-system-notes.yml delete mode 100644 changelogs/unreleased/redesign-searchbar-admin-project-26794.yml delete mode 100644 changelogs/unreleased/redirect-to-commit-when-only-commit-found.yml delete mode 100644 changelogs/unreleased/relative-url-assets.yml delete mode 100644 changelogs/unreleased/remove-deploy-key-endpoint.yml delete mode 100644 changelogs/unreleased/remove-issue-and-mr-counts-from-labels-page.yml delete mode 100644 changelogs/unreleased/route-map.yml delete mode 100644 changelogs/unreleased/rs-warden-blocked-users.yml delete mode 100644 changelogs/unreleased/sh-add-index-to-ci-trigger-requests.yml delete mode 100644 changelogs/unreleased/sh-add-labels-index.yml delete mode 100644 changelogs/unreleased/slash-commands-typo.yml delete mode 100644 changelogs/unreleased/small-screen-fullscreen-button.yml delete mode 100644 changelogs/unreleased/snippets-search-performance.yml delete mode 100644 changelogs/unreleased/tc-only-mr-button-if-allowed.yml delete mode 100644 changelogs/unreleased/terminal-max-session-time.yml delete mode 100644 changelogs/unreleased/updated-pages-0-3-1.yml delete mode 100644 changelogs/unreleased/upgrade-babel-v6.yml delete mode 100644 changelogs/unreleased/upgrade-omniauth.yml delete mode 100644 changelogs/unreleased/upgrade-webpack-v2-2.yml delete mode 100644 changelogs/unreleased/wip-mr-from-commits.yml delete mode 100644 changelogs/unreleased/zj-format-chat-messages.yml delete mode 100644 changelogs/unreleased/zj-remove-deprecated-ci-service.yml delete mode 100644 changelogs/unreleased/zj-requeue-pending-delete.yml diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b8cf2ad83..7f5b101ad6b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,186 @@ documentation](doc/development/changelog.md) for instructions on adding your own entry. +## 8.17.0 (2017-02-22) + +- API: Fix file downloading. !0 (8267) +- Changed composer installer script in the CI PHP example doc. !4342 (Jeffrey Cafferata) +- Display fullscreen button on small screens. !5302 (winniehell) +- Add system hook for when a project is updated (other than rename/transfer). !5711 (Tommy Beadle) +- Fix notifications when set at group level. !6813 (Alexandre Maia) +- Project labels can now be promoted to group labels. !7242 (Olaf Tomalka) +- use webpack to bundle frontend assets and use karma for frontend testing. !7288 +- Adds back ability to stop all environments. !7379 +- Added labels empty state. !7443 +- Add ability to define a coverage regex in the .gitlab-ci.yml. !7447 (Leandro Camargo) +- Disable automatic login after clicking email confirmation links. !7472 +- Search feature: redirects to commit page if query is commit sha and only commit found. !8028 (YarNayar) +- Create a TODO for user who set auto-merge when a build fails, merge conflict occurs. !8056 (twonegatives) +- Don't group issues by project on group-level and dashboard issue indexes. !8111 (Bernardo Castro) +- Mark MR as WIP when pushing WIP commits. !8124 (Jurre Stender @jurre) +- Flag multiple empty lines in eslint, fix offenses. !8137 +- Add sorting pipeline for a commit. !8319 (Takuya Noguchi) +- Adds service trigger events to api. !8324 +- Update pipeline and commit links when CI status is updated. !8351 +- Hide version check image if there is no internet connection. !8355 (Ken Ding) +- Prevent removal of input fields if it is the parent dropdown element. !8397 +- Introduce maximum session time for terminal websocket connection. !8413 +- Allow creating protected branches when user can merge to such branch. !8458 +- Refactor MergeRequests::BuildService. !8462 (Rydkin Maxim) +- Added GitLab Pages to CE. !8463 +- Support notes when a project is not specified (personal snippet notes). !8468 +- Use warning icon in mini-graph if stage passed conditionally. !8503 +- Don’t count tasks that are not defined as list items correctly. !8526 +- Reformat messages ChatOps. !8528 +- Copy commit SHA to clipboard. !8547 +- Improve button accessibility on pipelines page. !8561 +- Display project ID in project settings. !8572 (winniehell) +- PlantUML support for Markdown. !8588 (Horacio Sanson) +- Fix reply by email without sub-addressing for some clients from Microsoft and Apple. !8620 +- Fix nested tasks in ordered list. !8626 +- Fix Sort by Recent Sign-in in Admin Area. !8637 (Poornima M) +- Avoid repeated dashes in $CI_ENVIRONMENT_SLUG. !8638 +- Only show Merge Request button when user can create a MR. !8639 +- Prevent copying of line numbers in parallel diff view. !8706 +- Improve build policy and access abilities. !8711 +- API: Remove /projects/:id/keys/.. endpoints. !8716 (Robert Schilling) +- API: Remove deprecated 'expires_at' from project snippets. !8723 (Robert Schilling) +- Add `copy` backup strategy to combat file changed errors. !8728 +- adds avatar for discussion note. !8734 +- Add link verification to badge partial in order to render a badge without a link. !8740 +- Reduce hits to LDAP on Git HTTP auth by reordering auth mechanisms. !8752 +- prevent diff unfolding link from appearing when there are no more lines to show. !8761 +- Redesign searchbar in admin project list. !8776 +- Rename Builds to Pipelines, CI/CD Pipelines, or Jobs everywhere. !8787 +- dismiss sidebar on repo buttons click. !8798 (Adam Pahlevi) +- fixed small mini pipeline graph line glitch. !8804 +- Make all system notes lowercase. !8807 +- Support unauthenticated LFS object downloads for public projects. !8824 (Ben Boeckel) +- Add read-only full_path and full_name attributes to Group API. !8827 +- allow relative url change without recompiling frontend assets. !8831 +- Use vue.js Pipelines table in commit and merge request view. !8844 +- Use reCaptcha when an issue is identified as a spam. !8846 +- resolve deprecation warnings. !8855 (Adam Pahlevi) +- Cop for gem fetched from a git source. !8856 (Adam Pahlevi) +- Remove flash warning from login page. !8864 (Gerald J. Padilla) +- Adds documentation for how to use Vue.js. !8866 +- Add 'View on [env]' link to blobs and individual files in diffs. !8867 +- Replace word user with member. !8872 +- Change the reply shortcut to focus the field even without a selection. !8873 (Brian Hall) +- Unify MR diff file button style. !8874 +- Unify projects search by removing /projects/:search endpoint. !8877 +- Fix disable storing of sensitive information when importing a new repo. !8885 (Bernard Pietraga) +- Fix pipeline graph vertical spacing in Firefox and Safari. !8886 +- Fix filtered search user autocomplete for gitlab instances that are hosted on a subdirectory. !8891 +- Fix Ctrl+Click support for Todos and Merge Request page tabs. !8898 +- Fix wrong call to ProjectCacheWorker.perform. !8910 +- Don't perform Devise trackable updates on blocked User records. !8915 +- Add ability to export project inherited group members to Import/Export. !8923 +- replace `find_with_namespace` with `find_by_full_path`. !8949 (Adam Pahlevi) +- Fixes flickering of avatar border in mention dropdown. !8950 +- Remove unnecessary queries for .atom and .json in Dashboard::ProjectsController#index. !8956 +- Fix deleting projects with pipelines and builds. !8960 +- Fix broken anchor links when special characters are used. !8961 (Andrey Krivko) +- Ensure autogenerated title does not cause failing spec. !8963 (brian m. carlson) +- Update doc for enabling or disabling GitLab CI. !8965 (Takuya Noguchi) +- Remove deprecated MR and Issue endpoints and preserve V3 namespace. !8967 +- Fixed "substract" typo on /help/user/project/slash_commands. !8976 (Jason Aquino) +- Preserve backward compatibility CI/CD and disallow setting `coverage` regexp in global context. !8981 +- use babel to transpile all non-vendor javascript assets regardless of file extension. !8988 +- Fix MR widget url. !8989 +- Fixes hover cursor on pipeline pagenation. !9003 +- Layer award emoji dropdown over the right sidebar. !9004 +- Do not display deploy keys in user's own ssh keys list. !9024 +- upgrade babel 5.8.x to babel 6.22.x. !9072 +- upgrade to webpack v2.2. !9078 +- Trigger autocomplete after selecting a slash command. !9117 +- Add space between text and loading icon in Megre Request Widget. !9119 +- Fix job to pipeline renaming. !9147 +- Replace static fixture for merge_request_tabs_spec.js. !9172 (winniehell) +- Replace static fixture for right_sidebar_spec.js. !9211 (winniehell) +- Show merge errors in merge request widget. !9229 +- Increase process_commit queue weight from 2 to 3. !9326 (blackst0ne) +- Don't require lib/gitlab/request_profiler/middleware.rb in config/initializers/request_profiler.rb. +- Force new password after password reset via API. (George Andrinopoulos) +- Allows to search within project by commit hash. (YarNayar) +- Show organisation membership and delete comment on smaller viewports, plus change comment author name to username. +- Remove turbolinks. +- Convert pipeline action icons to svg to have them propperly positioned. +- Remove rogue scrollbars for issue comments with inline elements. +- Align Segoe UI label text. +- Color + and - signs in diffs to increase code legibility. +- Fix tab index order on branch commits list page. (Ryan Harris) +- Add hover style to copy icon on commit page header. (Ryan Harris) +- Remove hover animation from row elements. +- Improve pipeline status icon linking in widgets. +- Fix commit title bar and repository view copy clipboard button order on last commit in repository view. +- Fix mini-pipeline stage tooltip text wrapping. +- Updated builds info link on the project settings page. (Ryan Harris) +- 27240 Make progress bars consistent. +- Only render hr when user can't archive project. +- 27352-search-label-filter-header. +- Include :author, :project, and :target in Event.with_associations. +- Don't instantiate AR objects in Event.in_projects. +- Don't capitalize environment name in show page. +- Update and pin the `jwt` gem to ~> 1.5.6. +- Edited the column header for the environments list from created to updated and added created to environments detail page colum header titles. +- Give ci status text on pipeline graph a better font-weight. +- Add default labels to bulk assign dropdowns. +- Only return target project's comments for a commit. +- Fixes Pipelines table is not showing branch name for commit. +- Fix regression where cmd-click stopped working for todos and merge request tabs. +- Fix stray pipelines API request when showing MR. +- Fix Merge request pipelines displays JSON. +- Fix current build arrow indicator. +- Fix contribution activity alignment. +- Show Pipeline(not Job) in MR desktop notification. +- Fix tooltips in mini pipeline graph. +- Display loading indicator when filtering ref switcher dropdown. +- Show pipeline graph in MR widget if there are any stages. +- Fix icon colors in merge request widget mini graph. +- Improve blockquote formatting in notification emails. +- Adds container to tooltip in order to make it work with overflow:hidden in parent element. +- Restore pagination to admin abuse reports. +- Ensure export files are removed after a namespace is deleted. +- Add `y` keyboard shortcut to move to file permalink. +- Adds /target_branch slash command functionality for merge requests. (YarNayar) +- Patch Asciidocs rendering to block XSS. +- contribution calendar scrolls from right to left. +- Copying a rendered issue/comment will paste into GFM textareas as actual GFM. +- Don't delete assigned MRs/issues when user is deleted. +- Remove new branch button for confidential issues. +- Don't allow project guests to subscribe to merge requests through the API. (Robert Schilling) +- Don't connect in Gitlab::Database.adapter_name. +- Prevent users from creating notes on resources they can't access. +- Ignore encrypted attributes in Import/Export. +- Change rspec test to guarantee window is resized before visiting page. +- Prevent users from deleting system deploy keys via the project deploy key API. +- Fix XSS vulnerability in SVG attachments. +- Make MR-review-discussions more reliable. +- fix incorrect sidekiq concurrency count in admin background page. (wendy0402) +- Make notification_service spec DRYer by making test reusable. (YarNayar) +- Redirect http://someproject.git to http://someproject. (blackst0ne) +- Fixed group label links in issue/merge request sidebar. +- Improve gl.utils.handleLocationHash tests. +- Fixed Issuable sidebar not closing on smaller/mobile sized screens. +- Resets assignee dropdown when sidebar is open. +- Disallow system notes for closed issuables. +- Fix timezone on issue boards due date. +- Remove unused js response from refs controller. +- Prevent the GitHub importer from assigning labels and comments to merge requests or issues belonging to other projects. +- Fixed merge requests tab extra margin when fixed to window. +- Patch XSS vulnerability in RDOC support. +- Refresh authorizations when transferring projects. +- Remove issue and MR counts from labels index. +- Don't use backup Active Record connections for Sidekiq. +- Add index to ci_trigger_requests for commit_id. +- Add indices to improve loading of labels page. +- Reduced query count for snippet search. +- Update GitLab Pages to v0.3.1. +- Upgrade omniauth gem to 1.3.2. +- Remove deprecated GitlabCiService. +- Requeue pending deletion projects. + ## 8.16.6 (2017-02-17) - API: Fix file downloading. !0 (8267) diff --git a/changelogs/unreleased/17662-rename-builds.yml b/changelogs/unreleased/17662-rename-builds.yml deleted file mode 100644 index 12f2998d1c8..00000000000 --- a/changelogs/unreleased/17662-rename-builds.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Rename Builds to Pipelines, CI/CD Pipelines, or Jobs everywhere -merge_request: 8787 -author: diff --git a/changelogs/unreleased/20452-remove-require-from-request_profiler-initializer.yml b/changelogs/unreleased/20452-remove-require-from-request_profiler-initializer.yml deleted file mode 100644 index 965d0648adf..00000000000 --- a/changelogs/unreleased/20452-remove-require-from-request_profiler-initializer.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't require lib/gitlab/request_profiler/middleware.rb in config/initializers/request_profiler.rb -merge_request: -author: diff --git a/changelogs/unreleased/20852-getting-started-project-better-blank-state-for-labels-view.yml b/changelogs/unreleased/20852-getting-started-project-better-blank-state-for-labels-view.yml deleted file mode 100644 index eda872049fd..00000000000 --- a/changelogs/unreleased/20852-getting-started-project-better-blank-state-for-labels-view.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added labels empty state -merge_request: 7443 -author: diff --git a/changelogs/unreleased/21518_recaptcha_spam_issues.yml b/changelogs/unreleased/21518_recaptcha_spam_issues.yml deleted file mode 100644 index bd6c9d7521e..00000000000 --- a/changelogs/unreleased/21518_recaptcha_spam_issues.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use reCaptcha when an issue is identified as a spam -merge_request: 8846 -author: diff --git a/changelogs/unreleased/22007-unify-projects-search.yml b/changelogs/unreleased/22007-unify-projects-search.yml deleted file mode 100644 index f43c1925ad0..00000000000 --- a/changelogs/unreleased/22007-unify-projects-search.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Unify projects search by removing /projects/:search endpoint -merge_request: 8877 -author: diff --git a/changelogs/unreleased/22638-creating-a-branch-matching-a-wildcard-fails.yml b/changelogs/unreleased/22638-creating-a-branch-matching-a-wildcard-fails.yml deleted file mode 100644 index 2c6883bcf7b..00000000000 --- a/changelogs/unreleased/22638-creating-a-branch-matching-a-wildcard-fails.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Allow creating protected branches when user can merge to such branch -merge_request: 8458 -author: diff --git a/changelogs/unreleased/22974-trigger-service-events-through-api.yml b/changelogs/unreleased/22974-trigger-service-events-through-api.yml deleted file mode 100644 index 57106e8c676..00000000000 --- a/changelogs/unreleased/22974-trigger-service-events-through-api.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds service trigger events to api -merge_request: 8324 -author: diff --git a/changelogs/unreleased/23524-notify-automerge-user-of-failed-build.yml b/changelogs/unreleased/23524-notify-automerge-user-of-failed-build.yml deleted file mode 100644 index 268be6b9b83..00000000000 --- a/changelogs/unreleased/23524-notify-automerge-user-of-failed-build.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Create a TODO for user who set auto-merge when a build fails, merge conflict occurs -merge_request: 8056 -author: twonegatives diff --git a/changelogs/unreleased/23634-remove-project-grouping.yml b/changelogs/unreleased/23634-remove-project-grouping.yml deleted file mode 100644 index dde8b2d1815..00000000000 --- a/changelogs/unreleased/23634-remove-project-grouping.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't group issues by project on group-level and dashboard issue indexes. -merge_request: 8111 -author: Bernardo Castro diff --git a/changelogs/unreleased/23767-disable-storing-of-sensitive-information.yml b/changelogs/unreleased/23767-disable-storing-of-sensitive-information.yml deleted file mode 100644 index 587ef4f9a73..00000000000 --- a/changelogs/unreleased/23767-disable-storing-of-sensitive-information.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix disable storing of sensitive information when importing a new repo -merge_request: 8885 -author: Bernard Pietraga diff --git a/changelogs/unreleased/24147-delete-env-button.yml b/changelogs/unreleased/24147-delete-env-button.yml deleted file mode 100644 index 14e80cacbfb..00000000000 --- a/changelogs/unreleased/24147-delete-env-button.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds back ability to stop all environments -merge_request: 7379 -author: diff --git a/changelogs/unreleased/24606-force-password-reset-on-next-login.yml b/changelogs/unreleased/24606-force-password-reset-on-next-login.yml deleted file mode 100644 index fd671d04a9f..00000000000 --- a/changelogs/unreleased/24606-force-password-reset-on-next-login.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Force new password after password reset via API -merge_request: -author: George Andrinopoulos diff --git a/changelogs/unreleased/24716-fix-ctrl-click-links.yml b/changelogs/unreleased/24716-fix-ctrl-click-links.yml deleted file mode 100644 index 13de5db5e41..00000000000 --- a/changelogs/unreleased/24716-fix-ctrl-click-links.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Ctrl+Click support for Todos and Merge Request page tabs -merge_request: 8898 -author: diff --git a/changelogs/unreleased/24795_refactor_merge_request_build_service.yml b/changelogs/unreleased/24795_refactor_merge_request_build_service.yml deleted file mode 100644 index b735fb57649..00000000000 --- a/changelogs/unreleased/24795_refactor_merge_request_build_service.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Refactor MergeRequests::BuildService -merge_request: 8462 -author: Rydkin Maxim diff --git a/changelogs/unreleased/24833-Allow-to-search-by-commit-hash-within-project.yml b/changelogs/unreleased/24833-Allow-to-search-by-commit-hash-within-project.yml deleted file mode 100644 index be66c370f36..00000000000 --- a/changelogs/unreleased/24833-Allow-to-search-by-commit-hash-within-project.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Allows to search within project by commit hash' -merge_request: -author: YarNayar diff --git a/changelogs/unreleased/24923_nested_tasks.yml b/changelogs/unreleased/24923_nested_tasks.yml deleted file mode 100644 index de35cad3dd6..00000000000 --- a/changelogs/unreleased/24923_nested_tasks.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix nested tasks in ordered list -merge_request: 8626 -author: diff --git a/changelogs/unreleased/25134-mobile-issue-view-doesn-t-show-organization-membership.yml b/changelogs/unreleased/25134-mobile-issue-view-doesn-t-show-organization-membership.yml deleted file mode 100644 index d35ad0be0db..00000000000 --- a/changelogs/unreleased/25134-mobile-issue-view-doesn-t-show-organization-membership.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show organisation membership and delete comment on smaller viewports, plus change comment author name to username -merge_request: -author: diff --git a/changelogs/unreleased/25312-search-input-cmd-click-issue.yml b/changelogs/unreleased/25312-search-input-cmd-click-issue.yml deleted file mode 100644 index 56e03a48692..00000000000 --- a/changelogs/unreleased/25312-search-input-cmd-click-issue.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent removal of input fields if it is the parent dropdown element -merge_request: 8397 -author: diff --git a/changelogs/unreleased/25360-remove-flash-warning-from-login-page.yml b/changelogs/unreleased/25360-remove-flash-warning-from-login-page.yml deleted file mode 100644 index 50a5c879446..00000000000 --- a/changelogs/unreleased/25360-remove-flash-warning-from-login-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove flash warning from login page -merge_request: 8864 -author: Gerald J. Padilla diff --git a/changelogs/unreleased/25460-replace-word-users-with-members.yml b/changelogs/unreleased/25460-replace-word-users-with-members.yml deleted file mode 100644 index dac90eaa34d..00000000000 --- a/changelogs/unreleased/25460-replace-word-users-with-members.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replace word user with member -merge_request: 8872 -author: diff --git a/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml b/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml deleted file mode 100644 index d7f950d7be9..00000000000 --- a/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove turbolinks. -merge_request: !8570 -author: diff --git a/changelogs/unreleased/25811-pipeline-number-and-url-do-not-update-when-new-pipeline-is-triggered.yml b/changelogs/unreleased/25811-pipeline-number-and-url-do-not-update-when-new-pipeline-is-triggered.yml deleted file mode 100644 index f74e9fa8b6d..00000000000 --- a/changelogs/unreleased/25811-pipeline-number-and-url-do-not-update-when-new-pipeline-is-triggered.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update pipeline and commit links when CI status is updated -merge_request: 8351 -author: diff --git a/changelogs/unreleased/25910-convert-manual-action-icons-to-svg-to-propperly-position-them.yml b/changelogs/unreleased/25910-convert-manual-action-icons-to-svg-to-propperly-position-them.yml deleted file mode 100644 index 9506692dd40..00000000000 --- a/changelogs/unreleased/25910-convert-manual-action-icons-to-svg-to-propperly-position-them.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Convert pipeline action icons to svg to have them propperly positioned -merge_request: -author: diff --git a/changelogs/unreleased/25989-fix-rogue-scrollbars-on-comments.yml b/changelogs/unreleased/25989-fix-rogue-scrollbars-on-comments.yml deleted file mode 100644 index e67a9c0da15..00000000000 --- a/changelogs/unreleased/25989-fix-rogue-scrollbars-on-comments.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove rogue scrollbars for issue comments with inline elements -merge_request: -author: diff --git a/changelogs/unreleased/26059-segoe-ui-vertical.yml b/changelogs/unreleased/26059-segoe-ui-vertical.yml deleted file mode 100644 index fc3f1af5b61..00000000000 --- a/changelogs/unreleased/26059-segoe-ui-vertical.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Align Segoe UI label text -merge_request: -author: diff --git a/changelogs/unreleased/26068_tasklist_issue.yml b/changelogs/unreleased/26068_tasklist_issue.yml deleted file mode 100644 index c938351b8a7..00000000000 --- a/changelogs/unreleased/26068_tasklist_issue.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don’t count tasks that are not defined as list items correctly -merge_request: 8526 -author: diff --git a/changelogs/unreleased/26117-sort-pipeline-for-commit.yml b/changelogs/unreleased/26117-sort-pipeline-for-commit.yml deleted file mode 100644 index b2f5294d380..00000000000 --- a/changelogs/unreleased/26117-sort-pipeline-for-commit.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add sorting pipeline for a commit -merge_request: 8319 -author: Takuya Noguchi diff --git a/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml b/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml deleted file mode 100644 index 565672917b2..00000000000 --- a/changelogs/unreleased/26186-diff-view-plus-and-minus-signs-as-part-of-line-number.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Color + and - signs in diffs to increase code legibility -merge_request: -author: diff --git a/changelogs/unreleased/26445-accessible-piplelines-buttons.yml b/changelogs/unreleased/26445-accessible-piplelines-buttons.yml deleted file mode 100644 index fb5274e5253..00000000000 --- a/changelogs/unreleased/26445-accessible-piplelines-buttons.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve button accessibility on pipelines page -merge_request: 8561 -author: diff --git a/changelogs/unreleased/26447-fix-tab-list-order.yml b/changelogs/unreleased/26447-fix-tab-list-order.yml deleted file mode 100644 index 351c53bd076..00000000000 --- a/changelogs/unreleased/26447-fix-tab-list-order.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix tab index order on branch commits list page -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/26468-fix-users-sort-in-admin-area.yml b/changelogs/unreleased/26468-fix-users-sort-in-admin-area.yml deleted file mode 100644 index 87ae8233c4a..00000000000 --- a/changelogs/unreleased/26468-fix-users-sort-in-admin-area.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Sort by Recent Sign-in in Admin Area -merge_request: 8637 -author: Poornima M diff --git a/changelogs/unreleased/26787-add-copy-icon-hover-state.yml b/changelogs/unreleased/26787-add-copy-icon-hover-state.yml deleted file mode 100644 index 31f1812c6f8..00000000000 --- a/changelogs/unreleased/26787-add-copy-icon-hover-state.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add hover style to copy icon on commit page header -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/26824-diff-unfold-link-is-still-visible-when-there-are-no-lines-to-unfold.yml b/changelogs/unreleased/26824-diff-unfold-link-is-still-visible-when-there-are-no-lines-to-unfold.yml deleted file mode 100644 index 182a9ae126b..00000000000 --- a/changelogs/unreleased/26824-diff-unfold-link-is-still-visible-when-there-are-no-lines-to-unfold.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: prevent diff unfolding link from appearing when there are no more lines to - show -merge_request: 8761 -author: diff --git a/changelogs/unreleased/26852-fix-slug-for-openshift.yml b/changelogs/unreleased/26852-fix-slug-for-openshift.yml deleted file mode 100644 index fb65b068b23..00000000000 --- a/changelogs/unreleased/26852-fix-slug-for-openshift.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Avoid repeated dashes in $CI_ENVIRONMENT_SLUG -merge_request: 8638 -author: diff --git a/changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml b/changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml deleted file mode 100644 index 8dfabf87c2a..00000000000 --- a/changelogs/unreleased/26863-Remove-hover-animation-from-row-elements.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove hover animation from row elements -merge_request: -author: diff --git a/changelogs/unreleased/26881-backup-fails-if-data-changes.yml b/changelogs/unreleased/26881-backup-fails-if-data-changes.yml deleted file mode 100644 index 00bf105560b..00000000000 --- a/changelogs/unreleased/26881-backup-fails-if-data-changes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add `copy` backup strategy to combat file changed errors -merge_request: 8728 -author: diff --git a/changelogs/unreleased/26920-hover-cursor-on-pagination-element.yml b/changelogs/unreleased/26920-hover-cursor-on-pagination-element.yml deleted file mode 100644 index ea567437ac2..00000000000 --- a/changelogs/unreleased/26920-hover-cursor-on-pagination-element.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes hover cursor on pipeline pagenation -merge_request: 9003 -author: diff --git a/changelogs/unreleased/26947-build-status-self-link.yml b/changelogs/unreleased/26947-build-status-self-link.yml deleted file mode 100644 index 15c5821874e..00000000000 --- a/changelogs/unreleased/26947-build-status-self-link.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add link verification to badge partial in order to render a badge without a link -merge_request: 8740 -author: diff --git a/changelogs/unreleased/26982-improve-pipeline-status-icon-linking-in-widgets.yml b/changelogs/unreleased/26982-improve-pipeline-status-icon-linking-in-widgets.yml deleted file mode 100644 index c5c57af5aaf..00000000000 --- a/changelogs/unreleased/26982-improve-pipeline-status-icon-linking-in-widgets.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve pipeline status icon linking in widgets -merge_request: -author: diff --git a/changelogs/unreleased/27013-regression-in-commit-title-bar.yml b/changelogs/unreleased/27013-regression-in-commit-title-bar.yml deleted file mode 100644 index 7cb5e4b273d..00000000000 --- a/changelogs/unreleased/27013-regression-in-commit-title-bar.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix commit title bar and repository view copy clipboard button order on last commit in repository view -merge_request: -author: diff --git a/changelogs/unreleased/27014-fix-pipeline-tooltip-wrapping.yml b/changelogs/unreleased/27014-fix-pipeline-tooltip-wrapping.yml deleted file mode 100644 index f0301c849b6..00000000000 --- a/changelogs/unreleased/27014-fix-pipeline-tooltip-wrapping.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix mini-pipeline stage tooltip text wrapping -merge_request: -author: diff --git a/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml b/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml deleted file mode 100644 index b5584749098..00000000000 --- a/changelogs/unreleased/27021-line-numbers-now-in-copy-pasta-data.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent copying of line numbers in parallel diff view -merge_request: 8706 -author: diff --git a/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml b/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml deleted file mode 100644 index 52406bba464..00000000000 --- a/changelogs/unreleased/27178-update-builds-link-in-project-settings.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Updated builds info link on the project settings page -merge_request: -author: Ryan Harris diff --git a/changelogs/unreleased/27240-make-progress-bars-consistent.yml b/changelogs/unreleased/27240-make-progress-bars-consistent.yml deleted file mode 100644 index 3f902fb324e..00000000000 --- a/changelogs/unreleased/27240-make-progress-bars-consistent.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 27240 Make progress bars consistent -merge_request: -author: diff --git a/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml b/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml deleted file mode 100644 index 9456251025b..00000000000 --- a/changelogs/unreleased/27277-small-mini-pipeline-graph-glitch-upon-hover.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: fixed small mini pipeline graph line glitch -merge_request: 8804 -author: diff --git a/changelogs/unreleased/27291-unify-mr-diff-file-buttons.yml b/changelogs/unreleased/27291-unify-mr-diff-file-buttons.yml deleted file mode 100644 index 293aab67d39..00000000000 --- a/changelogs/unreleased/27291-unify-mr-diff-file-buttons.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Unify MR diff file button style -merge_request: 8874 -author: diff --git a/changelogs/unreleased/27321-double-separator-line-in-edit-projects-settings.yml b/changelogs/unreleased/27321-double-separator-line-in-edit-projects-settings.yml deleted file mode 100644 index 502927cd160..00000000000 --- a/changelogs/unreleased/27321-double-separator-line-in-edit-projects-settings.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Only render hr when user can't archive project. -merge_request: !8917 -author: diff --git a/changelogs/unreleased/27332-mini-pipeline-graph-with-many-stages-has-no-line-spacing-in-firefox-and-safari.yml b/changelogs/unreleased/27332-mini-pipeline-graph-with-many-stages-has-no-line-spacing-in-firefox-and-safari.yml deleted file mode 100644 index 79316abbaf7..00000000000 --- a/changelogs/unreleased/27332-mini-pipeline-graph-with-many-stages-has-no-line-spacing-in-firefox-and-safari.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix pipeline graph vertical spacing in Firefox and Safari -merge_request: 8886 -author: diff --git a/changelogs/unreleased/27352-search-label-filter-header.yml b/changelogs/unreleased/27352-search-label-filter-header.yml deleted file mode 100644 index 191b530aee8..00000000000 --- a/changelogs/unreleased/27352-search-label-filter-header.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 27352-search-label-filter-header -merge_request: -author: diff --git a/changelogs/unreleased/27395-reduce-group-activity-sql-queries-2.yml b/changelogs/unreleased/27395-reduce-group-activity-sql-queries-2.yml deleted file mode 100644 index f3ce1709518..00000000000 --- a/changelogs/unreleased/27395-reduce-group-activity-sql-queries-2.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Include :author, :project, and :target in Event.with_associations -merge_request: -author: diff --git a/changelogs/unreleased/27395-reduce-group-activity-sql-queries.yml b/changelogs/unreleased/27395-reduce-group-activity-sql-queries.yml deleted file mode 100644 index 3f6d922f2a0..00000000000 --- a/changelogs/unreleased/27395-reduce-group-activity-sql-queries.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't instantiate AR objects in Event.in_projects -merge_request: -author: diff --git a/changelogs/unreleased/27484-environment-show-name.yml b/changelogs/unreleased/27484-environment-show-name.yml deleted file mode 100644 index dc400d65006..00000000000 --- a/changelogs/unreleased/27484-environment-show-name.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't capitalize environment name in show page -merge_request: -author: diff --git a/changelogs/unreleased/27488-fix-jwt-version.yml b/changelogs/unreleased/27488-fix-jwt-version.yml deleted file mode 100644 index 5135ff0fd60..00000000000 --- a/changelogs/unreleased/27488-fix-jwt-version.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update and pin the `jwt` gem to ~> 1.5.6 -merge_request: -author: diff --git a/changelogs/unreleased/27494-environment-list-column-headers.yml b/changelogs/unreleased/27494-environment-list-column-headers.yml deleted file mode 100644 index 798c01f3238..00000000000 --- a/changelogs/unreleased/27494-environment-list-column-headers.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Edited the column header for the environments list from created to updated and added created to environments detail page colum header titles -merge_request: -author: diff --git a/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml b/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml deleted file mode 100644 index a5bb37ec8a9..00000000000 --- a/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes flickering of avatar border in mention dropdown -merge_request: 8950 -author: diff --git a/changelogs/unreleased/27632_fix_mr_widget_url.yml b/changelogs/unreleased/27632_fix_mr_widget_url.yml deleted file mode 100644 index 958621a43a1..00000000000 --- a/changelogs/unreleased/27632_fix_mr_widget_url.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix MR widget url -merge_request: 8989 -author: diff --git a/changelogs/unreleased/27639-emoji-panel-under-the-side-panel-in-the-merge-request.yml b/changelogs/unreleased/27639-emoji-panel-under-the-side-panel-in-the-merge-request.yml deleted file mode 100644 index 0531ef2c038..00000000000 --- a/changelogs/unreleased/27639-emoji-panel-under-the-side-panel-in-the-merge-request.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Layer award emoji dropdown over the right sidebar -merge_request: 9004 -author: diff --git a/changelogs/unreleased/27656-doc-ci-enable-ci.yml b/changelogs/unreleased/27656-doc-ci-enable-ci.yml deleted file mode 100644 index e6315d683d4..00000000000 --- a/changelogs/unreleased/27656-doc-ci-enable-ci.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update doc for enabling or disabling GitLab CI -merge_request: 8965 -author: Takuya Noguchi diff --git a/changelogs/unreleased/27774-text-color-contrast-is-barely-readable-for-pipelines-visualization-graph-page-with-roboto-fonts.yml b/changelogs/unreleased/27774-text-color-contrast-is-barely-readable-for-pipelines-visualization-graph-page-with-roboto-fonts.yml deleted file mode 100644 index aa89d9f9850..00000000000 --- a/changelogs/unreleased/27774-text-color-contrast-is-barely-readable-for-pipelines-visualization-graph-page-with-roboto-fonts.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Give ci status text on pipeline graph a better font-weight -merge_request: -author: diff --git a/changelogs/unreleased/27822-default-bulk-assign-labels.yml b/changelogs/unreleased/27822-default-bulk-assign-labels.yml deleted file mode 100644 index ee2431869f0..00000000000 --- a/changelogs/unreleased/27822-default-bulk-assign-labels.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add default labels to bulk assign dropdowns -merge_request: -author: diff --git a/changelogs/unreleased/27873-when-a-commit-appears-in-several-projects-commit-comments-are-shared-across-projects.yml b/changelogs/unreleased/27873-when-a-commit-appears-in-several-projects-commit-comments-are-shared-across-projects.yml deleted file mode 100644 index 89e2bdc69bc..00000000000 --- a/changelogs/unreleased/27873-when-a-commit-appears-in-several-projects-commit-comments-are-shared-across-projects.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Only return target project's comments for a commit -merge_request: -author: diff --git a/changelogs/unreleased/27880-pipelines-table-not-showing-commit-branch.yml b/changelogs/unreleased/27880-pipelines-table-not-showing-commit-branch.yml deleted file mode 100644 index 4251754618b..00000000000 --- a/changelogs/unreleased/27880-pipelines-table-not-showing-commit-branch.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixes Pipelines table is not showing branch name for commit -merge_request: -author: diff --git a/changelogs/unreleased/27883-autocomplete-seems-to-not-trigger-when-at-character-is-part-of-an-autocompleted-text.yml b/changelogs/unreleased/27883-autocomplete-seems-to-not-trigger-when-at-character-is-part-of-an-autocompleted-text.yml deleted file mode 100644 index 52b7e96682d..00000000000 --- a/changelogs/unreleased/27883-autocomplete-seems-to-not-trigger-when-at-character-is-part-of-an-autocompleted-text.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Trigger autocomplete after selecting a slash command -merge_request: 9117 -author: diff --git a/changelogs/unreleased/27922-cmd-click-todo-doesn-t-work.yml b/changelogs/unreleased/27922-cmd-click-todo-doesn-t-work.yml deleted file mode 100644 index 79a54429ee8..00000000000 --- a/changelogs/unreleased/27922-cmd-click-todo-doesn-t-work.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix regression where cmd-click stopped working for todos and merge request - tabs -merge_request: -author: diff --git a/changelogs/unreleased/27925-fix-mr-stray-pipelines-api-request.yml b/changelogs/unreleased/27925-fix-mr-stray-pipelines-api-request.yml deleted file mode 100644 index f7bdb62b7f3..00000000000 --- a/changelogs/unreleased/27925-fix-mr-stray-pipelines-api-request.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix stray pipelines API request when showing MR -merge_request: -author: diff --git a/changelogs/unreleased/27932-merge-request-pipelines-displays-json.yml b/changelogs/unreleased/27932-merge-request-pipelines-displays-json.yml deleted file mode 100644 index b7505e28401..00000000000 --- a/changelogs/unreleased/27932-merge-request-pipelines-displays-json.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix Merge request pipelines displays JSON -merge_request: -author: diff --git a/changelogs/unreleased/27939-fix-current-build-arrow.yml b/changelogs/unreleased/27939-fix-current-build-arrow.yml deleted file mode 100644 index 280ab090f2c..00000000000 --- a/changelogs/unreleased/27939-fix-current-build-arrow.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix current build arrow indicator -merge_request: -author: diff --git a/changelogs/unreleased/27943-contribution-list-on-profile-page-is-aligned-right.yml b/changelogs/unreleased/27943-contribution-list-on-profile-page-is-aligned-right.yml deleted file mode 100644 index fcbd48b0357..00000000000 --- a/changelogs/unreleased/27943-contribution-list-on-profile-page-is-aligned-right.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix contribution activity alignment -merge_request: -author: diff --git a/changelogs/unreleased/27947-missing-margin-between-loading-icon-and-text-in-merge-request-widget.yml b/changelogs/unreleased/27947-missing-margin-between-loading-icon-and-text-in-merge-request-widget.yml deleted file mode 100644 index 1dfabd3813b..00000000000 --- a/changelogs/unreleased/27947-missing-margin-between-loading-icon-and-text-in-merge-request-widget.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add space between text and loading icon in Megre Request Widget -merge_request: 9119 -author: diff --git a/changelogs/unreleased/27955-mr-notification-use-pipeline-language.yml b/changelogs/unreleased/27955-mr-notification-use-pipeline-language.yml deleted file mode 100644 index d9f78db4bec..00000000000 --- a/changelogs/unreleased/27955-mr-notification-use-pipeline-language.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show Pipeline(not Job) in MR desktop notification -merge_request: -author: diff --git a/changelogs/unreleased/27963-tooltips-jobs.yml b/changelogs/unreleased/27963-tooltips-jobs.yml deleted file mode 100644 index ba418d86433..00000000000 --- a/changelogs/unreleased/27963-tooltips-jobs.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix tooltips in mini pipeline graph -merge_request: -author: diff --git a/changelogs/unreleased/27966-branch-ref-switcher-input-filter-broken.yml b/changelogs/unreleased/27966-branch-ref-switcher-input-filter-broken.yml deleted file mode 100644 index 6fa13395a7d..00000000000 --- a/changelogs/unreleased/27966-branch-ref-switcher-input-filter-broken.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Display loading indicator when filtering ref switcher dropdown -merge_request: -author: diff --git a/changelogs/unreleased/27987-skipped-pipeline-mr-graph.yml b/changelogs/unreleased/27987-skipped-pipeline-mr-graph.yml deleted file mode 100644 index e4287d6276c..00000000000 --- a/changelogs/unreleased/27987-skipped-pipeline-mr-graph.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Show pipeline graph in MR widget if there are any stages -merge_request: -author: diff --git a/changelogs/unreleased/27991-success-with-warnings-caret.yml b/changelogs/unreleased/27991-success-with-warnings-caret.yml deleted file mode 100644 index 703d34a5ede..00000000000 --- a/changelogs/unreleased/27991-success-with-warnings-caret.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix icon colors in merge request widget mini graph -merge_request: -author: diff --git a/changelogs/unreleased/28029-improve-blockquote-formatting-on-emails.yml b/changelogs/unreleased/28029-improve-blockquote-formatting-on-emails.yml deleted file mode 100644 index be2a0afbc52..00000000000 --- a/changelogs/unreleased/28029-improve-blockquote-formatting-on-emails.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve blockquote formatting in notification emails -merge_request: -author: diff --git a/changelogs/unreleased/28032-tooltips-file-name.yml b/changelogs/unreleased/28032-tooltips-file-name.yml deleted file mode 100644 index 9fe11e7c2b6..00000000000 --- a/changelogs/unreleased/28032-tooltips-file-name.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Adds container to tooltip in order to make it work with overflow:hidden in - parent element -merge_request: -author: diff --git a/changelogs/unreleased/28059-add-pagination-to-admin-abuse-reports.yml b/changelogs/unreleased/28059-add-pagination-to-admin-abuse-reports.yml deleted file mode 100644 index 1b2e678bbed..00000000000 --- a/changelogs/unreleased/28059-add-pagination-to-admin-abuse-reports.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Restore pagination to admin abuse reports -merge_request: -author: diff --git a/changelogs/unreleased/395-fix-notification-when-group-set-to-watch.yml b/changelogs/unreleased/395-fix-notification-when-group-set-to-watch.yml deleted file mode 100644 index 11d1f55172b..00000000000 --- a/changelogs/unreleased/395-fix-notification-when-group-set-to-watch.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix notifications when set at group level -merge_request: 6813 -author: Alexandre Maia diff --git a/changelogs/unreleased/8-15-stable.yml b/changelogs/unreleased/8-15-stable.yml deleted file mode 100644 index 75502e139e7..00000000000 --- a/changelogs/unreleased/8-15-stable.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Ensure export files are removed after a namespace is deleted -merge_request: -author: diff --git a/changelogs/unreleased/8082-permalink-to-file.yml b/changelogs/unreleased/8082-permalink-to-file.yml deleted file mode 100644 index 136d2108c63..00000000000 --- a/changelogs/unreleased/8082-permalink-to-file.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add `y` keyboard shortcut to move to file permalink -merge_request: -author: diff --git a/changelogs/unreleased/9-0-api-changes.yml b/changelogs/unreleased/9-0-api-changes.yml deleted file mode 100644 index 2f0f1887257..00000000000 --- a/changelogs/unreleased/9-0-api-changes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove deprecated MR and Issue endpoints and preserve V3 namespace -merge_request: 8967 -author: diff --git a/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml b/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml deleted file mode 100644 index 9fd6ea5bc52..00000000000 --- a/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds /target_branch slash command functionality for merge requests -merge_request: -author: YarNayar diff --git a/changelogs/unreleased/add_project_update_hook.yml b/changelogs/unreleased/add_project_update_hook.yml deleted file mode 100644 index 915c9538843..00000000000 --- a/changelogs/unreleased/add_project_update_hook.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add system hook for when a project is updated (other than rename/transfer) -merge_request: 5711 -author: Tommy Beadle diff --git a/changelogs/unreleased/api-remove-snippets-expires-at.yml b/changelogs/unreleased/api-remove-snippets-expires-at.yml deleted file mode 100644 index 67603bfab3b..00000000000 --- a/changelogs/unreleased/api-remove-snippets-expires-at.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'API: Remove deprecated ''expires_at'' from project snippets' -merge_request: 8723 -author: Robert Schilling diff --git a/changelogs/unreleased/babel-all-the-things.yml b/changelogs/unreleased/babel-all-the-things.yml deleted file mode 100644 index fda1c3bd562..00000000000 --- a/changelogs/unreleased/babel-all-the-things.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: use babel to transpile all non-vendor javascript assets regardless of file - extension -merge_request: 8988 -author: diff --git a/changelogs/unreleased/broken_iamge_when_doing_offline_update_check-help_page-.yml b/changelogs/unreleased/broken_iamge_when_doing_offline_update_check-help_page-.yml deleted file mode 100644 index 77750b55e7e..00000000000 --- a/changelogs/unreleased/broken_iamge_when_doing_offline_update_check-help_page-.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Hide version check image if there is no internet connection -merge_request: 8355 -author: Ken Ding diff --git a/changelogs/unreleased/change_queue_weight.yml b/changelogs/unreleased/change_queue_weight.yml deleted file mode 100644 index e4c650e8f79..00000000000 --- a/changelogs/unreleased/change_queue_weight.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Increase process_commit queue weight from 2 to 3 -merge_request: 9326 -author: blackst0ne diff --git a/changelogs/unreleased/clipboard-button-commit-sha.yml b/changelogs/unreleased/clipboard-button-commit-sha.yml deleted file mode 100644 index 6aa4a5664e7..00000000000 --- a/changelogs/unreleased/clipboard-button-commit-sha.yml +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: 'Copy commit SHA to clipboard' -merge_request: 8547 diff --git a/changelogs/unreleased/contribution-calendar-scroll.yml b/changelogs/unreleased/contribution-calendar-scroll.yml deleted file mode 100644 index a504d59e61c..00000000000 --- a/changelogs/unreleased/contribution-calendar-scroll.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: contribution calendar scrolls from right to left -merge_request: -author: diff --git a/changelogs/unreleased/cop-gem-fetcher.yml b/changelogs/unreleased/cop-gem-fetcher.yml deleted file mode 100644 index 506815a5b54..00000000000 --- a/changelogs/unreleased/cop-gem-fetcher.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Cop for gem fetched from a git source -merge_request: 8856 -author: Adam Pahlevi diff --git a/changelogs/unreleased/copy-as-md.yml b/changelogs/unreleased/copy-as-md.yml deleted file mode 100644 index 637e9dc36e2..00000000000 --- a/changelogs/unreleased/copy-as-md.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Copying a rendered issue/comment will paste into GFM textareas as actual GFM -merge_request: -author: diff --git a/changelogs/unreleased/disable-autologin-on-email-confirmation-links.yml b/changelogs/unreleased/disable-autologin-on-email-confirmation-links.yml deleted file mode 100644 index 6dd0d748001..00000000000 --- a/changelogs/unreleased/disable-autologin-on-email-confirmation-links.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Disable automatic login after clicking email confirmation links -merge_request: 7472 -author: diff --git a/changelogs/unreleased/display-project-id.yml b/changelogs/unreleased/display-project-id.yml deleted file mode 100644 index 8705ed28400..00000000000 --- a/changelogs/unreleased/display-project-id.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Display project ID in project settings -merge_request: 8572 -author: winniehell diff --git a/changelogs/unreleased/document-how-to-vue.yml b/changelogs/unreleased/document-how-to-vue.yml deleted file mode 100644 index 863e41b6413..00000000000 --- a/changelogs/unreleased/document-how-to-vue.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Adds documentation for how to use Vue.js -merge_request: 8866 -author: diff --git a/changelogs/unreleased/dynamic-todos-fixture.yml b/changelogs/unreleased/dynamic-todos-fixture.yml deleted file mode 100644 index 580bc729e3c..00000000000 --- a/changelogs/unreleased/dynamic-todos-fixture.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replace static fixture for right_sidebar_spec.js -merge_request: 9211 -author: winniehell diff --git a/changelogs/unreleased/dz-nested-groups-improvements-2.yml b/changelogs/unreleased/dz-nested-groups-improvements-2.yml deleted file mode 100644 index 8e4eb7f1fff..00000000000 --- a/changelogs/unreleased/dz-nested-groups-improvements-2.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add read-only full_path and full_name attributes to Group API -merge_request: 8827 -author: diff --git a/changelogs/unreleased/empty-selection-reply-shortcut.yml b/changelogs/unreleased/empty-selection-reply-shortcut.yml deleted file mode 100644 index 5a42c98a800..00000000000 --- a/changelogs/unreleased/empty-selection-reply-shortcut.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Change the reply shortcut to focus the field even without a selection. -merge_request: 8873 -author: Brian Hall diff --git a/changelogs/unreleased/fe-commit-mr-pipelines.yml b/changelogs/unreleased/fe-commit-mr-pipelines.yml deleted file mode 100644 index b5cc6bbf8b6..00000000000 --- a/changelogs/unreleased/fe-commit-mr-pipelines.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use vue.js Pipelines table in commit and merge request view -merge_request: 8844 -author: diff --git a/changelogs/unreleased/feature-success-warning-icons-in-stages-builds.yml b/changelogs/unreleased/feature-success-warning-icons-in-stages-builds.yml deleted file mode 100644 index 5fba0332881..00000000000 --- a/changelogs/unreleased/feature-success-warning-icons-in-stages-builds.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Use warning icon in mini-graph if stage passed conditionally -merge_request: 8503 -author: diff --git a/changelogs/unreleased/fix-27479.yml b/changelogs/unreleased/fix-27479.yml deleted file mode 100644 index cc72a830695..00000000000 --- a/changelogs/unreleased/fix-27479.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove new branch button for confidential issues -merge_request: -author: diff --git a/changelogs/unreleased/fix-api-mr-permissions.yml b/changelogs/unreleased/fix-api-mr-permissions.yml deleted file mode 100644 index 33b677b1f29..00000000000 --- a/changelogs/unreleased/fix-api-mr-permissions.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't allow project guests to subscribe to merge requests through the API -merge_request: -author: Robert Schilling diff --git a/changelogs/unreleased/fix-ar-connection-leaks.yml b/changelogs/unreleased/fix-ar-connection-leaks.yml deleted file mode 100644 index 9da715560ad..00000000000 --- a/changelogs/unreleased/fix-ar-connection-leaks.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't connect in Gitlab::Database.adapter_name -merge_request: -author: diff --git a/changelogs/unreleased/fix-ci-build-policy.yml b/changelogs/unreleased/fix-ci-build-policy.yml deleted file mode 100644 index 26003713ed4..00000000000 --- a/changelogs/unreleased/fix-ci-build-policy.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve build policy and access abilities -merge_request: 8711 -author: diff --git a/changelogs/unreleased/fix-deleting-project-again.yml b/changelogs/unreleased/fix-deleting-project-again.yml deleted file mode 100644 index e13215f22a7..00000000000 --- a/changelogs/unreleased/fix-deleting-project-again.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix deleting projects with pipelines and builds -merge_request: 8960 -author: diff --git a/changelogs/unreleased/fix-depr-warn.yml b/changelogs/unreleased/fix-depr-warn.yml deleted file mode 100644 index 61817027720..00000000000 --- a/changelogs/unreleased/fix-depr-warn.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: resolve deprecation warnings -merge_request: 8855 -author: Adam Pahlevi diff --git a/changelogs/unreleased/fix-gb-backwards-compatibility-coverage-ci-yml.yml b/changelogs/unreleased/fix-gb-backwards-compatibility-coverage-ci-yml.yml deleted file mode 100644 index df7e3776700..00000000000 --- a/changelogs/unreleased/fix-gb-backwards-compatibility-coverage-ci-yml.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Preserve backward compatibility CI/CD and disallow setting `coverage` regexp in global context -merge_request: 8981 -author: diff --git a/changelogs/unreleased/fix-guest-access-posting-to-notes.yml b/changelogs/unreleased/fix-guest-access-posting-to-notes.yml deleted file mode 100644 index 81377c0c6f0..00000000000 --- a/changelogs/unreleased/fix-guest-access-posting-to-notes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent users from creating notes on resources they can't access -merge_request: -author: diff --git a/changelogs/unreleased/fix-import-encrypt-atts.yml b/changelogs/unreleased/fix-import-encrypt-atts.yml deleted file mode 100644 index e34d895570b..00000000000 --- a/changelogs/unreleased/fix-import-encrypt-atts.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Ignore encrypted attributes in Import/Export -merge_request: -author: diff --git a/changelogs/unreleased/fix-import-group-members.yml b/changelogs/unreleased/fix-import-group-members.yml deleted file mode 100644 index fe580af31b3..00000000000 --- a/changelogs/unreleased/fix-import-group-members.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add ability to export project inherited group members to Import/Export -merge_request: 8923 -author: diff --git a/changelogs/unreleased/fix-job-to-pipeline-renaming.yml b/changelogs/unreleased/fix-job-to-pipeline-renaming.yml deleted file mode 100644 index d5f34b4b25d..00000000000 --- a/changelogs/unreleased/fix-job-to-pipeline-renaming.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix job to pipeline renaming -merge_request: 9147 -author: diff --git a/changelogs/unreleased/fix-references-header-parsing.yml b/changelogs/unreleased/fix-references-header-parsing.yml deleted file mode 100644 index b927279cdf4..00000000000 --- a/changelogs/unreleased/fix-references-header-parsing.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Fix reply by email without sub-addressing for some clients from - Microsoft and Apple -merge_request: 8620 -author: diff --git a/changelogs/unreleased/fix-scroll-test.yml b/changelogs/unreleased/fix-scroll-test.yml deleted file mode 100644 index e98ac755b88..00000000000 --- a/changelogs/unreleased/fix-scroll-test.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Change rspec test to guarantee window is resized before visiting page -merge_request: -author: diff --git a/changelogs/unreleased/fix-users-deleting-public-deployment-keys.yml b/changelogs/unreleased/fix-users-deleting-public-deployment-keys.yml deleted file mode 100644 index c9edd1de86c..00000000000 --- a/changelogs/unreleased/fix-users-deleting-public-deployment-keys.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Prevent users from deleting system deploy keys via the project deploy key API -merge_request: -author: diff --git a/changelogs/unreleased/fix_broken_diff_discussions.yml b/changelogs/unreleased/fix_broken_diff_discussions.yml deleted file mode 100644 index 4551212759f..00000000000 --- a/changelogs/unreleased/fix_broken_diff_discussions.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make MR-review-discussions more reliable -merge_request: -author: diff --git a/changelogs/unreleased/fix_sidekiq_concurrency_warning_message_in_admin_background_job_page.yml b/changelogs/unreleased/fix_sidekiq_concurrency_warning_message_in_admin_background_job_page.yml deleted file mode 100644 index e09d03bb608..00000000000 --- a/changelogs/unreleased/fix_sidekiq_concurrency_warning_message_in_admin_background_job_page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: fix incorrect sidekiq concurrency count in admin background page -merge_request: -author: wendy0402 diff --git a/changelogs/unreleased/fwn-to-find-by-full-path.yml b/changelogs/unreleased/fwn-to-find-by-full-path.yml deleted file mode 100644 index 1427e4e7624..00000000000 --- a/changelogs/unreleased/fwn-to-find-by-full-path.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: replace `find_with_namespace` with `find_by_full_path` -merge_request: 8949 -author: Adam Pahlevi diff --git a/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml b/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml deleted file mode 100644 index f60417d185e..00000000000 --- a/changelogs/unreleased/get-rid-of-water-from-notification_service_spec-to-make-it-DRY.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make notification_service spec DRYer by making test reusable -merge_request: -author: YarNayar diff --git a/changelogs/unreleased/git_to_html_redirection.yml b/changelogs/unreleased/git_to_html_redirection.yml deleted file mode 100644 index b2959c02c07..00000000000 --- a/changelogs/unreleased/git_to_html_redirection.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Redirect http://someproject.git to http://someproject -merge_request: -author: blackst0ne diff --git a/changelogs/unreleased/go-go-gadget-webpack.yml b/changelogs/unreleased/go-go-gadget-webpack.yml deleted file mode 100644 index 7f372ccb428..00000000000 --- a/changelogs/unreleased/go-go-gadget-webpack.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: use webpack to bundle frontend assets and use karma for frontend testing -merge_request: 7288 -author: diff --git a/changelogs/unreleased/group-label-sidebar-link.yml b/changelogs/unreleased/group-label-sidebar-link.yml deleted file mode 100644 index c11c2d4ede1..00000000000 --- a/changelogs/unreleased/group-label-sidebar-link.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed group label links in issue/merge request sidebar -merge_request: -author: diff --git a/changelogs/unreleased/hardcode-title-system-note.yml b/changelogs/unreleased/hardcode-title-system-note.yml deleted file mode 100644 index 1b0a63efa51..00000000000 --- a/changelogs/unreleased/hardcode-title-system-note.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Ensure autogenerated title does not cause failing spec -merge_request: 8963 -author: brian m. carlson diff --git a/changelogs/unreleased/improve-ci-example-php-doc.yml b/changelogs/unreleased/improve-ci-example-php-doc.yml deleted file mode 100644 index 39a85e3d261..00000000000 --- a/changelogs/unreleased/improve-ci-example-php-doc.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Changed composer installer script in the CI PHP example doc -merge_request: 4342 -author: Jeffrey Cafferata diff --git a/changelogs/unreleased/improve-handleLocationHash-tests.yml b/changelogs/unreleased/improve-handleLocationHash-tests.yml deleted file mode 100644 index 8ae3dfe079c..00000000000 --- a/changelogs/unreleased/improve-handleLocationHash-tests.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Improve gl.utils.handleLocationHash tests -merge_request: -author: diff --git a/changelogs/unreleased/issuable-sidebar-bug.yml b/changelogs/unreleased/issuable-sidebar-bug.yml deleted file mode 100644 index 4086292eb89..00000000000 --- a/changelogs/unreleased/issuable-sidebar-bug.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed Issuable sidebar not closing on smaller/mobile sized screens -merge_request: -author: diff --git a/changelogs/unreleased/issue-20428.yml b/changelogs/unreleased/issue-20428.yml deleted file mode 100644 index 60da1c14702..00000000000 --- a/changelogs/unreleased/issue-20428.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add ability to define a coverage regex in the .gitlab-ci.yml -merge_request: 7447 -author: Leandro Camargo diff --git a/changelogs/unreleased/issue-sidebar-empty-assignee.yml b/changelogs/unreleased/issue-sidebar-empty-assignee.yml deleted file mode 100644 index 263af75b9e9..00000000000 --- a/changelogs/unreleased/issue-sidebar-empty-assignee.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Resets assignee dropdown when sidebar is open -merge_request: -author: diff --git a/changelogs/unreleased/issue_19262.yml b/changelogs/unreleased/issue_19262.yml deleted file mode 100644 index 5dea1493f23..00000000000 --- a/changelogs/unreleased/issue_19262.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Disallow system notes for closed issuables -merge_request: -author: diff --git a/changelogs/unreleased/issue_23317.yml b/changelogs/unreleased/issue_23317.yml deleted file mode 100644 index 788ae159f5e..00000000000 --- a/changelogs/unreleased/issue_23317.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fix timezone on issue boards due date -merge_request: -author: diff --git a/changelogs/unreleased/issue_27211.yml b/changelogs/unreleased/issue_27211.yml deleted file mode 100644 index ad48fec5d85..00000000000 --- a/changelogs/unreleased/issue_27211.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove unused js response from refs controller -merge_request: -author: diff --git a/changelogs/unreleased/jej-pages-picked-from-ee.yml b/changelogs/unreleased/jej-pages-picked-from-ee.yml deleted file mode 100644 index ee4a43a93db..00000000000 --- a/changelogs/unreleased/jej-pages-picked-from-ee.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Added GitLab Pages to CE -merge_request: 8463 -author: diff --git a/changelogs/unreleased/label-promotion.yml b/changelogs/unreleased/label-promotion.yml deleted file mode 100644 index 2ab997bf420..00000000000 --- a/changelogs/unreleased/label-promotion.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: "Project labels can now be promoted to group labels" -merge_request: 7242 -author: Olaf Tomalka diff --git a/changelogs/unreleased/lfs-noauth-public-repo.yml b/changelogs/unreleased/lfs-noauth-public-repo.yml deleted file mode 100644 index 60f62d7691b..00000000000 --- a/changelogs/unreleased/lfs-noauth-public-repo.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Support unauthenticated LFS object downloads for public projects -merge_request: 8824 -author: Ben Boeckel diff --git a/changelogs/unreleased/markdown-plantuml.yml b/changelogs/unreleased/markdown-plantuml.yml deleted file mode 100644 index c855f0cbcf7..00000000000 --- a/changelogs/unreleased/markdown-plantuml.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: PlantUML support for Markdown -merge_request: 8588 -author: Horacio Sanson diff --git a/changelogs/unreleased/merge-request-tabs-fixture.yml b/changelogs/unreleased/merge-request-tabs-fixture.yml deleted file mode 100644 index 289cd7b604a..00000000000 --- a/changelogs/unreleased/merge-request-tabs-fixture.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Replace static fixture for merge_request_tabs_spec.js -merge_request: 9172 -author: winniehell diff --git a/changelogs/unreleased/misalinged-discussion-with-no-avatar-26854.yml b/changelogs/unreleased/misalinged-discussion-with-no-avatar-26854.yml deleted file mode 100644 index f32b3aea3c8..00000000000 --- a/changelogs/unreleased/misalinged-discussion-with-no-avatar-26854.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: adds avatar for discussion note -merge_request: 8734 -author: diff --git a/changelogs/unreleased/mr-tabs-container-offset.yml b/changelogs/unreleased/mr-tabs-container-offset.yml deleted file mode 100644 index c5df8abfcf2..00000000000 --- a/changelogs/unreleased/mr-tabs-container-offset.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed merge requests tab extra margin when fixed to window -merge_request: -author: diff --git a/changelogs/unreleased/newline-eslint-rule.yml b/changelogs/unreleased/newline-eslint-rule.yml deleted file mode 100644 index 5ce080b6912..00000000000 --- a/changelogs/unreleased/newline-eslint-rule.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Flag multiple empty lines in eslint, fix offenses. -merge_request: 8137 -author: diff --git a/changelogs/unreleased/no-sidebar-on-action-btn-click.yml b/changelogs/unreleased/no-sidebar-on-action-btn-click.yml deleted file mode 100644 index 09e0b3a12d8..00000000000 --- a/changelogs/unreleased/no-sidebar-on-action-btn-click.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: dismiss sidebar on repo buttons click -merge_request: 8798 -author: Adam Pahlevi diff --git a/changelogs/unreleased/no_project_notes.yml b/changelogs/unreleased/no_project_notes.yml deleted file mode 100644 index 6106c027360..00000000000 --- a/changelogs/unreleased/no_project_notes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Support notes when a project is not specified (personal snippet notes) -merge_request: 8468 -author: diff --git a/changelogs/unreleased/pms-lowercase-system-notes.yml b/changelogs/unreleased/pms-lowercase-system-notes.yml deleted file mode 100644 index c2fa1a7fad0..00000000000 --- a/changelogs/unreleased/pms-lowercase-system-notes.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Make all system notes lowercase -merge_request: 8807 -author: diff --git a/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml b/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml deleted file mode 100644 index 547a7c6755c..00000000000 --- a/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Redesign searchbar in admin project list -merge_request: 8776 -author: diff --git a/changelogs/unreleased/redirect-to-commit-when-only-commit-found.yml b/changelogs/unreleased/redirect-to-commit-when-only-commit-found.yml deleted file mode 100644 index e0f7e11b6d1..00000000000 --- a/changelogs/unreleased/redirect-to-commit-when-only-commit-found.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'Search feature: redirects to commit page if query is commit sha and only commit - found' -merge_request: 8028 -author: YarNayar diff --git a/changelogs/unreleased/relative-url-assets.yml b/changelogs/unreleased/relative-url-assets.yml deleted file mode 100644 index 0877664aca4..00000000000 --- a/changelogs/unreleased/relative-url-assets.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: allow relative url change without recompiling frontend assets -merge_request: 8831 -author: diff --git a/changelogs/unreleased/remove-deploy-key-endpoint.yml b/changelogs/unreleased/remove-deploy-key-endpoint.yml deleted file mode 100644 index 3ff69adb4d3..00000000000 --- a/changelogs/unreleased/remove-deploy-key-endpoint.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'API: Remove /projects/:id/keys/.. endpoints' -merge_request: 8716 -author: Robert Schilling diff --git a/changelogs/unreleased/remove-issue-and-mr-counts-from-labels-page.yml b/changelogs/unreleased/remove-issue-and-mr-counts-from-labels-page.yml deleted file mode 100644 index b75b4644ba3..00000000000 --- a/changelogs/unreleased/remove-issue-and-mr-counts-from-labels-page.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove issue and MR counts from labels index -merge_request: -author: diff --git a/changelogs/unreleased/route-map.yml b/changelogs/unreleased/route-map.yml deleted file mode 100644 index 9b6df0c54af..00000000000 --- a/changelogs/unreleased/route-map.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add 'View on [env]' link to blobs and individual files in diffs -merge_request: 8867 -author: diff --git a/changelogs/unreleased/rs-warden-blocked-users.yml b/changelogs/unreleased/rs-warden-blocked-users.yml deleted file mode 100644 index c0c23fb6f11..00000000000 --- a/changelogs/unreleased/rs-warden-blocked-users.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Don't perform Devise trackable updates on blocked User records -merge_request: 8915 -author: diff --git a/changelogs/unreleased/sh-add-index-to-ci-trigger-requests.yml b/changelogs/unreleased/sh-add-index-to-ci-trigger-requests.yml deleted file mode 100644 index bab76812a17..00000000000 --- a/changelogs/unreleased/sh-add-index-to-ci-trigger-requests.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add index to ci_trigger_requests for commit_id -merge_request: -author: diff --git a/changelogs/unreleased/sh-add-labels-index.yml b/changelogs/unreleased/sh-add-labels-index.yml deleted file mode 100644 index b948a75081c..00000000000 --- a/changelogs/unreleased/sh-add-labels-index.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Add indices to improve loading of labels page -merge_request: -author: diff --git a/changelogs/unreleased/slash-commands-typo.yml b/changelogs/unreleased/slash-commands-typo.yml deleted file mode 100644 index e6ffb94bd08..00000000000 --- a/changelogs/unreleased/slash-commands-typo.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Fixed "substract" typo on /help/user/project/slash_commands -merge_request: 8976 -author: Jason Aquino diff --git a/changelogs/unreleased/small-screen-fullscreen-button.yml b/changelogs/unreleased/small-screen-fullscreen-button.yml deleted file mode 100644 index f4c269bc473..00000000000 --- a/changelogs/unreleased/small-screen-fullscreen-button.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Display fullscreen button on small screens -merge_request: 5302 -author: winniehell diff --git a/changelogs/unreleased/snippets-search-performance.yml b/changelogs/unreleased/snippets-search-performance.yml deleted file mode 100644 index 2895478abfd..00000000000 --- a/changelogs/unreleased/snippets-search-performance.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Reduced query count for snippet search -merge_request: -author: diff --git a/changelogs/unreleased/tc-only-mr-button-if-allowed.yml b/changelogs/unreleased/tc-only-mr-button-if-allowed.yml deleted file mode 100644 index a7f5dcb560c..00000000000 --- a/changelogs/unreleased/tc-only-mr-button-if-allowed.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Only show Merge Request button when user can create a MR -merge_request: 8639 -author: diff --git a/changelogs/unreleased/terminal-max-session-time.yml b/changelogs/unreleased/terminal-max-session-time.yml deleted file mode 100644 index db1e66770d1..00000000000 --- a/changelogs/unreleased/terminal-max-session-time.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Introduce maximum session time for terminal websocket connection -merge_request: 8413 -author: diff --git a/changelogs/unreleased/updated-pages-0-3-1.yml b/changelogs/unreleased/updated-pages-0-3-1.yml deleted file mode 100644 index 8622b823c86..00000000000 --- a/changelogs/unreleased/updated-pages-0-3-1.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Update GitLab Pages to v0.3.1 -merge_request: -author: diff --git a/changelogs/unreleased/upgrade-babel-v6.yml b/changelogs/unreleased/upgrade-babel-v6.yml deleted file mode 100644 index 55f9b3e407c..00000000000 --- a/changelogs/unreleased/upgrade-babel-v6.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: upgrade babel 5.8.x to babel 6.22.x -merge_request: 9072 -author: diff --git a/changelogs/unreleased/upgrade-omniauth.yml b/changelogs/unreleased/upgrade-omniauth.yml deleted file mode 100644 index 7e0334566dc..00000000000 --- a/changelogs/unreleased/upgrade-omniauth.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Upgrade omniauth gem to 1.3.2 -merge_request: -author: diff --git a/changelogs/unreleased/upgrade-webpack-v2-2.yml b/changelogs/unreleased/upgrade-webpack-v2-2.yml deleted file mode 100644 index 6a49859d68c..00000000000 --- a/changelogs/unreleased/upgrade-webpack-v2-2.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: upgrade to webpack v2.2 -merge_request: 9078 -author: diff --git a/changelogs/unreleased/wip-mr-from-commits.yml b/changelogs/unreleased/wip-mr-from-commits.yml deleted file mode 100644 index 0083798be08..00000000000 --- a/changelogs/unreleased/wip-mr-from-commits.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Mark MR as WIP when pushing WIP commits -merge_request: 8124 -author: Jurre Stender @jurre diff --git a/changelogs/unreleased/zj-format-chat-messages.yml b/changelogs/unreleased/zj-format-chat-messages.yml deleted file mode 100644 index 2494884f5c9..00000000000 --- a/changelogs/unreleased/zj-format-chat-messages.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Reformat messages ChatOps -merge_request: 8528 -author: diff --git a/changelogs/unreleased/zj-remove-deprecated-ci-service.yml b/changelogs/unreleased/zj-remove-deprecated-ci-service.yml deleted file mode 100644 index 044f4ae627d..00000000000 --- a/changelogs/unreleased/zj-remove-deprecated-ci-service.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Remove deprecated GitlabCiService -merge_request: -author: diff --git a/changelogs/unreleased/zj-requeue-pending-delete.yml b/changelogs/unreleased/zj-requeue-pending-delete.yml deleted file mode 100644 index 464c5948f8c..00000000000 --- a/changelogs/unreleased/zj-requeue-pending-delete.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: Requeue pending deletion projects -merge_request: -author: From 12ac140a119b6802ebdfc3c596264f7fc292d4df Mon Sep 17 00:00:00 2001 From: Felipe Artur Date: Wed, 22 Feb 2017 11:36:02 -0300 Subject: [PATCH 73/76] Update VERSION to 8.18.0-pre --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 5c99c061a47..64de8316674 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -8.17.0-pre +8.18.0-pre From cf521c95761540f273804d23a1150dbb0af4e63b Mon Sep 17 00:00:00 2001 From: Yorick Peterse Date: Wed, 22 Feb 2017 15:43:01 +0100 Subject: [PATCH 74/76] Allow setting of a custom connection pool host This allows you to set a custom host when calling Gitlab::Database.create_connection_pool. This is necessary for load balancing as in this case we want to inherit all settings except for the hostname. --- lib/gitlab/database.rb | 7 ++++++- spec/lib/gitlab/database_spec.rb | 21 ++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/gitlab/database.rb b/lib/gitlab/database.rb index a47d7e98a62..d160cadc2d0 100644 --- a/lib/gitlab/database.rb +++ b/lib/gitlab/database.rb @@ -79,11 +79,16 @@ module Gitlab end end - def self.create_connection_pool(pool_size) + # pool_size - The size of the DB pool. + # host - An optional host name to use instead of the default one. + def self.create_connection_pool(pool_size, host = nil) # See activerecord-4.2.7.1/lib/active_record/connection_adapters/connection_specification.rb env = Rails.env original_config = ActiveRecord::Base.configurations + env_config = original_config[env].merge('pool' => pool_size) + env_config['host'] = host if host + config = original_config.merge(env => env_config) spec = diff --git a/spec/lib/gitlab/database_spec.rb b/spec/lib/gitlab/database_spec.rb index f01c42aff91..edd01d032c8 100644 --- a/spec/lib/gitlab/database_spec.rb +++ b/spec/lib/gitlab/database_spec.rb @@ -119,9 +119,24 @@ describe Gitlab::Database, lib: true do it 'creates a new connection pool with specific pool size' do pool = described_class.create_connection_pool(5) - expect(pool) - .to be_kind_of(ActiveRecord::ConnectionAdapters::ConnectionPool) - expect(pool.spec.config[:pool]).to eq(5) + begin + expect(pool) + .to be_kind_of(ActiveRecord::ConnectionAdapters::ConnectionPool) + + expect(pool.spec.config[:pool]).to eq(5) + ensure + pool.disconnect! + end + end + + it 'allows setting of a custom hostname' do + pool = described_class.create_connection_pool(5, '127.0.0.1') + + begin + expect(pool.spec.config[:host]).to eq('127.0.0.1') + ensure + pool.disconnect! + end end end From 9f56b57b55307fc3fa25737b89806564259354f8 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Tue, 21 Feb 2017 16:47:25 -0300 Subject: [PATCH 75/76] Present GitLab version for each V3 to V4 API change on v3_to_v4.md --- .../28458-present-gitlab-version-for-v4-changes-on-docs.yml | 4 ++++ doc/api/v3_to_v4.md | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/28458-present-gitlab-version-for-v4-changes-on-docs.yml diff --git a/changelogs/unreleased/28458-present-gitlab-version-for-v4-changes-on-docs.yml b/changelogs/unreleased/28458-present-gitlab-version-for-v4-changes-on-docs.yml new file mode 100644 index 00000000000..dbbe8a19204 --- /dev/null +++ b/changelogs/unreleased/28458-present-gitlab-version-for-v4-changes-on-docs.yml @@ -0,0 +1,4 @@ +--- +title: Present GitLab version for each V3 to V4 API change on v3_to_v4.md +merge_request: +author: diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md index 59d7f0634b2..d99a52e4dc2 100644 --- a/doc/api/v3_to_v4.md +++ b/doc/api/v3_to_v4.md @@ -4,7 +4,7 @@ Our V4 API version is currently available as *Beta*! It means that V3 will still be supported and remain unchanged for now, but be aware that the following changes are in V4: -### Changes +### 8.17 - Removed `/projects/:search` (use: `/projects?search=x`) - `iid` filter has been removed from `projects/:id/issues` @@ -12,6 +12,9 @@ changes are in V4: - Endpoints under `projects/merge_request/:id` have been removed (use: `projects/merge_requests/:id`) - Project snippets do not return deprecated field `expires_at` - Endpoints under `projects/:id/keys` have been removed (use `projects/:id/deploy_keys`) + +### 9.0 + - Status 409 returned for POST `project/:id/members` when a member already exists - Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` - Removed the following deprecated Templates endpoints (these are still accessible with `/templates` prefix) From eeb567d1b1b1988e9d3e07f1a6d7fa23ce7d06e3 Mon Sep 17 00:00:00 2001 From: Toon Claes Date: Wed, 22 Feb 2017 10:24:38 +0100 Subject: [PATCH 76/76] Add Merge Request link to the v3 to v4 documentation Similar to changelog, mention the Merge Request id & link for each change. --- doc/api/v3_to_v4.md | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md index d99a52e4dc2..1fea3d3407f 100644 --- a/doc/api/v3_to_v4.md +++ b/doc/api/v3_to_v4.md @@ -6,18 +6,18 @@ changes are in V4: ### 8.17 -- Removed `/projects/:search` (use: `/projects?search=x`) -- `iid` filter has been removed from `projects/:id/issues` -- `projects/:id/merge_requests?iid[]=x&iid[]=y` array filter has been renamed to `iids` -- Endpoints under `projects/merge_request/:id` have been removed (use: `projects/merge_requests/:id`) -- Project snippets do not return deprecated field `expires_at` -- Endpoints under `projects/:id/keys` have been removed (use `projects/:id/deploy_keys`) +- Removed `/projects/:search` (use: `/projects?search=x`) [!8877](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8877) +- `iid` filter has been removed from `projects/:id/issues` [!8967](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8967) +- `projects/:id/merge_requests?iid[]=x&iid[]=y` array filter has been renamed to `iids` [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793) +- Endpoints under `projects/merge_request/:id` have been removed (use: `projects/merge_requests/:id`) [!8793](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8793) +- Project snippets do not return deprecated field `expires_at` [!8723](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8723) +- Endpoints under `projects/:id/keys` have been removed (use `projects/:id/deploy_keys`) [!8716](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8716) ### 9.0 -- Status 409 returned for POST `project/:id/members` when a member already exists -- Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` -- Removed the following deprecated Templates endpoints (these are still accessible with `/templates` prefix) +- Status 409 returned for POST `project/:id/members` when a member already exists [!9093](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9093) +- Moved `DELETE /projects/:id/star` to `POST /projects/:id/unstar` [!9328](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9328) +- Removed the following deprecated Templates endpoints (these are still accessible with `/templates` prefix) [!8853](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8853) - `/licences` - `/licences/:key` - `/gitignores` @@ -26,17 +26,17 @@ changes are in V4: - `/gitignores/:key` - `/gitlab_ci_ymls/:key` - `/dockerfiles/:key` -- Moved `/projects/fork/:id` to `/projects/:id/fork` -- Moved `DELETE /todos` to `POST /todos/mark_as_done` and `DELETE /todos/:todo_id` to `POST /todos/:todo_id/mark_as_done` -- Endpoints `/projects/owned`, `/projects/visible`, `/projects/starred` & `/projects/all` are consolidated into `/projects` using query parameters -- Return pagination headers for all endpoints that return an array -- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead -- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)` -- Make subscription API more RESTful. Use `post ":project_id/:subscribable_type/:subscribable_id/subscribe"` to subscribe and `post ":project_id/:subscribable_type/:subscribable_id/unsubscribe"` to unsubscribe from a resource. -- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR) -- Renamed param `branch_name` to `branch` on the following endpoints +- Moved `/projects/fork/:id` to `/projects/:id/fork` [!8940](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8940) +- Moved `DELETE /todos` to `POST /todos/mark_as_done` and `DELETE /todos/:todo_id` to `POST /todos/:todo_id/mark_as_done` [!9410](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9410) +- Endpoints `/projects/owned`, `/projects/visible`, `/projects/starred` & `/projects/all` are consolidated into `/projects` using query parameters [!8962](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8962) +- Return pagination headers for all endpoints that return an array [!8606](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8606) +- Removed `DELETE projects/:id/deploy_keys/:key_id/disable`. Use `DELETE projects/:id/deploy_keys/:key_id` instead [!9366](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9366) +- Moved `PUT /users/:id/(block|unblock)` to `POST /users/:id/(block|unblock)` [!9371](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9371) +- Make subscription API more RESTful. Use `post ":project_id/:subscribable_type/:subscribable_id/subscribe"` to subscribe and `post ":project_id/:subscribable_type/:subscribable_id/unsubscribe"` to unsubscribe from a resource. [!9325](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/9325) +- Labels filter on `projects/:id/issues` and `/issues` now matches only issues containing all labels (i.e.: Logical AND, not OR) [!8849](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8849) +- Renamed param `branch_name` to `branch` on the following endpoints [!8936](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8936) - POST `:id/repository/branches` - POST `:id/repository/commits` - POST/PUT/DELETE `:id/repository/files` -- Renamed `branch_name` to `branch` on DELETE `id/repository/branches/:branch` response - +- Renamed `branch_name` to `branch` on DELETE `id/repository/branches/:branch` response [!8936](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8936) +- Remove `public` param from create and edit actions of projects [!8736](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/8736)