summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml2
-rw-r--r--CHANGELOG1
-rw-r--r--Gemfile6
-rw-r--r--app/assets/javascripts/notes.js.coffee87
-rw-r--r--app/assets/stylesheets/framework/blocks.scss6
-rw-r--r--app/assets/stylesheets/framework/panels.scss12
-rw-r--r--app/assets/stylesheets/framework/tw_bootstrap.scss13
-rw-r--r--app/assets/stylesheets/highlight/solarized_dark.scss2
-rw-r--r--app/controllers/projects/notes_controller.rb22
-rw-r--r--app/helpers/snippets_helper.rb75
-rw-r--r--app/models/issue.rb1
-rw-r--r--app/models/project.rb4
-rw-r--r--app/models/project_wiki.rb1
-rw-r--r--app/views/admin/deploy_keys/index.html.haml2
-rw-r--r--app/views/admin/projects/index.html.haml4
-rw-r--r--app/views/groups/edit.html.haml1
-rw-r--r--app/views/groups/group_members/index.html.haml3
-rw-r--r--app/views/groups/projects.html.haml4
-rw-r--r--app/views/profiles/accounts/show.html.haml1
-rw-r--r--app/views/projects/issues/show.html.haml4
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_commits.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_how_to_merge.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml2
-rw-r--r--app/views/projects/milestones/show.html.haml15
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply.html.haml2
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml5
-rw-r--r--app/views/projects/notes/_note.html.haml2
-rw-r--r--app/views/projects/notes/discussions/_commit.html.haml3
-rw-r--r--app/views/projects/project_members/_group_members.html.haml2
-rw-r--r--app/views/projects/project_members/_team.html.haml2
-rw-r--r--app/views/projects/project_members/index.html.haml3
-rw-r--r--app/views/search/results/_merge_request.html.haml2
-rw-r--r--doc/administration/housekeeping.md4
-rw-r--r--doc/ci/build_artifacts/README.md2
-rw-r--r--doc/integration/README.md2
-rw-r--r--features/project/merge_requests.feature11
-rw-r--r--features/steps/project/merge_requests.rb31
-rw-r--r--features/steps/shared/diff_note.rb12
-rw-r--r--lib/gitlab/snippet_search_results.rb82
-rwxr-xr-xscripts/ci/prepare_build.sh22
-rwxr-xr-xscripts/prepare_build.sh16
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb2
43 files changed, 260 insertions, 221 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2dc09e4a1a5..ec53271b6bc 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -9,7 +9,7 @@ variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
before_script:
- - ./scripts/prepare_build.sh
+ - source ./scripts/prepare_build.sh
- ruby -v
- which ruby
- gem install bundler --no-ri --no-rdoc
diff --git a/CHANGELOG b/CHANGELOG
index 0d3e0571b59..7af6a22f37f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -5,6 +5,7 @@ v 8.5.0 (unreleased)
- Ignore binary files in code search to prevent Error 500 (Stan Hu)
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
- New UI for pagination
+ - Fix diff comments loaded by AJAX to load comment with diff in discussion tab
v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server
diff --git a/Gemfile b/Gemfile
index 746d8e5d6de..8e727d950bf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -212,6 +212,9 @@ gem 'select2-rails', '~> 3.5.9'
gem 'virtus', '~> 1.0.1'
gem 'net-ssh', '~> 3.0.1'
+# Sentry integration
+gem 'sentry-raven'
+
# Metrics
group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri
@@ -293,9 +296,6 @@ end
group :production do
gem "gitlab_meta", '7.0'
-
- # Sentry integration
- gem 'sentry-raven'
end
gem "newrelic_rpm", '~> 3.9.4.245'
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index 2bfc5cb2d9c..53d72be66e3 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -15,6 +15,8 @@ class @Notes
@last_fetched_at = last_fetched_at
@view = view
@noteable_url = document.URL
+ @notesCountBadge ||= $(".issuable-details").find(".notes-tab .badge")
+
@initRefresh()
@setupMainTargetNoteForm()
@cleanBinding()
@@ -89,7 +91,7 @@ class @Notes
, 15000
refresh: ->
- unless document.hidden or (@noteable_url != document.URL)
+ if not document.hidden and document.URL.indexOf(@noteable_url) is 0
@getContent()
getContent: ->
@@ -101,7 +103,10 @@ class @Notes
notes = data.notes
@last_fetched_at = data.last_fetched_at
$.each notes, (i, note) =>
- @renderNote(note)
+ if note.discussion_with_diff_html?
+ @renderDiscussionNote(note)
+ else
+ @renderNote(note)
###
@@ -116,18 +121,21 @@ class @Notes
flash.pinTo('.header-content')
return
+ if note.award
+ awards_handler.addAwardToEmojiBar(note.note)
+ awards_handler.scrollToAwards()
+
# render note if it not present in loaded list
# or skip if rendered
- if @isNewNote(note) && !note.award
+ else if @isNewNote(note)
@note_ids.push(note.id)
- $('ul.main-notes-list').
- append(note.html).
- syntaxHighlight()
+
+ $('ul.main-notes-list')
+ .append(note.html)
+ .syntaxHighlight()
@initTaskList()
+ @updateNotesCount(1)
- if note.award
- awards_handler.addAwardToEmojiBar(note.note)
- awards_handler.scrollToAwards()
###
Check if note does not exists on page
@@ -144,34 +152,39 @@ class @Notes
Note: for rendering inline notes use renderDiscussionNote
###
renderDiscussionNote: (note) ->
+ return unless @isNewNote(note)
+
@note_ids.push(note.id)
- form = $("form[rel='" + note.discussion_id + "']")
+ form = $("#new-discussion-note-form-#{note.discussion_id}")
row = form.closest("tr")
note_html = $(note.html)
note_html.syntaxHighlight()
# is this the first note of discussion?
- if row.is(".js-temp-notes-holder")
+ discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
+ if discussionContainer.length is 0
# insert the note and the reply button after the temp row
row.after note.discussion_html
# remove the note (will be added again below)
row.next().find(".note").remove()
+ # Before that, the container didn't exist
+ discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']")
+
# Add note to 'Changes' page discussions
- $(".notes[rel='" + note.discussion_id + "']").append note_html
+ discussionContainer.append note_html
# Init discussion on 'Discussion' page if it is merge request page
- if $('body').attr('data-page').indexOf('projects:merge_request') == 0
- discussion_html = $(note.discussion_with_diff_html)
- discussion_html.syntaxHighlight()
- $('ul.main-notes-list').append(discussion_html)
+ if $('body').attr('data-page').indexOf('projects:merge_request') is 0
+ $('ul.main-notes-list')
+ .append(note.discussion_with_diff_html)
+ .syntaxHighlight()
else
# append new note to all matching discussions
- $(".notes[rel='" + note.discussion_id + "']").append note_html
+ discussionContainer.append note_html
- # cleanup after successfully creating a diff/discussion note
- @removeDiscussionNoteForm(form)
+ @updateNotesCount(1)
###
Called in response the main target form has been successfully submitted.
@@ -278,6 +291,9 @@ class @Notes
addDiscussionNote: (xhr, note, status) =>
@renderDiscussionNote(note)
+ # cleanup after successfully creating a diff/discussion note
+ @removeDiscussionNoteForm($("#new-discussion-note-form-#{note.discussion_id}"))
+
###
Called in response to the edit note form being submitted
@@ -349,30 +365,32 @@ class @Notes
Removes the actual note from view.
Removes the whole discussion if the last note is being removed.
###
- removeNote: ->
- note = $(this).closest(".note")
- note_id = note.attr('id')
+ removeNote: (e) =>
+ noteId = $(e.currentTarget)
+ .closest(".note")
+ .attr("id")
- $('.note[id="' + note_id + '"]').each ->
- note = $(this)
+ # A same note appears in the "Discussion" and in the "Changes" tab, we have
+ # to remove all. Using $(".note[id='noteId']") ensure we get all the notes,
+ # where $("#noteId") would return only one.
+ $(".note[id='#{noteId}']").each (i, el) =>
+ note = $(el)
notes = note.closest(".notes")
- count = notes.closest(".issuable-details").find(".notes-tab .badge")
# check if this is the last note for this line
if notes.find(".note").length is 1
- # for discussions
- notes.closest(".discussion").remove()
+ # "Discussions" tab
+ notes.closest(".timeline-entry").remove()
- # for diff lines
+ # "Changes" tab / commit view
notes.closest("tr").remove()
- # update notes count
- oldNum = parseInt(count.text())
- count.text(oldNum - 1)
-
note.remove()
+ # Decrement the "Discussions" counter only once
+ @updateNotesCount(-1)
+
###
Called in response to clicking the delete attachment link
@@ -412,7 +430,7 @@ class @Notes
###
setupDiscussionNoteForm: (dataHolder, form) =>
# setup note target
- form.attr "rel", dataHolder.data("discussionId")
+ form.attr 'id', "new-discussion-note-form-#{dataHolder.data("discussionId")}"
form.find("#line_type").val dataHolder.data("lineType")
form.find("#note_commit_id").val dataHolder.data("commitId")
form.find("#note_line_code").val dataHolder.data("lineCode")
@@ -542,3 +560,6 @@ class @Notes
updateTaskList: ->
$('form', this).submit()
+
+ updateNotesCount: (updateCount) ->
+ @notesCountBadge.text(parseInt(@notesCountBadge.text()) + updateCount)
diff --git a/app/assets/stylesheets/framework/blocks.scss b/app/assets/stylesheets/framework/blocks.scss
index d0f5d33bf4d..bd89cc7dc1d 100644
--- a/app/assets/stylesheets/framework/blocks.scss
+++ b/app/assets/stylesheets/framework/blocks.scss
@@ -146,6 +146,10 @@
border-bottom: 1px solid $border-color;
&.oneline-block {
- line-height: 42px;
+ line-height: 36px;
+ }
+
+ > .controls {
+ float: right;
}
}
diff --git a/app/assets/stylesheets/framework/panels.scss b/app/assets/stylesheets/framework/panels.scss
index 57b9451b264..ae7bdf14c40 100644
--- a/app/assets/stylesheets/framework/panels.scss
+++ b/app/assets/stylesheets/framework/panels.scss
@@ -2,7 +2,13 @@
margin-bottom: $gl-padding;
.panel-heading {
- padding: 7px $gl-padding;
+ padding: $gl-vert-padding $gl-padding;
+ line-height: 36px;
+
+ .controls {
+ margin-top: -2px;
+ float: right;
+ }
}
.panel-body {
@@ -14,7 +20,3 @@
}
}
}
-
-.container-blank .panel .panel-heading {
- line-height: 42px !important;
-}
diff --git a/app/assets/stylesheets/framework/tw_bootstrap.scss b/app/assets/stylesheets/framework/tw_bootstrap.scss
index 88072606bf5..3e709244879 100644
--- a/app/assets/stylesheets/framework/tw_bootstrap.scss
+++ b/app/assets/stylesheets/framework/tw_bootstrap.scss
@@ -114,22 +114,9 @@
*
*/
-.container-blank .panel .panel-heading {
- font-size: 17px;
- line-height: 38px;
-}
-
.panel {
box-shadow: none;
- .panel-heading {
- .panel-head-actions {
- position: relative;
- top: -5px;
- float: right;
- }
- }
-
.panel-body {
form, pre {
margin: 0;
diff --git a/app/assets/stylesheets/highlight/solarized_dark.scss b/app/assets/stylesheets/highlight/solarized_dark.scss
index ae7ecc65c39..b0aaadd0f7f 100644
--- a/app/assets/stylesheets/highlight/solarized_dark.scss
+++ b/app/assets/stylesheets/highlight/solarized_dark.scss
@@ -26,7 +26,7 @@
}
.diff-line-num.old, .line_content.old {
- @include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #808080);
+ @include diff_background(rgba(220, 50, 47, 0.3), rgba(220, 50, 47, 0.3), #808080);
}
.line_content.match {
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 6f1e186d408..4a2599dda37 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -11,11 +11,9 @@ class Projects::NotesController < Projects::ApplicationController
notes_json = { notes: [], last_fetched_at: current_fetched_at }
@notes.each do |note|
- notes_json[:notes] << {
- id: note.id,
- html: note_to_html(note),
- valid: note.valid?
- }
+ next if note.cross_reference_not_visible_for?(current_user)
+
+ notes_json[:notes] << note_json(note)
end
render json: notes_json
@@ -25,7 +23,7 @@ class Projects::NotesController < Projects::ApplicationController
@note = Notes::CreateService.new(project, current_user, note_params).execute
respond_to do |format|
- format.json { render_note_json(@note) }
+ format.json { render json: note_json(@note) }
format.html { redirect_back_or_default }
end
end
@@ -34,7 +32,7 @@ class Projects::NotesController < Projects::ApplicationController
@note = Notes::UpdateService.new(project, current_user, note_params).execute(note)
respond_to do |format|
- format.json { render_note_json(@note) }
+ format.json { render json: note_json(@note) }
format.html { redirect_back_or_default }
end
end
@@ -99,6 +97,8 @@ class Projects::NotesController < Projects::ApplicationController
end
def note_to_discussion_html(note)
+ return unless note.for_diff_line?
+
if params[:view] == 'parallel'
template = "projects/notes/_diff_notes_with_reply_parallel"
locals =
@@ -131,9 +131,9 @@ class Projects::NotesController < Projects::ApplicationController
)
end
- def render_note_json(note)
+ def note_json(note)
if note.valid?
- render json: {
+ {
valid: true,
id: note.id,
discussion_id: note.discussion_id,
@@ -144,7 +144,7 @@ class Projects::NotesController < Projects::ApplicationController
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
}
else
- render json: {
+ {
valid: false,
award: note.is_award,
errors: note.errors
@@ -163,8 +163,6 @@ class Projects::NotesController < Projects::ApplicationController
)
end
- private
-
def find_current_user_notes
@notes = NotesFinder.new.execute(project, current_user, params)
end
diff --git a/app/helpers/snippets_helper.rb b/app/helpers/snippets_helper.rb
index 906cb12cd48..bc36434f549 100644
--- a/app/helpers/snippets_helper.rb
+++ b/app/helpers/snippets_helper.rb
@@ -17,4 +17,79 @@ module SnippetsHelper
snippet_path(snippet)
end
end
+
+ # Get an array of line numbers surrounding a matching
+ # line, bounded by min/max.
+ #
+ # @returns Array of line numbers
+ def bounded_line_numbers(line, min, max, surrounding_lines)
+ lower = line - surrounding_lines > min ? line - surrounding_lines : min
+ upper = line + surrounding_lines < max ? line + surrounding_lines : max
+ (lower..upper).to_a
+ end
+
+ # Returns a sorted set of lines to be included in a snippet preview.
+ # This ensures matching adjacent lines do not display duplicated
+ # surrounding code.
+ #
+ # @returns Array, unique and sorted.
+ def matching_lines(lined_content, surrounding_lines)
+ used_lines = []
+ lined_content.each_with_index do |line, line_number|
+ used_lines.concat bounded_line_numbers(
+ line_number,
+ 0,
+ lined_content.size,
+ surrounding_lines
+ ) if line.include?(query)
+ end
+
+ used_lines.uniq.sort
+ end
+
+ # 'Chunkify' entire snippet. Splits the snippet data into matching lines +
+ # surrounding_lines() worth of unmatching lines.
+ #
+ # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
+ def chunk_snippet(snippet, surrounding_lines = 3)
+ lined_content = snippet.content.split("\n")
+ used_lines = matching_lines(lined_content, surrounding_lines)
+
+ snippet_chunk = []
+ snippet_chunks = []
+ snippet_start_line = 0
+ last_line = -1
+
+ # Go through each used line, and add consecutive lines as a single chunk
+ # to the snippet chunk array.
+ used_lines.each do |line_number|
+ if last_line < 0
+ # Start a new chunk.
+ snippet_start_line = line_number
+ snippet_chunk << lined_content[line_number]
+ elsif last_line == line_number - 1
+ # Consecutive line, continue chunk.
+ snippet_chunk << lined_content[line_number]
+ else
+ # Non-consecutive line, add chunk to chunk array.
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Start a new chunk.
+ snippet_chunk = [lined_content[line_number]]
+ snippet_start_line = line_number
+ end
+ last_line = line_number
+ end
+ # Add final chunk to chunk array
+ snippet_chunks << {
+ data: snippet_chunk.join("\n"),
+ start_line: snippet_start_line + 1
+ }
+
+ # Return snippet with chunk array
+ { snippet_object: snippet, snippet_chunks: snippet_chunks }
+ end
end
diff --git a/app/models/issue.rb b/app/models/issue.rb
index 7beba984608..5f58c0508fd 100644
--- a/app/models/issue.rb
+++ b/app/models/issue.rb
@@ -38,6 +38,7 @@ class Issue < ActiveRecord::Base
scope :cared, ->(user) { where(assignee_id: user) }
scope :open_for, ->(user) { opened.assigned_to(user) }
+ scope :in_projects, ->(project_ids) { where(project_id: project_ids) }
state_machine :state, initial: :opened do
event :close do
diff --git a/app/models/project.rb b/app/models/project.rb
index 5579710a476..4bd51449c25 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -904,4 +904,8 @@ class Project < ActiveRecord::Base
def runners_token
ensure_runners_token!
end
+
+ def wiki
+ @wiki ||= ProjectWiki.new(self, self.owner)
+ end
end
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 8ce47495971..c847eba8d1c 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -12,6 +12,7 @@ class ProjectWiki
# Returns a string describing what went wrong after
# an operation fails.
attr_reader :error_message
+ attr_reader :project
def initialize(project, user = nil)
@project = project
diff --git a/app/views/admin/deploy_keys/index.html.haml b/app/views/admin/deploy_keys/index.html.haml
index 841e6971fb2..41c43899978 100644
--- a/app/views/admin/deploy_keys/index.html.haml
+++ b/app/views/admin/deploy_keys/index.html.haml
@@ -2,7 +2,7 @@
.panel.panel-default
.panel-heading
Public deploy keys (#{@deploy_keys.count})
- .panel-head-actions
+ .controls
= link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
- if @deploy_keys.any?
.table-holder
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index d9b481404f7..b96ad6e2208 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -1,7 +1,7 @@
- page_title "Projects"
= render 'shared/show_aside'
-.row
+.row.prepend-top-default
%aside.col-md-3
.admin-filter
= form_tag admin_namespaces_projects_path, method: :get, class: '' do
@@ -47,7 +47,7 @@
.panel.panel-default
.panel-heading
Projects (#{@projects.total_count})
- .panel-head-actions
+ .controls
.dropdown.inline
%button.dropdown-toggle.btn.btn-sm{type: 'button', 'data-toggle' => 'dropdown'}
%span.light sort:
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index e2f97fd9337..3430f56a9c9 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -1,5 +1,4 @@
- header_title group_title(@group, "Settings", edit_group_path(@group))
-- @blank_container = true
.panel.panel-default.prepend-top-default
.panel-heading
diff --git a/app/views/groups/group_members/index.html.haml b/app/views/groups/group_members/index.html.haml
index 6a8acc42af9..6b7fd5746d6 100644
--- a/app/views/groups/group_members/index.html.haml
+++ b/app/views/groups/group_members/index.html.haml
@@ -1,6 +1,5 @@
- page_title "Members"
- header_title group_title(@group, "Members", group_group_members_path(@group))
-- @blank_container = true
.group-members-page.prepend-top-default
- if current_user && current_user.can?(:admin_group_member, @group)
@@ -20,7 +19,7 @@
group members
%small
(#{@members.total_count})
- .pull-right
+ .controls
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false }
diff --git a/app/views/groups/projects.html.haml b/app/views/groups/projects.html.haml
index 9ca11ed1177..dd75766121e 100644
--- a/app/views/groups/projects.html.haml
+++ b/app/views/groups/projects.html.haml
@@ -6,9 +6,9 @@
%strong= @group.name
projects:
- if can? current_user, :admin_group, @group
- .panel-head-actions
+ .controls
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-sm btn-success" do
- %i.fa.fa-plus
+ = icon('plus')
New Project
%ul.well-list
- @projects.each do |project|
diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml
index a42fd38de3a..52bfc595fda 100644
--- a/app/views/profiles/accounts/show.html.haml
+++ b/app/views/profiles/accounts/show.html.haml
@@ -1,6 +1,5 @@
- page_title "Account"
- header_title page_title, profile_account_path
-- @blank_container = true
- if current_user.ldap_user?
.alert.alert-info
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 7ed898ce72f..51dcca7a1ab 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -35,7 +35,7 @@
Edit
.issue-details.issuable-details
- .detail-page-description.gray-content-block.second-block
+ .detail-page-description.content-block
%h2.title
= markdown escape_once(@issue.title), pipeline: :single_line
%div
@@ -50,7 +50,7 @@
.merge-requests
= render 'merge_requests'
- .gray-content-block.second-block.oneline-block
+ .content-block
= render 'votes/votes_block', votable: @issue
.row
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 200bfa5ac4f..8641c3d8b4b 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -66,7 +66,7 @@
.tab-content
#notes.notes.tab-pane.voting_notes
- .gray-content-block.second-block.oneline-block
+ .content-block.oneline-block
= render 'votes/votes_block', votable: @merge_request
.row
diff --git a/app/views/projects/merge_requests/show/_commits.html.haml b/app/views/projects/merge_requests/show/_commits.html.haml
index 7f904ec42a0..a8f09f855d4 100644
--- a/app/views/projects/merge_requests/show/_commits.html.haml
+++ b/app/views/projects/merge_requests/show/_commits.html.haml
@@ -1,4 +1,4 @@
-.gray-content-block.middle-block.oneline-block
+.content-block.oneline-block
= icon("sort-amount-desc")
Most recent commits displayed first
diff --git a/app/views/projects/merge_requests/show/_how_to_merge.html.haml b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
index 877cc3d744b..0dbd159298e 100644
--- a/app/views/projects/merge_requests/show/_how_to_merge.html.haml
+++ b/app/views/projects/merge_requests/show/_how_to_merge.html.haml
@@ -45,6 +45,10 @@
- unless @merge_request.can_be_merged_by?(current_user)
%p
Note that pushing to GitLab requires write access to this repository.
+ %p
+ %strong Tip:
+ You can also checkout merge requests locally by
+ %a{href: 'https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/workflow/merge_requests.md#checkout-merge-requests-locally', target: '_blank'} following these guidelines
:javascript
$(function(){
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 0f81e5e8914..905823f79d9 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,4 +1,4 @@
-.detail-page-description.gray-content-block.second-block
+.detail-page-description.content-block
%h2.title
= markdown escape_once(@merge_request.title), pipeline: :single_line
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 1142c584592..528a4f9552f 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -32,7 +32,7 @@
= icon('pencil-square-o')
Edit
-.detail-page-description.gray-content-block.second-block
+.detail-page-description.content-block
%h2.title
= markdown escape_once(@milestone.title), pipeline: :single_line
%div
@@ -73,8 +73,8 @@
.tab-content
.tab-pane.active#tab-issues
- .gray-content-block.middle-block
- .pull-right
+ .content-block.oneline-block
+ .controls
- if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
%i.fa.fa-plus
@@ -94,8 +94,8 @@
= render('issues', title: 'Completed Issues (closed)', issues: @issues.closed, id: 'closed')
.tab-pane#tab-merge-requests
- .gray-content-block.middle-block
- .pull-right
+ .content-block.oneline-block
+ .controls
- if can?(current_user, :read_merge_request, @project)
= link_to 'Browse Merge Requests', namespace_project_merge_requests_path(@milestone.project.namespace, @milestone.project, milestone_title: @milestone.title), class: "btn btn-grouped"
@@ -117,9 +117,8 @@
= render 'merge_request', merge_request: merge_request
.tab-pane#tab-participants
- .gray-content-block.middle-block
- .oneline
- All participants to this milestone
+ .content-block.oneline-block
+ All participants to this milestone
%ul.bordered-list
- @users.each do |user|
diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml
index c731baf0a65..11f9859a90f 100644
--- a/app/views/projects/notes/_diff_notes_with_reply.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply.html.haml
@@ -7,7 +7,7 @@
%i.fa.fa-comment
= notes.count
%td.notes_content
- %ul.notes{ rel: note.discussion_id }
+ %ul.notes{ data: { discussion_id: note.discussion_id } }
= render notes
.discussion-reply-holder
= link_to_reply_diff(note)
diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
index c6726cbafa3..bb761ed2f94 100644
--- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
@@ -8,7 +8,7 @@
%i.fa.fa-comment
= notes_left.count
%td.notes_content.parallel.old
- %ul.notes{ rel: note1.discussion_id }
+ %ul.notes{ data: { discussion_id: note1.discussion_id } }
= render notes_left
.discussion-reply-holder
@@ -23,7 +23,7 @@
%i.fa.fa-comment
= notes_right.count
%td.notes_content.parallel.new
- %ul.notes{ rel: note2.discussion_id }
+ %ul.notes{ data: { discussion_id: note2.discussion_id } }
= render notes_right
.discussion-reply-holder
@@ -31,4 +31,3 @@
- else
%td.notes_line.new= ""
%td.notes_content.parallel.new= ""
-
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 922535e5c4a..e858c412836 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -1,4 +1,4 @@
-%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)], data: { discussion: note.discussion_id } }
+%li.timeline-entry{ id: dom_id(note), class: [dom_class(note), "note-row-#{note.id}", ('system-note' if note.system)] }
.timeline-entry-inner
.timeline-icon
%a{href: user_path(note.author)}
diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml
index 6903fad4a0a..3da2f2060b8 100644
--- a/app/views/projects/notes/discussions/_commit.html.haml
+++ b/app/views/projects/notes/discussions/_commit.html.haml
@@ -20,8 +20,7 @@
= render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
- else
.panel.panel-default
- .notes{ rel: discussion_notes.first.discussion_id }
+ .notes{ data: { discussion_id: discussion_notes.first.discussion_id } }
= render discussion_notes
.discussion-reply-holder
= link_to_reply_diff(discussion_notes.first)
-
diff --git a/app/views/projects/project_members/_group_members.html.haml b/app/views/projects/project_members/_group_members.html.haml
index 1c2458fa144..c53033e367c 100644
--- a/app/views/projects/project_members/_group_members.html.haml
+++ b/app/views/projects/project_members/_group_members.html.haml
@@ -5,7 +5,7 @@
%small
(#{members.count})
- if can?(current_user, :admin_group_member, @group)
- .pull-right
+ .controls
= link_to group_group_members_path(@group), class: 'btn' do
= icon('pencil-square-o')
Manage group members
diff --git a/app/views/projects/project_members/_team.html.haml b/app/views/projects/project_members/_team.html.haml
index ccddab13aaf..e8dce30425f 100644
--- a/app/views/projects/project_members/_team.html.haml
+++ b/app/views/projects/project_members/_team.html.haml
@@ -4,7 +4,7 @@
project members
%small
(#{members.count})
- .pull-right
+ .controls
= form_tag namespace_project_project_members_path(@project.namespace, @project), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing member by name', class: 'form-control', spellcheck: false }
diff --git a/app/views/projects/project_members/index.html.haml b/app/views/projects/project_members/index.html.haml
index 6239a148905..0f8848a5cbe 100644
--- a/app/views/projects/project_members/index.html.haml
+++ b/app/views/projects/project_members/index.html.haml
@@ -1,13 +1,12 @@
- page_title "Members"
= render "header_title"
-- @blank_container = true
.project-members-page.prepend-top-default
- if can?(current_user, :admin_project_member, @project)
.panel.panel-default
.panel-heading
Add new user to project
- .pull-right
+ .controls
= link_to import_namespace_project_project_members_path(@project.namespace, @project), class: "btn btn-grouped", title: "Import members from another project" do
Import members
.panel-body
diff --git a/app/views/search/results/_merge_request.html.haml b/app/views/search/results/_merge_request.html.haml
index 2efa616d664..faeb2b55c6f 100644
--- a/app/views/search/results/_merge_request.html.haml
+++ b/app/views/search/results/_merge_request.html.haml
@@ -6,7 +6,7 @@
- if merge_request.description.present?
.description.term
= preserve do
- = search_md_sanitize(markdown(merge_request.description))
+ = search_md_sanitize(markdown(merge_request.description, { project: merge_request.project }))
%span.light
#{merge_request.project.name_with_namespace}
.pull-right
diff --git a/doc/administration/housekeeping.md b/doc/administration/housekeeping.md
index c27cf1812dc..a5fa7d358a2 100644
--- a/doc/administration/housekeeping.md
+++ b/doc/administration/housekeeping.md
@@ -4,8 +4,8 @@ _**Note:** This feature was [introduced][ce-2371] in GitLab 8.4_
---
-The housekeeping function runs [`git gc`][man] on the current project Git
-repository.
+The housekeeping function runs `git gc` ([man page][man]) on the current
+project Git repository.
`git gc` runs a number of housekeeping tasks, such as compressing file
revisions (to reduce disk space and increase performance) and removing
diff --git a/doc/ci/build_artifacts/README.md b/doc/ci/build_artifacts/README.md
index 61418cef2c6..b112beef7b0 100644
--- a/doc/ci/build_artifacts/README.md
+++ b/doc/ci/build_artifacts/README.md
@@ -152,7 +152,7 @@ inside GitLab that make that possible.
1. While inside a specific build, you are presented with a download button
along with the one that browses the archive
-1. And finally, when browsing and archive you can see the download button at
+1. And finally, when browsing an archive you can see the download button at
the top right corner
---
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 5edac746c7b..846526f4e80 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -8,7 +8,7 @@ See the documentation below for details on how to configure these services.
- [Jira](jira.md) Integrate with the JIRA issue tracker
- [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
- [LDAP](ldap.md) Set up sign in via LDAP
-- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab, and Google via OAuth.
+- [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, GitLab.com, Google, Bitbucket, Facebook, Shibboleth, SAML, Crowd and Azure
- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
- [CAS](cas.md) Configure GitLab to sign in using CAS
- [Slack](slack.md) Integrate with the Slack chat service
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index f1629a26f10..4f780aa680f 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -102,6 +102,15 @@ Feature: Project Merge Requests
And I leave a comment like "Line is wrong" on diff
And I switch to the merge request's comments tab
Then I should see a discussion has started on diff
+ And I should see a badge of "1" next to the discussion link
+
+ @javascript
+ Scenario: I see a new comment on merge request diff from another user in the discussion tab
+ Given project "Shop" have "Bug NS-05" open merge request with diffs inside
+ And I visit merge request page "Bug NS-05"
+ And user "John Doe" leaves a comment like "Line is wrong" on diff
+ Then I should see a discussion by user "John Doe" has started on diff
+ And I should see a badge of "1" next to the discussion link
@javascript
Scenario: I edit a comment on a merge request diff
@@ -119,9 +128,11 @@ Feature: Project Merge Requests
And I visit merge request page "Bug NS-05"
And I click on the Changes tab
And I leave a comment like "Line is wrong" on diff
+ And I should see a badge of "1" next to the discussion link
And I delete the comment "Line is wrong" on diff
And I click on the Discussion tab
Then I should not see any discussion
+ And I should see a badge of "0" next to the discussion link
@javascript
Scenario: I comment on a line of a commit in merge request
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index 8af635689e0..337893e6209 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -181,6 +181,15 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
leave_comment "Line is wrong"
end
+ step 'user "John Doe" leaves a comment like "Line is wrong" on diff' do
+ mr = MergeRequest.find_by(title: "Bug NS-05")
+ create(:note_on_merge_request_diff, project: project,
+ noteable_id: mr.id,
+ author: user_exists("John Doe"),
+ line_code: sample_commit.line_code,
+ note: 'Line is wrong')
+ end
+
step 'I leave a comment like "Line is wrong" on diff in commit' do
click_diff_line(sample_commit.line_code)
leave_comment "Line is wrong"
@@ -238,6 +247,22 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
end
+ step 'I should see a discussion by user "John Doe" has started on diff' do
+ page.within(".notes .discussion") do
+ page.should have_content "#{user_exists("John Doe").name} started a discussion"
+ page.should have_content sample_commit.line_code_path
+ page.should have_content "Line is wrong"
+ end
+ end
+
+ step 'I should see a badge of "1" next to the discussion link' do
+ expect_discussion_badge_to_have_counter("1")
+ end
+
+ step 'I should see a badge of "0" next to the discussion link' do
+ expect_discussion_badge_to_have_counter("0")
+ end
+
step 'I should see a discussion has started on commit diff' do
page.within(".notes .discussion") do
page.should have_content "#{current_user.name} started a discussion on commit"
@@ -452,4 +477,10 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
def have_visible_content (text)
have_css("*", text: text, visible: true)
end
+
+ def expect_discussion_badge_to_have_counter(value)
+ page.within(".notes-tab .badge") do
+ page.should have_content value
+ end
+ end
end
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index c6a0ae2ba38..06e69441894 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -23,7 +23,7 @@ module SharedDiffNote
page.within(diff_file_selector) do
click_diff_line(sample_commit.line_code)
- page.within("form[rel$='#{sample_commit.line_code}']") do
+ page.within("form[id$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "Typo, please fix"
find(".js-comment-button").trigger("click")
sleep 0.05
@@ -33,7 +33,7 @@ module SharedDiffNote
step 'I leave a diff comment in a parallel view on the left side like "Old comment"' do
click_parallel_diff_line(sample_commit.line_code, 'old')
- page.within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
+ page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "Old comment"
find(".js-comment-button").trigger("click")
end
@@ -41,7 +41,7 @@ module SharedDiffNote
step 'I leave a diff comment in a parallel view on the right side like "New comment"' do
click_parallel_diff_line(sample_commit.line_code, 'new')
- page.within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
+ page.within("#{diff_file_selector} form[id$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "New comment"
find(".js-comment-button").trigger("click")
end
@@ -51,7 +51,7 @@ module SharedDiffNote
page.within(diff_file_selector) do
click_diff_line(sample_commit.line_code)
- page.within("form[rel$='#{sample_commit.line_code}']") do
+ page.within("form[id$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "Should fix it :smile:"
find('.js-md-preview-button').click
end
@@ -62,7 +62,7 @@ module SharedDiffNote
page.within(diff_file_selector) do
click_diff_line(sample_commit.del_line_code)
- page.within("form[rel$='#{sample_commit.del_line_code}']") do
+ page.within("form[id$='#{sample_commit.del_line_code}']") do
fill_in "note[note]", with: "DRY this up"
find('.js-md-preview-button').click
end
@@ -91,7 +91,7 @@ module SharedDiffNote
page.within(diff_file_selector) do
click_diff_line(sample_commit.line_code)
- page.within("form[rel$='#{sample_commit.line_code}']") do
+ page.within("form[id$='#{sample_commit.line_code}']") do
fill_in 'note[note]', with: ':smile:'
click_button('Add Comment')
end
diff --git a/lib/gitlab/snippet_search_results.rb b/lib/gitlab/snippet_search_results.rb
index 938219efdb2..38364a0b151 100644
--- a/lib/gitlab/snippet_search_results.rb
+++ b/lib/gitlab/snippet_search_results.rb
@@ -1,5 +1,7 @@
module Gitlab
class SnippetSearchResults < SearchResults
+ include SnippetsHelper
+
attr_reader :limit_snippet_ids
def initialize(limit_snippet_ids, query)
@@ -47,85 +49,5 @@ module Gitlab
def default_scope
'snippet_blobs'
end
-
- # Get an array of line numbers surrounding a matching
- # line, bounded by min/max.
- #
- # @returns Array of line numbers
- def bounded_line_numbers(line, min, max)
- lower = line - surrounding_lines > min ? line - surrounding_lines : min
- upper = line + surrounding_lines < max ? line + surrounding_lines : max
- (lower..upper).to_a
- end
-
- # Returns a sorted set of lines to be included in a snippet preview.
- # This ensures matching adjacent lines do not display duplicated
- # surrounding code.
- #
- # @returns Array, unique and sorted.
- def matching_lines(lined_content)
- used_lines = []
- lined_content.each_with_index do |line, line_number|
- used_lines.concat bounded_line_numbers(
- line_number,
- 0,
- lined_content.size
- ) if line.include?(query)
- end
-
- used_lines.uniq.sort
- end
-
- # 'Chunkify' entire snippet. Splits the snippet data into matching lines +
- # surrounding_lines() worth of unmatching lines.
- #
- # @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
- def chunk_snippet(snippet)
- lined_content = snippet.content.split("\n")
- used_lines = matching_lines(lined_content)
-
- snippet_chunk = []
- snippet_chunks = []
- snippet_start_line = 0
- last_line = -1
-
- # Go through each used line, and add consecutive lines as a single chunk
- # to the snippet chunk array.
- used_lines.each do |line_number|
- if last_line < 0
- # Start a new chunk.
- snippet_start_line = line_number
- snippet_chunk << lined_content[line_number]
- elsif last_line == line_number - 1
- # Consecutive line, continue chunk.
- snippet_chunk << lined_content[line_number]
- else
- # Non-consecutive line, add chunk to chunk array.
- snippet_chunks << {
- data: snippet_chunk.join("\n"),
- start_line: snippet_start_line + 1
- }
-
- # Start a new chunk.
- snippet_chunk = [lined_content[line_number]]
- snippet_start_line = line_number
- end
- last_line = line_number
- end
- # Add final chunk to chunk array
- snippet_chunks << {
- data: snippet_chunk.join("\n"),
- start_line: snippet_start_line + 1
- }
-
- # Return snippet with chunk array
- { snippet_object: snippet, snippet_chunks: snippet_chunks }
- end
-
- # Defines how many unmatching lines should be
- # included around the matching lines in a snippet
- def surrounding_lines
- 3
- end
end
end
diff --git a/scripts/ci/prepare_build.sh b/scripts/ci/prepare_build.sh
deleted file mode 100755
index 864a683a1bd..00000000000
--- a/scripts/ci/prepare_build.sh
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/bash
-if [ -f /.dockerinit ]; then
- export FLAGS=(--deployment --path /cache)
-
- apt-get update -qq
- apt-get install -y -qq nodejs
-
- wget -q http://ftp.de.debian.org/debian/pool/main/p/phantomjs/phantomjs_1.9.0-1+b1_amd64.deb
- dpkg -i phantomjs_1.9.0-1+b1_amd64.deb
-
- cp config/database.yml.mysql config/database.yml
- sed -i "s/username:.*/username: root/g" config/database.yml
- sed -i "s/password:.*/password:/g" config/database.yml
- sed -i "s/# socket:.*/host: mysql/g" config/database.yml
-else
- export PATH=$HOME/bin:/usr/local/bin:/usr/bin:/bin
-
- cp config/database.yml.mysql config/database.yml
- sed -i "s/username\:.*$/username\: runner/" config/database.yml
- sed -i "s/password\:.*$/password\: 'password'/" config/database.yml
- sed -i "s/gitlab_ci_test/gitlab_ci_test_$((RANDOM/5000))/" config/database.yml
-fi
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 119cc90fc1e..fb648d27621 100755
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -1,10 +1,16 @@
#!/bin/bash
+
if [ -f /.dockerinit ]; then
- wget -q https://gitlab.com/axil/phantomjs-debian/raw/master/phantomjs_1.9.8-0jessie_amd64.deb
- dpkg -i phantomjs_1.9.8-0jessie_amd64.deb
+ # Docker runners use `/cache` folder which is persisted every build
+ if [ ! -e /cache/phantomjs_1.9.8-0jessie_amd64.deb ]; then
+ wget -q https://gitlab.com/axil/phantomjs-debian/raw/master/phantomjs_1.9.8-0jessie_amd64.deb
+ mv phantomjs_1.9.8-0jessie_amd64.deb /cache
+ fi
+ dpkg -i /cache/phantomjs_1.9.8-0jessie_amd64.deb
apt-get update -qq
- apt-get install -y -qq libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client
+ apt-get -o dir::cache::archives="/cache/apt" install -y -qq \
+ libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client
cp config/database.yml.mysql config/database.yml
sed -i 's/username:.*/username: root/g' config/database.yml
@@ -13,8 +19,8 @@ if [ -f /.dockerinit ]; then
cp config/resque.yml.example config/resque.yml
sed -i 's/localhost/redis/g' config/resque.yml
- FLAGS=(--deployment --path /cache)
- export FLAGS
+
+ export FLAGS=(--path /cache)
else
export PATH=$HOME/bin:/usr/local/bin:/usr/bin:/bin
cp config/database.yml.mysql config/database.yml
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index f0fc6916c4d..1a360cd1ebc 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -167,7 +167,7 @@ describe 'Comments', feature: true do
end
it 'should be removed when canceled' do
- page.within(".diff-file form[rel$='#{line_code}']") do
+ page.within(".diff-file form[id$='#{line_code}']") do
find('.js-close-discussion-note-form').trigger('click')
end