Commit 831eb946 authored by Achilleas Pipinellis's avatar Achilleas Pipinellis

Merge branch 'master' into doc_refactor_commits_api

parents b4d61ac4 8be4e545
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
v 8.4.0 (unreleased)
- 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
- Add pagination headers to already paginated API resources
- Properly generate diff of orphan commits, like the first commit in a repository
- Improve the consistency of commit titles, branch names, tag names, issue/MR titles, on their respective project pages
- Autocomplete data is now always loaded, instead of when focusing a comment text area (Yorick Peterse)
- Improved performance of finding issues for an entire group (Yorick Peterse)
- Added custom application performance measuring system powered by InfluxDB (Yorick Peterse)
- 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)
- Add housekeeping function to project settings page
......@@ -60,11 +67,16 @@ v 8.4.0 (unreleased)
- Autosize Markdown textareas
- Import GitHub wiki into GitLab
- Add reporters ability to download and browse build artifacts (Andrew Johnson)
- Autofill referring url in message box when reporting user abuse. (Josh Frye)
- Autofill referring url in message box when reporting user abuse.
- Remove leading comma on award emoji when the user is the first to award the emoji (Zeger-Jan van de Weg)
- Add build artifacts browser
- Improve UX in builds artifacts browser
- Increase default size of `data` column in `events` table when using MySQL
- Expose button to CI Lint tool on project builds page
- 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)
......
......@@ -49,7 +49,7 @@ gem "browser", '~> 1.0.0'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '~> 7.2.22'
gem "gitlab_git", '~> 7.2.23'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -293,6 +293,9 @@ end
group :production do
gem "gitlab_meta", '7.0'
# Sentry integration
gem 'sentry-raven'
end
gem "newrelic_rpm", '~> 3.9.4.245'
......
......@@ -356,7 +356,7 @@ GEM
posix-spawn (~> 0.3)
gitlab_emoji (0.2.0)
gemojione (~> 2.1)
gitlab_git (7.2.22)
gitlab_git (7.2.23)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -725,6 +725,8 @@ GEM
activesupport (>= 3.1, < 4.3)
select2-rails (3.5.9.3)
thor (~> 0.14)
sentry-raven (0.15.3)
faraday (>= 0.7.6)
settingslogic (2.0.9)
sexp_processor (4.6.0)
sham_rack (1.3.6)
......@@ -932,7 +934,7 @@ DEPENDENCIES
github-markup (~> 1.3.1)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab_emoji (~> 0.2.0)
gitlab_git (~> 7.2.22)
gitlab_git (~> 7.2.23)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.1.0)
......@@ -1008,6 +1010,7 @@ DEPENDENCIES
sdoc (~> 0.3.20)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven
settingslogic (~> 2.0.9)
sham_rack
shoulda-matchers (~> 2.8.0)
......
File mode changed from 100644 to 100755
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
......@@ -44,7 +44,6 @@ class @AwardsHandler
decrementCounter: (emoji) ->
counter = @findEmojiIcon(emoji).siblings(".counter")
emojiIcon = counter.parent()
if parseInt(counter.text()) > 1
counter.text(parseInt(counter.text()) - 1)
emojiIcon.removeClass("active")
......@@ -60,20 +59,18 @@ class @AwardsHandler
removeMeFromAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
authors = award_block.attr("data-original-title").split(", ")
authors = _.without(authors, "me").join(", ")
award_block.attr("title", authors)
authors.splice(authors.indexOf("me"),1)
award_block.closest(".award").attr("data-original-title", authors.join(", "))
@resetTooltip(award_block)
addMeToAuthorList: (emoji) ->
award_block = @findEmojiIcon(emoji).parent()
authors = _.compact(award_block.attr("data-original-title").split(", "))
origTitle = award_block.attr("data-original-title").trim()
authors = []
if origTitle
authors = origTitle.split(', ')
authors.push("me")
if authors.length == 1
award_block.attr("title", "me")
else
award_block.attr("title", authors.join(", "))
award_block.attr("title", authors.join(", "))
@resetTooltip(award_block)
resetTooltip: (award) ->
......
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
......@@ -87,7 +87,6 @@ class Dispatcher
new GroupAvatar()
when 'projects:tree:show'
new TreeView()
shortcut_handler = new ShortcutsTree()
when 'projects:find_file:show'
shortcut_handler = true
when 'projects:blob:show'
......@@ -101,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()
......
......@@ -4,6 +4,7 @@ class @Shortcuts
Mousetrap.reset()
Mousetrap.bind('?', @selectiveHelp)
Mousetrap.bind('s', Shortcuts.focusSearch)
Mousetrap.bind('t', -> Turbolinks.visit(findFileURL)) if findFileURL?
selectiveHelp: (e) =>
Shortcuts.showHelp(e, @enabledHelp)
......
class @ShortcutsTree extends ShortcutsNavigation
constructor: ->
super()
Mousetrap.bind('t', -> ShortcutsTree.findAndFollowLink('.shortcuts-find-file'))
......@@ -6,7 +6,7 @@ class @Star
$starIcon = $this.find('i')
toggleStar = (isStarred) ->
$this.parent().find('span.count').text data.star_count
$this.parent().find('.star-count').text data.star_count
if isStarred
$starSpan.removeClass('starred').text 'Star'
$starIcon.removeClass('fa-star').addClass 'fa-star-o'
......@@ -19,4 +19,4 @@ class @Star
return
).on 'ajax:error', (e, xhr, status, error) ->
new Flash('Star toggle failed. Try again later.', 'alert')
return
\ No newline at end of file
return
......@@ -120,14 +120,6 @@ span.update-author {
display: inline;
}
.line_holder {
&:hover {
td {
background: #FFFFCF !important;
}
}
}
p.time {
color: #999;
font-size: 90%;
......
......@@ -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;
}
}
}
......
......@@ -53,3 +53,14 @@
color: #333;
}
}
.ui-sortable-handle {
cursor: move;
cursor: -webkit-grab;
cursor: -moz-grab;
&:active {
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
}
.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;
}
}
}
......
......@@ -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
......
......@@ -26,6 +26,7 @@ $gl-vert-padding: 6px;
$gl-padding-top:10px;
$gl-avatar-size: 46px;
$secondary-text: #7f8fa4;
$error-exclamation-point: #E62958;
/*
* Color schema
......
/* https://github.com/MozMorris/tomorrow-pygments */
.code.dark {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #1d1f21;
}
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #1d1f21 !important;
color: #c5c8c6 !important;
.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;
......
/* https://github.com/richleland/pygments-css/blob/master/monokai.css */
.code.monokai {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #272822;
}
background-color: #272822 !important;
color: #f8f8f2 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color :#272822 !important;
color: #f8f8f2 !important;
.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;
......
/* https://gist.github.com/qguv/7936275 */
.code.solarized-dark {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #002b36;
}
background-color: #002b36 !important;
color: #93a1a1 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #002b36 !important;
color: #93a1a1 !important;
.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;
......
/* https://gist.github.com/qguv/7936275 */
.code.solarized-light {
// Line numbers
.line-numbers, .diff-line-num {
background-color: #fdf6e3;
}
background-color: #fdf6e3 !important;
color: #586e75 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: #fdf6e3 !important;
color: #586e75 !important;
.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;
......
/* https://github.com/aahan/pygments-github-style */
.code.white {
// Line numbers
.line-numbers, .diff-line-num {
background-color: $background-color;
}
background-color: #f8fafc !important;
color: #5b6169 !important;
pre.highlight,
.line-numbers,
.line-numbers a {
background-color: $background-color !important;
color: $gl-gray !important;
.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
......
......@@ -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;
}
}
......@@ -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;
}
}
}
}
\ No newline at end of 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);
......
......@@ -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;
}
}
}
......@@ -558,3 +558,9 @@ pre.light-well {
width: 101%;
}
}
.cannot-be-merged,
.cannot-be-merged:hover {
color: #E62958;
margin-top: 2px;
}
......@@ -3,10 +3,6 @@
border-bottom: 1px solid #DDD;
padding-bottom: 15px;
margin-bottom: 15px;
.term {
height: 22px;
}
}
}
......
......@@ -74,9 +74,13 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_timeout,
:metrics_method_call_threshold,
:metrics_sample_interval,
:ip_blocking_enabled,
:dnsbl_servers_list,
:recaptcha_enabled,
:recaptcha_site_key,
:recaptcha_private_key,
:sentry_enabled,
:sentry_dsn,
restricted_visibility_levels: [],
import_sources: []
)
......
......@@ -15,6 +15,7 @@ class ApplicationController < ActionController::Base
before_action :check_password_expiration
before_action :check_2fa_requirement
before_action :ldap_security_check
before_action :sentry_user_context
before_action :default_headers
before_action :add_gon_variables
before_action :configure_permitted_parameters, if: :devise_controller?
......@@ -24,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)
......@@ -41,6 +43,16 @@ class ApplicationController < ActionController::Base
protected
def sentry_user_context
if Rails.env.production? && current_application_settings.sentry_enabled && current_user
Raven.user_context(
id: current_user.id,
email: current_user.email,
username: current_user.username,
)
end
end
# From https://github.com/plataformatec/devise/wiki/How-To:-Simple-Token-Authentication-Example
# https://gist.github.com/josevalim/fb706b1e933ef01e4fb6
def authenticate_user_from_token!
......
......@@ -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
......@@ -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 = ''
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -8,6 +8,11 @@ class RegistrationsController < Devise::RegistrationsController
def create
if !Gitlab::Recaptcha.load_configurations! || verify_recaptcha
if Gitlab::IpCheck.new(request.remote_ip).spam?
flash[:alert] = 'Could not create an account. This IP is listed for spam.'
return render action: 'new'
end
super
else
flash[:alert] = "There was an error with the reCAPTCHA code below. Please re-enter the code."
......
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'
)
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
def highlighter(blob_name, blob_content, nowrap: false)
Gitlab::Highlight.new(blob_name, blob_content, nowrap: nowrap)
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 = {
......
......@@ -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')
......
......@@ -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
......
......@@ -3,13 +3,26 @@ module Emails
def build_fail_email(build_id, to)
@build = Ci::Build.find(build_id)
@project = @build.project
add_project_headers
add_build_headers
headers['X-GitLab-Build-Status'] = "failed"
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
end
def build_success_email(build_id, to)
@build = Ci::Build.find(build_id)
@project = @build.project
add_project_headers
add_build_headers
headers['X-GitLab-Build-Status'] = "success"
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
end
private
def add_build_headers
headers['X-GitLab-Build-Id'] = @build.id
headers['X-GitLab-Build-Ref'] = @build.ref
end
end
end
......@@ -43,7 +43,7 @@ module Emails
@current_user = @created_by = User.find(created_by_id)
@access_level = access_level
@invite_email = invite_email
@target_url = namespace_project_url(@project.namespace, @project)
mail(to: @created_by.notification_email,
......@@ -65,6 +65,10 @@ module Emails
# used in notify layout
@target_url = @message.target_url
@project = Project.find project_id
add_project_headers
headers['X-GitLab-Author'] = @message.author_username
mail(from: sender(@message.author_id, @message.send_from_committer_email?),
reply_to: @message.reply_to,
......
......@@ -100,12 +100,7 @@ class Notify < BaseMailer
end
def mail_thread(model, headers = {})
if @project
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
add_project_headers
headers["X-GitLab-#{model.class.name}-ID"] = model.id
headers['X-GitLab-Reply-Key'] = reply_key
......@@ -152,4 +147,12 @@ class Notify < BaseMailer
def reply_key
@reply_key ||= SentNotification.reply_key
end
def add_project_headers
return unless @project
headers['X-GitLab-Project'] = @project.name
headers['X-GitLab-Project-Id'] = @project.id
headers['X-GitLab-Project-Path'] = @project.path_with_namespace
end
end
......@@ -41,6 +41,10 @@
# recaptcha_site_key :string
# recaptcha_private_key :string
# metrics_port :integer default(8089)
# sentry_enabled :boolean default(FALSE)
# sentry_dsn :string
# ip_blocking_enabled :boolean default(FALSE)
# dns_blacklist_threshold :float default(0.33)
#
class ApplicationSetting < ActiveRecord::Base
......@@ -82,6 +86,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
if: :recaptcha_enabled
validates :sentry_dsn,
presence: true,
if: :sentry_enabled
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
......
......@@ -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
......
......@@ -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?
......
......@@ -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
......
......@@ -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
......@@ -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
......
......@@ -33,7 +33,7 @@ class Note < ActiveRecord::Base
participant :author
belongs_to :project
belongs_to :noteable, polymorphic: true
belongs_to :noteable, polymorphic: true, touch: true
belongs_to :author, class_name: "User"
belongs_to :updated_by, class_name: "User"
......@@ -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
......
......@@ -272,6 +272,10 @@ class Project < ActiveRecord::Base
query: "%#{query.try(:downcase)}%")
end
def search_by_visibility(level)
where(visibility_level: Gitlab::VisibilityLevel.const_get(level.upcase))
end
def search_by_title(query)
where('projects.archived = ?', false).where('LOWER(projects.name) LIKE :query', query: "%#{query.downcase}%")
end
......@@ -468,12 +472,9 @@ class Project < ActiveRecord::Base
!external_issue_tracker
end
def external_issues_trackers
services.select(&:issue_tracker?).reject(&:default?)
end
def external_issue_tracker
@external_issues_tracker ||= external_issues_trackers.find(&:activated?)
@external_issue_tracker ||=
services.issue_trackers.active.without_defaults.first
end
def can_have_issues_tracker_id?
......
......@@ -23,14 +23,12 @@
# List methods you need to implement to get your CI service
# working with GitLab Merge Requests
class CiService < Service
def category
:ci
end
default_value_for :category, 'ci'
def valid_token?(token)
self.respond_to?(:token) && self.token.present? && self.token == token
end
def supported_events
%w(push)
end
......
......@@ -24,9 +24,7 @@ class GitlabIssueTrackerService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
def default?
true
end
default_value_for :default, true
def to_param
'gitlab'
......
......@@ -23,12 +23,10 @@ class IssueTrackerService < Service
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
def category
:issue_tracker
end
default_value_for :category, 'issue_tracker'
def default?
false
default
end
def issue_url(iid)
......
......@@ -43,6 +43,9 @@ class Service < ActiveRecord::Base
validates :project_id, presence: true, unless: Proc.new { |service| service.template? }
scope :visible, -> { where.not(type: ['GitlabIssueTrackerService', 'GitlabCiService']) }
scope :issue_trackers, -> { where(category: 'issue_tracker') }
scope :active, -> { where(active: true) }
scope :without_defaults, -> { where(default: false) }
scope :push_hooks, -> { where(push_events: true, active: true) }
scope :tag_push_hooks, -> { where(tag_push_events: true, active: true) }
......@@ -51,6 +54,8 @@ class Service < ActiveRecord::Base
scope :note_hooks, -> { where(note_events: true, active: true) }
scope :build_hooks, -> { where(build_events: true, active: true) }
default_value_for :category, 'common'
def activated?
active
end
......@@ -60,7 +65,7 @@ class Service < ActiveRecord::Base
end
def category
:common
read_attribute(:category).to_sym
end
def initialize_properties
......@@ -153,7 +158,7 @@ class Service < ActiveRecord::Base
# Returns a hash of the properties that have been assigned a new value since last save,
# indicating their original values (attr => original value).
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
# ActiveRecord does not provide a mechanism to track changes in serialized keys,
# so we need a specific implementation for service properties.
# This allows to track changes to properties set with the accessor methods,
# but not direct manipulation of properties hash.
......@@ -164,7 +169,7 @@ class Service < ActiveRecord::Base
def reset_updated_properties
@updated_properties = nil
end
def async_execute(data)
return unless supported_events.include?(data[:object_kind])
......
......@@ -664,7 +664,10 @@ class User < ActiveRecord::Base
end
def all_emails
[self.email, *self.emails.map(&:email)]
all_emails = []
all_emails << self.email unless self.temp_oauth_email?
all_emails.concat(self.emails.map(&:email))
all_emails
end
def hook_attrs
......
......@@ -376,10 +376,10 @@ class NotificationService
end
def reassign_resource_email(target, project, current_user, method)
previous_assignee_id = previous_record(target, "assignee_id")
previous_assignee_id = previous_record(target, 'assignee_id')
previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
recipients = build_recipients(target, project, current_user, [previous_assignee])
recipients = build_recipients(target, project, current_user, action: :reassign, previous_assignee: previous_assignee)
recipients.each do |recipient|
mailer.send(
......@@ -400,22 +400,27 @@ class NotificationService
end
end
def build_recipients(target, project, current_user, extra_recipients = nil)
def build_recipients(target, project, current_user, action: nil, previous_assignee: nil)
recipients = target.participants(current_user)
recipients = recipients.concat(extra_recipients).compact.uniq if extra_recipients
recipients = add_project_watchers(recipients, project)
recipients = reject_mention_users(recipients, project)
recipients = reject_muted_users(recipients, project)
# Re-assign is considered as a mention of the new assignee so we add the
# new assignee to the list of recipients after we rejected users with
# the "on mention" notification level
if action == :reassign
recipients << previous_assignee if previous_assignee
recipients << target.assignee
end
recipients = reject_muted_users(recipients, project)
recipients = add_subscribed_users(recipients, target)
recipients = reject_unsubscribed_users(recipients, target)
recipients.delete(current_user)
recipients = recipients.uniq
recipients
recipients.uniq
end
def mailer
......
......@@ -212,6 +212,22 @@
%fieldset
%legend Spam and Anti-bot Protection
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :ip_blocking_enabled do
= f.check_box :ip_blocking_enabled
Enable IP check against blacklist at sign-up
.help-block Helps preventing accounts creation from 'known spam sources'
.form-group
= f.label :dnsbl_servers_list, class: 'control-label col-sm-2' do
DNSBL servers list
.col-sm-10
= f.text_field :dnsbl_servers_list, class: 'form-control'
.help-block
Please enter DNSBL servers separated with comma
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
......@@ -226,11 +242,30 @@
= f.text_field :recaptcha_site_key, class: 'form-control'
.help-block
Generate site and private keys here:
%a{ href: 'http://www.google.com/recaptcha', target: 'blank'} http://www.google.com/recaptcha
%a{ href: 'http://www.google.com/recaptcha', target: '_blank'} http://www.google.com/recaptcha
.form-group
= f.label :recaptcha_private_key, 'reCAPTCHA Private Key', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :recaptcha_private_key, class: 'form-control'
%fieldset
%legend Error Reporting and Logging
%p
These settings require a restart to take effect.
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :sentry_enabled do
= f.check_box :sentry_enabled
Enable Sentry
.help-block
Sentry is an error reporting and logging tool which is currently not shipped with GitLab, get it here:
%a{ href: 'https://getsentry.com', target: '_blank' } https://getsentry.com
.form-group
= f.label :sentry_dsn, 'Sentry DSN', class: 'control-label col-sm-2'
.col-sm-10
= f.text_field :sentry_dsn, class: 'form-control'
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
......@@ -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
......@@ -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
......@@ -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
......@@ -37,3 +37,6 @@
%h1.title= title
= render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
:javascript
var findFileURL = "#{namespace_project_find_file_path(@project.namespace, @project, @ref || @project.repository.root_ref)}";
\ No newline at end of file
......@@ -21,10 +21,10 @@
.form-group
= f.label :email, class: "control-label"
.col-sm-10
- if @user.ldap_user?
- if @user.ldap_user? && @user.ldap_email?
= f.text_field :email, class: "form-control", required: true, readonly: true
%span.help-block.light
Email is read-only for LDAP user
Your email address was automatically set based on the LDAP server.
- else
- if @user.temp_oauth_email?
= f.text_field :email, class: "form-control", required: true, value: nil
......
......@@ -6,4 +6,3 @@
%span.str-truncated
= link_to directory.name, path_to_directory
%td
%td
......@@ -7,5 +7,3 @@
= link_to file.name, path_to_file
%td
= number_to_human_size(file.metadata[:size], precision: 2)
%td
= number_to_human_size(file.metadata[:zipped], precision: 2)
......@@ -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
......@@ -15,14 +15,8 @@
%tr
%th Name
%th Size
%th Compressed to
= render partial: 'tree_directory', collection: @entry.directories(parent: true), as: :directory
= render partial: 'tree_file', collection: @entry.files, as: :file
- if @entry.empty?
.center Empty
:javascript
$(document).on('click', 'tr[data-link]', function(e) {
window.location = this.dataset.link;
});
......@@ -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)}
......@@ -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 }
......
......@@ -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.
......@@ -6,7 +6,12 @@
- if can?(current_user, :manage_builds, @project)
.pull-left.hidden-xs
- if @all_builds.running_or_pending.any?
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project), data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
= link_to ci_lint_path, class: 'btn btn-default' do
= icon('wrench')
%span CI Lint
%ul.nav-links
%li{class: ('active' if @scope.nil?)}
......
......@@ -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
......
......@@ -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"
......@@ -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
......
- 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
......
.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)
......
......@@ -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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment