Merge branch 'master' into issue_5546

This commit is contained in:
Rubén Dávila 2016-01-22 17:54:37 -05:00
commit 9ef468922c
167 changed files with 2871 additions and 966 deletions

View file

@ -1,4 +1,13 @@
# This file is generated by GitLab CI
image: "ruby:2.1"
services:
- mysql:latest
- postgres:latest
- redis:latest
variables:
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
before_script:
- ./scripts/prepare_build.sh
- ruby -v

View file

@ -3,8 +3,10 @@ Please view this file on the master branch, on stable branches it's out of date.
v 8.5.0 (unreleased)
- Add "visibility" flag to GET /projects api endpoint
- 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 (unreleased)
v 8.4.0
- Allow LDAP users to change their email if it was not set by the LDAP server
- Ensure Gravatar host looks like an actual host
- Consider re-assign as a mention from a notification point of view
@ -14,6 +16,7 @@ v 8.4.0 (unreleased)
- Autocomplete data is now always loaded, instead of when focusing a comment text area
- Improved performance of finding issues for an entire group
- Added custom application performance measuring system powered by InfluxDB
- Add syntax highlighting to diffs
- Gracefully handle invalid UTF-8 sequences in Markdown links (Stan Hu)
- Bump fog to 1.36.0 (Stan Hu)
- Add user's last used IP addresses to admin page (Stan Hu)
@ -74,6 +77,7 @@ v 8.4.0 (unreleased)
- Fix: Creator should be added as a master of the project on creation
- Added X-GitLab-... headers to emails from CI and Email On Push services (Anton Baklanov)
- Add IP check against DNSBLs at account sign-up
- Added cache:key to .gitlab-ci.yml allowing to fine tune the caching
v 8.3.4
- Use gitlab-workhorse 0.5.4 (fixes API routing bug)

View file

@ -1 +1 @@
0.6.0
0.6.1

0
Rakefile Normal file → Executable file
View file

0
app/assets/fonts/OFL.txt Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Black.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Black.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-BlackIt.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-BlackIt.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Bold.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Bold.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-BoldIt.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-BoldIt.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-ExtraLight.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-ExtraLightIt.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-It.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-It.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Light.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Light.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-LightIt.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-LightIt.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Regular.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Regular.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Semibold.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-Semibold.ttf.woff2 Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff Executable file → Normal file
View file

0
app/assets/fonts/SourceSansPro-SemiboldIt.ttf.woff2 Executable file → Normal file
View file

View file

@ -0,0 +1,14 @@
class @BuildArtifacts
constructor: () ->
@disablePropagation()
@setupEntryClick()
disablePropagation: ->
$('.top-block').on 'click', '.download', (e) ->
e.stopPropagation()
$('.tree-holder').on 'click', 'tr[data-link] a', (e) ->
e.stopImmediatePropagation()
setupEntryClick: ->
$('.tree-holder').on 'click', 'tr[data-link]', (e) ->
window.location = @dataset.link

View file

@ -100,6 +100,8 @@ class Dispatcher
shortcut_handler = true
when 'projects:forks:new'
new ProjectFork()
when 'projects:artifacts:browse'
new BuildArtifacts()
when 'users:show'
new User()
new Activities()

View file

@ -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,19 +121,22 @@ class @Notes
flash.pinTo('.header-content')
return
# render note if it not present in loaded list
# or skip if rendered
if @isNewNote(note) && !note.award
@note_ids.push(note.id)
$('ul.main-notes-list').
append(note.html).
syntaxHighlight()
@initTaskList()
if note.award
awards_handler.addAwardToEmojiBar(note.note)
awards_handler.scrollToAwards()
# render note if it not present in loaded list
# or skip if rendered
else if @isNewNote(note)
@note_ids.push(note.id)
$('ul.main-notes-list')
.append(note.html)
.syntaxHighlight()
@initTaskList()
@updateNotesCount(1)
###
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)

View file

@ -120,14 +120,6 @@ span.update-author {
display: inline;
}
.line_holder {
&:hover {
td {
background: #FFFFCF !important;
}
}
}
p.time {
color: #999;
font-size: 90%;

View file

@ -92,15 +92,6 @@
&:last-child {
border-right: none;
}
background: #fff;
}
.lines {
pre {
padding: 0;
margin: 0;
background: none;
border: none;
}
}
img.avatar {
border: 0 none;
@ -116,18 +107,18 @@
color: #888;
}
}
td.blame-numbers {
pre {
color: #AAA;
white-space: pre;
}
background: #f1f1f1;
td.line-numbers {
float: none;
border-left: 1px solid #DDD;
}
td.lines {
padding: 0;
code {
font-family: $monospace_font;
}
pre {
margin: 0;
}
}
}

View file

@ -53,3 +53,14 @@
color: #333;
}
}
.ui-sortable-handle {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
&:active {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
}

View file

@ -1,35 +1,11 @@
.gl-pagination {
text-align: center;
border-top: 1px solid $border-color;
background-color: $background-color;
margin: -$gl-padding;
margin: 0;
margin-top: 0;
.pagination {
padding: 0;
margin: 0;
display: block;
li.first,
li.last,
li.next,
li.prev {
> a {
color: $link-color;
&:hover {
color: #fff;
}
}
}
li > a,
li > span {
border: none;
margin: 0;
@include border-radius(0 !important);
padding: 13px 19px;
border-right: 1px solid $border-color;
}
}
}

View file

@ -66,20 +66,20 @@ $legend-color: $text-color;
//##
$pagination-color: $gl-gray;
$pagination-bg: $background-color;
$pagination-border: transparent;
$pagination-bg: #fff;
$pagination-border: $border-color;
$pagination-hover-color: #fff;
$pagination-hover-bg: $brand-info;
$pagination-hover-border: transparent;
$pagination-hover-color: $gl-gray;
$pagination-hover-bg: $hover;
$pagination-hover-border: $border-color;
$pagination-active-color: #fff;
$pagination-active-bg: $brand-info;
$pagination-active-border: transparent;
$pagination-active-color: $blue-dark;
$pagination-active-bg: #fff;
$pagination-active-border: $border-color;
$pagination-disabled-color: #fff;
$pagination-disabled-bg: lighten($brand-info, 15%);
$pagination-disabled-border: transparent;
$pagination-disabled-color: #cdcdcd;
$pagination-disabled-bg: $background-color;
$pagination-disabled-border: $border-color;
//== Form states and alerts

View file

@ -1,20 +1,40 @@
/* https://github.com/MozMorris/tomorrow-pygments */
.code.dark {
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
// Line numbers
.line-numbers, .diff-line-num {
background-color: #1d1f21;
}
.diff-line-num, .diff-line-num a {
color: rgba(255, 255, 255, 0.3);
}
// Code itself
pre.code {
border-left: 1px solid #666;
}
&, pre.code, .line_holder .line_content {
background-color: #1d1f21;
color: #c5c8c6;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(51, 255, 51, 0.1), rgba(51, 255, 51, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(255, 51, 51, 0.2), rgba(255, 51, 51, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor
pre .hll {
background-color: #557 !important;

View file

@ -1,20 +1,40 @@
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
.code.monokai {
background-color: #272822 !important;
color: #f8f8f2 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color :#272822 !important;
color: #f8f8f2 !important;
// Line numbers
.line-numbers, .diff-line-num {
background-color: #272822;
}
.diff-line-num, .diff-line-num a {
color: rgba(255, 255, 255, 0.3);
}
// Code itself
pre.code {
border-left: 1px solid #555;
}
&, pre.code, .line_holder .line_content {
background-color: #272822;
color: #f8f8f2;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(166, 226, 46, 0.2), rgba(166, 226, 46, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(254, 147, 140, 0.2), rgba(254, 147, 140, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor
pre .hll {
background-color: #49483e !important;

View file

@ -1,20 +1,40 @@
/* https://gist.github.com/qguv/7936275 */
.code.solarized-dark {
background-color: #002b36 !important;
color: #93a1a1 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #002b36 !important;
color: #93a1a1 !important;
// Line numbers
.line-numbers, .diff-line-num {
background-color: #002b36;
}
.diff-line-num, .diff-line-num a {
color: rgba(255, 255, 255, 0.3);
}
// Code itself
pre.code {
border-left: 1px solid #113b46;
}
&, pre.code, .line_holder .line_content {
background-color: #002b36;
color: #93a1a1;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #808080);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #808080);
}
.line_content.match {
color: rgba(255, 255, 255, 0.3);
background: rgba(255, 255, 255, 0.1);
}
}
// highlight line via anchor
pre .hll {
background-color: #174652 !important;

View file

@ -1,20 +1,40 @@
/* https://gist.github.com/qguv/7936275 */
.code.solarized-light {
background-color: #fdf6e3 !important;
color: #586e75 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #fdf6e3 !important;
color: #586e75 !important;
// Line numbers
.line-numbers, .diff-line-num {
background-color: #fdf6e3;
}
.diff-line-num, .diff-line-num a {
color: rgba(0, 0, 0, 0.3);
}
// Code itself
pre.code {
border-left: 1px solid #c5d0d4;
}
&, pre.code, .line_holder .line_content {
background-color: #fdf6e3;
color: #586e75;
}
// Diff line
.line_holder {
.diff-line-num.new, .line_content.new {
@include diff_background(rgba(133, 153, 0, 0.2), rgba(133, 153, 0, 0.3), #FAF3DD);
}
.diff-line-num.old, .line_content.old {
@include diff_background(rgba(220, 50, 47, 0.2), rgba(220, 50, 47, 0.3), #FAF3DD);
}
.line_content.match {
color: rgba(0, 0, 0, 0.3);
background: rgba(255, 255, 255, 0.4);
}
}
// highlight line via anchor
pre .hll {
background-color: #ddd8c5 !important;

View file

@ -1,20 +1,60 @@
/* https://github.com/aahan/pygments-github-style */
.code.white {
background-color: #f8fafc !important;
color: #5b6169 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: $background-color !important;
color: $gl-gray !important;
// Line numbers
.line-numbers, .diff-line-num {
background-color: $background-color;
}
.diff-line-num, .diff-line-num a {
color: rgba(0, 0, 0, 0.3);
}
// Code itself
pre.code {
border-left: 1px solid $border-color;
background-color: #fff !important;
color: #333 !important;
}
&, pre.code, .line_holder .line_content {
background-color: #fff;
color: #333;
}
// Diff line
.line_holder {
.diff-line-num {
&.old {
background: #ffdddd;
border-color: #f1c0c0;
}
&.new {
background: #dbffdb;
border-color: #c1e9c1;
}
}
.line_content {
&.old {
background: #ffecec;
span.idiff {
background-color: #f8cbcb;
}
}
&.new {
background: #eaffea;
span.idiff {
background-color: #a6f3a6;
}
}
&.match {
color: rgba(0, 0, 0, 0.3);
background: #fafafa;
}
}
}
// highlight line via anchor

View file

@ -32,16 +32,6 @@
background: #FFF;
color: #333;
.old {
span.idiff {
background-color: #f8cbcb;
}
}
.new {
span.idiff {
background-color: #a6f3a6;
}
}
.unfold {
cursor: pointer;
}
@ -76,7 +66,7 @@
}
tr.line_holder.parallel {
.old_line, .new_line, .diff_line {
.old_line, .new_line {
min-width: 50px;
}
@ -85,7 +75,7 @@
}
}
.old_line, .new_line, .diff_line {
.old_line, .new_line {
margin: 0px;
padding: 0px;
border: none;
@ -107,43 +97,12 @@
text-decoration: underline;
}
}
&.new {
background: #CFD;
}
&.old {
background: #FDD;
}
}
.diff_line {
padding: 0;
}
.line_holder {
&.old .old_line,
&.old .new_line {
background: #ffdddd;
border-color: #f1c0c0;
}
&.new .old_line,
&.new .new_line {
background: #dbffdb;
border-color: #c1e9c1;
}
}
.line_content {
display: block;
margin: 0px;
padding: 0px 0.5em;
border: none;
&.new {
background: #eaffea;
}
&.old {
background: #ffecec;
}
&.matched {
color: $border-color;
background: #fafafa;
}
&.parallel {
display: table-cell;
}
@ -393,3 +352,15 @@
right: 15px;
}
}
@mixin diff_background($background, $idiff, $border) {
background: $background;
&.line_content span.idiff {
background: $idiff;
}
&.diff-line-num {
border-color: $border;
}
}

View file

@ -201,3 +201,39 @@
.mr-source-target {
line-height: 31px;
}
.disabled-comment-area {
padding: 16px 0;
.disabled-profile {
width: 40px;
height: 40px;
background: $border-gray-dark;
border-radius: 20px;
display: inline-block;
margin-right: 10px;
}
.disabled-comment {
background: $gray-light;
display: inline-block;
vertical-align: top;
height: 200px;
border-radius: 4px;
border: 1px solid $border-gray-normal;
padding-top: 90px;
text-align: center;
right: 20px;
position: absolute;
left: 70px;
margin-bottom: 20px;
span {
color: #B2B2B2;
a {
color: $md-link-color;
}
}
}
}

View file

@ -10,18 +10,6 @@
margin: 10px $gl-padding;
}
.diff-file .diff-content {
tr.line_holder:hover {
&> td.line_content {
background: $hover !important;
border-color: darken($hover, 10%) !important;
}
&> td.new_line,
&> td.old_line {
background: darken($hover, 4%) !important;
border-color: darken($hover, 10%) !important;
}
}
tr.line_holder:hover > td .line_note_link {
opacity: 1.0;
filter: alpha(opacity=100);

View file

@ -242,11 +242,8 @@ ul.notes {
// "show" the icon also if we just hover somewhere over the line
&:hover > td {
background: $hover !important;
.add-diff-note {
@include show-add-diff-note;
}
}
}

View file

@ -3,10 +3,6 @@
border-bottom: 1px solid #DDD;
padding-bottom: 15px;
margin-bottom: 15px;
.term {
height: 22px;
}
}
}

View file

@ -25,6 +25,7 @@ class ApplicationController < ActionController::Base
helper_method :abilities, :can?, :current_application_settings
helper_method :import_sources_enabled?, :github_import_enabled?, :github_import_configured?, :gitlab_import_enabled?, :gitlab_import_configured?, :bitbucket_import_enabled?, :bitbucket_import_configured?, :gitorious_import_enabled?, :google_code_import_enabled?, :fogbugz_import_enabled?, :git_import_enabled?
helper_method :repository
rescue_from Encoding::CompatibilityError do |exception|
log_exception(exception)

View file

@ -97,7 +97,7 @@ module CreatesCommit
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_target_project = @project
@mr_target_branch = @mr_target_project.repository.root_ref
@mr_target_branch = @ref
end
end
end

View file

@ -52,7 +52,9 @@ class Projects::BlobController < Projects::ApplicationController
def preview
@content = params[:content]
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3', include_diff_info: true)
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
diff_lines = diffy.diff.scan(/.*\n/)[2..-1]
diff_lines = Gitlab::Diff::Parser.new.parse(diff_lines)
@diff_lines = Gitlab::Diff::Highlight.new(diff_lines).highlight
render layout: false
end
@ -65,8 +67,9 @@ class Projects::BlobController < Projects::ApplicationController
end
def diff
@form = UnfoldForm.new(params)
@lines = @blob.data.lines[@form.since - 1..@form.to - 1]
@form = UnfoldForm.new(params)
@lines = Gitlab::Highlight.highlight_lines(repository, @ref, @path)
@lines = @lines[@form.since - 1..@form.to - 1]
if @form.bottom?
@match_line = ''

View file

@ -72,6 +72,7 @@ class Projects::CommitController < Projects::ApplicationController
@diffs = commit.diffs
end
@diff_refs = [commit.parent || commit, commit]
@notes_count = commit.notes.count
@statuses = ci_commit.statuses if ci_commit

View file

@ -21,7 +21,8 @@ class Projects::CompareController < Projects::ApplicationController
@commits = Commit.decorate(compare_result.commits, @project)
@diffs = compare_result.diffs
@commit = @project.commit(head_ref)
@first_commit = @project.commit(base_ref)
@base_commit = @project.commit(base_ref)
@diff_refs = [@base_commit, @commit]
@line_notes = []
end
end

View file

@ -58,7 +58,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def diffs
@commit = @merge_request.last_commit
@first_commit = @merge_request.first_commit
@base_commit = @merge_request.diff_base_commit
# MRs created before 8.4 don't have a diff_base_commit,
# but we need it for the "View file @ ..." link by deleted files
@base_commit ||= @merge_request.first_commit.parent || @merge_request.first_commit
@comments_allowed = @reply_allowed = true
@comments_target = {
@ -102,7 +106,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@source_project = merge_request.source_project
@commits = @merge_request.compare_commits.reverse
@commit = @merge_request.last_commit
@first_commit = @merge_request.first_commit
@base_commit = @merge_request.diff_base_commit
@diffs = @merge_request.compare_diffs
@ci_commit = @merge_request.ci_commit

View file

@ -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

View file

@ -1,21 +1,10 @@
module BlobHelper
def highlight(blob_name, blob_content, nowrap: false, continue: false)
@formatter ||= Rouge::Formatters::HTMLGitlab.new(
nowrap: nowrap,
cssclass: 'code highlight',
lineanchors: true,
lineanchorsid: 'LC'
)
def highlighter(blob_name, blob_content, nowrap: false)
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
end
begin
@lexer ||= Rouge::Lexer.guess(filename: blob_name, source: blob_content).new
result = @formatter.format(@lexer.lex(blob_content, continue: continue)).html_safe
rescue
@lexer = Rouge::Lexers::PlainText
result = @formatter.format(@lexer.lex(blob_content)).html_safe
end
result
def highlight(blob_name, blob_content, nowrap: false)
Gitlab::Highlight.highlight(blob_name, blob_content, nowrap: nowrap)
end
def no_highlight_files
@ -37,10 +26,10 @@ module BlobHelper
tree_join(ref, path),
link_opts)
if !on_top_of_branch?
if !on_top_of_branch?(project, ref)
button_tag "Edit", class: "btn btn-default disabled has_tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' }
elsif can_edit_blob?(blob)
link_to "Edit", edit_path, class: 'btn btn-small'
elsif can_edit_blob?(blob, project, ref)
link_to "Edit", edit_path, class: 'btn'
elsif can?(current_user, :fork_project, project)
continue_params = {
to: edit_path,
@ -50,7 +39,7 @@ module BlobHelper
fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id,
continue: continue_params)
link_to "Edit", fork_path, class: 'btn btn-small', method: :post
link_to "Edit", fork_path, class: 'btn', method: :post
end
end
@ -61,11 +50,11 @@ module BlobHelper
return unless blob
if !on_top_of_branch?
if !on_top_of_branch?(project, ref)
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "You can only #{action} files when you are on a branch", data: { container: 'body' }
elsif blob.lfs_pointer?
button_tag label, class: "btn btn-#{btn_class} disabled has_tooltip", title: "It is not possible to #{action} files that are stored in LFS using the web interface", data: { container: 'body' }
elsif can_edit_blob?(blob)
elsif can_edit_blob?(blob, project, ref)
button_tag label, class: "btn btn-#{btn_class}", 'data-target' => "#modal-#{modal_type}-blob", 'data-toggle' => 'modal'
elsif can?(current_user, :fork_project, project)
continue_params = {

View file

@ -166,7 +166,7 @@ module CommitsHelper
link_to(
namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff.new_path)),
class: 'btn btn-small view-file js-view-file'
class: 'btn view-file js-view-file'
) do
raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id')

View file

@ -19,13 +19,13 @@ module DiffHelper
end
end
def safe_diff_files(diffs)
def safe_diff_files(diffs, diff_refs)
lines = 0
safe_files = []
diffs.first(allowed_diff_size).each do |diff|
lines += diff.diff.lines.count
break if lines > allowed_diff_lines
safe_files << Gitlab::Diff::File.new(diff)
safe_files << Gitlab::Diff::File.new(diff, diff_refs)
end
safe_files
end
@ -43,64 +43,6 @@ module DiffHelper
Gitlab::Diff::LineCode.generate(file_path, line.new_pos, line.old_pos)
end
def parallel_diff(diff_file, index)
lines = []
skip_next = false
# Building array of lines
#
# [
# left_type, left_line_number, left_line_content, left_line_code,
# right_line_type, right_line_number, right_line_content, right_line_code
# ]
#
diff_file.diff_lines.each do |line|
full_line = line.text
type = line.type
line_code = generate_line_code(diff_file.file_path, line)
line_new = line.new_pos
line_old = line.old_pos
next_line = diff_file.next_line(line.index)
if next_line
next_line_code = generate_line_code(diff_file.file_path, next_line)
next_type = next_line.type
next_line = next_line.text
end
if type == 'match' || type.nil?
# line in the right panel is the same as in the left one
line = [type, line_old, full_line, line_code, type, line_new, full_line, line_code]
lines.push(line)
elsif type == 'old'
if next_type == 'new'
# Left side has text removed, right side has text added
line = [type, line_old, full_line, line_code, next_type, line_new, next_line, next_line_code]
lines.push(line)
skip_next = true
elsif next_type == 'old' || next_type.nil?
# Left side has text removed, right side doesn't have any change
# No next line code, no new line number, no new line text
line = [type, line_old, full_line, line_code, next_type, nil, "&nbsp;", nil]
lines.push(line)
end
elsif type == 'new'
if skip_next
# Change has been already included in previous line so no need to do it again
skip_next = false
next
else
# Change is only on the right side, left side has no change
line = [nil, nil, "&nbsp;", line_code, type, line_new, full_line, line_code]
lines.push(line)
end
end
end
lines
end
def unfold_bottom_class(bottom)
(bottom) ? 'js-unfold-bottom' : ''
end
@ -111,9 +53,9 @@ module DiffHelper
def diff_line_content(line)
if line.blank?
" &nbsp;"
" &nbsp;".html_safe
else
line
line.html_safe
end
end
@ -160,8 +102,7 @@ module DiffHelper
def commit_for_diff(diff)
if diff.deleted_file
first_commit = @first_commit || @commit
first_commit.parent || @first_commit
@base_commit || @commit.parent || @commit
else
@commit
end

View file

@ -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

View file

@ -346,17 +346,17 @@ module Ci
end
def artifacts_browse_url
if artifacts_browser_supported?
if artifacts_metadata?
browse_namespace_project_build_artifacts_path(project.namespace, project, self)
end
end
def artifacts_browser_supported?
def artifacts_metadata?
artifacts? && artifacts_metadata.exists?
end
def artifacts_metadata_entry(path)
Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path).to_entry
def artifacts_metadata_entry(path, **options)
Gitlab::Ci::Build::Artifacts::Metadata.new(artifacts_metadata.path, path, **options).to_entry
end
private

View file

@ -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

View file

@ -91,7 +91,7 @@ class Member < ActiveRecord::Base
member.invite_email = user
end
if can_update_member?(current_user, member)
if can_update_member?(current_user, member) || project_creator?(member, access_level)
member.created_by ||= current_user
member.access_level = access_level
@ -107,6 +107,11 @@ class Member < ActiveRecord::Base
current_user.can?(:update_group_member, member) ||
current_user.can?(:update_project_member, member)
end
def project_creator?(member, access_level)
member.new_record? && member.owner? &&
access_level.to_i == ProjectMember::MASTER
end
end
def invite?

View file

@ -84,7 +84,7 @@ class ProjectMember < Member
def truncate_teams(project_ids)
ProjectMember.transaction do
members = ProjectMember.where(source_id: project_ids)
members.each do |member|
member.destroy
end
@ -133,13 +133,13 @@ class ProjectMember < Member
event_service.join_project(self.project, self.user)
notification_service.new_project_member(self)
end
super
end
def post_update_hook
if access_level_changed?
notification_service.update_project_member(self)
notification_service.update_project_member(self)
end
super

View file

@ -180,6 +180,14 @@ class MergeRequest < ActiveRecord::Base
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end
def diff_base_commit
if merge_request_diff
merge_request_diff.base_commit
else
self.target_project.commit(self.target_branch)
end
end
def last_commit_short_sha
last_commit.short_id
end
@ -254,7 +262,7 @@ class MergeRequest < ActiveRecord::Base
end
def mergeable?
return false unless open? && !work_in_progress?
return false unless open? && !work_in_progress? && !broken?
check_if_can_be_merged
@ -477,8 +485,7 @@ class MergeRequest < ActiveRecord::Base
end
def target_sha
@target_sha ||= target_project.
repository.commit(target_branch).sha
@target_sha ||= target_project.repository.commit(target_branch).sha
end
def source_sha
@ -517,4 +524,10 @@ class MergeRequest < ActiveRecord::Base
def ci_commit
@ci_commit ||= source_project.ci_commit(last_commit.id) if last_commit && source_project
end
def diff_refs
return nil unless diff_base_commit
[diff_base_commit, last_commit]
end
end

View file

@ -73,6 +73,12 @@ class MergeRequestDiff < ActiveRecord::Base
commits.last
end
def base_commit
return nil unless self.base_commit_sha
merge_request.target_project.commit(self.base_commit_sha)
end
def last_commit_short_sha
@last_commit_short_sha ||= last_commit.short_id
end
@ -156,6 +162,9 @@ class MergeRequestDiff < ActiveRecord::Base
end
self.st_diffs = new_diffs
self.base_commit_sha = merge_request.target_project.commit(target_branch).try(:sha)
self.save
end

View file

@ -244,7 +244,7 @@ class Note < ActiveRecord::Base
prev_match_line = nil
prev_lines = []
diff_lines.each do |line|
highlighted_diff_lines.each do |line|
if line.type == "match"
prev_lines.clear
prev_match_line = line
@ -261,7 +261,11 @@ class Note < ActiveRecord::Base
end
def diff_lines
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines.to_a)
@diff_lines ||= Gitlab::Diff::Parser.new.parse(diff.diff.lines)
end
def highlighted_diff_lines
Gitlab::Diff::Highlight.new(diff_lines).highlight
end
def discussion_id

View file

@ -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

View file

@ -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

View file

@ -95,7 +95,7 @@ module Projects
system_hook_service.execute_hooks_for(@project, :create)
unless @project.group
@project.team << [current_user, :master]
@project.team << [current_user, :master, current_user]
end
@project.import_start if @project.import?

View file

@ -5,5 +5,9 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%li.next
= link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, rel: 'next', remote: remote
- if current_page.last?
%li{ class: "next disabled" }
%span= raw(t 'views.pagination.next')
- else
%li{ class: "next" }
= link_to raw(t 'views.pagination.next'), url, rel: 'next', remote: remote

View file

@ -10,13 +10,13 @@
%ul.pagination.clearfix
- unless current_page.first?
= first_page_tag unless num_pages < 5 # As kaminari will always show the first 5 pages
= prev_page_tag
= prev_page_tag
- each_page do |page|
- if page.left_outer? || page.right_outer? || page.inside_window?
= page_tag page
- elsif !page.was_truncated?
= gap_tag
= next_page_tag
- unless current_page.last?
= next_page_tag
= last_page_tag unless num_pages < 5

View file

@ -5,5 +5,9 @@
-# num_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%li{class: "prev" }
= link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote
- if current_page.first?
%li{ class: "prev disabled" }
%span= raw(t 'views.pagination.previous')
- else
%li{ class: "prev" }
= link_to raw(t 'views.pagination.previous'), url, rel: 'prev', remote: remote

View file

@ -4,7 +4,7 @@
.top-block.gray-content-block.clearfix
.pull-right
= link_to download_namespace_project_build_artifacts_path(@project.namespace, @project, @build),
class: 'btn btn-default' do
class: 'btn btn-default download' do
= icon('download')
Download artifacts archive
@ -20,12 +20,3 @@
- if @entry.empty?
.center Empty
:javascript
$('.tree-holder').on('click', 'tr[data-link] a', function(e) {
e.stopImmediatePropagation();
});
$('.tree-holder').on('click', 'tr[data-link]', function(e) {
window.location = this.dataset.link;
});

View file

@ -12,9 +12,10 @@
%small= number_to_human_size @blob.size
.file-actions
= render "projects/blob/actions"
.file-content.blame.highlight
.file-content.blame.code.js-syntax-highlight
%table
- current_line = 1
- blame_highlighter = highlighter(@blob.name, @blob.data, nowrap: true)
- @blame.each do |blame_group|
%tr
%td.blame-commit
@ -30,16 +31,15 @@
= commit_author_link(commit, avatar: false)
authored
#{time_ago_with_tooltip(commit.committed_date, skip_js: true)}
%td.lines.blame-numbers
%pre
- line_count = blame_group[:lines].count
- (current_line...(current_line + line_count)).each do |i|
= i
\
- current_line += line_count
%td.line-numbers
- line_count = blame_group[:lines].count
- (current_line...(current_line + line_count)).each do |i|
%a.diff-line-num= i
\
- current_line += line_count
%td.lines
%pre{class: 'code highlight white'}
%pre{class: 'code highlight'}
%code
- blame_group[:lines].each do |line|
:erb
<%= highlight(@blob.name, line, nowrap: true, continue: true).html_safe %>
:preserve
#{blame_highlighter.highlight(line)}

View file

@ -10,8 +10,9 @@
%tr.line_holder
%td.old_line.diff-line-num{data: {linenumber: line_old}}
= link_to raw(line_old), "#"
%td.new_line= link_to raw(line_new) , "#"
%td.line_content.noteable_line= ' ' * @form.indent + line
%td.new_line.diff-line-num
= link_to raw(line_new) , "#"
%td.line_content.noteable_line==#{' ' * @form.indent}#{line}
- if @form.unfold? && @form.bottom? && @form.to < @blob.loc
%tr.line_holder{ id: @form.to }

View file

@ -14,12 +14,12 @@
- @diff_lines.each do |line|
%tr.line_holder{ class: "#{line.type}" }
- if line.type == "match"
%td.old_line= "..."
%td.new_line= "..."
%td.line_content.matched= line.text
%td.old_line.diff-line-num= "..."
%td.new_line.diff-line-num= "..."
%td.line_content.match= line.text
- else
%td.old_line
%td.new_line
%td.line_content{class: "#{line.type}"}= raw diff_line_content(line.text)
%td.old_line.diff-line-num
%td.new_line.diff-line-num
%td.line_content{class: "#{line.type}"}= diff_line_content(line.text)
- else
.nothing-here-block No changes.

View file

@ -96,7 +96,7 @@
.center
.btn-group{ role: :group }
= link_to "Download", @build.artifacts_download_url, class: 'btn btn-sm btn-primary'
- if @build.artifacts_browser_supported?
- if @build.artifacts_metadata?
= link_to "Browse", @build.artifacts_browse_url, class: 'btn btn-sm btn-primary'
.build-widget

View file

@ -9,5 +9,6 @@
= render "ci_menu"
- else
%div.block-connector
= render "projects/diffs/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project,
diff_refs: @diff_refs
= render "projects/notes/notes_with_form"

View file

@ -9,7 +9,7 @@
- if @commits.present?
.prepend-top-default
= render "projects/commits/commit_list"
= render "projects/diffs/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @diff_refs
- else
.light-well.prepend-top-default
.center

View file

@ -1,7 +1,7 @@
- if diff_view == 'parallel'
- fluid_layout true
- diff_files = safe_diff_files(diffs)
- diff_files = safe_diff_files(diffs, diff_refs)
.content-block.oneline-block
.inline-parallel-buttons

View file

@ -1,39 +1,37 @@
.diff-file{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
.diff-header{id: "file-path-#{hexdigest(diff_file.file_path)}"}
.diff-file.file-holder{id: "diff-#{i}", data: diff_file_html_data(project, diff_commit, diff_file)}
.file-title{id: "file-path-#{hexdigest(diff_file.file_path)}"}
- if diff_file.diff.submodule?
%span
= icon('archive fw')
%strong
= submodule_link(blob, @commit.id, project.repository)
- else
%span
= blob_icon blob.mode, blob.name
= link_to "#diff-#{i}" do
%strong
= diff_file.new_path
= blob_icon blob.mode, blob.name
= link_to "#diff-#{i}" do
%strong
= diff_file.new_path
- if diff_file.deleted_file
deleted
- elsif diff_file.renamed_file
renamed from
%strong
= diff_file.old_path
- if diff_file.deleted_file
deleted
- elsif diff_file.renamed_file
renamed from
%strong
= diff_file.old_path
- if diff_file.mode_changed?
%small
= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
- if diff_file.mode_changed?
%small
= "#{diff_file.diff.a_mode} → #{diff_file.diff.b_mode}"
.diff-controls
.file-actions.hidden-xs
- if blob_text_viewable?(blob)
= link_to '#', class: 'js-toggle-diff-comments btn btn-sm active has_tooltip', title: "Toggle comments for this file" do
%i.fa.fa-comments
&nbsp;
= link_to '#', class: 'js-toggle-diff-comments btn active has_tooltip', title: "Toggle comments for this file" do
= icon('comments')
\
- if editable_diff?(diff_file)
= edit_blob_link(@merge_request.source_project,
@merge_request.source_branch, diff_file.new_path,
from_merge_request_id: @merge_request.id)
&nbsp;
= view_file_btn(diff_commit.id, diff_file, project)

View file

@ -4,4 +4,4 @@
%td.new_line.diff-line-num{data: {linenumber: line_new},
class: [unfold_bottom_class(bottom), unfold_class(!new_file)]}
\...
%td.line_content.matched= line
%td.line_content.match= line

View file

@ -1,4 +1,4 @@
%td.old_line
%td.line_content.parallel.matched= line
%td.new_line
%td.line_content.parallel.matched= line
%td.old_line.diff-line-num
%td.line_content.parallel.match= line
%td.new_line.diff-line-num
%td.line_content.parallel.match= line

View file

@ -1,42 +1,40 @@
/ Side-by-side diff view
%div.text-file.diff-wrap-lines
%div.text-file.diff-wrap-lines.code.file-content.js-syntax-highlight
%table
- parallel_diff(diff_file, index).each do |line|
- type_left = line[0]
- line_number_left = line[1]
- line_content_left = line[2]
- line_code_left = line[3]
- type_right = line[4]
- line_number_right = line[5]
- line_content_right = line[6]
- line_code_right = line[7]
- diff_file.parallel_diff_lines.each do |line|
- left = line[:left]
- right = line[:right]
%tr.line_holder.parallel
- if type_left == 'match'
= render "projects/diffs/match_line_parallel", { line: line_content_left,
line_old: line_number_left, line_new: line_number_right }
- elsif type_left == 'old' || type_left.nil?
%td.old_line{id: line_code_left, class: "#{type_left}"}
= link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
- if left[:type] == 'match'
= render "projects/diffs/match_line_parallel", { line: left[:text],
line_old: left[:number], line_new: right[:number] }
- elsif left[:type] == 'nonewline'
%td.old_line.diff-line-num
%td.line_content.parallel.match= left[:text]
%td.new_line.diff-line-num
%td.line_content.parallel.match= left[:text]
- else
%td.old_line.diff-line-num{id: left[:line_code], class: "#{left[:type]}"}
= link_to raw(left[:number]), "##{left[:line_code]}", id: left[:line_code]
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_left, 'old')
%td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw line_content_left
= link_to_new_diff_note(left[:line_code], 'old')
%td.line_content{class: "parallel noteable_line #{left[:type]} #{left[:line_code]}", data: { line_code: left[:line_code] }}= diff_line_content(left[:text])
- if type_right == 'new'
- if right[:type] == 'new'
- new_line_class = 'new'
- new_line_code = line_code_right
- new_line_code = right[:line_code]
- else
- new_line_class = nil
- new_line_code = line_code_left
- new_line_code = left[:line_code]
%td.new_line{id: new_line_code, class: "#{new_line_class}", data: { linenumber: line_number_right }}
= link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
%td.new_line.diff-line-num{id: new_line_code, class: "#{new_line_class}", data: { linenumber: right[:number] }}
= link_to raw(right[:number]), "##{new_line_code}", id: new_line_code
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_right, 'new')
%td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw line_content_right
= link_to_new_diff_note(right[:line_code], 'new')
%td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", data: { line_code: new_line_code }}= diff_line_content(right[:text])
- if @reply_allowed
- comments_left, comments_right = organize_comments(type_left, type_right, line_code_left, line_code_right)
- comments_left, comments_right = organize_comments(left[:type], right[:type], left[:line_code], right[:line_code])
- if comments_left.present? || comments_right.present?
= render "projects/notes/diff_notes_with_reply_parallel", notes_left: comments_left, notes_right: comments_right

View file

@ -3,9 +3,11 @@
.suppressed-container
%a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show.
%table.text-file{class: "#{'hide' if too_big}"}
%table.text-file.code.js-syntax-highlight{ class: too_big ? 'hide' : '' }
- last_line = 0
- diff_file.diff_lines.each_with_index do |line, index|
- raw_diff_lines = diff_file.diff_lines
- diff_file.highlighted_diff_lines.each_with_index do |line, index|
- type = line.type
- last_line = line.new_pos
- line_code = generate_line_code(diff_file.file_path, line)
@ -14,19 +16,23 @@
- if type == "match"
= render "projects/diffs/match_line", {line: line.text,
line_old: line_old, line_new: line.new_pos, bottom: false, new_file: diff_file.new_file}
- elsif type == 'nonewline'
%td.old_line.diff-line-num
%td.new_line.diff-line-num
%td.line_content.match= line.text
- else
%td.old_line
%td.old_line.diff-line-num{class: type}
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
- if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code)
%td.new_line{data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
%td.new_line.diff-line-num{class: type, data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos), "##{line_code}", id: line_code
%td.line_content{class: "noteable_line #{type} #{line_code}", data: { line_code: line_code }}= diff_line_content(line.text)
- if @reply_allowed
- comments = @line_notes.select { |n| n.line_code == line_code && n.active? }.sort_by(&:created_at)
- unless comments.empty?
= render "projects/notes/diff_notes_with_reply", notes: comments, line: line.text
= render "projects/notes/diff_notes_with_reply", notes: comments, line: raw_diff_lines[index].text
- if last_line > 0
= render "projects/diffs/match_line", {line: "",

View file

@ -5,9 +5,4 @@
.nothing-here-block No issues to show
- if @issues.present?
.issuable-filter-count
%span.pull-right
= number_with_delimiter(@issues.total_count)
issues for this filter
= paginate @issues, theme: "gitlab"

View file

@ -5,10 +5,5 @@
.nothing-here-block No merge requests to show
- if @merge_requests.present?
.issuable-filter-count
%span.pull-right
= number_with_delimiter(@merge_requests.total_count)
merge requests for this filter
= paginate @merge_requests, theme: "gitlab"

View file

@ -38,7 +38,7 @@
= render "projects/merge_requests/show/commits"
#diffs.diffs.tab-pane.active
- if @diffs.present?
= render "projects/diffs/diffs", diffs: @diffs, project: @project
= render "projects/diffs/diffs", diffs: @diffs, project: @project, diff_refs: @merge_request.diff_refs
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.alert.alert-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.

View file

@ -1,5 +1,6 @@
- if @merge_request_diff.collected?
= render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs, project: @merge_request.project
= render "projects/diffs/diffs", diffs: params[:w] == '1' ? @merge_request.diffs_no_whitespace : @merge_request.diffs,
project: @merge_request.project, diff_refs: @merge_request.diff_refs
- elsif @merge_request_diff.empty?
.nothing-here-block Nothing to merge from #{@merge_request.source_branch} into #{@merge_request.target_branch}
- else

View file

@ -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)

View file

@ -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= ""

View file

@ -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)}

View file

@ -5,6 +5,16 @@
.js-main-target-form
- if can? current_user, :create_note, @project
= render "projects/notes/form", view: diff_view
- else
.disabled-comment-area
.disabled-profile
.disabled-comment
%span
Please
= link_to "register",new_user_session_path
or
= link_to "login",new_user_session_path
to post a comment
:javascript
var notes = new Notes("#{namespace_project_notes_path(namespace_id: @project.namespace, target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i}, "#{diff_view}")

View file

@ -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)

View file

@ -16,15 +16,15 @@
- line_code = generate_line_code(note.file_path, line)
%tr.line_holder{ id: line_code, class: "#{type}" }
- if type == "match"
%td.old_line= "..."
%td.new_line= "..."
%td.line_content.matched= line.text
%td.old_line.diff-line-num= "..."
%td.new_line.diff-line-num= "..."
%td.line_content.match= line.text
- else
%td.old_line
%td.old_line.diff-line-num
= raw(type == "new" ? "&nbsp;" : line.old_pos)
%td.new_line
%td.new_line.diff-line-num
= raw(type == "old" ? "&nbsp;" : line.new_pos)
%td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line.text)
%td.line_content{class: "noteable_line #{type} #{line_code}", line_code: line_code}= diff_line_content(line.text)
- if line_code == note.line_code
= render "projects/notes/diff_notes_with_reply", notes: discussion_notes

View file

@ -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

View file

@ -22,29 +22,27 @@
.file-content.code
.nothing-here-block Empty file
- else
.file-content.code
%div.highlighted-data{ class: user_color_scheme }
.line-numbers
.file-content.code.js-syntax-highlight
.line-numbers
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
- snippet[:data].lines.to_a.size.times do |index|
- offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
- i = index + offset
= link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
%i.fa.fa-link
= i
- unless snippet == snippet_blob[:snippet_chunks].last
%a.diff-line-num
= "."
%pre.code
%code
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
- snippet[:data].lines.to_a.size.times do |index|
- offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
- i = index + offset
= link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}" do
%i.fa.fa-link
= i
= snippet[:data]
- unless snippet == snippet_blob[:snippet_chunks].last
%a
= "."
.highlight.term
%pre
%code
- snippet_blob[:snippet_chunks].each do |snippet|
- unless snippet[:data].empty?
= snippet[:data]
- unless snippet == snippet_blob[:snippet_chunks].last
%a
= "..."
- else
.file-content.code
.nothing-here-block Empty file
= "..."
- else
.file-content.code
.nothing-here-block Empty file

View file

@ -1,13 +1,12 @@
.file-content.code.js-syntax-highlight{ class: user_color_scheme }
.file-content.code.js-syntax-highlight
.line-numbers
- if blob.data.present?
- blob.data.lines.each_index do |index|
- offset = defined?(first_line_number) ? first_line_number : 1
- i = index + offset
-# We're not using `link_to` because it is too slow once we get to thousands of lines.
%a{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%a.diff-line-num{href: "#L#{i}", id: "L#{i}", 'data-line-number' => i}
%i.fa.fa-link
= i
.blob-content{data: {blob_id: blob.id}}
:preserve
#{highlight(blob.name, blob.data)}
= highlight(blob.name, blob.data)

View file

@ -49,6 +49,7 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(Gitlab::Shell)
config.instrument_methods(Gitlab::Git)
config.instrument_instance_methods(Gitlab::Git::Repository)
Gitlab::Git.constants.each do |name|
const = Gitlab::Git.const_get(name)

View file

@ -8,3 +8,7 @@ en:
wrong_size: "is the wrong size (should be %{file_size})"
size_too_small: "is too small (should be at least %{file_size})"
size_too_big: "is too big (should be at most %{file_size})"
views:
pagination:
previous: "Prev"
next: "Next"

View file

@ -0,0 +1,5 @@
class AddBaseCommitShaToMergeRequestDiffs < ActiveRecord::Migration
def change
add_column :merge_request_diffs, :base_commit_sha, :string
end
end

Some files were not shown because too many files have changed in this diff Show more