Commit 98305c17 authored by Valery Sizov's avatar Valery Sizov

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into ce_upstream

parents 6fef1152 68162ba9
CHANGELOG merge=union
CHANGELOG-EE merge=union
*.js.es6 gitlab-language=javascript
Please view this file on the master branch, on stable branches it's out of date.
v 8.11.0 (unreleased)
- Remove magic comments (`# encoding: UTF-8`) from Ruby files !5456 (winniehell)
- Fix CI status icon link underline (ClemMakesApps)
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
- Limit git rev-list output count to one in forced push check
v 8.10.0 (unreleased)
- Add green outline to New Branch button !5447 (winniehell)
- Retrieve rendered HTML from cache in one request
- Nokogiri's various parsing methods are now instrumented
- Make fork counter always clickable !5463 (winniehell)
- Load project invited groups and members eagerly in ProjectTeam#fetch_members
- Add GitLab Workhorse version to admin dashboard (Katarzyna Kobierska Ula Budziszewska)
- Add ES6 gem
v 8.10.2 (unreleased)
- User can now search branches by name. !5144
- Fix backup restore. !5459
- Use project ID in repository cache to prevent stale data from persisting across projects. !5460
v 8.10.1
- Refactor repository storages documentation. !5428
- Gracefully handle case when keep-around references are corrupted or exist already. !5430
- Add detailed info on storage path mountpoints. !5437
- Fix Error 500 when creating Wiki pages with hyphens or spaces. !5444
- Fix bug where replies to commit notes displayed in the MR discussion tab wouldn't show up on the commit page. !5446
- Ignore invalid trusted proxies in X-Forwarded-For header. !5454
- Add links to the real markdown.md file for all GFM examples. !5458
- Remove `search_id` of labels dropdown filter to fix 'Missleading URI for labels in Merge Requests and Issues view' !5368 (Scott Le)
v 8.10.1 (unreleased)
- Fix bug where replies to commit notes displayed in the MR discussion tab wouldn't show up on the commit page
v 8.10.0
- Fix profile activity heatmap to show correct day name (eanplatter)
- Speed up ExternalWikiHelper#get_project_wiki_path
- Expose {should,force}_remove_source_branch (Ben Boeckel)
......@@ -21,6 +48,7 @@ v 8.10.0 (unreleased)
- Delete award emoji when deleting a user
- Remove pinTo from Flash and make inline flash messages look nicer. !4854 (winniehell)
- Add an API for downloading latest successful build from a particular branch or tag. !5347
- Avoid data-integrity issue when cleaning up repository archive cache.
- Add link to profile to commit avatar. !5163 (winniehell)
- Wrap code blocks on Activies and Todos page. !4783 (winniehell)
- Align flash messages with left side of page content. !4959 (winniehell)
......
......@@ -9,6 +9,7 @@ gem 'responders', '~> 2.0'
# Specify a sprockets version due to increased performance
# See https://gitlab.com/gitlab-org/gitlab-ce/issues/6069
gem 'sprockets', '~> 3.6.0'
gem 'sprockets-es6'
# Default values for AR models
gem 'default_value_for', '~> 3.0.0'
......@@ -358,5 +359,5 @@ gem 'paranoia', '~> 2.0'
gem 'health_check', '~> 2.1.0'
# System information
gem 'vmstat', '~> 2.1.0'
gem 'vmstat', '~> 2.1.1'
gem 'sys-filesystem', '~> 1.1.6'
......@@ -85,6 +85,10 @@ GEM
faraday (~> 0.9)
faraday_middleware (~> 0.10)
nokogiri (~> 1.6)
babel-source (5.8.35)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
execjs (~> 2.0)
babosa (1.0.2)
base32 (0.3.2)
bcrypt (3.1.11)
......@@ -724,6 +728,10 @@ GEM
sprockets (3.6.3)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
sprockets-es6 (0.9.0)
babel-source (>= 5.8.11)
babel-transpiler
sprockets (>= 3.0.0)
sprockets-rails (3.1.1)
actionpack (>= 4.0)
activesupport (>= 4.0)
......@@ -802,7 +810,7 @@ GEM
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
vmstat (2.1.0)
vmstat (2.1.1)
warden (1.2.6)
rack (>= 1.0)
web-console (2.3.0)
......@@ -996,6 +1004,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.1.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 3.6.0)
sprockets-es6
state_machines-activerecord (~> 0.4.0)
sys-filesystem (~> 1.1.6)
task_list (~> 1.0.2)
......@@ -1014,7 +1023,7 @@ DEPENDENCIES
validates_hostname (~> 1.0.0)
version_sorter (~> 2.0.0)
virtus (~> 1.0.1)
vmstat (~> 2.1.0)
vmstat (~> 2.1.1)
web-console (~> 2.0)
webmock (~> 1.21.0)
wikicloth (= 0.8.1)
......
8.10.0-ee-pre
8.11.0-ee-pre
......@@ -12,7 +12,10 @@
/*= require jquery.atwho */
/*= require jquery.scrollTo */
/*= require jquery.turbolinks */
<<<<<<< HEAD
/*= require jquery.tablesorter */
=======
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
/*= require turbolinks */
/*= require autosave */
/*= require bootstrap/affix */
......@@ -129,8 +132,11 @@
window.addEventListener("hashchange", shiftWindow);
<<<<<<< HEAD
$.timeago.settings.allowFuture = true;
=======
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
window.onload = function() {
if (location.hash) {
return setTimeout(shiftWindow, 100);
......@@ -232,6 +238,7 @@
});
$document.off("click", '.js-confirm-danger');
$document.on("click", '.js-confirm-danger', function(e) {
<<<<<<< HEAD
var btn, form, text, warningMessage;
e.preventDefault();
btn = $(e.target);
......@@ -241,6 +248,14 @@
return new ConfirmDangerModal(form, text, {
warningMessage: warningMessage
});
=======
var btn, form, text;
e.preventDefault();
btn = $(e.target);
text = btn.data("confirm-danger-message");
form = btn.closest("form");
return new ConfirmDangerModal(form, text);
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
});
$document.on('click', 'button', function() {
return $(this).blur();
......
(function() {
this.ConfirmDangerModal = (function() {
<<<<<<< HEAD
function ConfirmDangerModal(form, text, arg) {
var project_path, submit, warningMessage;
warningMessage = (arg != null ? arg : {}).warningMessage;
......@@ -8,6 +9,12 @@
if (warningMessage) {
$('.js-warning-text').html(warningMessage);
}
=======
function ConfirmDangerModal(form, text) {
var project_path, submit;
this.form = form;
$('.js-confirm-text').text(text || '');
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
$('.js-confirm-danger-input').val('');
$('#modal-confirm-danger').modal('show');
project_path = $('.js-confirm-danger-match').text();
......
......@@ -171,6 +171,7 @@
break;
case 'search:show':
new Search();
<<<<<<< HEAD
break;
case 'projects:mirrors:show':
case 'projects:mirrors:update':
......@@ -178,6 +179,8 @@
break;
case 'admin:emails:show':
new AdminEmailSelect();
=======
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
}
switch (path.first()) {
case 'admin':
......
......@@ -5,14 +5,20 @@
function GroupsSelect() {
$('.ajax-groups-select').each((function(_this) {
return function(i, select) {
<<<<<<< HEAD
var skip_group, url;
skip_group = $(select).data("skip-group");
url = $(select).data("url");
=======
var skip_ldap;
skip_ldap = $(select).hasClass('skip_ldap');
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
return $(select).select2({
placeholder: "Search for a group",
multiple: $(select).hasClass('multiselect'),
minimumInputLength: 0,
query: function(query) {
<<<<<<< HEAD
return $.ajax({
url: url,
data: {
......@@ -32,6 +38,13 @@
}
data.results.push(group);
}
=======
return Api.groups(query.term, skip_ldap, function(groups) {
var data;
data = {
results: groups
};
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
return query.callback(data);
});
},
......
......@@ -35,9 +35,12 @@
}
});
};
<<<<<<< HEAD
gl.utils.capitalize = function(str) {
return str[0].toUpperCase() + str.slice(1);
};
=======
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
gl.utils.getPagePath = function() {
return $('body').data('page').split(':')[0];
};
......
......@@ -61,6 +61,7 @@
callback = function() {
return merge_request_widget.mergeInProgress(deleteSourceBranch);
};
<<<<<<< HEAD
return setTimeout(callback, 1000);
}
};
......@@ -79,6 +80,9 @@
return setTimeout(merge_request_widget.rebaseInProgress, 1000);
} else {
return location.reload();
=======
return setTimeout(callback, 2000);
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
}
};
})(this),
......
......@@ -181,7 +181,11 @@
_this.last_fetched_at = data.last_fetched_at;
_this.setPollingInterval(data.notes.length);
return $.each(notes, function(i, note) {
<<<<<<< HEAD
if (note.discussion_with_diff_html != null) {
=======
if (note.discussion_html != null) {
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
return _this.renderDiscussionNote(note);
} else {
return _this.renderNote(note);
......@@ -287,12 +291,20 @@
discussionContainer = $(".notes[data-discussion-id='" + note.original_discussion_id + "']");
}
if (discussionContainer.length === 0) {
<<<<<<< HEAD
row.after(note.discussion_html);
=======
row.after(note.diff_discussion_html);
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
row.next().find(".note").remove();
discussionContainer = $(".notes[data-discussion-id='" + note.discussion_id + "']");
discussionContainer.append(note_html);
if ($('body').attr('data-page').indexOf('projects:merge_request') === 0) {
<<<<<<< HEAD
$('ul.main-notes-list').append(note.discussion_with_diff_html).syntaxHighlight();
=======
$('ul.main-notes-list').append(note.discussion_html).syntaxHighlight();
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
}
} else {
discussionContainer.append(note_html);
......
......@@ -16,12 +16,20 @@
ProjectNew.prototype.toggleSettings = function() {
this._showOrHide('#project_builds_enabled', '.builds-feature');
<<<<<<< HEAD
this._showOrHide('#project_merge_requests_enabled', '.merge-requests-feature');
return this._showOrHide('#project_issues_enabled', '.issues-feature');
};
ProjectNew.prototype.toggleSettingsOnclick = function() {
return $('#project_builds_enabled, #project_merge_requests_enabled, #project_issues_enabled').on('click', this.toggleSettings);
=======
return this._showOrHide('#project_merge_requests_enabled', '.merge-requests-feature');
};
ProjectNew.prototype.toggleSettingsOnclick = function() {
return $('#project_builds_enabled, #project_merge_requests_enabled').on('click', this.toggleSettings);
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
};
ProjectNew.prototype._showOrHide = function(checkElement, container) {
......
......@@ -185,6 +185,7 @@
$('.ajax-users-select').each((function(_this) {
return function(i, select) {
var firstUser, showAnyUser, showEmailUser, showNullUser;
<<<<<<< HEAD
_this.skipLdap = $(select).hasClass('skip_ldap');
_this.projectId = $(select).data('project-id');
_this.groupId = $(select).data('group-id');
......@@ -192,6 +193,12 @@
_this.pushCodeToProtectedBranches = $(select).data('push-code-to-protected-branches');
_this.authorId = $(select).data('author-id');
_this.skipUsers = $(select).data('skip-users');
=======
_this.projectId = $(select).data('project-id');
_this.groupId = $(select).data('group-id');
_this.showCurrentUser = $(select).data('current-user');
_this.authorId = $(select).data('author-id');
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
showNullUser = $(select).data('null-user');
showAnyUser = $(select).data('any-user');
showEmailUser = $(select).data('email-user');
......@@ -322,11 +329,16 @@
active: true,
project_id: this.projectId,
group_id: this.groupId,
<<<<<<< HEAD
skip_ldap: this.skipLdap,
current_user: this.showCurrentUser,
push_code_to_protected_branches: this.pushCodeToProtectedBranches,
author_id: this.authorId,
skip_users: this.skipUsers
=======
current_user: this.showCurrentUser,
author_id: this.authorId
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
},
dataType: "json"
}).done(function(users) {
......
......@@ -5,6 +5,7 @@
height: 40px;
padding: 0;
@include border-radius($avatar_radius);
border: 1px solid rgba(0, 0, 0, .1);
&.avatar-inline {
float: none;
......@@ -15,8 +16,9 @@
&.s24 { margin-right: 4px; }
}
&.group-avatar, &.project-avatar, &.avatar-tile {
&.avatar-tile {
@include border-radius(0);
border: none;
}
&.s16 { width: 16px; height: 16px; margin-right: 6px; }
......@@ -43,12 +45,12 @@
&.s16 { font-size: 12px; line-height: 1.33; }
&.s24 { font-size: 14px; line-height: 1.8; }
&.s26 { font-size: 20px; line-height: 1.33; }
&.s32 { font-size: 20px; line-height: 32px; }
&.s40 { font-size: 16px; line-height: 40px; }
&.s60 { font-size: 32px; line-height: 60px; }
&.s70 { font-size: 34px; line-height: 70px; }
&.s90 { font-size: 36px; line-height: 90px; }
&.s110 { font-size: 40px; line-height: 112px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 140px; }
&.s160 { font-size: 96px; line-height: 160px; }
&.s32 { font-size: 20px; line-height: 30px; }
&.s40 { font-size: 16px; line-height: 38px; }
&.s60 { font-size: 32px; line-height: 58px; }
&.s70 { font-size: 34px; line-height: 68px; }
&.s90 { font-size: 36px; line-height: 88px; }
&.s110 { font-size: 40px; line-height: 108px; font-weight: 300; }
&.s140 { font-size: 72px; line-height: 138px; }
&.s160 { font-size: 96px; line-height: 158px; }
}
......@@ -135,6 +135,15 @@
@include btn-green;
}
&.btn-inverted {
&.btn-success,
&.btn-new,
&.btn-create,
&.btn-save {
@include btn-outline($white-light, $green-normal, $green-normal, $green-light, $white-light, $green-light);
}
}
&.btn-gray {
@include btn-gray;
}
......
......@@ -350,6 +350,7 @@
.dropdown-input-field, .default-dropdown-input {
width: 100%;
min-height: 30px;
padding: 0 7px;
color: $dropdown-input-color;
line-height: 30px;
......
......@@ -10,83 +10,48 @@
// preference): plain class selectors, type (element name) selectors, or
// explicit child selectors.
table.code {
width: 100%;
.code {
background-color: #fff;
font-family: monospace;
border: none;
border-collapse: separate;
margin: 0;
padding: 0;
font-size: $code_font_size;
-premailer-cellpadding: 0;
-premailer-cellspacing: 0;
-premailer-width: 100%;
> tr > td {
> tr {
line-height: $code_line_height;
font-family: monospace;
font-size: $code_font_size;
}
}
&.diff-line-num {
margin: 0;
padding: 0;
border: none;
.diff-line-num {
padding: 0 5px;
border-right: 1px solid;
text-align: right;
min-width: 35px;
max-width: 50px;
width: 35px;
}
&.line_content {
display: block;
margin: 0;
padding: 0 0.5em;
border: none;
white-space: pre;
}
}
}
.line-numbers, .diff-line-num {
background-color: $background-color;
}
.diff-line-num, .diff-line-num a {
color: $black-transparent;
}
pre.code, .diff-line-num {
border-color: $table-border-gray;
}
.code.white, pre.code, .line_content {
background-color: #fff;
color: #333;
}
border-right: 1px solid $table-border-gray;
.diff-line-num {
&.old {
background-color: $line-number-old;
border-color: $line-removed-dark;
border-right-color: $line-removed-dark;
}
&.new {
background-color: $line-number-new;
border-color: $line-added-dark;
}
&.hll:not(.empty-cell) {
background-color: $line-number-select;
border-color: $line-select-yellow-dark;
border-right-color: $line-added-dark;
}
}
.line_content {
padding-left: 0.5em;
padding-right: 0.5em;
white-space: pre;
&.old {
background-color: $line-removed;
> .line > span.idiff, > .line > span > span.idiff {
> .line > span.idiff,
> .line > span > span.idiff {
background-color: $line-removed-dark;
}
}
......@@ -94,7 +59,8 @@ pre.code, .diff-line-num {
&.new {
background-color: $line-added;
> .line > span.idiff, > .line > span > span.idiff {
> .line > span.idiff,
> .line > span > span.idiff {
background-color: $line-added-dark;
}
}
......@@ -103,14 +69,6 @@ pre.code, .diff-line-num {
color: $black-transparent;
background-color: $match-line;
}
&.hll:not(.empty-cell) {
background-color: $line-select-yellow;
}
}
pre > .hll {
background-color: #f8eec7 !important;
}
span.highlight_word {
......
......@@ -53,6 +53,14 @@
left: 70px;
}
}
.nav-links {
svg {
position: relative;
top: 2px;
margin-right: 3px;
}
}
}
.build-header {
......
......@@ -68,6 +68,12 @@
}
}
.ci-status-link {
svg {
overflow: visible;
}
}
.commit-box {
border-top: 1px solid $border-color;
......
......@@ -36,10 +36,6 @@
.dash-project-avatar {
float: left;
.avatar {
@include border-radius(50%);
}
}
.dash-project-access-icon {
......
......@@ -64,6 +64,7 @@
margin-right: 4px;
position: relative;
top: 1px;
overflow: visible;
}
&.ci-success {
......@@ -215,6 +216,11 @@
position: relative;
top: 3px;
}
&:hover,
&:focus {
text-decoration: none;
}
}
}
}
......
......@@ -29,9 +29,18 @@
}
}
.pipeline-holder {
width: 100%;
overflow: auto;
}
.table.builds {
min-width: 1200px;
&.pipeline {
min-width: 650px;
}
tr {
th {
padding: 16px 8px;
......@@ -76,7 +85,7 @@
svg {
height: 14px;
width: auto;
width: 14px;
vertical-align: middle;
fill: $table-text-gray;
}
......@@ -93,7 +102,7 @@
.commit-title {
margin-top: 4px;
max-width: 320px;
max-width: 300px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
......@@ -138,6 +147,11 @@
height: 18px;
width: 18px;
vertical-align: middle;
overflow: visible;
}
.light {
width: 3px;
}
}
......@@ -153,7 +167,7 @@
svg {
width: 12px;
height: auto;
height: 12px;
vertical-align: middle;
margin-right: 4px;
}
......
......@@ -49,6 +49,7 @@
position: relative;
top: 1px;
margin: 0 3px;
overflow: visible;
}
}
......@@ -74,3 +75,11 @@
color: $gl-gray;
}
}
.visible-xs-inline {
.ci-status-link {
position: relative;
top: 2px;
left: 5px;
}
}
......@@ -6,8 +6,7 @@ class Projects::BranchesController < Projects::ApplicationController
before_action :authorize_push_code!, only: [:new, :create, :destroy]
def index
@sort = params[:sort] || 'name'
@branches = @repository.branches_sorted_by(@sort)
@branches = BranchesFinder.new(@repository, params).execute
@branches = Kaminari.paginate_array(@branches).page(params[:page])
@max_commits = @branches.reduce(0) do |memo, branch|
......
......@@ -115,11 +115,11 @@ class Projects::CommitController < Projects::ApplicationController
end
def define_note_vars
@grouped_diff_notes = commit.notes.grouped_diff_notes
@grouped_diff_discussions = commit.notes.grouped_diff_discussions
@notes = commit.notes.non_diff_notes.fresh
Banzai::NoteRenderer.render(
@grouped_diff_notes.values.flatten + @notes,
@grouped_diff_discussions.values.flat_map(&:notes) + @notes,
@project,
current_user,
)
......
......@@ -54,7 +54,7 @@ class Projects::CompareController < Projects::ApplicationController
)
@diff_notes_disabled = true
@grouped_diff_notes = {}
@grouped_diff_discussions = {}
end
end
......
......@@ -98,7 +98,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
else
build_merge_request
@diff_notes_disabled = true
@grouped_diff_notes = {}
@grouped_diff_discussions = {}
end
define_commit_vars
......@@ -418,7 +418,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
# This is not executed lazily
@notes = Banzai::NoteRenderer.render(
@discussions.flatten,
@discussions.flat_map(&:notes),
@project,
current_user,
@path,
......@@ -444,10 +444,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
}
@use_legacy_diff_notes = !@merge_request.support_new_diff_notes?
@grouped_diff_notes = @merge_request.notes.grouped_diff_notes
@grouped_diff_discussions = @merge_request.notes.grouped_diff_discussions
Banzai::NoteRenderer.render(
@grouped_diff_notes.values.flatten,
@grouped_diff_discussions.values.flat_map(&:notes),
@project,
current_user,
@path,
......
......@@ -73,7 +73,7 @@ class Projects::NotesController < Projects::ApplicationController
end
alias_method :awardable, :note
def note_to_html(note)
def note_html(note)
render_to_string(
"projects/notes/_note",
layout: false,
......@@ -82,20 +82,20 @@ class Projects::NotesController < Projects::ApplicationController
)
end
def note_to_discussion_html(note)
return unless note.diff_note?
def diff_discussion_html(discussion)
return unless discussion.diff_discussion?
if params[:view] == 'parallel'
template = "projects/notes/_diff_notes_with_reply_parallel"
template = "discussions/_parallel_diff_discussion"
locals =
if params[:line_type] == 'old'
{ notes_left: [note], notes_right: [] }
{ discussion_left: discussion, discussion_right: nil }
else
{ notes_left: [], notes_right: [note] }
{ discussion_left: nil, discussion_right: discussion }
end
else
template = "projects/notes/_diff_notes_with_reply"
locals = { notes: [note] }
template = "discussions/_diff_discussion"
locals = { discussion: discussion }
end
render_to_string(
......@@ -106,14 +106,14 @@ class Projects::NotesController < Projects::ApplicationController
)
end
def note_to_discussion_with_diff_html(note)
return unless note.diff_note?
def discussion_html(discussion)
return unless discussion.diff_discussion?
render_to_string(
"projects/notes/_discussion",
"discussions/_discussion",
layout: false,
formats: [:html],
locals: { discussion_notes: [note] }
locals: { discussion: discussion }
)
end
......@@ -132,13 +132,19 @@ class Projects::NotesController < Projects::ApplicationController
valid: true,
id: note.id,
discussion_id: note.discussion_id,
html: note_to_html(note),
html: note_html(note),
award: false,
note: note.note,
discussion_html: note_to_discussion_html(note),
discussion_with_diff_html: note_to_discussion_with_diff_html(note)
note: note.note
}
if note.diff_note?
discussion = Discussion.new([note])
attrs.merge!(
diff_discussion_html: diff_discussion_html(discussion),
discussion_html: discussion_html(discussion)
)
# The discussion_id is used to add the comment to the correct discussion
# element on the merge request page. Among other things, the discussion_id
# contains the sha of head commit of the merge request.
......@@ -153,6 +159,7 @@ class Projects::NotesController < Projects::ApplicationController
if note.new_diff_note? && note.position != note.original_position
attrs[:original_discussion_id] = note.original_discussion_id
end
end
attrs
else
......
class BranchesFinder
def initialize(repository, params)
@repository = repository
@params = params
end
def execute
branches = @repository.branches_sorted_by(sort)
filter_by_name(branches)
end
private
attr_reader :repository, :params
def search
@params[:search].presence
end
def sort
@params[:sort].presence || 'name'
end
def filter_by_name(branches)
if search
branches.select { |branch| branch.name.include?(search) }
else
branches
end
end
end
......@@ -9,6 +9,17 @@ module BranchesHelper
end
end
def filter_branches_path(options = {})
exist_opts = {
search: params[:search],
sort: params[:sort]
}
options = exist_opts.merge(options)
namespace_project_branches_path(@project.namespace, @project, @id, options)
end
def can_push_branch?(project, branch_name)
return false unless project.repository.branch_exists?(branch_name)
......
......@@ -45,10 +45,10 @@ module CiStatusHelper
custom_icon(icon_name)
end
def render_commit_status(commit, tooltip_placement: 'auto left', cssclass: '')
def render_commit_status(commit, tooltip_placement: 'auto left')
project = commit.project
path = builds_namespace_project_commit_path(project.namespace, project, commit)
render_status_with_link('commit', commit.status, path, tooltip_placement, cssclass: cssclass)
render_status_with_link('commit', commit.status, path, tooltip_placement)
end
def render_pipeline_status(pipeline, tooltip_placement: 'auto left')
......
# encoding: utf-8
module CommitsHelper
# Returns a link to the commit author. If the author has a matching user and
# is a member of the current @project it will link to the team member page.
......
......@@ -54,18 +54,20 @@ module DiffHelper
end
end
def organize_comments(left, right)
notes_left = notes_right = nil
def parallel_diff_discussions(left, right, diff_file)
discussion_left = discussion_right = nil
unless left[:type].nil? && right[:type] == 'new'
notes_left = @grouped_diff_notes[left[:line_code]]
if left && (left.unchanged? || left.removed?)
line_code = diff_file.line_code(left)
discussion_left = @grouped_diff_discussions[line_code]
end
unless left[:type].nil? && right[:type].nil?
notes_right = @grouped_diff_notes[right[:line_code]]
if right && right.added?
line_code = diff_file.line_code(right)
discussion_right = @grouped_diff_discussions[line_code]
end
[notes_left, notes_right]
[discussion_left, discussion_right]
end
def inline_diff_btn
......
module NotesHelper
# Helps to distinguish e.g. commit notes in mr notes list
def note_for_main_target?(note)
@noteable.class.name == note.noteable_type && !note.diff_note?
end
def note_target_fields(note)
if note.noteable
hidden_field_tag(:target_type, note.noteable.class.name.underscore) +
......@@ -44,8 +39,8 @@ module NotesHelper
# If we didn't, diff notes that would show for the same line on the changes
# tab, would show in different discussions on the discussion tab.
use_legacy_diff_note ||= begin
line_diff_notes = @grouped_diff_notes[line_code]
line_diff_notes && line_diff_notes.any?(&:legacy_diff_note?)
discussion = @grouped_diff_discussions[line_code]
discussion && discussion.legacy_diff_discussion?
end
data = {
......@@ -81,22 +76,10 @@ module NotesHelper
data
end
def link_to_reply_discussion(note, line_type = nil)
def link_to_reply_discussion(discussion, line_type = nil)
return unless current_user
data = {
noteable_type: note.noteable_type,
noteable_id: note.noteable_id,
commit_id: note.commit_id,
discussion_id: note.discussion_id,
line_type: line_type
}
if note.diff_note?
data[:note_type] = note.type
data.merge!(note.diff_attributes)
end
data = discussion.reply_attributes.merge(line_type: line_type)
content_tag(:div, class: "discussion-reply-holder") do
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
......@@ -114,13 +97,13 @@ module NotesHelper
@max_access_by_user_id[full_key]
end
def diff_note_path(note)
return unless note.diff_note?
def discussion_diff_path(discussion)
return unless discussion.diff_discussion?
if note.for_merge_request? && note.active?
diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
elsif note.for_commit?
namespace_project_commit_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code)
if discussion.for_merge_request? && discussion.active?
diffs_namespace_project_merge_request_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code)
elsif discussion.for_commit?
namespace_project_commit_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code)
end
end
end
......@@ -112,7 +112,8 @@ module SearchHelper
search: params[:search],
project_id: params[:project_id],
group_id: params[:group_id],
scope: params[:scope]
scope: params[:scope],
repository_ref: params[:repository_ref]
}
options = exist_opts.merge(options)
......
module NoteOnDiff
extend ActiveSupport::Concern
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
included do
delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true
end
def diff_note?
true
end
......@@ -30,23 +24,4 @@ module NoteOnDiff
def can_be_award_emoji?
false
end
# Returns an array of at most 16 highlighted lines above a diff note
def truncated_diff_lines
prev_lines = []
highlighted_diff_lines.each do |line|
if line.meta?
prev_lines.clear
else
prev_lines << line
break if for_line?(line)
prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
end
end
prev_lines
end
end
class Discussion
NUMBER_OF_TRUNCATED_DIFF_LINES = 16
attr_reader :first_note, :notes
delegate :created_at,
:project,
:author,
:noteable,
:for_commit?,
:for_merge_request?,
:line_code,
:diff_file,
:for_line?,
:active?,
to: :first_note
delegate :blob, :highlighted_diff_lines, to: :diff_file, allow_nil: true
def self.for_notes(notes)
notes.group_by(&:discussion_id).values.map { |notes| new(notes) }
end
def self.for_diff_notes(notes)
notes.group_by(&:line_code).values.map { |notes| new(notes) }
end
def initialize(notes)
@first_note = notes.first
@notes = notes
end
def id
first_note.discussion_id
end
def diff_discussion?
first_note.diff_note?
end
def legacy_diff_discussion?
notes.any?(&:legacy_diff_note?)
end
def for_target?(target)
self.noteable == target && !diff_discussion?
end
def expanded?
!diff_discussion? || active?
end
def reply_attributes
data = {
noteable_type: first_note.noteable_type,
noteable_id: first_note.noteable_id,
commit_id: first_note.commit_id,
discussion_id: self.id,
}
if diff_discussion?
data[:note_type] = first_note.type
data.merge!(first_note.diff_attributes)
end
data
end
# Returns an array of at most 16 highlighted lines above a diff note
def truncated_diff_lines
prev_lines = []
highlighted_diff_lines.each do |line|
if line.meta?
prev_lines.clear
else
prev_lines << line
break if for_line?(line)
prev_lines.shift if prev_lines.length >= NUMBER_OF_TRUNCATED_DIFF_LINES
end
end
prev_lines
end
end
......@@ -71,7 +71,7 @@ class Note < ActiveRecord::Base
project: [:project_members, { group: [:group_members] }])
end
before_validation :clear_blank_line_code!
before_validation :nullify_blank_type, :nullify_blank_line_code
after_save :keep_around_commit
class << self
......@@ -84,11 +84,12 @@ class Note < ActiveRecord::Base
end
def discussions
all.group_by(&:discussion_id).values
Discussion.for_notes(all)
end
def grouped_diff_notes
diff_notes.select(&:active?).sort_by(&:created_at).group_by(&:line_code)
def grouped_diff_discussions
notes = diff_notes.fresh.select(&:active?)
Discussion.for_diff_notes(notes).map { |d| [d.line_code, d] }.to_h
end
# Searches for notes matching the given query.
......@@ -222,10 +223,6 @@ class Note < ActiveRecord::Base
!system?
end
def clear_blank_line_code!
self.line_code = nil if self.line_code.blank?
end
def can_be_award_emoji?
noteable.is_a?(Awardable)
end
......@@ -243,4 +240,12 @@ class Note < ActiveRecord::Base
def keep_around_commit
project.repository.keep_around(self.commit_id)
end
def nullify_blank_type
self.type = nil if self.type.blank?
end
def nullify_blank_line_code
self.line_code = nil if self.line_code.blank?
end
end
......@@ -462,13 +462,13 @@ class Project < ActiveRecord::Base
# ref can't be HEAD, can only be branch/tag name or SHA
def latest_successful_builds_for(ref = default_branch)
pipeline = pipelines.latest_successful_for(ref).to_sql
join_sql = "INNER JOIN (#{pipeline}) pipelines" +
" ON pipelines.id = #{Ci::Build.quoted_table_name}.commit_id"
builds.joins(join_sql).latest.with_artifacts
# TODO: Whenever we dropped support for MySQL, we could change to:
# pipeline = pipelines.latest_successful_for(ref)
# builds.where(pipeline: pipeline).latest.with_artifacts
latest_pipeline = pipelines.latest_successful_for(ref).first
if latest_pipeline
latest_pipeline.builds.latest.with_artifacts
else
builds.none
end
end
def merge_base_commit(first_commit_id, second_commit_id)
......@@ -989,9 +989,13 @@ class Project < ActiveRecord::Base
old_path_with_namespace = File.join(namespace_dir, path_was)
new_path_with_namespace = File.join(namespace_dir, path)
Rails.logger.error "Attempting to rename #{old_path_with_namespace} -> #{new_path_with_namespace}"
expire_caches_before_rename(old_path_with_namespace)
if has_container_registry_tags?
Rails.logger.error "Project #{old_path_with_namespace} cannot be renamed because container registry tags are present"
# we currently doesn't support renaming repository if it contains tags in container registry
raise Exception.new('Project cannot be renamed, because tags are present in its container registry')
end
......@@ -1010,17 +1014,22 @@ class Project < ActiveRecord::Base
SystemHooksService.new.execute_hooks_for(self, :rename)
@repository = nil
rescue
rescue => e
Rails.logger.error "Exception renaming #{old_path_with_namespace} -> #{new_path_with_namespace}: #{e}"
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
else
Rails.logger.error "Repository could not be renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Exception.new('repository cannot be renamed')
end
Gitlab::AppLogger.info "Project was renamed: #{old_path_with_namespace} -> #{new_path_with_namespace}"
Gitlab::UploadsTransfer.new.rename_project(path_was, path, namespace.path)
Gitlab::PagesTransfer.new.rename_project(path_was, path, namespace.path)
end
......
......@@ -175,7 +175,7 @@ class ProjectTeam
invited_members = []
if project.invited_groups.any? && project.allowed_to_share_with_group?
project.project_group_links.each do |group_link|
project.project_group_links.includes(group: [:group_members]).each do |group_link|
invited_group = group_link.group
im = invited_group.members
......
......@@ -18,16 +18,6 @@ class Repository
attr_accessor :path_with_namespace, :project
def self.clean_old_archives
Gitlab::Metrics.measure(:clean_old_archives) do
repository_downloads_path = Gitlab.config.gitlab.repository_downloads_path
return unless File.directory?(repository_downloads_path)
Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
end
end
def initialize(path_with_namespace, project)
@path_with_namespace = path_with_namespace
@project = project
......@@ -279,11 +269,20 @@ class Repository
return if kept_around?(sha)
rugged.references.create(keep_around_ref_name(sha), sha)
# This will still fail if the file is corrupted (e.g. 0 bytes)
begin
rugged.references.create(keep_around_ref_name(sha), sha, force: true)
rescue Rugged::ReferenceError => ex
Rails.logger.error "Unable to create keep-around reference for repository #{path}: #{ex}"
end
end
def kept_around?(sha)
begin
ref_exists?(keep_around_ref_name(sha))
rescue Rugged::ReferenceError
false
end
end
def tag_names
......@@ -674,6 +673,8 @@ class Repository
# Remove archives older than 2 hours
def branches_sorted_by(value)
case value
when 'name'
branches.sort_by(&:name)
when 'recently_updated'
branches.sort do |a, b|
commit(b.target).committed_date <=> commit(a.target).committed_date
......@@ -1228,7 +1229,7 @@ class Repository
private
def cache
@cache ||= RepositoryCache.new(path_with_namespace)
@cache ||= RepositoryCache.new(path_with_namespace, @project.id)
end
def head_exists?
......
......@@ -44,7 +44,11 @@ class WikiPage
# The escaped URL path of this page.
def slug
if @attributes[:slug].present?
@attributes[:slug]
else
wiki.wiki.preview_page(title, '', format).url_path
end
end
alias_method :to_param, :slug
......
class RepositoryArchiveCleanUpService
LAST_MODIFIED_TIME_IN_MINUTES = 120
def initialize(mmin = LAST_MODIFIED_TIME_IN_MINUTES)
@mmin = mmin
@path = Gitlab.config.gitlab.repository_downloads_path
end
def execute
Gitlab::Metrics.measure(:repository_archive_clean_up) do
return unless File.directory?(path)
clean_up_old_archives
clean_up_empty_directories
end
end
private
attr_reader :mmin, :path
def clean_up_old_archives
run(%W(find #{path} -not -path #{path} -type f \( -name \*.tar -o -name \*.bz2 -o -name \*.tar.gz -o -name \*.zip \) -maxdepth 2 -mmin +#{mmin} -delete))
end
def clean_up_empty_directories
run(%W(find #{path} -not -path #{path} -type d -empty -name \*.git -maxdepth 1 -delete))
end
def run(cmd)
Gitlab::Popen.popen(cmd)
end
end
# encoding: utf-8
class ArtifactUploader < CarrierWave::Uploader::Base
storage :file
......
# encoding: utf-8
class AttachmentUploader < CarrierWave::Uploader::Base
include UploaderHelper
......
# encoding: utf-8
class AvatarUploader < CarrierWave::Uploader::Base
include UploaderHelper
......
# encoding: utf-8
class FileUploader < CarrierWave::Uploader::Base
include UploaderHelper
MARKDOWN_PATTERN = %r{\!?\[.*?\]\(/uploads/(?<secret>[0-9a-f]{32})/(?<file>.*?)\)}
......
# encoding: utf-8
class LfsObjectUploader < CarrierWave::Uploader::Base
storage :file
......
......@@ -90,6 +90,10 @@
GitLab Shell
%span.pull-right
= Gitlab::Shell.new.version
%p
GitLab Workhorse
%span.pull-right
= Gitlab::Workhorse.version
%p
GitLab API
%span.pull-right
......
%tr.notes_holder
%td.notes_line{ colspan: 2 }
%td.notes_content
%ul.notes{ data: { discussion_id: discussion.id } }
= render partial: "projects/notes/note", collection: discussion.notes, as: :note
= link_to_reply_discussion(discussion)
- note = discussion_notes.first
- diff_file = note.diff_file
- return unless diff_file
- blob = note.blob
- diff_file = discussion.diff_file
- blob = discussion.blob
.diff-file.file-holder
.file-title
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: note.project, url: diff_note_path(note)
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion)
.diff-content.code.js-syntax-highlight
%table
- note.truncated_diff_lines.each do |line|
- discussion.truncated_diff_lines.each do |line|
= render "projects/diffs/line", line: line, diff_file: diff_file, plain: true
- if note.for_line?(line)
= render "projects/notes/diff_notes_with_reply", notes: discussion_notes
- if discussion.for_line?(line)
= render "discussions/diff_discussion", discussion: discussion
- note = discussion_notes.first
- expanded = !note.diff_note? || note.active?
- expanded = discussion.expanded?
%li.note.note-discussion.timeline-entry
.timeline-entry-inner
.timeline-icon
= link_to user_path(note.author) do
= image_tag avatar_icon(note.author), class: "avatar s40"
= link_to user_path(discussion.author) do
= image_tag avatar_icon(discussion.author), class: "avatar s40"
.timeline-content
.discussion.js-toggle-container{ class: note.discussion_id }
.discussion.js-toggle-container{ class: discussion.id }
.discussion-header
= link_to_member(@project, note.author, avatar: false)
= link_to_member(@project, discussion.author, avatar: false)
.inline.discussion-headline-light
= note.author.to_reference
= discussion.author.to_reference
started a discussion on
- if note.for_commit?
- commit = note.noteable
- if discussion.for_commit?
- commit = discussion.noteable
- if commit
commit
= link_to commit.short_id, namespace_project_commit_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code), class: 'monospace'
= link_to commit.short_id, namespace_project_commit_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code), class: 'monospace'
- else
a deleted commit
- else
- if note.active?
= link_to diffs_namespace_project_merge_request_path(note.project.namespace, note.project, note.noteable, anchor: note.line_code) do
- if discussion.active?
= link_to diffs_namespace_project_merge_request_path(discussion.project.namespace, discussion.project, discussion.noteable, anchor: discussion.line_code) do
the diff
- else
an outdated diff
= time_ago_with_tooltip(note.created_at, placement: "bottom", html_class: "note-created-ago")
= time_ago_with_tooltip(discussion.created_at, placement: "bottom", html_class: "note-created-ago")
.discussion-actions
= link_to "#", class: "note-action-button discussion-toggle-button js-toggle-button" do
......@@ -40,7 +39,7 @@
Toggle discussion
.discussion-body.js-toggle-content{ class: ("hide" unless expanded) }
- if note.diff_note?
= render "projects/notes/discussions/diff_with_notes", discussion_notes: discussion_notes
- if discussion.diff_discussion? && discussion.diff_file
= render "discussions/diff_with_notes", discussion: discussion
- else
= render "projects/notes/discussions/notes", discussion_notes: discussion_notes
= render "discussions/notes", discussion: discussion
- note = discussion_notes.first
.panel.panel-default
.notes{ data: { discussion_id: note.discussion_id } }
.notes{ data: { discussion_id: discussion.id } }
%ul.notes.timeline
= render partial: "projects/notes/note", collection: discussion_notes, as: :note
= link_to_reply_discussion(note)
= render partial: "projects/notes/note", collection: discussion.notes, as: :note
= link_to_reply_discussion(discussion)
- note_left = notes_left.present? ? notes_left.first : nil
- note_right = notes_right.present? ? notes_right.first : nil
%tr.notes_holder
- if note_left
- if discussion_left
%td.notes_line.old
%td.notes_content.parallel.old
%ul.notes{ data: { discussion_id: note_left.discussion_id } }
= render partial: "projects/notes/note", collection: notes_left, as: :note
%ul.notes{ data: { discussion_id: discussion_left.id } }
= render partial: "projects/notes/note", collection: discussion_left.notes, as: :note
= link_to_reply_discussion(note_left, 'old')
= link_to_reply_discussion(discussion_left, 'old')
- else
%td.notes_line.old= ""
%td.notes_content.parallel.old= ""
- if note_right
- if discussion_right
%td.notes_line.new
%td.notes_content.parallel.new
%ul.notes{ data: { discussion_id: note_right.discussion_id } }
= render partial: "projects/notes/note", collection: notes_right, as: :note
%ul.notes{ data: { discussion_id: discussion_right.id } }
= render partial: "projects/notes/note", collection: discussion_right.notes, as: :note
= link_to_reply_discussion(note_right, 'new')
= link_to_reply_discussion(discussion_right, 'new')
- else
%td.notes_line.new= ""
%td.notes_content.parallel.new= ""
......@@ -6,7 +6,7 @@
.cover-block.groups-cover-block
%div{ class: container_class }
= image_tag group_icon(@group), class: "avatar group-avatar s70"
= image_tag group_icon(@group), class: "avatar group-avatar s70 avatar-tile"
.group-info
.cover-title
%h1
......
......@@ -30,7 +30,7 @@
%span
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
= nav_link(controller: :snippets) do
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, title: 'Snippets' do
%span
Snippets
......
......@@ -6,7 +6,7 @@
- content_for :scripts_body_top do
- project = @target_project || @project
- if @project_wiki && @page
- markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, @page.title)
- markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, @page.slug)
- else
- markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project)
- if current_user
......
- empty_repo = @project.empty_repo?
.project-home-panel.text-center{ class: ("empty-project" if empty_repo) }
%div{ class: container_class }
= project_icon(@project, alt: @project.name, class: 'project-avatar avatar s70')
= project_icon(@project, alt: @project.name, class: 'project-avatar avatar s70 avatar-tile')
%h1.project-title
= @project.name
%span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
......
......@@ -9,29 +9,36 @@
- if can? current_user, :push_code, @project
.nav-controls
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
New branch
= form_tag(filter_branches_path, method: :get) do
= search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
.dropdown.inline
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
- if @sort.present?
= @sort.humanize
- if params[:sort].present?
= params[:sort].humanize
- else
Name
%b.caret
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to namespace_project_branches_path(sort: nil) do
Name
= link_to namespace_project_branches_path(sort: 'recently_updated') do
= link_to filter_branches_path(sort: nil) do
= sort_title_name
= link_to filter_branches_path(sort: 'recently_updated') do
= sort_title_recently_updated
= link_to namespace_project_branches_path(sort: 'last_updated') do
= link_to filter_branches_path(sort: 'last_updated') do
= sort_title_oldest_updated
<<<<<<< HEAD
= render 'projects/commits/mirror_status'
=======
= link_to new_namespace_project_branch_path(@project.namespace, @project), class: 'btn btn-create' do
New branch
>>>>>>> 68162ba900f1b9003fa3d07613333f201be8154a
- if @branches.any?
%ul.content-list.all-branches
- @branches.each do |branch|
= render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab'
- else
.nothing-here-block No branches to show
......@@ -4,10 +4,6 @@
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn has-tooltip' do
= custom_icon('icon_fork')
Fork
%div.count-with-arrow
%span.arrow
%span.count
= @project.forks_count
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn has-tooltip' do
= custom_icon('icon_fork')
......
......@@ -14,8 +14,10 @@
%span ##{build.id}
- if build.stuck?
.icon-container
= icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
- if defined?(retried) && retried
.icon-container
= icon('warning', class: 'text-warning has-tooltip', title: 'Build was retried.')
- if defined?(ref) && ref
......@@ -23,6 +25,7 @@
= link_to build.ref, namespace_project_commits_path(build.project.namespace, build.project, build.ref), class: "monospace branch-name"
- else
.light none
.icon-container
= custom_icon("icon_commit")
- if defined?(commit_sha) && commit_sha
......@@ -88,4 +91,3 @@
- elsif build.playable?
= link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do
= icon('play')
......@@ -35,8 +35,8 @@
.bs-callout.bs-callout-warning
\.gitlab-ci.yml not found in this commit
.table-holder
%table.table.builds
.table-holder.pipeline-holder
%table.table.builds.pipeline
%thead
%tr
%th Status
......
......@@ -19,13 +19,14 @@
&middot;
= commit.short_id
- if commit.status
= render_commit_status(commit, cssclass: 'visible-xs-inline')
.visible-xs-inline
= render_commit_status(commit)
- if commit.description?
%a.text-expander.hidden-xs.js-toggle-button ...
.commit-actions.hidden-xs
- if commit.status
= render_commit_status(commit, cssclass: 'btn btn-transparent')
= render_commit_status(commit)
= clipboard_button(clipboard_text: commit.id)
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit-short-id btn btn-transparent"
= link_to_browse_code(project, commit)
......
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.match= line
%td.new_line.diff-line-num.empty-cell
%td.line_content.parallel.match= line
......@@ -5,32 +5,35 @@
- left = line[:left]
- right = line[:right]
%tr.line_holder.parallel
- if left[:type] == 'match'
= render "projects/diffs/match_line_parallel", { line: left[:text] }
- elsif left[:type] == 'nonewline'
- if left
- if left.meta?
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.match= left[:text]
%td.new_line.diff-line-num.empty-cell
%td.line_content.parallel.match= left[:text]
%td.line_content.parallel.match= left.text
- else
%td.old_line.diff-line-num{id: left[:line_code], class: [left[:type], ('empty-cell' unless left[:number])], data: { linenumber: left[:number] }}
%a{href: "##{left[:line_code]}" }= raw(left[:number])
%td.line_content.parallel.noteable_line{class: [left[:type], ('empty-cell' if left[:text].empty?)], data: diff_view_line_data(left[:line_code], left[:position], 'old')}= diff_line_content(left[:text])
- if right[:type] == 'new'
- new_line_type = 'new'
- new_line_code = right[:line_code]
- new_position = right[:position]
- left_line_code = diff_file.line_code(left)
- left_position = diff_file.position(left)
%td.old_line.diff-line-num{id: left_line_code, class: left.type, data: { linenumber: left.old_pos }}
%a{href: "##{left_line_code}" }= raw(left.old_pos)
%td.line_content.parallel.noteable_line{class: left.type, data: diff_view_line_data(left_line_code, left_position, 'old')}= diff_line_content(left.text)
- else
- new_line_type = nil
- new_line_code = left[:line_code]
- new_position = left[:position]
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel
%td.new_line.diff-line-num{id: new_line_code, class: [new_line_type, ('empty-cell' unless right[:number])], data: { linenumber: right[:number] }}
%a{href: "##{new_line_code}" }= raw(right[:number])
%td.line_content.parallel.noteable_line{class: [new_line_type, ('empty-cell' if right[:text].empty?)], data: diff_view_line_data(new_line_code, new_position, 'new')}= diff_line_content(right[:text])
- if right
- if right.meta?
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel.match= left.text
- else
- right_line_code = diff_file.line_code(right)
- right_position = diff_file.position(right)
%td.new_line.diff-line-num{id: right_line_code, class: right.type, data: { linenumber: right.new_pos }}
%a{href: "##{right_line_code}" }= raw(right.new_pos)
%td.line_content.parallel.noteable_line{class: right.type, data: diff_view_line_data(right_line_code, right_position, 'new')}= diff_line_content(right.text)
- else
%td.old_line.diff-line-num.empty-cell
%td.line_content.parallel
- unless @diff_notes_disabled
- notes_left, notes_right = organize_comments(left, right)
- if notes_left.present? || notes_right.present?
= render "projects/notes/diff_notes_with_reply_parallel", notes_left: notes_left, notes_right: notes_right
- discussion_left, discussion_right = parallel_diff_discussions(left, right, diff_file)
- if discussion_left || discussion_right
= render "discussions/parallel_diff_discussion", discussion_left: discussion_left, discussion_right: discussion_right
......@@ -11,9 +11,9 @@
- unless @diff_notes_disabled
- line_code = diff_file.line_code(line)
- diff_notes = @grouped_diff_notes[line_code] if line_code
- if diff_notes
= render "projects/notes/diff_notes_with_reply", notes: diff_notes
- discussion = @grouped_diff_discussions[line_code] if line_code
- if discussion
= render "discussions/diff_discussion", discussion: discussion
- if last_line > 0
= render "projects/diffs/match_line", { line: "",
......
......@@ -2,7 +2,7 @@
.pull-right
#new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)}
= link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid),
method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
method: :post, class: 'btn btn-new btn-inverted has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
.checking
= icon('spinner spin')
Checking branches
......
- note = notes.first
%tr.notes_holder
%td.notes_line{ colspan: 2 }
%td.notes_content
%ul.notes{ data: { discussion_id: note.discussion_id } }
= render partial: "projects/notes/note", collection: notes, as: :note
= link_to_reply_discussion(note)
- if @discussions.present?
- @discussions.each do |discussion_notes|
- note = discussion_notes.first
- if note_for_main_target?(note)
= render partial: "projects/notes/note", object: note, as: :note
- @discussions.each do |discussion|
- if discussion.for_target?(@noteable)
= render partial: "projects/notes/note", object: discussion.first_note, as: :note
- else
= render 'projects/notes/discussion', discussion_notes: discussion_notes
= render 'discussions/discussion', discussion: discussion
- else
- @notes.each do |note|
= render partial: "projects/notes/note", object: note, as: :note
= render partial: "projects/notes/note", collection: @notes, as: :note
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><circle id="a" cx="4" cy="4" r="4"/><mask id="d" width="8" height="8" x="0" y="0" fill="#fff"><use xlink:href="#a"/></mask><circle id="b" cx="20" cy="4" r="4"/><mask id="e" width="8" height="8" x="0" y="0" fill="#fff"><use xlink:href="#b"/></mask><circle id="c" cx="12" cy="30" r="4"/><mask id="f" width="8" height="8" x="0" y="0" fill="#fff"><use xlink:href="#c"/></mask></defs><g fill="none" fill-rule="evenodd" transform="translate(8 3)"><path fill="#7E7E7E" d="M10 19.667c-4.14-1.29-7.389-5.878-7.389-5.878C2.274 13.353 2 12.545 2 12.01V6h4v5.509c0 .276.166.65.367.831 0 0 1.136 1.028 1.746 1.574C9.617 15.261 11.048 16 12.09 16c1.028 0 2.41-.723 3.858-2.048.588-.54 1.84-1.742 1.84-1.742a.784.784 0 0 0 .211-.502V6h4v6.008c0 .548-.259 1.349-.601 1.795 0 0-3.21 4.707-7.399 5.916V27h-4v-7.333z"/><use stroke="#7E7E7E" stroke-width="4" mask="url(#d)" xlink:href="#a"/><use stroke="#7E7E7E" stroke-width="4" mask="url(#e)" xlink:href="#b"/><use stroke="#7E7E7E" stroke-width="4" mask="url(#f)" xlink:href="#c"/></g></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40">
<path fill="#7E7E7E" fill-rule="evenodd" d="M22,29.5351288 L22,22.7193602 C26.1888699,21.5098039 29.3985457,16.802989 29.3985457,16.802989 C29.740988,16.3567547 30,15.5559546 30,15.0081969 L30,10.4648712 C31.1956027,9.77325238 32,8.48056471 32,7 C32,4.790861 30.209139,3 28,3 C25.790861,3 24,4.790861 24,7 C24,8.48056471 24.8043973,9.77325238 26,10.4648712 L26,14.7083871 C26,14.8784435 25.9055559,15.0987329 25.7890533,15.2104147 C25.7890533,15.2104147 24.5373893,16.4126202 23.9488702,16.9515733 C22.5015398,18.2770075 21.1191354,19 20.090554,19 C19.0477772,19 17.6172728,18.2608988 16.1128852,16.9142923 C15.5030182,16.3683886 14.3672121,15.3403307 14.3672121,15.3403307 C14.1659605,15.1583364 14.0000086,14.7846305 14.0000192,14.5088473 C14.0000192,14.5088473 14.0000932,12.7539451 14.0001308,10.4647956 C15.1956614,9.77315812 16,8.48051074 16,7 C16,4.790861 14.209139,3 12,3 C9.790861,3 8,4.790861 8,7 C8,8.48056471 8.80439726,9.77325238 10,10.4648712 L10,15.0081969 C10,15.5446944 10.2736352,16.3534183 10.6111812,16.7893819 C10.6111812,16.7893819 13.8599776,21.3779363 18,22.6668724 L18,29.5351288 C16.8043973,30.2267476 16,31.5194353 16,33 C16,35.209139 17.790861,37 20,37 C22.209139,37 24,35.209139 24,33 C24,31.5194353 23.1956027,30.2267476 22,29.5351288 Z M14,7 C14,5.8954305 13.1045695,5 12,5 C10.8954305,5 10,5.8954305 10,7 C10,8.1045695 10.8954305,9 12,9 C13.1045695,9 14,8.1045695 14,7 Z M30,7 C30,5.8954305 29.1045695,5 28,5 C26.8954305,5 26,5.8954305 26,7 C26,8.1045695 26.8954305,9 28,9 C29.1045695,9 30,8.1045695 30,7 Z M22,33 C22,31.8954305 21.1045695,31 20,31 C18.8954305,31 18,31.8954305 18,33 C18,34.1045695 18.8954305,35 20,35 C21.1045695,35 22,34.1045695 22,33 Z"/>
</svg>
......@@ -4,7 +4,7 @@
- filter_placeholder = local_assigns.fetch(:filter_placeholder, 'Search labels')
.dropdown-page-one
= dropdown_title(title)
= dropdown_filter(filter_placeholder, search_id: "label-name")
= dropdown_filter(filter_placeholder)
= dropdown_content
- if @project && show_footer
= dropdown_footer do
......
......@@ -4,6 +4,6 @@ class RepositoryArchiveCacheWorker
sidekiq_options queue: :default
def perform
Repository.clean_old_archives
RepositoryArchiveCleanUpService.new.execute
end
end
......@@ -106,8 +106,8 @@ production: &base
## Repository downloads directory
# When a user clicks e.g. 'Download zip' on a project, a temporary zip file is created in the following directory.
# The default is 'tmp/repositories' relative to the root of the Rails app.
# repository_downloads_path: tmp/repositories
# The default is 'shared/cache/archive/' relative to the root of the Rails app.
# repository_downloads_path: shared/cache/archive/
## Reply by email
# Allow users to comment on issues and merge requests by replying to notification emails.
......
......@@ -258,7 +258,6 @@ Settings.gitlab.default_projects_features['snippets'] = false if Setti
Settings.gitlab.default_projects_features['builds'] = true if Settings.gitlab.default_projects_features['builds'].nil?
Settings.gitlab.default_projects_features['container_registry'] = true if Settings.gitlab.default_projects_features['container_registry'].nil?
Settings.gitlab.default_projects_features['visibility_level'] = Settings.send(:verify_constant, Gitlab::VisibilityLevel, Settings.gitlab.default_projects_features['visibility_level'], Gitlab::VisibilityLevel::PRIVATE)
Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive') if Settings.gitlab['repository_downloads_path'].nil?
Settings.gitlab['domain_whitelist'] ||= []
Settings.gitlab['import_sources'] ||= %w[github bitbucket gitlab gitorious google_code fogbugz git gitlab_project]
Settings.gitlab['trusted_proxies'] ||= []
......@@ -406,6 +405,21 @@ Settings.repositories['storages'] ||= {}
# Setting gitlab_shell.repos_path is DEPRECATED and WILL BE REMOVED in version 9.0
Settings.repositories.storages['default'] ||= Settings.gitlab_shell['repos_path'] || Settings.gitlab['user_home'] + '/repositories/'
#
# The repository_downloads_path is used to remove outdated repository
# archives, if someone has it configured incorrectly, and it points
# to the path where repositories are stored this can cause some
# data-integrity issue. In this case, we sets it to the default
# repository_downloads_path value.
#
repositories_storages_path = Settings.repositories.storages.values
repository_downloads_path = Settings.gitlab['repository_downloads_path'].to_s.gsub(/\/$/, '')
repository_downloads_full_path = File.expand_path(repository_downloads_path, Settings.gitlab['user_home'])
if repository_downloads_path.blank? || repositories_storages_path.any? { |path| [repository_downloads_path, repository_downloads_full_path].include?(path.gsub(/\/$/, '')) }
Settings.gitlab['repository_downloads_path'] = File.join(Settings.shared['path'], 'cache/archive')
end
#
# Backup
#
......
......@@ -3,22 +3,27 @@ def storage_name_valid?(name)
end
def find_parent_path(name, path)
parent = Pathname.new(path).realpath.parent
Gitlab.config.repositories.storages.detect do |n, p|
name != n && path.chomp('/').start_with?(p.chomp('/'))
name != n && Pathname.new(p).realpath == parent
end
end
def error(message)
def storage_validation_error(message)
raise "#{message}. Please fix this in your gitlab.yml before starting GitLab."
end
error('No repository storage path defined') if Gitlab.config.repositories.storages.empty?
def validate_storages
storage_validation_error('No repository storage path defined') if Gitlab.config.repositories.storages.empty?
Gitlab.config.repositories.storages.each do |name, path|
error("\"#{name}\" is not a valid storage name") unless storage_name_valid?(name)
Gitlab.config.repositories.storages.each do |name, path|
storage_validation_error("\"#{name}\" is not a valid storage name") unless storage_name_valid?(name)
parent_name, _parent_path = find_parent_path(name, path)
if parent_name
error("#{name} is a nested path of #{parent_name}. Nested paths are not supported for repository storages")
storage_validation_error("#{name} is a nested path of #{parent_name}. Nested paths are not supported for repository storages")
end
end
end
validate_storages unless Rails.env.test?
......@@ -136,6 +136,13 @@ if Gitlab::Metrics.enabled?
config.instrument_instance_methods(Rouge::Plugins::Redcarpet)
config.instrument_instance_methods(Rouge::Formatters::HTMLGitlab)
[:XML, :HTML].each do |namespace|
namespace_mod = Nokogiri.const_get(namespace)
config.instrument_methods(namespace_mod)
config.instrument_methods(namespace_mod::Document)
end
config.instrument_methods(Rinku)
end
......
......@@ -11,6 +11,12 @@ module Rack
end
end
gitlab_trusted_proxies = Array(Gitlab.config.gitlab.trusted_proxies).map do |proxy|
begin
IPAddr.new(proxy)
rescue IPAddr::InvalidAddressError
end
end.compact
Rails.application.config.action_dispatch.trusted_proxies = (
[ '127.0.0.1', '::1' ] + Array(Gitlab.config.gitlab.trusted_proxies)
).map { |proxy| IPAddr.new(proxy) }
[ '127.0.0.1', '::1' ] + gitlab_trusted_proxies)
class NullifyBlankTypeOnNotes < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
execute "UPDATE notes SET type = NULL WHERE type = ''"
end
end
......@@ -283,6 +283,40 @@ Response:
[ce-2893]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/2893
## Download the artifacts file
> [Introduced][ce-5347] in GitLab 8.10.
Download the artifacts file from the given reference name and job provided the
build finished successfully.
```
GET /projects/:id/builds/artifacts/:ref_name/download?job=name
```
Parameters
| Attribute | Type | Required | Description |
|-------------|---------|----------|-------------------------- |
| `id` | integer | yes | The ID of a project |
| `ref_name` | string | yes | The ref from a repository |
| `job` | string | yes | The name of the job |
Example request:
```
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/1/builds/artifacts/master/download?job=test"
```
Example response:
| Status | Description |
|-----------|---------------------------------|
| 200 | Serves the artifacts file |
| 404 | Build not found or no artifacts |
[ce-5347]: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/5347
## Get a trace file
Get a trace of a specific build of a project
......@@ -409,7 +443,7 @@ POST /projects/:id/builds/:build_id/erase
Parameters
| Attribute | Type | required | Description |
| Attribute | Type | Required | Description |
|-------------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a project |
| `build_id` | integer | yes | The ID of a build |
......@@ -459,7 +493,7 @@ POST /projects/:id/builds/:build_id/artifacts/keep
Parameters
| Attribute | Type | required | Description |
| Attribute | Type | Required | Description |
|-------------|---------|----------|---------------------|
| `id` | integer | yes | The ID of a project |
| `build_id` | integer | yes | The ID of a build |
......
......@@ -289,6 +289,7 @@ order for it to take effect:
```json
{
"id": 1,
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
"project_id": 3,
......@@ -364,6 +365,7 @@ Parameters:
```json
{
"id": 1,
"iid": 1,
"target_branch": "master",
"project_id": 3,
"title": "test1",
......@@ -464,6 +466,7 @@ Parameters:
```json
{
"id": 1,
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
"project_id": 3,
......@@ -635,6 +638,7 @@ Parameters:
```json
{
"id": 1,
"iid": 1,
"target_branch": "master",
"source_branch": "test1",
"project_id": 3,
......
......@@ -38,7 +38,7 @@ The `API_TOKEN` will take the Secure Variable value: `SECURE`.
| **CI_PIPELINE_ID** | 8.10 | 0.5 | The unique id of the current pipeline that GitLab CI uses internally |
| **CI_PROJECT_ID** | all | all | The unique id of the current project that GitLab CI uses internally |
| **CI_PROJECT_NAME** | 8.10 | 0.5 | The project name that is currently being built |
| **CI_PROJECT_NAMESPACE**| 8.10 | 0.5 | The project namespace that is currently being built |
| **CI_PROJECT_NAMESPACE**| 8.10 | 0.5 | The project namespace (username or groupname) that is currently being built |
| **CI_PROJECT_PATH** | 8.10 | 0.5 | The namespace with project name |
| **CI_PROJECT_URL** | 8.10 | 0.5 | The HTTP address to access project |
| **CI_PROJECT_DIR** | all | all | The full path where the repository is cloned and where the build is run |
......
......@@ -32,26 +32,39 @@
## GitLab Flavored Markdown (GFM)
> **Note:**
Not all of the GitLab-specific extensions to Markdown that are described in
this document currently work on our documentation website.
>
For the best result, we encourage you to check this document out as rendered
by GitLab: [markdown.md]
_GitLab uses the [Redcarpet Ruby library][redcarpet] for Markdown processing._
GitLab uses "GitLab Flavored Markdown" (GFM). It extends the standard Markdown in a few significant ways to add some useful functionality. It was inspired by [GitHub Flavored Markdown](https://help.github.com/articles/basic-writing-and-formatting-syntax/).
You can use GFM in
You can use GFM in the following areas:
- comments
- issues
- merge requests
- milestones
- snippets (the snippet must be named with a `.md` extension)
- wiki pages
- markdown documents inside the repository
You can also use other rich text files in GitLab. You might have to install a dependency to do so. Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
You can also use other rich text files in GitLab. You might have to install a
dependency to do so. Please see the [github-markup gem readme](https://github.com/gitlabhq/markup#markups) for more information.
## Newlines
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#newlines
GFM honors the markdown specification in how [paragraphs and line breaks are handled](https://daringfireball.net/projects/markdown/syntax#p).
A paragraph is simply one or more consecutive lines of text, separated by one or more blank lines.
Line-breaks, or softreturns, are rendered if you end a line with two or more spaces
Line-breaks, or softreturns, are rendered if you end a line with two or more spaces:
Roses are red [followed by two or more spaces]
Violets are blue
......@@ -65,17 +78,25 @@ Sugar is sweet
## Multiple underscores in words
It is not reasonable to italicize just _part_ of a word, especially when you're dealing with code and names that often appear with multiple underscores. Therefore, GFM ignores multiple underscores in words.
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#multiple-underscores-in-words
It is not reasonable to italicize just _part_ of a word, especially when you're dealing with code and names that often appear with multiple underscores. Therefore, GFM ignores multiple underscores in words:
perform_complicated_task
do_this_and_do_that_and_another_thing
perform_complicated_task
do_this_and_do_that_and_another_thing
## URL auto-linking
GFM will autolink almost any URL you copy and paste into your text.
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#url-auto-linking
GFM will autolink almost any URL you copy and paste into your text:
* https://www.google.com
* https://google.com/
......@@ -93,8 +114,11 @@ GFM will autolink almost any URL you copy and paste into your text.
## Multiline Blockquote
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#multiline-blockquote
On top of standard Markdown [blockquotes](#blockquotes), which require prepending `>` to quoted lines,
GFM supports multiline blockquotes fenced by <code>>>></code>.
GFM supports multiline blockquotes fenced by <code>>>></code>:
```no-highlight
>>>
......@@ -124,10 +148,15 @@ you can quote that without having to manually prepend `>` to every line!
## Code and Syntax Highlighting
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#code-and-syntax-highlighting
_GitLab uses the [Rouge Ruby library][rouge] for syntax highlighting. For a
list of supported languages visit the Rouge website._
Blocks of code are either fenced by lines with three back-ticks <code>```</code>, or are indented with four spaces. Only the fenced code blocks support syntax highlighting.
Blocks of code are either fenced by lines with three back-ticks <code>```</code>,
or are indented with four spaces. Only the fenced code blocks support syntax
highlighting:
```no-highlight
Inline `code` has `back-ticks around` it.
......@@ -189,6 +218,9 @@ But let's throw in a <b>tag</b>.
## Inline Diff
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#inline-diff
With inline diffs tags you can display {+ additions +} or [- deletions -].
The wrapping tags can be either curly braces or square brackets [+ additions +] or {- deletions -}.
......@@ -202,6 +234,9 @@ However the wrapping tags cannot be mixed as such:
## Emoji
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#emoji
Sometimes you want to :monkey: around a bit and add some :star2: to your :speech_balloon:. Well we have a gift for you:
:zap: You can use emoji anywhere GFM is supported. :v:
......@@ -264,6 +299,9 @@ GFM also recognizes certain cross-project references:
## Task Lists
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#task-lists
You can add task lists to issues, merge requests and comments. To create a task list, add a specially-formatted Markdown list, like so:
```no-highlight
......@@ -284,6 +322,9 @@ Task lists can only be created in descriptions, not in titles. Task item state c
## Videos
> If this is not rendered correctly, see
https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md#videos
Image tags with a video extension are automatically converted to a video player.
The valid video extensions are `.mp4`, `.m4v`, `.mov`, `.webm`, and `.ogv`.
......@@ -657,6 +698,7 @@ By including colons in the header row, you can align the text within that column
- The [Markdown Syntax Guide](https://daringfireball.net/projects/markdown/syntax) at Daring Fireball is an excellent resource for a detailed explanation of standard markdown.
- [Dillinger.io](http://dillinger.io) is a handy tool for testing standard markdown.
[markdown.md]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/markdown/markdown.md
[rouge]: http://rouge.jneen.net/ "Rouge website"
[redcarpet]: https://github.com/vmg/redcarpet "Redcarpet website"
[^1]: This link will be broken if you see this document from the Help page or docs.gitlab.com
......@@ -2,7 +2,7 @@
## Remove garbage from filesystem. Important! Data loss!
Remove namespaces(dirs) from `/home/git/repositories` if they don't exist in GitLab database.
Remove namespaces(dirs) from all repository storage paths if they don't exist in GitLab database.
```
# omnibus-gitlab
......@@ -12,7 +12,7 @@ sudo gitlab-rake gitlab:cleanup:dirs
bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production
```
Rename repositories from `/home/git/repositories` if they don't exist in GitLab database.
Rename repositories from all repository storage paths if they don't exist in GitLab database.
The repositories get a `+orphaned+TIMESTAMP` suffix so that they cannot block new repositories from being created.
```
......
......@@ -8,6 +8,12 @@ Feature: Project Wiki
Given I create the Wiki Home page
Then I should see the newly created wiki page
Scenario: Add new page with errors
Given I create the Wiki Home page with no content
Then I should see a "Content can't be blank" error message
When I create the Wiki Home page
Then I should see the newly created wiki page
Scenario: Pressing Cancel while editing a brand new Wiki
Given I click on the Cancel button
Then I should be redirected back to the Edit Home Wiki page
......
......@@ -19,6 +19,11 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
click_on "Create page"
end
step 'I create the Wiki Home page with no content' do
fill_in "wiki_content", with: ''
click_on "Create page"
end
step 'I should see the newly created wiki page' do
expect(page).to have_content "Home"
expect(page).to have_content "link test"
......@@ -126,15 +131,15 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
step 'I create a New page with paths' do
click_on 'New Page'
fill_in 'Page slug', with: 'one/two/three'
fill_in 'Page slug', with: 'one/two/three-test'
click_on 'Create Page'
fill_in "wiki_content", with: 'wiki content'
click_on "Create page"
expect(current_path).to include 'one/two/three'
expect(current_path).to include 'one/two/three-test'
end
step 'I should see non-escaped link in the pages list' do
expect(page).to have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three']")
expect(page).to have_xpath("//a[@href='/#{project.path_with_namespace}/wikis/one/two/three-test']")
end
step 'I edit the Wiki page with a path' do
......@@ -143,7 +148,7 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
end
step 'I should see a non-escaped path' do
expect(current_path).to include 'one/two/three'
expect(current_path).to include 'one/two/three-test'
end
step 'I should see the Editing page' do
......@@ -174,6 +179,11 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
find('a[href*="?version_id"]')
end
step 'I should see a "Content can\'t be blank" error message' do
expect(page).to have_content('The form contains the following error:')
expect(page).to have_content('Content can\'t be blank')
end
def wiki
@project_wiki = ProjectWiki.new(project, current_user)
end
......
......@@ -80,7 +80,7 @@ module API
# ref_name (required) - The ref from repository
# job (required) - The name for the build
# Example Request:
# GET /projects/:id/artifacts/:ref_name/download?job=name
# GET /projects/:id/builds/artifacts/:ref_name/download?job=name
get ':id/builds/artifacts/:ref_name/download',
requirements: { ref_name: /.+/ } do
authorize_read_builds!
......
......@@ -54,10 +54,10 @@ module Backup
# Move repos dir to 'repositories.old' dir
bk_repos_path = File.join(path, '..', 'repositories.old.' + Time.now.to_i.to_s)
FileUtils.mv(path, bk_repos_path)
# This is expected from gitlab:check
FileUtils.mkdir_p(path, mode: 2770)
end
FileUtils.mkdir_p(repos_path)
Project.find_each(batch_size: 1000) do |project|
$progress.print " * #{project.path_with_namespace} ... "
......
......@@ -2,11 +2,11 @@ module Banzai
# Extract possible GFM references from an arbitrary String for further processing.
class ReferenceExtractor
def initialize
@texts = []
@texts_and_contexts = []
end
def analyze(text, context = {})
@texts << Renderer.render(text, context)
@texts_and_contexts << { text: text, context: context }
end
def references(type, project, current_user = nil)
......@@ -21,9 +21,10 @@ module Banzai
def html_documents
# This ensures that we don't memoize anything until we have a number of
# text blobs to parse.
return [] if @texts.empty?
return [] if @texts_and_contexts.empty?
@html_documents ||= @texts.map { |html| Nokogiri::HTML.fragment(html) }
@html_documents ||= Renderer.cache_collection_render(@texts_and_contexts)
.map { |html| Nokogiri::HTML.fragment(html) }
end
end
end
......@@ -8,72 +8,35 @@ module Gitlab
end
def parallelize
i = 0
free_right_index = nil
lines = []
highlighted_diff_lines = diff_file.highlighted_diff_lines
highlighted_diff_lines.each do |line|
line_code = diff_file.line_code(line)
position = diff_file.position(line)
case line.type
when 'match', nil
if line.meta? || line.unchanged?
# line in the right panel is the same as in the left one
lines << {
left: {
type: line.type,
number: line.old_pos,
text: line.text,
line_code: line_code,
position: position
},
right: {
type: line.type,
number: line.new_pos,
text: line.text,
line_code: line_code,
position: position
}
left: line,
right: line
}
free_right_index = nil
i += 1
when 'old'
elsif line.removed?
lines << {
left: {
type: line.type,
number: line.old_pos,
text: line.text,
line_code: line_code,
position: position
},
right: {
type: nil,
number: nil,
text: "",
line_code: line_code,
position: position
}
left: line,
right: nil
}
# Once we come upon a new line it can be put on the right of this old line
free_right_index ||= i
i += 1
when 'new'
data = {
type: line.type,
number: line.new_pos,
text: line.text,
line_code: line_code,
position: position
}
elsif line.added?
if free_right_index
# If an old line came before this without a line on the right, this
# line can be put to the right of it.
lines[free_right_index][:right] = data
lines[free_right_index][:right] = line
# If there are any other old lines on the left that don't yet have
# a new counterpart on the right, update the free_right_index
......@@ -81,14 +44,8 @@ module Gitlab
free_right_index = next_free_right_index < i ? next_free_right_index : nil
else
lines << {
left: {
type: nil,
number: nil,
text: "",
line_code: line_code,
position: position
},
right: data
left: nil,
right: line
}
free_right_index = nil
......
......@@ -4,6 +4,7 @@ require 'json'
module Gitlab
class Workhorse
SEND_DATA_HEADER = 'Gitlab-Workhorse-Send-Data'
VERSION_FILE = 'GITLAB_WORKHORSE_VERSION'
class << self
def git_http_ok(repository, user)
......@@ -75,6 +76,11 @@ module Gitlab
]
end
def version
path = Rails.root.join(VERSION_FILE)
path.readable? ? path.read.chomp : 'unknown'
end
protected
def encode(hash)
......
# Interface to the Redis-backed cache store used by the Repository model
class RepositoryCache
attr_reader :namespace, :backend
attr_reader :namespace, :backend, :project_id
def initialize(namespace, backend = Rails.cache)
def initialize(namespace, project_id, backend = Rails.cache)
@namespace = namespace
@backend = backend
@project_id = project_id
end
def cache_key(type)
"#{type}:#{namespace}"
"#{type}:#{namespace}:#{project_id}"
end
def expire(key)
......
......@@ -18,5 +18,15 @@ FactoryGirl.define do
factory :closed_issue, traits: [:closed]
factory :reopened_issue, traits: [:reopened]
factory :labeled_issue do
transient do
labels []
end
after(:create) do |issue, evaluator|
issue.update_attributes(labels: evaluator.labels)
end
end
end
end
......@@ -205,7 +205,7 @@ feature 'Issue filtering by Labels', feature: true do
page.within '.labels-filter' do
click_button 'Label'
wait_for_ajax
fill_in 'label-name', with: 'bug'
find('.dropdown-input input').set 'bug'
page.within '.dropdown-content' do
expect(page).not_to have_content 'enhancement'
......
require 'spec_helper'
describe 'Branches', feature: true do
let(:project) { create(:project) }
let(:repository) { project.repository }
before do
login_as :user
project.team << [@user, :developer]
end
describe 'Initial branches page' do
it 'shows all the branches' do
visit namespace_project_branches_path(project.namespace, project)
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
visit namespace_project_branches_path(project.namespace, project, project.id)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
end
end
end
require 'spec_helper'
describe 'Branches', feature: true do
let(:project) { create(:project) }
let(:repository) { project.repository }
before do
login_as :user
project.team << [@user, :developer]
end
describe 'Initial branches page' do
it 'shows all the branches' do
visit namespace_project_branches_path(project.namespace, project)
repository.branches { |branch| expect(page).to have_content("#{branch.name}") }
expect(page).to have_content("Protected branches can be managed in project settings")
end
end
describe 'Find branches' do
it 'shows filtered branches', js: true do
visit namespace_project_branches_path(project.namespace, project, project.id)
fill_in 'branch-search', with: 'fix'
find('#branch-search').native.send_keys(:enter)
expect(page).to have_content('fix')
expect(find('.all-branches')).to have_selector('li', count: 1)
end
end
end
require 'spec_helper'
feature 'Projects > Wiki > User previews markdown changes', feature: true, js: true do
let(:user) { create(:user) }
let(:project) { create(:project, namespace: user.namespace) }
let(:wiki_content) do
<<-HEREDOC
[regular link](regular)
[relative link 1](../relative)
[relative link 2](./relative)
[relative link 3](./e/f/relative)
HEREDOC
end
background do
project.team << [user, :master]
login_as(user)
visit namespace_project_path(project.namespace, project)
click_link 'Wiki'
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
end
context "while creating a new wiki page" do
context "when there are no spaces or hyphens in the page name" do
it "rewrites relative links as expected" do
click_link 'New Page'
fill_in :new_wiki_path, with: 'a/b/c/d'
click_button 'Create Page'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
end
end
context "when there are spaces in the page name" do
it "rewrites relative links as expected" do
click_link 'New Page'
fill_in :new_wiki_path, with: 'a page/b page/c page/d page'
click_button 'Create Page'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
context "when there are hyphens in the page name" do
it "rewrites relative links as expected" do
click_link 'New Page'
fill_in :new_wiki_path, with: 'a-page/b-page/c-page/d-page'
click_button 'Create Page'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
end
context "while editing a wiki page" do
def create_wiki_page(path)
click_link 'New Page'
fill_in :new_wiki_path, with: path
click_button 'Create Page'
fill_in :wiki_content, with: 'content'
click_on "Create page"
end
context "when there are no spaces or hyphens in the page name" do
it "rewrites relative links as expected" do
create_wiki_page 'a/b/c/d'
click_link 'Edit'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a/b/c/e/f/relative\">relative link 3</a>")
end
end
context "when there are spaces in the page name" do
it "rewrites relative links as expected" do
create_wiki_page 'a page/b page/c page/d page'
click_link 'Edit'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
context "when there are hyphens in the page name" do
it "rewrites relative links as expected" do
create_wiki_page 'a-page/b-page/c-page/d-page'
click_link 'Edit'
fill_in :wiki_content, with: wiki_content
click_on "Preview"
expect(page).to have_content("regular link")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/regular\">regular link</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/relative\">relative link 1</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/relative\">relative link 2</a>")
expect(page.html).to include("<a href=\"/#{project.path_with_namespace}/wikis/a-page/b-page/c-page/e/f/relative\">relative link 3</a>")
end
end
end
end
......@@ -30,7 +30,8 @@ feature 'Projects > Wiki > User creates wiki page', feature: true do
WikiPages::CreateService.new(project, user, title: 'home', content: 'Home page').execute
end
scenario 'via the "new wiki page" page', js: true do
context 'via the "new wiki page" page' do
scenario 'when the wiki page has a single word name', js: true do
click_link 'New Page'
fill_in :new_wiki_path, with: 'foo'
......@@ -43,6 +44,35 @@ feature 'Projects > Wiki > User creates wiki page', feature: true do
expect(page).to have_content("last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
scenario 'when the wiki page has spaces in the name', js: true do
click_link 'New Page'
fill_in :new_wiki_path, with: 'Spaces in the name'
click_button 'Create Page'
fill_in :wiki_content, with: 'My awesome wiki!'
click_button 'Create page'
expect(page).to have_content('Spaces in the name')
expect(page).to have_content("last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
scenario 'when the wiki page has hyphens in the name', js: true do
click_link 'New Page'
fill_in :new_wiki_path, with: 'hyphens-in-the-name'
click_button 'Create Page'
fill_in :wiki_content, with: 'My awesome wiki!'
click_button 'Create page'
expect(page).to have_content('Hyphens in the name')
expect(page).to have_content("last edited by #{user.name}")
expect(page).to have_content('My awesome wiki!')
end
end
end
end
......
require 'spec_helper'
describe BranchesFinder do
let(:user) { create(:user) }
let(:project) { create(:project) }
let(:repository) { project.repository }
describe '#execute' do
context 'sort only' do
it 'sorts by name' do
branches_finder = described_class.new(repository, {})
result = branches_finder.execute
expect(result.first.name).to eq("'test'")
end
it 'sorts by recently_updated' do
branches_finder = described_class.new(repository, { sort: 'recently_updated' })
result = branches_finder.execute
expect(result.first.name).to eq('expand-collapse-lines')
end
it 'sorts by last_updated' do
branches_finder = described_class.new(repository, { sort: 'last_updated' })
result = branches_finder.execute
expect(result.first.name).to eq('feature')
end
end
context 'filter only' do
it 'filters branches by name' do
branches_finder = described_class.new(repository, { search: 'fix' })
result = branches_finder.execute
expect(result.first.name).to eq('fix')
expect(result.count).to eq(1)
end
it 'does not find any branch with that name' do
branches_finder = described_class.new(repository, { search: 'random' })
result = branches_finder.execute
expect(result.count).to eq(0)
end
end
context 'filter and sort' do
it 'filters branches by name and sorts by recently_updated' do
params = { sort: 'recently_updated', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature_conflict')
expect(result.count).to eq(2)
end
it 'filters branches by name and sorts by last_updated' do
params = { sort: 'last_updated', search: 'feature' }
branches_finder = described_class.new(repository, params)
result = branches_finder.execute
expect(result.first.name).to eq('feature')
expect(result.count).to eq(2)
end
end
end
end
---
- :left:
:type: match
:number: 6
:text: "@@ -6,12 +6,18 @@ module Popen"
:line_code:
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: match
:number: 6
:text: "@@ -6,12 +6,18 @@ module Popen"
:line_code:
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 6
:text: |2
<span id="LC6" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 6
:new_line: 6
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 6
:text: |2
<span id="LC6" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_6_6
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 6
:new_line: 6
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 7
:text: |2
<span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 7
:new_line: 7
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 7
:text: |2
<span id="LC7" class="line"> <span class="k">def</span> <span class="nf">popen</span><span class="p">(</span><span class="n">cmd</span><span class="p">,</span> <span class="n">path</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_7_7
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 7
:new_line: 7
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 8
:text: |2
<span id="LC8" class="line"> <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 8
:new_line: 8
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 8
:text: |2
<span id="LC8" class="line"> <span class="k">unless</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">is_a?</span><span class="p">(</span><span class="no">Array</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_8_8
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 8
:new_line: 8
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type: old
:number: 9
:text: |
-<span id="LC9" class="line"> <span class="k">raise</span> <span class="s2">"System commands must be given as an array of strings"</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_9_9
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 9
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 9
:text: |
+<span id="LC9" class="line"> <span class="k">raise</span> <span class="no"><span class='idiff left'>RuntimeError</span></span><span class="p"><span class='idiff'>,</span></span><span class='idiff right'> </span><span class="s2">"System commands must be given as an array of strings"</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_9
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 9
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 10
:text: |2
<span id="LC10" class="line"> <span class="k">end</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 10
:new_line: 10
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 10
:text: |2
<span id="LC10" class="line"> <span class="k">end</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_10_10
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 10
:new_line: 10
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 11
:text: |2
<span id="LC11" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 11
:new_line: 11
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 11
:text: |2
<span id="LC11" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_11_11
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 11
:new_line: 11
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 12
:text: |2
<span id="LC12" class="line"> <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 12
:new_line: 12
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 12
:text: |2
<span id="LC12" class="line"> <span class="n">path</span> <span class="o">||=</span> <span class="no">Dir</span><span class="p">.</span><span class="nf">pwd</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_12_12
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 12
:new_line: 12
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type: old
:number: 13
:text: |
-<span id="LC13" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span> <span class="s2">"PWD"</span> <span class="o">=&gt;</span> <span class="n">path</span> <span class="p">}</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_13_13
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 13
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 13
:text: |
+<span id="LC13" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_13
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 13
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type: old
:number: 14
:text: |
-<span id="LC14" class="line"> <span class="n">options</span> <span class="o">=</span> <span class="p">{</span> <span class="ss">chdir: </span><span class="n">path</span> <span class="p">}</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_14_13
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 14
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 14
:text: |
+<span id="LC14" class="line"> <span class="n">vars</span> <span class="o">=</span> <span class="p">{</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_14
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 14
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 15
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 15
:text: |
+<span id="LC15" class="line"> <span class="s2">"PWD"</span> <span class="o">=&gt;</span> <span class="n">path</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_15
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 15
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 16
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 16
:text: |
+<span id="LC16" class="line"> <span class="p">}</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_16
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 16
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 17
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 17
:text: |
+<span id="LC17" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_17
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 17
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 18
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 18
:text: |
+<span id="LC18" class="line"> <span class="n">options</span> <span class="o">=</span> <span class="p">{</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_18
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 18
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 19
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 19
:text: |
+<span id="LC19" class="line"> <span class="ss">chdir: </span><span class="n">path</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_19
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 19
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 20
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 20
:text: |
+<span id="LC20" class="line"> <span class="p">}</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_20
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 20
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 15
:text: |2
<span id="LC21" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 15
:new_line: 21
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 21
:text: |2
<span id="LC21" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_15_21
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 15
:new_line: 21
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 16
:text: |2
<span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 16
:new_line: 22
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 22
:text: |2
<span id="LC22" class="line"> <span class="k">unless</span> <span class="no">File</span><span class="p">.</span><span class="nf">directory?</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_16_22
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 16
:new_line: 22
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 17
:text: |2
<span id="LC23" class="line"> <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 17
:new_line: 23
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 23
:text: |2
<span id="LC23" class="line"> <span class="no">FileUtils</span><span class="p">.</span><span class="nf">mkdir_p</span><span class="p">(</span><span class="n">path</span><span class="p">)</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_17_23
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 17
:new_line: 23
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type: match
:number: 19
:text: "@@ -19,6 +25,7 @@ module Popen"
:line_code:
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: match
:number: 25
:text: "@@ -19,6 +25,7 @@ module Popen"
:line_code:
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line:
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 19
:text: |2
<span id="LC25" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 19
:new_line: 25
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 25
:text: |2
<span id="LC25" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_19_25
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 19
:new_line: 25
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 20
:text: |2
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 20
:new_line: 26
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 26
:text: |2
<span id="LC26" class="line"> <span class="vi">@cmd_output</span> <span class="o">=</span> <span class="s2">""</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_20_26
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 20
:new_line: 26
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 21
:text: |2
<span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 21
:new_line: 27
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 27
:text: |2
<span id="LC27" class="line"> <span class="vi">@cmd_status</span> <span class="o">=</span> <span class="mi">0</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_21_27
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 21
:new_line: 27
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number:
:text: ''
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 28
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type: new
:number: 28
:text: |
+<span id="LC28" class="line"></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_28
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line:
:new_line: 28
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 22
:text: |2
<span id="LC29" class="line"> <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 22
:new_line: 29
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 29
:text: |2
<span id="LC29" class="line"> <span class="no">Open3</span><span class="p">.</span><span class="nf">popen3</span><span class="p">(</span><span class="n">vars</span><span class="p">,</span> <span class="o">*</span><span class="n">cmd</span><span class="p">,</span> <span class="n">options</span><span class="p">)</span> <span class="k">do</span> <span class="o">|</span><span class="n">stdin</span><span class="p">,</span> <span class="n">stdout</span><span class="p">,</span> <span class="n">stderr</span><span class="p">,</span> <span class="n">wait_thr</span><span class="o">|</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_22_29
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 22
:new_line: 29
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 23
:text: |2
<span id="LC30" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 23
:new_line: 30
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 30
:text: |2
<span id="LC30" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stdout</span><span class="p">.</span><span class="nf">read</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_23_30
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 23
:new_line: 30
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
- :left:
:type:
:number: 24
:text: |2
<span id="LC31" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 24
:new_line: 31
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
:right:
:type:
:number: 31
:text: |2
<span id="LC31" class="line"> <span class="vi">@cmd_output</span> <span class="o">&lt;&lt;</span> <span class="n">stderr</span><span class="p">.</span><span class="nf">read</span></span>
:line_code: 2f6fcd96b88b36ce98c38da085c795a27d92a3dd_24_31
:position: !ruby/object:Gitlab::Diff::Position
attributes:
:old_path: files/ruby/popen.rb
:new_path: files/ruby/popen.rb
:old_line: 24
:new_line: 31
:base_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:start_sha: 6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9
:head_sha: 570e7b2abdd848b95f2f578043fc23bd6f6fd24d
require 'spec_helper'
require_relative '../../config/initializers/6_validations.rb'
describe '6_validations', lib: true do
before :all do
FileUtils.mkdir_p('tmp/tests/paths/a/b/c/d')
FileUtils.mkdir_p('tmp/tests/paths/a/b/c2')
FileUtils.mkdir_p('tmp/tests/paths/a/b/d')
end
after :all do
FileUtils.rm_rf('tmp/tests/paths')
end
context 'with correct settings' do
before do
mock_storages('foo' => '/a/b/c', 'bar' => 'a/b/d')
mock_storages('foo' => 'tmp/tests/paths/a/b/c', 'bar' => 'tmp/tests/paths/a/b/d')
end
it 'passes through' do
expect { load_validations }.not_to raise_error
expect { validate_storages }.not_to raise_error
end
end
context 'with invalid storage names' do
before do
mock_storages('name with spaces' => '/a/b/c')
mock_storages('name with spaces' => 'tmp/tests/paths/a/b/c')
end
it 'throws an error' do
expect { load_validations }.to raise_error('"name with spaces" is not a valid storage name. Please fix this in your gitlab.yml before starting GitLab.')
expect { validate_storages }.to raise_error('"name with spaces" is not a valid storage name. Please fix this in your gitlab.yml before starting GitLab.')
end
end
context 'with nested storage paths' do
before do
mock_storages('foo' => '/a/b/c', 'bar' => '/a/b/c/d')
mock_storages('foo' => 'tmp/tests/paths/a/b/c', 'bar' => 'tmp/tests/paths/a/b/c/d')
end
it 'throws an error' do
expect { load_validations }.to raise_error('bar is a nested path of foo. Nested paths are not supported for repository storages. Please fix this in your gitlab.yml before starting GitLab.')
expect { validate_storages }.to raise_error('bar is a nested path of foo. Nested paths are not supported for repository storages. Please fix this in your gitlab.yml before starting GitLab.')
end
end
def mock_storages(storages)
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
context 'with similar but un-nested storage paths' do
before do
mock_storages('foo' => 'tmp/tests/paths/a/b/c', 'bar' => 'tmp/tests/paths/a/b/c2')
end
def load_validations
load File.join(__dir__, '../../config/initializers/6_validations.rb')
it 'passes through' do
expect { validate_storages }.not_to raise_error
end
end
def mock_storages(storages)
allow(Gitlab.config.repositories).to receive(:storages).and_return(storages)
end
end
......@@ -17,6 +17,12 @@ describe 'trusted_proxies', lib: true do
expect(request.remote_ip).to eq('10.1.5.89')
expect(request.ip).to eq('10.1.5.89')
end
it 'filters out bad values' do
request = stub_request('HTTP_X_FORWARDED_FOR' => '(null), 10.1.5.89')
expect(request.remote_ip).to eq('10.1.5.89')
expect(request.ip).to eq('10.1.5.89')
end
end
context 'with private IP ranges added' do
......
# encoding: UTF-8
require 'spec_helper'
describe Banzai::Filter::RelativeLinkFilter, lib: true do
......
# encoding: UTF-8
require 'spec_helper'
describe Banzai::Filter::TableOfContentsFilter, lib: true do
......
# encoding: UTF-8
require 'spec_helper'
describe Banzai::Filter::UploadLinkFilter, lib: true do
......
......@@ -11,11 +11,51 @@ describe Gitlab::Diff::ParallelDiff, lib: true do
let(:diff_file) { Gitlab::Diff::File.new(diff, diff_refs: commit.diff_refs, repository: repository) }
subject { described_class.new(diff_file) }
let(:parallel_diff_result_array) { YAML.load_file("#{Rails.root}/spec/fixtures/parallel_diff_result.yml") }
describe '#parallelize' do
it 'should return an array of arrays containing the parsed diff' do
expect(subject.parallelize).to match_array(parallel_diff_result_array)
diff_lines = diff_file.highlighted_diff_lines
expected = [
# Unchanged lines
{ left: diff_lines[0], right: diff_lines[0] },
{ left: diff_lines[1], right: diff_lines[1] },
{ left: diff_lines[2], right: diff_lines[2] },
{ left: diff_lines[3], right: diff_lines[3] },
{ left: diff_lines[4], right: diff_lines[5] },
{ left: diff_lines[6], right: diff_lines[6] },
{ left: diff_lines[7], right: diff_lines[7] },
{ left: diff_lines[8], right: diff_lines[8] },
# Changed lines
{ left: diff_lines[9], right: diff_lines[11] },
{ left: diff_lines[10], right: diff_lines[12] },
# Added lines
{ left: nil, right: diff_lines[13] },
{ left: nil, right: diff_lines[14] },
{ left: nil, right: diff_lines[15] },
{ left: nil, right: diff_lines[16] },
{ left: nil, right: diff_lines[17] },
{ left: nil, right: diff_lines[18] },
# Unchanged lines
{ left: diff_lines[19], right: diff_lines[19] },
{ left: diff_lines[20], right: diff_lines[20] },
{ left: diff_lines[21], right: diff_lines[21] },
{ left: diff_lines[22], right: diff_lines[22] },
{ left: diff_lines[23], right: diff_lines[23] },
{ left: diff_lines[24], right: diff_lines[24] },
{ left: diff_lines[25], right: diff_lines[25] },
# Added line
{ left: nil, right: diff_lines[26] },
# Unchanged lines
{ left: diff_lines[27], right: diff_lines[27] },
{ left: diff_lines[28], right: diff_lines[28] },
{ left: diff_lines[29], right: diff_lines[29] }
]
expect(subject.parallelize).to eq(expected)
end
end
end
require_relative '../../lib/repository_cache'
require 'spec_helper'
describe RepositoryCache, lib: true do
let(:project) { create(:project) }
let(:backend) { double('backend').as_null_object }
let(:cache) { RepositoryCache.new('example', backend) }
let(:cache) { RepositoryCache.new('example', project.id, backend) }
describe '#cache_key' do
it 'includes the namespace' do
expect(cache.cache_key(:foo)).to eq 'foo:example'
expect(cache.cache_key(:foo)).to eq "foo:example:#{project.id}"
end
end
describe '#expire' do
it 'expires the given key from the cache' do
cache.expire(:foo)
expect(backend).to have_received(:delete).with('foo:example')
expect(backend).to have_received(:delete).with("foo:example:#{project.id}")
end
end
describe '#fetch' do
it 'fetches the given key from the cache' do
cache.fetch(:bar)
expect(backend).to have_received(:fetch).with('bar:example')
expect(backend).to have_received(:fetch).with("bar:example:#{project.id}")
end
it 'accepts a block' do
p = -> {}
cache.fetch(:baz, &p)
expect(backend).to have_received(:fetch).with('baz:example', &p)
expect(backend).to have_received(:fetch).with("baz:example:#{project.id}", &p)
end
end
end
......@@ -12,7 +12,7 @@ describe Notify do
context 'for a project' do
describe 'items that are assignable, the email' do
let(:current_user) { create(:user, email: "current@email.com") }
let(:assignee) { create(:user, email: 'assignee@example.com') }
let(:assignee) { create(:user, email: 'assignee@example.com', name: 'John Doe') }
let(:previous_assignee) { create(:user, name: 'Previous Assignee') }
shared_examples 'an assignee email' do
......
......@@ -135,22 +135,30 @@ describe Note, models: true do
let!(:note2) { create(:note_on_issue) }
it "reads the rendered note body from the cache" do
expect(Banzai::Renderer).to receive(:render).
with(note1.note,
expect(Banzai::Renderer).to receive(:cache_collection_render).
with([{
text: note1.note,
context: {
pipeline: :note,
cache_key: [note1, "note"],
project: note1.project,
author: note1.author)
expect(Banzai::Renderer).to receive(:render).
with(note2.note,
author: note1.author
}
}]).and_call_original
expect(Banzai::Renderer).to receive(:cache_collection_render).
with([{
text: note2.note,
context: {
pipeline: :note,
cache_key: [note2, "note"],
project: note2.project,
author: note2.author)
author: note2.author
}
}]).and_call_original
note1.all_references
note2.all_references
note1.all_references.users
note2.all_references.users
end
end
......
......@@ -1290,30 +1290,36 @@ describe Repository, models: true do
context 'when the downloads directory does not exist' do
it 'does not remove any archives' do
expect(File).to receive(:directory?).with(path).and_return(false)
expect(Gitlab::Popen).not_to receive(:popen)
described_class.clean_old_archives
end
end
context 'when the downloads directory exists' do
it 'removes old archives' do
expect(File).to receive(:directory?).with(path).and_return(true)
expect(Gitlab::Popen).to receive(:popen)
described_class.clean_old_archives
end
end
end
describe "#keep_around" do
it "does not fail if we attempt to reference bad commit" do
expect(repository.kept_around?('abc1234')).to be_falsey
end
it "stores a reference to the specified commit sha so it isn't garbage collected" do
repository.keep_around(sample_commit.id)
expect(repository.kept_around?(sample_commit.id)).to be_truthy
end
it "attempting to call keep_around on truncated ref does not fail" do
repository.keep_around(sample_commit.id)
ref = repository.send(:keep_around_ref_name, sample_commit.id)
path = File.join(repository.path, ref)
# Corrupt the reference
File.truncate(path, 0)
expect(repository.kept_around?(sample_commit.id)).to be_falsey
repository.keep_around(sample_commit.id)
expect(repository.kept_around?(sample_commit.id)).to be_falsey
File.delete(path)
end
end
def create_remote_branch(remote_name, branch_name, target)
......
......@@ -2,89 +2,81 @@ require 'spec_helper'
describe Issues::BulkUpdateService, services: true do
let(:user) { create(:user) }
let(:project) { Projects::CreateService.new(user, namespace: user.namespace, name: 'test').execute }
let(:project) { create(:empty_project, namespace: user.namespace) }
let!(:result) { Issues::BulkUpdateService.new(project, user, params).execute }
def bulk_update(issues, extra_params = {})
bulk_update_params = extra_params
.reverse_merge(issues_ids: Array(issues).map(&:id).join(','))
describe :close_issue do
let(:issues) { create_list(:issue, 5, project: project) }
let(:params) do
{
state_event: 'close',
issues_ids: issues.map(&:id).join(',')
}
Issues::BulkUpdateService.new(project, user, bulk_update_params).execute
end
describe 'close issues' do
let(:issues) { create_list(:issue, 2, project: project) }
it 'succeeds and returns the correct number of issues updated' do
result = bulk_update(issues, state_event: 'close')
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(issues.count)
end
it 'closes all the issues passed' do
bulk_update(issues, state_event: 'close')
expect(project.issues.opened).to be_empty
expect(project.issues.closed).not_to be_empty
end
end
describe :reopen_issues do
let(:issues) { create_list(:closed_issue, 5, project: project) }
let(:params) do
{
state_event: 'reopen',
issues_ids: issues.map(&:id).join(',')
}
end
describe 'reopen issues' do
let(:issues) { create_list(:closed_issue, 2, project: project) }
it 'succeeds and returns the correct number of issues updated' do
result = bulk_update(issues, state_event: 'reopen')
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(issues.count)
end
it 'reopens all the issues passed' do
bulk_update(issues, state_event: 'reopen')
expect(project.issues.closed).to be_empty
expect(project.issues.opened).not_to be_empty
end
end
describe 'updating assignee' do
let(:issue) do
create(:issue, project: project) { |issue| issue.update_attributes(assignee: user) }
end
let(:params) do
{
assignee_id: assignee_id,
issues_ids: issue.id.to_s
}
end
let(:issue) { create(:issue, project: project, assignee: user) }
context 'when the new assignee ID is a valid user' do
let(:new_assignee) { create(:user) }
let(:assignee_id) { new_assignee.id }
it 'succeeds' do
result = bulk_update(issue, assignee_id: create(:user).id)
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(1)
end
it 'updates the assignee to the use ID passed' do
expect(issue.reload.assignee).to eq(new_assignee)
assignee = create(:user)
expect { bulk_update(issue, assignee_id: assignee.id) }
.to change { issue.reload.assignee }.from(user).to(assignee)
end
end
context 'when the new assignee ID is -1' do
let(:assignee_id) { -1 }
it 'unassigns the issues' do
expect(issue.reload.assignee).to be_nil
expect { bulk_update(issue, assignee_id: -1) }
.to change { issue.reload.assignee }.to(nil)
end
end
context 'when the new assignee ID is not present' do
let(:assignee_id) { nil }
it 'does not unassign' do
expect(issue.reload.assignee).to eq(user)
expect { bulk_update(issue, assignee_id: nil) }
.not_to change { issue.reload.assignee }
end
end
end
......@@ -93,26 +85,22 @@ describe Issues::BulkUpdateService, services: true do
let(:issue) { create(:issue, project: project) }
let(:milestone) { create(:milestone, project: project) }
let(:params) do
{
issues_ids: issue.id.to_s,
milestone_id: milestone.id
}
end
it 'succeeds' do
result = bulk_update(issue, milestone_id: milestone.id)
expect(result[:success]).to be_truthy
expect(result[:count]).to eq(1)
end
it 'updates the issue milestone' do
expect(project.issues.first.milestone).to eq(milestone)
expect { bulk_update(issue, milestone_id: milestone.id) }
.to change { issue.reload.milestone }.from(nil).to(milestone)
end
end
describe 'updating labels' do
def create_issue_with_labels(labels)
create(:issue, project: project) { |issue| issue.update_attributes(labels: labels) }
create(:labeled_issue, project: project, labels: labels)
end
let(:bug) { create(:label, project: project) }
......@@ -129,15 +117,18 @@ describe Issues::BulkUpdateService, services: true do
let(:add_labels) { [] }
let(:remove_labels) { [] }
let(:params) do
let(:bulk_update_params) do
{
label_ids: labels.map(&:id),
add_label_ids: add_labels.map(&:id),
remove_label_ids: remove_labels.map(&:id),
issues_ids: issues.map(&:id).join(',')
}
end
before do
bulk_update(issues, bulk_update_params)
end
context 'when label_ids are passed' do
let(:issues) { [issue_all_labels, issue_no_labels] }
let(:labels) { [bug, regression] }
......@@ -263,40 +254,28 @@ describe Issues::BulkUpdateService, services: true do
end
end
describe :subscribe_issues do
let(:issues) { create_list(:issue, 5, project: project) }
let(:params) do
{
subscription_event: 'subscribe',
issues_ids: issues.map(&:id).join(',')
}
end
describe 'subscribe to issues' do
let(:issues) { create_list(:issue, 2, project: project) }
it 'subscribes the given user' do
issues.each do |issue|
expect(issue.subscribed?(user)).to be_truthy
end
end
end
bulk_update(issues, subscription_event: 'subscribe')
describe :unsubscribe_issues do
let(:issues) { create_list(:closed_issue, 5, project: project) }
let(:params) do
{
subscription_event: 'unsubscribe',
issues_ids: issues.map(&:id).join(',')
}
expect(issues).to all(be_subscribed(user))
end
end
before do
issues.each do |issue|
describe 'unsubscribe from issues' do
let(:issues) do
create_list(:closed_issue, 2, project: project) do |issue|
issue.subscriptions.create(user: user, subscribed: true)
end
end
it 'unsubscribes the given user' do
bulk_update(issues, subscription_event: 'unsubscribe')
issues.each do |issue|
expect(issue.subscribed?(user)).to be_falsey
expect(issue).not_to be_subscribed(user)
end
end
end
......
require 'spec_helper'
describe RepositoryArchiveCleanUpService, services: true do
describe '#execute' do
subject(:service) { described_class.new }
context 'when the downloads directory does not exist' do
it 'does not remove any archives' do
path = '/invalid/path/'
stub_repository_downloads_path(path)
expect(File).to receive(:directory?).with(path).and_return(false)
expect(service).not_to receive(:clean_up_old_archives)
expect(service).not_to receive(:clean_up_empty_directories)
service.execute
end
end
context 'when the downloads directory exists' do
shared_examples 'invalid archive files' do |dirname, extensions, mtime|
it 'does not remove files and directoy' do
in_directory_with_files(dirname, extensions, mtime) do |dir, files|
service.execute
files.each { |file| expect(File.exist?(file)).to eq true }
expect(File.directory?(dir)).to eq true
end
end
end
it 'removes files older than 2 hours that matches valid archive extensions' do
in_directory_with_files('sample.git', %w[tar tar.bz2 tar.gz zip], 2.hours) do |dir, files|
service.execute
files.each { |file| expect(File.exist?(file)).to eq false }
expect(File.directory?(dir)).to eq false
end
end
context 'with files older than 2 hours that does not matches valid archive extensions' do
it_behaves_like 'invalid archive files', 'sample.git', %w[conf rb], 2.hours
end
context 'with files older than 2 hours inside invalid directories' do
it_behaves_like 'invalid archive files', 'john_doe/sample.git', %w[conf rb tar tar.gz], 2.hours
end
context 'with files newer than 2 hours that matches valid archive extensions' do
it_behaves_like 'invalid archive files', 'sample.git', %w[tar tar.bz2 tar.gz zip], 1.hour
end
context 'with files newer than 2 hours that does not matches valid archive extensions' do
it_behaves_like 'invalid archive files', 'sample.git', %w[conf rb], 1.hour
end
context 'with files newer than 2 hours inside invalid directories' do
it_behaves_like 'invalid archive files', 'sample.git', %w[conf rb tar tar.gz], 1.hour
end
end
def in_directory_with_files(dirname, extensions, mtime)
Dir.mktmpdir do |tmpdir|
stub_repository_downloads_path(tmpdir)
dir = File.join(tmpdir, dirname)
files = create_temporary_files(dir, extensions, mtime)
yield(dir, files)
end
end
def stub_repository_downloads_path(path)
allow(Gitlab.config.gitlab).to receive(:repository_downloads_path).and_return(path)
end
def create_temporary_files(dir, extensions, mtime)
FileUtils.mkdir_p(dir)
FileUtils.touch(extensions.map { |ext| File.join(dir, "sample.#{ext}") }, mtime: Time.now - mtime)
end
end
end
require 'spec_helper'
describe 'admin/dashboard/index.html.haml' do
include Devise::TestHelpers
before do
assign(:projects, create_list(:empty_project, 1))
assign(:users, create_list(:user, 1))
assign(:groups, create_list(:group, 1))
allow(view).to receive(:admin?).and_return(true)
end
it "shows version of GitLab Workhorse" do
render
expect(rendered).to have_content 'GitLab Workhorse'
expect(rendered).to have_content Gitlab::Workhorse.version
end
end
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