Commit 1af3f3b6 authored by James Edwards-Jones's avatar James Edwards-Jones

Merge branch 'master' into jej-pages-picked-from-ee

parents 67c85260 bd8f2b15
......@@ -17,6 +17,7 @@ AllCops:
# Exclude some GitLab files
Exclude:
- 'vendor/**/*'
- 'node_modules/**/*'
- 'db/*'
- 'db/fixtures/**/*'
- 'tmp/**/*'
......
......@@ -112,7 +112,7 @@ gem 'org-ruby', '~> 0.9.12'
gem 'creole', '~> 0.5.0'
gem 'wikicloth', '0.8.1'
gem 'asciidoctor', '~> 1.5.2'
gem 'asciidoctor-plantuml', '0.0.6'
gem 'asciidoctor-plantuml', '0.0.7'
gem 'rouge', '~> 2.0'
gem 'truncato', '~> 0.7.8'
......
......@@ -54,7 +54,7 @@ GEM
faraday_middleware-multi_json (~> 0.0)
oauth2 (~> 1.0)
asciidoctor (1.5.3)
asciidoctor-plantuml (0.0.6)
asciidoctor-plantuml (0.0.7)
asciidoctor (~> 1.5)
ast (2.3.0)
attr_encrypted (3.0.3)
......@@ -844,7 +844,7 @@ DEPENDENCIES
allocations (~> 1.0)
asana (~> 0.4.0)
asciidoctor (~> 1.5.2)
asciidoctor-plantuml (= 0.0.6)
asciidoctor-plantuml (= 0.0.7)
attr_encrypted (~> 3.0.0)
awesome_print (~> 1.2.0)
babosa (~> 1.0.2)
......
/* eslint-disable wrap-iife, func-names, space-before-function-paren, prefer-arrow-callback, vars-on-top, no-var, max-len */
(function(w) {
$(function() {
var toggleContainer = function(container, /* optional */toggleState) {
var $container = $(container);
$container
.find('.js-toggle-button .fa')
.toggleClass('fa-chevron-up', toggleState)
.toggleClass('fa-chevron-down', toggleState !== undefined ? !toggleState : undefined);
$container
.find('.js-toggle-content')
.toggle(toggleState);
};
// Toggle button. Show/hide content inside parent container.
// Button does not change visibility. If button has icon - it changes chevron style.
//
......@@ -10,14 +23,7 @@
//
$('body').on('click', '.js-toggle-button', function(e) {
e.preventDefault();
$(this)
.find('.fa')
.toggleClass('fa-chevron-down fa-chevron-up')
.end()
.closest('.js-toggle-container')
.find('.js-toggle-content')
.toggle()
;
toggleContainer($(this).closest('.js-toggle-container'));
});
// If we're accessing a permalink, ensure it is not inside a
......@@ -26,8 +32,8 @@
var anchor = hash && document.getElementById(hash);
var container = anchor && $(anchor).closest('.js-toggle-container');
if (container && container.find('.js-toggle-content').is(':hidden')) {
container.find('.js-toggle-button').trigger('click');
if (container) {
toggleContainer(container, true);
anchor.scrollIntoView();
}
});
......
......@@ -180,9 +180,9 @@
<tr>
<th class="environments-name">Environment</th>
<th class="environments-deploy">Last deployment</th>
<th class="environments-build">Build</th>
<th class="environments-build">Job</th>
<th class="environments-commit">Commit</th>
<th class="environments-date">Created</th>
<th class="environments-date">Updated</th>
<th class="hidden-xs environments-actions"></th>
</tr>
</thead>
......
......@@ -39,8 +39,15 @@
getSearchInput() {
const query = gl.DropdownUtils.getSearchInput(this.input);
const { lastToken } = gl.FilteredSearchTokenizer.processTokens(query);
let value = lastToken.value || '';
return lastToken.value || '';
// Removes the first character if it is a quotation so that we can search
// with multiple words
if (value[0] === '"' || value[0] === '\'') {
value = value.slice(1);
}
return value;
}
init() {
......
......@@ -83,12 +83,12 @@
_a = decodeURI("%C3%80");
_y = decodeURI("%C3%BF");
regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?![" + atSymbolsWithBar + "])([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]*)$", 'gi');
regexp = new RegExp("^(?:\\B|[^a-zA-Z0-9_" + atSymbolsWithoutBar + "]|\\s)" + flag + "(?![" + atSymbolsWithBar + "])(([A-Za-z" + _a + "-" + _y + "0-9_\'\.\+\-]|[^\\x00-\\x7a])*)$", 'gi');
match = regexp.exec(subtext);
if (match) {
return match[2] || match[1];
return (match[1] || match[1] === "") ? match[1] : match[2];
} else {
return null;
}
......
......@@ -249,7 +249,7 @@
_this.fullData = data;
_this.parseData(_this.fullData);
_this.focusTextInput();
if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val().trim() !== '') {
if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') {
return _this.filter.input.trigger('input');
}
};
......
......@@ -162,6 +162,7 @@
w.gl.utils.getSelectedFragment = () => {
const selection = window.getSelection();
if (selection.rangeCount === 0) return null;
const documentFragment = selection.getRangeAt(0).cloneContents();
if (documentFragment.textContent.length === 0) return null;
......
......@@ -110,9 +110,8 @@
};
MergeRequest.prototype.initCommitMessageListeners = function() {
var textarea = $('textarea.js-commit-message');
$('a.js-with-description-link').on('click', function(e) {
$(document).on('click', 'a.js-with-description-link', function(e) {
var textarea = $('textarea.js-commit-message');
e.preventDefault();
textarea.val(textarea.data('messageWithDescription'));
......@@ -120,7 +119,8 @@
$('p.js-without-description-hint').show();
});
$('a.js-without-description-link').on('click', function(e) {
$(document).on('click', 'a.js-without-description-link', function(e) {
var textarea = $('textarea.js-commit-message');
e.preventDefault();
textarea.val(textarea.data('messageWithoutDescription'));
......
......@@ -154,12 +154,22 @@
return;
}
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
if (data.status !== _this.opts.ci_status && (data.status != null)) {
if (data.status !== _this.opts.ci_status ||
data.sha !== _this.opts.ci_sha ||
data.pipeline !== _this.opts.ci_pipeline) {
_this.opts.ci_status = data.status;
_this.showCIStatus(data.status);
if (data.coverage) {
_this.showCICoverage(data.coverage);
}
if (data.pipeline) {
_this.opts.ci_pipeline = data.pipeline;
_this.updatePipelineUrls(data.pipeline);
}
if (data.sha) {
_this.opts.ci_sha = data.sha;
_this.updateCommitUrls(data.sha);
}
if (showNotification) {
status = _this.ciLabelForStatus(data.status);
if (status === "preparing") {
......@@ -248,6 +258,16 @@
return $('.js-merge-button,.accept-action .dropdown-toggle').removeClass('btn-danger btn-info btn-create').addClass(css_class);
};
MergeRequestWidget.prototype.updatePipelineUrls = function(id) {
const pipelineUrl = this.opts.pipeline_path;
$('.pipeline').text(`#${id}`).attr('href', [pipelineUrl, id].join('/'));
};
MergeRequestWidget.prototype.updateCommitUrls = function(id) {
const commitsUrl = this.opts.commits_path;
$('.js-commit-link').text(`#${id}`).attr('href', [commitsUrl, id].join('/'));
};
return MergeRequestWidget;
})();
})(window.gl || (window.gl = {}));
......@@ -58,6 +58,11 @@
};
Project.prototype.initRefSwitcher = function() {
var refListItem = document.createElement('li'),
refLink = document.createElement('a');
refLink.href = '#';
return $('.js-project-refs-dropdown').each(function() {
var $dropdown, selected;
$dropdown = $(this);
......@@ -67,7 +72,8 @@
return $.ajax({
url: $dropdown.data('refs-url'),
data: {
ref: $dropdown.data('ref')
ref: $dropdown.data('ref'),
search: term
},
dataType: "json"
}).done(function(refs) {
......@@ -76,16 +82,29 @@
},
selectable: true,
filterable: true,
filterRemote: true,
filterByText: true,
fieldName: $dropdown.data('field-name'),
renderRow: function(ref) {
var link;
var li = refListItem.cloneNode(false);
if (ref.header != null) {
return $('<li />').addClass('dropdown-header').text(ref.header);
li.className = 'dropdown-header';
li.textContent = ref.header;
} else {
link = $('<a />').attr('href', '#').addClass(ref === selected ? 'is-active' : '').text(ref).attr('data-ref', ref);
return $('<li />').append(link);
var link = refLink.cloneNode(false);
if (ref === selected) {
link.className = 'is-active';
}
link.textContent = ref;
link.dataset.ref = ref;
li.appendChild(link);
}
return li;
},
id: function(obj, $el) {
return $el.attr('data-ref');
......
......@@ -49,7 +49,7 @@ class ProtectedBranchDropdown {
onClickCreateWildcard() {
// Refresh the dropdown's data, which ends up calling `getProtectedBranches`
this.$dropdown.data('glDropdown').remote.execute();
this.$dropdown.data('glDropdown').selectRowAtIndex(0);
this.$dropdown.data('glDropdown').selectRowAtIndex();
}
getProtectedBranches(term, callback) {
......
......@@ -39,17 +39,20 @@
}
ShortcutsIssuable.prototype.replyWithSelectedText = function() {
var quote, replyField, documentFragment, selected, separator;
var quote, documentFragment, selected, separator;
var replyField = $('.js-main-target-form #note_note');
documentFragment = window.gl.utils.getSelectedFragment();
if (!documentFragment) return;
if (!documentFragment) {
replyField.focus();
return;
}
// If the documentFragment contains more than just Markdown, don't copy as GFM.
if (documentFragment.querySelector('.md, .wiki')) return;
selected = window.gl.CopyAsGFM.nodeToGFM(documentFragment);
replyField = $('.js-main-target-form #note_note');
if (selected.trim() === "") {
return;
}
......
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, camelcase, vars-on-top, object-shorthand, comma-dangle, eqeqeq, no-mixed-operators, no-return-assign, newline-per-chained-call, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, no-else-return, max-len */
/* global d3 */
/* global dateFormat */
(function() {
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
......@@ -33,7 +32,7 @@
date.setDate(date.getDate() + i);
var day = date.getDay();
var count = timestamps[dateFormat(date, 'yyyy-mm-dd')];
var count = timestamps[date.format('yyyy-mm-dd')];
// Create a new group array if this is the first day of the week
// or if is first object
......@@ -122,7 +121,7 @@
if (stamp.count > 0) {
contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : '');
}
dateText = dateFormat(date, 'mmm d, yyyy');
dateText = date.format('mmm d, yyyy');
return contribText + "<br />" + (gl.utils.getDayName(date)) + " " + dateText;
};
})(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) {
......
......@@ -26,10 +26,9 @@
v-if='actions'
class="dropdown-toggle btn btn-default has-tooltip js-pipeline-dropdown-manual-actions"
data-toggle="dropdown"
title="Manual build"
title="Manual job"
data-placement="top"
data-toggle="dropdown"
aria-label="Manual build"
aria-label="Manual job"
>
<span v-html='svgs.iconPlay' aria-hidden="true"></span>
<i class="fa fa-caret-down" aria-hidden="true"></i>
......@@ -54,7 +53,6 @@
data-toggle="dropdown"
title="Artifacts"
data-placement="top"
data-toggle="dropdown"
aria-label="Artifacts"
>
<i class="fa fa-download" aria-hidden="true"></i>
......
......@@ -330,10 +330,6 @@
}
}
.btn-file-option {
background: linear-gradient(180deg, $white-light 25%, $gray-light 100%);
}
.btn-build {
margin-left: 10px;
......
......@@ -56,15 +56,24 @@
&.right {
float: right;
padding-right: 0;
}
a {
color: $gl-text-color;
}
.modify-merge-commit-link {
color: $gl-text-color;
}
.remove_source_checkbox {
.merge-param-checkbox {
margin: 0;
}
a .fa-question-circle {
color: $gl-text-color-secondary;
&:hover,
&:focus {
color: $link-hover-color;
}
}
}
}
......
......@@ -467,7 +467,7 @@ ul.notes {
}
.add-diff-note {
margin-top: -4px;
margin-top: -8px;
border-radius: 40px;
background: $white-light;
padding: 4px;
......
......@@ -201,7 +201,8 @@
.stage-container {
display: inline-block;
position: relative;
margin-right: 6px;
height: 22px;
margin: 3px 6px 3px 0;
.tooltip {
white-space: nowrap;
......
......@@ -45,7 +45,7 @@ class Admin::ProjectsController < Admin::ApplicationController
protected
def project
@project = Project.find_with_namespace(
@project = Project.find_by_full_path(
[params[:namespace_id], '/', params[:id]].join('')
)
@project || render_404
......
......@@ -24,7 +24,7 @@ class Admin::RunnerProjectsController < Admin::ApplicationController
private
def project
@project = Project.find_with_namespace(
@project = Project.find_by_full_path(
[params[:namespace_id], '/', params[:project_id]].join('')
)
@project || render_404
......
......@@ -4,13 +4,15 @@ module CreatesCommit
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
set_commit_variables
start_branch = @mr_target_branch unless initial_commit?
commit_params = @commit_params.merge(
source_project: @project,
source_branch: @ref,
target_branch: @target_branch
start_project: @mr_target_project,
start_branch: start_branch,
target_branch: @mr_source_branch
)
result = service.new(@tree_edit_project, current_user, commit_params).execute
result = service.new(
@mr_source_project, current_user, commit_params).execute
if result[:status] == :success
update_flash_notice(success_notice)
......@@ -89,20 +91,18 @@ module CreatesCommit
@mr_source_project != @mr_target_project
end
def different_branch?
@mr_source_branch != @mr_target_branch || different_project?
end
def create_merge_request?
params[:create_merge_request].present? && different_branch?
# XXX: Even if the field is set, if we're checking the same branch
# as the target branch in the same project,
# we don't want to create a merge request.
params[:create_merge_request].present? &&
(different_project? || @ref != @target_branch)
end
# TODO: We should really clean this up
def set_commit_variables
@mr_source_branch ||= @target_branch
if can?(current_user, :push_code, @project)
# Edit file in this project
@tree_edit_project = @project
@mr_source_project = @project
if @project.forked?
......@@ -112,15 +112,34 @@ module CreatesCommit
else
# Merge request to this project
@mr_target_project = @project
@mr_target_branch ||= @ref
@mr_target_branch = @ref || @target_branch
end
else
# Edit file in fork
@tree_edit_project = current_user.fork_of(@project)
# Merge request from fork to this project
@mr_source_project = @tree_edit_project
@mr_source_project = current_user.fork_of(@project)
@mr_target_project = @project
@mr_target_branch ||= @ref
@mr_target_branch = @ref || @target_branch
end
@mr_source_branch = guess_mr_source_branch
end
def initial_commit?
@mr_target_branch.nil? ||
!@mr_target_project.repository.branch_exists?(@mr_target_branch)
end
def guess_mr_source_branch
# XXX: Happens when viewing a commit without a branch. In this case,
# @target_branch would be the default branch for @mr_source_project,
# however we want a generated new branch here. Thus we can't use
# @target_branch, but should pass nil to indicate that we want a new
# branch instead of @target_branch.
return if
create_merge_request? &&
# XXX: Don't understand why rubocop prefers this indention
@mr_source_project.repository.branch_exists?(@target_branch)
@target_branch
end
end
......@@ -7,7 +7,7 @@ module SpammableActions
def mark_as_spam
if SpamService.new(spammable).mark_as_spam!
redirect_to spammable, notice: "#{spammable.class} was submitted to Akismet successfully."
redirect_to spammable, notice: "#{spammable.spammable_entity_type.titlecase} was submitted to Akismet successfully."
else
redirect_to spammable, alert: 'Error with Akismet. Please check the logs for more info.'
end
......
......@@ -10,10 +10,8 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page])
@last_push = current_user.recent_push
respond_to do |format|
format.html
format.html { @last_push = current_user.recent_push }
format.atom do
event_filter
load_events
......
......@@ -84,7 +84,7 @@ class GroupsController < Groups::ApplicationController
if Groups::UpdateService.new(@group, current_user, group_params).execute
redirect_to edit_group_path(@group), notice: "Group '#{@group.name}' was successfully updated."
else
@group.reset_path!
@group.restore_path!
render action: "edit"
end
......
......@@ -24,7 +24,7 @@ class Projects::ApplicationController < ApplicationController
end
project_path = "#{namespace}/#{id}"
@project = Project.find_with_namespace(project_path)
@project = Project.find_by_full_path(project_path)
if can?(current_user, :read_project, @project) && !@project.pending_delete?
if @project.path_with_namespace != project_path
......
......@@ -50,7 +50,7 @@ class Projects::CommitController < Projects::ApplicationController
end
def revert
assign_change_commit_vars(@commit.revert_branch_name)
assign_change_commit_vars
return render_404 if @target_branch.blank?
......@@ -59,7 +59,7 @@ class Projects::CommitController < Projects::ApplicationController
end
def cherry_pick
assign_change_commit_vars(@commit.cherry_pick_branch_name)
assign_change_commit_vars
return render_404 if @target_branch.blank?
......@@ -116,11 +116,9 @@ class Projects::CommitController < Projects::ApplicationController
}
end
def assign_change_commit_vars(mr_source_branch)
def assign_change_commit_vars
@commit = project.commit(params[:id])
@target_branch = params[:target_branch]
@mr_source_branch = mr_source_branch
@mr_target_branch = @target_branch
@commit_params = {
commit: @commit,
create_merge_request: params[:create_merge_request].present? || different_project?
......
......@@ -46,7 +46,8 @@ class Projects::CompareController < Projects::ApplicationController
end
def define_diff_vars
@compare = CompareService.new.execute(@project, @head_ref, @project, @start_ref)
@compare = CompareService.new(@project, @head_ref)
.execute(@project, @start_ref)
if @compare
@commits = @compare.commits
......
......@@ -79,7 +79,7 @@ class Projects::GitHttpClientController < Projects::ApplicationController
if project_id.blank?
@project = nil
else
@project = Project.find_with_namespace("#{params[:namespace_id]}/#{project_id}")
@project = Project.find_by_full_path("#{params[:namespace_id]}/#{project_id}")
end
end
......
......@@ -434,7 +434,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
title: merge_request.title,
sha: (merge_request.diff_head_commit.short_id if merge_request.diff_head_sha),
status: status,
coverage: coverage
coverage: coverage,
pipeline: pipeline.try(:id)
}
render json: response
......
class Projects::SnippetsController < Projects::ApplicationController
include ToggleAwardEmoji
include SpammableActions
before_action :module_enabled
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji]
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :toggle_award_emoji, :mark_as_spam]
# Allow read any snippet
before_action :authorize_read_project_snippet!, except: [:new, :create, :index]
......@@ -36,8 +37,8 @@ class Projects::SnippetsController < Projects::ApplicationController
end
def create
@snippet = CreateSnippetService.new(@project, current_user,
snippet_params).execute
create_params = snippet_params.merge(request: request)
@snippet = CreateSnippetService.new(@project, current_user, create_params).execute
if @snippet.valid?
respond_with(@snippet,
......@@ -88,6 +89,7 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet ||= @project.snippets.find(params[:id])
end
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_project_snippet!
return render_404 unless can?(current_user, :read_project_snippet, @snippet)
......
......@@ -36,7 +36,7 @@ class Projects::UploadsController < Projects::ApplicationController
namespace = params[:namespace_id]
id = params[:project_id]
file_project = Project.find_with_namespace("#{namespace}/#{id}")
file_project = Project.find_by_full_path("#{namespace}/#{id}")
if file_project.nil?
@uploader = nil
......
......@@ -231,12 +231,16 @@ class ProjectsController < Projects::ApplicationController
end
def refs
branches = BranchesFinder.new(@repository, params).execute.map(&:name)
options = {
'Branches' => @repository.branch_names,
'Branches' => branches.take(100),
}
unless @repository.tag_count.zero?
options['Tags'] = VersionSorter.rsort(@repository.tag_names)
tags = TagsFinder.new(@repository, params).execute.map(&:name)
options['Tags'] = tags.take(100)
end
# If reference is commit id - we should add it to branch/tag selectbox
......
class SnippetsController < ApplicationController
include ToggleAwardEmoji
include SpammableActions
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw, :download]
......@@ -40,8 +41,8 @@ class SnippetsController < ApplicationController
end
def create
@snippet = CreateSnippetService.new(nil, current_user,
snippet_params).execute
create_params = snippet_params.merge(request: request)
@snippet = CreateSnippetService.new(nil, current_user, create_params).execute
respond_with @snippet.becomes(Snippet)
end
......@@ -96,6 +97,7 @@ class SnippetsController < ApplicationController
end
end
alias_method :awardable, :snippet
alias_method :spammable, :snippet
def authorize_read_snippet!
authenticate_user! unless can?(current_user, :read_personal_snippet, @snippet)
......
......@@ -37,7 +37,7 @@ module ApplicationHelper
if project_id.is_a?(Project)
project_id
else
Project.find_with_namespace(project_id)
Project.find_by_full_path(project_id)
end
if project.avatar_url
......
......@@ -21,7 +21,7 @@ module BlobHelper
options[:link_opts])
if !on_top_of_branch?(project, ref)
button_tag "Edit", class: "btn disabled has-tooltip btn-file-option", title: "You can only edit files when you are on a branch", data: { container: 'body' }
button_tag "Edit", class: "btn disabled has-tooltip", title: "You can only edit files when you are on a branch", data: { container: 'body' }
elsif can_edit_blob?(blob, project, ref)
link_to "Edit", edit_path, class: 'btn btn-sm'
elsif can?(current_user, :fork_project, project)
......@@ -32,7 +32,7 @@ module BlobHelper
}
fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
link_to "Edit", fork_path, class: 'btn btn-file-option', method: :post
link_to "Edit", fork_path, class: 'btn', method: :post
end
end
......
......@@ -198,7 +198,7 @@ module CommitsHelper
link_to(
namespace_project_blob_path(project.namespace, project,
tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file btn-file-option'
class: 'btn view-file js-view-file'
) do
raw('View file @') + content_tag(:span, commit_sha[0..6],
class: 'commit-short-id')
......
......@@ -143,4 +143,16 @@ module MergeRequestsHelper
def different_base?(version1, version2)
version1 && version2 && version1.base_commit_sha != version2.base_commit_sha
end
def merge_params(merge_request)
{
merge_when_build_succeeds: true,
should_remove_source_branch: true,
sha: merge_request.diff_head_sha
}.merge(merge_params_ee(merge_request))
end
def merge_params_ee(merge_request)
{}
end
end
......@@ -93,10 +93,6 @@ module VisibilityLevelHelper
current_application_settings.default_project_visibility
end
def default_snippet_visibility
current_application_settings.default_snippet_visibility
end
def default_group_visibility
current_application_settings.default_group_visibility
end
......
......@@ -275,29 +275,23 @@ module Ci
end
def update_coverage
return unless project
coverage_regex = project.build_coverage_regex
return unless coverage_regex
coverage = extract_coverage(trace, coverage_regex)
if coverage.is_a? Numeric
update_attributes(coverage: coverage)
end
update_attributes(coverage: coverage) if coverage.present?
end
def extract_coverage(text, regex)
begin
matches = text.scan(Regexp.new(regex)).last
matches = matches.last if matches.kind_of?(Array)
coverage = matches.gsub(/\d+(\.\d+)?/).first
return unless regex
if coverage.present?
coverage.to_f
end
rescue
# if bad regex or something goes wrong we dont want to interrupt transition
# so we just silentrly ignore error for now
matches = text.scan(Regexp.new(regex)).last
matches = matches.last if matches.kind_of?(Array)
coverage = matches.gsub(/\d+(\.\d+)?/).first
if coverage.present?
coverage.to_f
end
rescue
# if bad regex or something goes wrong we dont want to interrupt transition
# so we just silentrly ignore error for now
end
def has_trace_file?
......@@ -523,6 +517,10 @@ module Ci
self.update(artifacts_expire_at: nil)
end
def coverage_regex
super || project.try(:build_coverage_regex)
end
def when
read_attribute(:when) || build_attributes_from_config[:when] || 'on_success'
end
......
......@@ -34,7 +34,13 @@ module Spammable
end
def check_for_spam
self.errors.add(:base, "Your #{self.class.name.underscore} has been recognized as spam and has been discarded.") if spam?
if spam?
self.errors.add(:base, "Your #{spammable_entity_type} has been recognized as spam and has been discarded.")
end
end
def spammable_entity_type
self.class.name.underscore
end
def spam_title
......
......@@ -169,7 +169,8 @@ class MergeRequestDiff < ActiveRecord::Base
# When compare merge request versions we want diff A..B instead of A...B
# so we handle cases when user does squash and rebase of the commits between versions.
# For this reason we set straight to true by default.
CompareService.new.execute(project, head_commit_sha, project, sha, straight: straight)
CompareService.new(project, head_commit_sha)
.execute(project, sha, straight: straight)
end
def commits_count
......
......@@ -373,10 +373,6 @@ class Project < ActiveRecord::Base
def group_ids
joins(:namespace).where(namespaces: { type: 'Group' }).select(:namespace_id)
end
# Add alias for Routable method for compatibility with old code.
# In future all calls `find_with_namespace` should be replaced with `find_by_full_path`
alias_method :find_with_namespace, :find_by_full_path
end
def lfs_enabled?
......@@ -1395,6 +1391,6 @@ class Project < ActiveRecord::Base
def pending_delete_twin
return false unless path
Project.unscoped.where(pending_delete: true).find_with_namespace(path_with_namespace)
Project.unscoped.where(pending_delete: true).find_by_full_path(path_with_namespace)
end
end
......@@ -31,13 +31,13 @@ class ChatSlashCommandsService < Service
return unless valid_token?(params[:token])
user = find_chat_user(params)
unless user
if user
Gitlab::ChatCommands::Command.new(project, user, params).execute
else
url = authorize_chat_name_url(params)
return presenter.authorize_chat_name(url)
Gitlab::ChatCommands::Presenters::Access.new(url).authorize
end
Gitlab::ChatCommands::Command.new(project, user,
params).execute
end
private
......@@ -49,8 +49,4 @@ class ChatSlashCommandsService < Service
def authorize_chat_name_url(params)
ChatNames::AuthorizeUserService.new(self, params).execute
end
def presenter
Gitlab::ChatCommands::Presenter.new
end
end
......@@ -9,4 +9,8 @@ class ProjectSnippet < Snippet
participant :author
participant :notes_with_associations
def check_for_spam?
super && project.public?
end
end
This diff is collapsed.
......@@ -7,6 +7,7 @@ class Snippet < ActiveRecord::Base
include Sortable
include Awardable
include Mentionable
include Spammable
cache_markdown_field :title, pipeline: :single_line
cache_markdown_field :content
......@@ -17,7 +18,7 @@ class Snippet < ActiveRecord::Base
default_content_html_invalidator || file_name_changed?
end
default_value_for :visibility_level, Snippet::PRIVATE
default_value_for(:visibility_level) { current_application_settings.default_snippet_visibility }
belongs_to :author, class_name: 'User'
belongs_to :project
......@@ -46,6 +47,9 @@ class Snippet < ActiveRecord::Base
participant :author
participant :notes_with_associations
attr_spammable :title, spam_title: true
attr_spammable :content, spam_description: true
def self.reference_prefix
'$'
end
......@@ -127,6 +131,14 @@ class Snippet < ActiveRecord::Base
notes.includes(:author)
end
def check_for_spam?
public?
end
def spammable_entity_type
'snippet'
end
class << self
# Searches for snippets with a matching title or file name.
#
......
......@@ -61,7 +61,7 @@ module Auth
end
def process_repository_access(type, name, actions)
requested_project = Project.find_with_namespace(name)
requested_project = Project.find_by_full_path(name)
return unless requested_project
actions = actions.select do |action|
......
......@@ -4,7 +4,8 @@ module Commits
class ChangeError < StandardError; end
def execute
@source_project = params[:source_project] || @project
@start_project = params[:start_project] || @project
@start_branch = params[:start_branch]
@target_branch = params[:target_branch]
@commit = params[:commit]
@create_merge_request = params[:create_merge_request].present?
......@@ -25,13 +26,28 @@ module Commits
def commit_change(action)
raise NotImplementedError unless repository.respond_to?(action)
into = @create_merge_request ? @commit.public_send("#{action}_branch_name") : @target_branch
tree_id = repository.public_send("check_#{action}_content", @commit, @target_branch)
if @create_merge_request
into = @commit.public_send("#{action}_branch_name")
tree_branch = @start_branch
else
into = tree_branch = @target_branch
end
tree_id = repository.public_send(
"check_#{action}_content", @commit, tree_branch)
if tree_id
create_target_branch(into) if @create_merge_request
validate_target_branch(into) if @create_merge_request
repository.public_send(
action,
current_user,
@commit,
into,
tree_id,
start_project: @start_project,
start_branch_name: @start_branch)
repository.public_send(action, current_user, @commit, into, tree_id)
success
else
error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title(current_user)} automatically.
......@@ -50,12 +66,12 @@ module Commits
true
end
def create_target_branch(new_branch)
def validate_target_branch(new_branch)
# Temporary branch exists and contains the change commit
return success if repository.find_branch(new_branch)
return if repository.find_branch(new_branch)
result = CreateBranchService.new(@project, current_user)
.execute(new_branch, @target_branch, source_project: @source_project)
result = ValidateNewBranchService.new(@project, current_user)
.execute(new_branch)
if result[:status] == :error
raise ChangeError, "There was an error creating the source branch: #{result[:message]}"
......
......@@ -3,23 +3,27 @@ require 'securerandom'
# Compare 2 branches for one repo or between repositories
# and return Gitlab::Git::Compare object that responds to commits and diffs
class CompareService
def execute(source_project, source_branch, target_project, target_branch, straight: false)
source_commit = source_project.commit(source_branch)
return unless source_commit
attr_reader :start_project, :start_branch_name
source_sha = source_commit.sha
def initialize(new_start_project, new_start_branch_name)
@start_project = new_start_project
@start_branch_name = new_start_branch_name
end
def execute(target_project, target_branch, straight: false)
# If compare with other project we need to fetch ref first
unless target_project == source_project
random_string = SecureRandom.hex
target_project.repository.with_repo_branch_commit(
start_project.repository,
start_branch_name) do |commit|
break unless commit
target_project.repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{source_branch}",
"refs/tmp/#{random_string}/head"
)
compare(commit.sha, target_project, target_branch, straight)
end
end
private
def compare(source_sha, target_project, target_branch, straight)
raw_compare = Gitlab::Git::Compare.new(
target_project.repository.raw_repository,
target_branch,
......
class CreateBranchService < BaseService
def execute(branch_name, ref, source_project: @project)
valid_branch = Gitlab::GitRefValidator.validate(branch_name)
def execute(branch_name, ref)
result = ValidateNewBranchService.new(project, current_user)
.execute(branch_name)
unless valid_branch
return error('Branch name is invalid')
end
repository = project.repository
existing_branch = repository.find_branch(branch_name)
if existing_branch
return error('Branch already exists')
end
new_branch = if source_project != @project
repository.fetch_ref(
source_project.repository.path_to_repo,
"refs/heads/#{ref}",
"refs/heads/#{branch_name}"
)
repository.after_create_branch
return result if result[:status] == :error
repository.find_branch(branch_name)
else
repository.add_branch(current_user, branch_name, ref)
end
new_branch = repository.add_branch(current_user, branch_name, ref)
if new_branch
success(new_branch)
......
class CreateSnippetService < BaseService
def execute
request = params.delete(:request)
api = params.delete(:api)
snippet = if project
project.snippets.build(params)
else
......@@ -12,8 +15,12 @@ class CreateSnippetService < BaseService
end
snippet.author = current_user
snippet.spam = SpamService.new(snippet, request).check(api)
if snippet.save
UserAgentDetailService.new(snippet, request).create
end
snippet.save
snippet
end
end
......@@ -7,7 +7,7 @@ class DeleteTagService < BaseService
return error('No such tag', 404)
end
if repository.rm_tag(tag_name)
if repository.rm_tag(current_user, tag_name)
release = project.releases.find_by(tag: tag_name)
release.destroy if release
......
......@@ -3,9 +3,9 @@ module Files
class ValidationError < StandardError; end
def execute
@source_project = params[:source_project] || @project
@source_branch = params[:source_branch]
@target_branch = params[:target_branch]
@start_project = params[:start_project] || @project
@start_branch = params[:start_branch]
@target_branch = params[:target_branch]
@commit_message = params[:commit_message]
@file_path = params[:file_path]
......@@ -22,10 +22,8 @@ module Files
# Validate parameters
validate
# Create new branch if it different from source_branch
if different_branch?
create_target_branch
end
# Create new branch if it different from start_branch
validate_target_branch if different_branch?
result = commit
if result
......@@ -40,7 +38,7 @@ module Files
private
def different_branch?
@source_branch != @target_branch || @source_project != @project
@start_branch != @target_branch || @start_project != @project
end
def file_has_changed?
......@@ -61,22 +59,23 @@ module Files
end
unless project.empty_repo?
unless @source_project.repository.branch_names.include?(@source_branch)
unless @start_project.repository.branch_exists?(@start_branch)
raise_error('You can only create or edit files when you are on a branch')
end
if different_branch?
if repository.branch_names.include?(@target_branch)
if repository.branch_exists?(@target_branch)
raise_error('Branch with such name already exists. You need to switch to this branch in order to make changes')
end
end
end
end
def create_target_branch
result = CreateBranchService.new(project, current_user).execute(@target_branch, @source_branch, source_project: @source_project)
def validate_target_branch
result = ValidateNewBranchService.new(project, current_user).
execute(@target_branch)
unless result[:status] == :success
if result[:status] == :error
raise_error("Something went wrong when we tried to create #{@target_branch} for you: #{result[:message]}")
end
end
......
module Files
class CreateDirService < Files::BaseService
def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name)
repository.commit_dir(
current_user,
@file_path,
message: @commit_message,
branch_name: @target_branch,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
def validate
......
module Files
class CreateService < Files::BaseService
def commit
repository.commit_file(current_user, @file_path, @file_content, @commit_message, @target_branch, false, author_email: @author_email, author_name: @author_name)
repository.commit_file(
current_user,
@file_path,
@file_content,
message: @commit_message,
branch_name: @target_branch,
update: false,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
def validate
......@@ -24,7 +34,7 @@ module Files
unless project.empty_repo?
@file_path.slice!(0) if @file_path.start_with?('/')
blob = repository.blob_at_branch(@source_branch, @file_path)
blob = repository.blob_at_branch(@start_branch, @file_path)
if blob
raise_error('Your changes could not be committed because a file with the same name already exists')
......
module Files
class DeleteService < Files::BaseService
def commit
repository.remove_file(current_user, @file_path, @commit_message, @target_branch, author_email: @author_email, author_name: @author_name)
repository.remove_file(
current_user,
@file_path,
message: @commit_message,
branch_name: @target_branch,
author_email: @author_email,
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
end
end
......@@ -5,11 +5,13 @@ module Files
def commit
repository.multi_action(
user: current_user,
branch: @target_branch,
message: @commit_message,
branch_name: @target_branch,
actions: params[:actions],
author_email: @author_email,
author_name: @author_name
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch
)
end
......@@ -61,7 +63,7 @@ module Files
end
def last_commit
Gitlab::Git::Commit.last_for_path(repository, @source_branch, @file_path)
Gitlab::Git::Commit.last_for_path(repository, @start_branch, @file_path)
end
def regex_check(file)
......
......@@ -4,11 +4,13 @@ module Files
def commit
repository.update_file(current_user, @file_path, @file_content,
branch: @target_branch,
previous_path: @previous_path,
message: @commit_message,
branch_name: @target_branch,
previous_path: @previous_path,
author_email: @author_email,
author_name: @author_name)
author_name: @author_name,
start_project: @start_project,
start_branch_name: @start_branch)
end
private
......@@ -23,7 +25,7 @@ module Files
def last_commit
@last_commit ||= Gitlab::Git::Commit.
last_for_path(@source_project.repository, @source_branch, @file_path)
last_for_path(@start_project.repository, @start_branch, @file_path)
end
end
end
......@@ -18,9 +18,9 @@ class GitHooksService
end
end
yield self
run_hook('post-receive')
yield(self).tap do
run_hook('post-receive')
end
end
private
......
class GitOperationService
attr_reader :user, :repository
def initialize(new_user, new_repository)
@user = new_user
@repository = new_repository
end
def add_branch(branch_name, newrev)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
oldrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev)
end
def rm_branch(branch)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch.name
oldrev = branch.target
newrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev)
end
def add_tag(tag_name, newrev, options = {})
ref = Gitlab::Git::TAG_REF_PREFIX + tag_name
oldrev = Gitlab::Git::BLANK_SHA
with_hooks(ref, newrev, oldrev) do |service|
# We want to pass the OID of the tag object to the hooks. For an
# annotated tag we don't know that OID until after the tag object
# (raw_tag) is created in the repository. That is why we have to
# update the value after creating the tag object. Only the
# "post-receive" hook will receive the correct value in this case.
raw_tag = repository.rugged.tags.create(tag_name, newrev, options)
service.newrev = raw_tag.target_id
end
end
def rm_tag(tag)
ref = Gitlab::Git::TAG_REF_PREFIX + tag.name
oldrev = tag.target
newrev = Gitlab::Git::BLANK_SHA
update_ref_in_hooks(ref, newrev, oldrev) do
repository.rugged.tags.delete(tag_name)
end
end
# Whenever `start_branch_name` is passed, if `branch_name` doesn't exist,
# it would be created from `start_branch_name`.
# If `start_project` is passed, and the branch doesn't exist,
# it would try to find the commits from it instead of current repository.
def with_branch(
branch_name,
start_branch_name: nil,
start_project: repository.project,
&block)
check_with_branch_arguments!(
branch_name, start_branch_name, start_project)
update_branch_with_hooks(branch_name) do
repository.with_repo_branch_commit(
start_project.repository,
start_branch_name || branch_name,
&block)
end
end
private
def update_branch_with_hooks(branch_name)
update_autocrlf_option
was_empty = repository.empty?
# Make commit
newrev = yield
unless newrev
raise Repository::CommitError.new('Failed to create commit')
end
branch = repository.find_branch(branch_name)
oldrev = find_oldrev_from_branch(newrev, branch)
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
update_ref_in_hooks(ref, newrev, oldrev)
# If repo was empty expire cache
repository.after_create if was_empty
repository.after_create_branch if
was_empty || Gitlab::Git.blank_ref?(oldrev)
newrev
end
def find_oldrev_from_branch(newrev, branch)
return Gitlab::Git::BLANK_SHA unless branch
oldrev = branch.target
if oldrev == repository.rugged.merge_base(newrev, branch.target)
oldrev
else
raise Repository::CommitError.new('Branch diverged')
end
end
def update_ref_in_hooks(ref, newrev, oldrev)
with_hooks(ref, newrev, oldrev) do
update_ref(ref, newrev, oldrev)
end
end
def with_hooks(ref, newrev, oldrev)
GitHooksService.new.execute(
user,
repository.path_to_repo,
oldrev,
newrev,
ref) do |service|
yield(service)
end
end
def update_ref(ref, newrev, oldrev)
# We use 'git update-ref' because libgit2/rugged currently does not
# offer 'compare and swap' ref updates. Without compare-and-swap we can
# (and have!) accidentally reset the ref to an earlier state, clobbering
# commits. See also https://github.com/libgit2/libgit2/issues/1534.
command = %W[#{Gitlab.config.git.bin_path} update-ref --stdin -z]
_, status = Gitlab::Popen.popen(
command,
repository.path_to_repo) do |stdin|
stdin.write("update #{ref}\x00#{newrev}\x00#{oldrev}\x00")
end
unless status.zero?
raise Repository::CommitError.new(
"Could not update branch #{Gitlab::Git.branch_name(ref)}." \
" Please refresh and try again.")
end
end
def update_autocrlf_option
if repository.raw_repository.autocrlf != :input
repository.raw_repository.autocrlf = :input
end
end
def check_with_branch_arguments!(
branch_name, start_branch_name, start_project)
return if repository.branch_exists?(branch_name)
if repository.project != start_project
unless start_branch_name
raise ArgumentError,
'Should also pass :start_branch_name if' +
' :start_project is different from current project'
end
unless start_project.repository.branch_exists?(start_branch_name)
raise ArgumentError,
"Cannot find branch #{branch_name} nor" \
" #{start_branch_name} from" \
" #{start_project.path_with_namespace}"
end
elsif start_branch_name
unless repository.branch_exists?(start_branch_name)
raise ArgumentError,
"Cannot find branch #{branch_name} nor" \
" #{start_branch_name} from" \
" #{repository.project.path_with_namespace}"
end
end
end
end
......@@ -47,9 +47,10 @@ module MergeRequests
end
def compare_branches
compare = CompareService.new.execute(
compare = CompareService.new(
source_project,
source_branch,
source_branch
).execute(
target_project,
target_branch
)
......
......@@ -6,13 +6,17 @@ module MergeRequests
# Executed when you do merge via GitLab UI
#
class MergeService < MergeRequests::BaseService
attr_reader :merge_request
attr_reader :merge_request, :source
def execute(merge_request)
@merge_request = merge_request
return log_merge_error('Merge request is not mergeable', true) unless @merge_request.mergeable?
@source = find_merge_source
return log_merge_error('No source for merge', true) unless @source
merge_request.in_locked_state do
if commit
after_merge
......@@ -34,7 +38,7 @@ module MergeRequests
committer: committer
}
commit_id = repository.merge(current_user, merge_request, options)
commit_id = repository.merge(current_user, source, merge_request, options)
if commit_id
merge_request.update(merge_commit_sha: commit_id)
......@@ -73,9 +77,11 @@ module MergeRequests
end
def merge_request_info
project = merge_request.project
merge_request.to_reference(full: true)
end
"#{project.to_reference}#{merge_request.to_reference}"
def find_merge_source
merge_request.diff_head_sha
end
end
end
require_relative 'base_service'
class ValidateNewBranchService < BaseService
def execute(branch_name)
valid_branch = Gitlab::GitRefValidator.validate(branch_name)
unless valid_branch
return error('Branch name is invalid')
end
repository = project.repository
existing_branch = repository.find_branch(branch_name)
if existing_branch
return error('Branch already exists')
end
success
rescue GitHooksService::PreReceiveError => ex
error(ex.message)
end
end
......@@ -212,7 +212,7 @@
.col-sm-10
= f.number_field :max_artifacts_size, class: 'form-control'
.help-block
Set the maximum file size each build's artifacts can have
Set the maximum file size each jobs's artifacts can have
= link_to "(?)", help_page_path("user/admin_area/settings/continuous_integration", anchor: "maximum-artifacts-size")
- if Gitlab.config.registry.enabled
......
......@@ -12,7 +12,7 @@
= link_to 'Cancel all', cancel_all_admin_builds_path, data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
.row-content-block.second-block
#{(@scope || 'all').capitalize} builds
#{(@scope || 'all').capitalize} jobs
%ul.content-list.builds-content-list.admin-builds-table
= render "projects/builds/table", builds: @builds, admin: true
......@@ -20,9 +20,9 @@
%span
Groups
= nav_link path: 'builds#index' do
= link_to admin_builds_path, title: 'Builds' do
= link_to admin_builds_path, title: 'Jobs' do
%span
Builds
Jobs
= nav_link path: ['runners#index', 'runners#show'] do
= link_to admin_runners_path, title: 'Runners' do
%span
......
......@@ -26,7 +26,7 @@
.bs-callout
%p
A 'Runner' is a process which runs a build.
A 'Runner' is a process which runs a job.
You can setup as many Runners as you need.
%br
Runners can be placed on separate users, servers, even on your local machine.
......@@ -37,16 +37,16 @@
%ul
%li
%span.label.label-success shared
\- Runner runs builds from all unassigned projects
\- Runner runs jobs from all unassigned projects
%li
%span.label.label-info specific
\- Runner runs builds from assigned projects
\- Runner runs jobs from assigned projects
%li
%span.label.label-warning locked
\- Runner cannot be assigned to other projects
%li
%span.label.label-danger paused
\- Runner will not receive any new builds
\- Runner will not receive any new jobs
.append-bottom-20.clearfix
.pull-left
......@@ -68,7 +68,7 @@
%th Runner token
%th Description
%th Projects
%th Builds
%th Jobs
%th Tags
%th Last contact
%th
......
......@@ -11,13 +11,13 @@
- if @runner.shared?
.bs-callout.bs-callout-success
%h4 This Runner will process builds from ALL UNASSIGNED projects
%h4 This Runner will process jobs from ALL UNASSIGNED projects
%p
If you want Runners to build only specific projects, enable them in the table below.
Keep in mind that this is a one way transition.
- else
.bs-callout.bs-callout-info
%h4 This Runner will process builds only from ASSIGNED projects
%h4 This Runner will process jobs only from ASSIGNED projects
%p You can't make this a shared Runner.
%hr
......@@ -70,11 +70,11 @@
= paginate @projects, theme: "gitlab"
.col-md-6
%h4 Recent builds served by this Runner
%h4 Recent jobs served by this Runner
%table.table.ci-table.runner-builds
%thead
%tr
%th Build
%th Job
%th Status
%th Project
%th Commit
......
......@@ -3,7 +3,7 @@
.col-md-4.col-lg-6
= users_select_tag(:user_ids, multiple: true, class: 'input-clamp', scope: :all, email_user: true)
.help-block.append-bottom-10
Search for users by name, username, or email, or invite new ones using their email address.
Search for members by name, username, or email, or invite new ones using their email address.
.col-md-3.col-lg-2
= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @group_member.access_level), class: "form-control project-access-select"
......@@ -16,7 +16,7 @@
= text_field_tag :expires_at, nil, class: 'form-control js-access-expiration-date', placeholder: 'Expiration date'
%i.clear-icon.js-clear-input
.help-block.append-bottom-10
On this date, the user(s) will automatically lose access to this group and all of its projects.
On this date, the member(s) will automatically lose access to this group and all of its projects.
.col-md-2
= f.submit 'Add to group', class: "btn btn-create btn-block"
......@@ -7,7 +7,7 @@
- if can?(current_user, :admin_group_member, @group)
.project-members-new.append-bottom-default
%p.clearfix
Add new user to
Add new member to
%strong= @group.name
= render "new_group_member"
......@@ -15,7 +15,7 @@
.append-bottom-default.clearfix
%h5.member.existing-title
Existing users
Existing members
= form_tag group_group_members_path(@group), method: :get, class: 'form-inline member-search-form' do
.form-group
= search_field_tag :search, params[:search], { placeholder: 'Find existing members by name', class: 'form-control', spellcheck: false }
......@@ -24,7 +24,7 @@
= render 'shared/members/sort_dropdown'
.panel.panel-default
.panel-heading
Users with access to
Members with access to
%strong= @group.name
%span.badge= @members.total_count
%ul.content-list
......
......@@ -143,7 +143,7 @@
.key g
.key b
%td
Go to builds
Go to jobs
%tr
%td.shortcut
.key g
......
......@@ -96,8 +96,8 @@
-# Shortcut to builds page
- if project_nav_tab? :builds
%li.hidden
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
Builds
= link_to project_builds_path(@project), title: 'Jobs', class: 'shortcuts-builds' do
Jobs
-# Shortcut to commits page
- if project_nav_tab? :commits
......
- content_for :header do
%h1{ style: "background: #c40834; color: #FFF; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;" }
GitLab (build failed)
GitLab (job failed)
%h3
Project:
......@@ -21,4 +21,4 @@
Message: #{@build.pipeline.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Job details: #{link_to "Job #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build failed for <%= @project.name %>
Job failed for <%= @project.name %>
Status: <%= @build.status %>
Commit: <%= @build.pipeline.short_sha %>
......
- content_for :header do
%h1{ style: "background: #38CF5B; color: #FFF; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;" }
GitLab (build successful)
GitLab (job successful)
%h3
Project:
......@@ -21,4 +21,4 @@
Message: #{@build.pipeline.git_commit_message}
%p
Build details: #{link_to "Build #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Job details: #{link_to "Job #{@build.id}", namespace_project_build_url(@build.project.namespace, @build.project, @build)}
Build successful for <%= @project.name %>
Job successful for <%= @project.name %>
Status: <%= @build.status %>
Commit: <%= @build.pipeline.short_sha %>
......
Build #<%= build.id %> ( <%= pipeline_build_url(pipeline, build) %> )
Job #<%= build.id %> ( <%= pipeline_build_url(pipeline, build) %> )
......@@ -3,6 +3,6 @@
%h4
Customize your workflow!
%p
Get started with GitLab by enabling features that work best for your project. From issues and wikis, to merge requests and builds, GitLab can help manage your workflow from idea to production!
Get started with GitLab by enabling features that work best for your project. From issues and wikis, to merge requests and pipelines, GitLab can help manage your workflow from idea to production!
- if can?(current_user, :admin_project, @project)
= link_to "Get started", edit_project_path(@project), class: "btn btn-success"
......@@ -4,10 +4,10 @@
.checkbox.builds-feature
= form.label :only_allow_merge_if_build_succeeds do
= form.check_box :only_allow_merge_if_build_succeeds
%strong Only allow merge requests to be merged if the build succeeds
%strong Only allow merge requests to be merged if the pipeline succeeds
%br
%span.descr
Builds need to be configured to enable this feature.
Pipelines need to be configured to enable this feature.
= link_to icon('question-circle'), help_page_path('user/project/merge_requests/merge_when_pipeline_succeeds', anchor: 'only-allow-merge-requests-to-be-merged-if-the-pipeline-succeeds')
.checkbox
= form.label :only_allow_merge_if_all_discussions_are_resolved do
......
- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Builds'
- page_title 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs'
.top-block.row-content-block.clearfix
.pull-right
......
.content-block.build-header
.header-content
= render 'ci/status/badge', status: @build.detailed_status(current_user), link: false
Build
Job
%strong.js-build-id ##{@build.id}
in pipeline
= link_to pipeline_path(@build.pipeline) do
......@@ -17,6 +17,6 @@
= render "user"
= time_ago_with_tooltip(@build.created_at)
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry build", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-inverted-secondary pull-right', method: :post
= link_to "Retry job", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-inverted-secondary pull-right', method: :post
%button.btn.btn-default.pull-right.visible-xs-block.visible-sm-block.build-gutter-toggle.js-sidebar-build-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
......@@ -2,7 +2,7 @@
%aside.right-sidebar.right-sidebar-expanded.build-sidebar.js-build-sidebar
.block.build-sidebar-header.visible-xs-block.visible-sm-block.append-bottom-default
Build
Job
%strong ##{@build.id}
%a.gutter-toggle.pull-right.js-sidebar-build-toggle{ href: "#" }
= icon('angle-double-right')
......@@ -17,7 +17,7 @@
- if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?)
.block{ class: ("block-first" if !@build.coverage) }
.title
Build artifacts
Job artifacts
- if @build.artifacts_expired?
%p.build-detail-row
The artifacts were removed
......@@ -42,9 +42,9 @@
.block{ class: ("block-first" if !@build.coverage && !(can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?))) }
.title
Build details
Job details
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry build", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right retry-link', method: :post
= link_to "Retry job", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right retry-link', method: :post
- if @build.merge_request
%p.build-detail-row
%span.build-light-text Merge Request:
......@@ -136,4 +136,4 @@
- else
= build.id
- if build.retried?
%i.fa.fa-refresh.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Build was retried' }
%i.fa.fa-refresh.has-tooltip{ data: { container: 'body', placement: 'bottom' }, title: 'Job was retried' }
......@@ -2,14 +2,14 @@
- if builds.blank?
%div
.nothing-here-block No builds to show
.nothing-here-block No jobs to show
- else
.table-holder
%table.table.ci-table.builds-page
%thead
%tr
%th Status
%th Build
%th Job
%th Pipeline
- if admin
%th Project
......
- @no_container = true
- page_title "Builds"
- page_title "Jobs"
= render "projects/pipelines/head"
%div{ class: container_class }
......@@ -14,7 +14,7 @@
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
- unless @repository.gitlab_ci_yml
= link_to 'Get started with Builds', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
= link_to 'Get started with CI/CD Pipelines', help_page_path('ci/quick_start/README'), class: 'btn btn-info'
= link_to ci_lint_path, class: 'btn btn-default' do
%span CI Lint
......
- @no_container = true
- page_title "#{@build.name} (##{@build.id})", "Builds"
- page_title "#{@build.name} (##{@build.id})", "Jobs"
- trace_with_state = @build.trace_with_state
= render "projects/pipelines/head", build_subnav: true
......@@ -12,14 +12,14 @@
.bs-callout.bs-callout-warning
%p
- if no_runners_for_project?(@build.project)
This build is stuck, because the project doesn't have any runners online assigned to it.
This job is stuck, because the project doesn't have any runners online assigned to it.
- elsif @build.tags.any?
This build is stuck, because you don't have any active runners online with any of these tags assigned to them:
This job is stuck, because you don't have any active runners online with any of these tags assigned to them:
- @build.tags.each do |tag|
%span.label.label-primary
= tag
- else
This build is stuck, because you don't have any active runners that can run this build.
This job is stuck, because you don't have any active runners that can run this job.
%br
Go to
......@@ -37,14 +37,14 @@
- environment = environment_for_build(@build.project, @build)
- if @build.success? && @build.last_deployment.present?
- if @build.last_deployment.last?
This build is the most recent deployment to #{environment_link_for_build(@build.project, @build)}.
This job is the most recent deployment to #{environment_link_for_build(@build.project, @build)}.
- else
This build is an out-of-date deployment to #{environment_link_for_build(@build.project, @build)}.
This job is an out-of-date deployment to #{environment_link_for_build(@build.project, @build)}.
View the most recent deployment #{deployment_link(environment.last_deployment)}.
- elsif @build.complete? && !@build.success?
The deployment of this build to #{environment_link_for_build(@build.project, @build)} did not succeed.
The deployment of this job to #{environment_link_for_build(@build.project, @build)} did not succeed.
- else
This build is creating a deployment to #{environment_link_for_build(@build.project, @build)}
This job is creating a deployment to #{environment_link_for_build(@build.project, @build)}
- if environment.try(:last_deployment)
and will overwrite the #{deployment_link(environment.last_deployment, text: 'latest deployment')}
......@@ -52,9 +52,9 @@
- if @build.erased?
.erased.alert.alert-warning
- if @build.erased_by_user?
Build has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)}
Job has been erased by #{link_to(@build.erased_by_name, user_path(@build.erased_by))} #{time_ago_with_tooltip(@build.erased_at)}
- else
Build has been erased #{time_ago_with_tooltip(@build.erased_at)}
Job has been erased #{time_ago_with_tooltip(@build.erased_at)}
- else
#js-build-scroll.scroll-controls
.scroll-step
......
......@@ -32,10 +32,10 @@
= link_to build.short_sha, namespace_project_commit_path(build.project.namespace, build.project, build.sha), class: "commit-id monospace"
- if build.stuck?
= icon('warning', class: 'text-warning has-tooltip', title: 'Build is stuck. Check runners.')
= icon('warning', class: 'text-warning has-tooltip', title: 'Job is stuck. Check runners.')
- if retried
= icon('refresh', class: 'text-warning has-tooltip', title: 'Build was retried')
= icon('refresh', class: 'text-warning has-tooltip', title: 'Job was retried')
.label-container
- if build.tags.any?
......
......@@ -15,7 +15,7 @@
- else
%span.api.monospace API
- if pipeline.latest?
%span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
%span.label.label-success.has-tooltip{ title: 'Latest job for this branch' } latest
- if pipeline.triggered?
%span.label.label-primary triggered
- if pipeline.yaml_errors.present?
......@@ -78,7 +78,7 @@
.btn-group.inline
- if actions.any?
.btn-group
%button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual build', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual build' }
%button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual job', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual job' }
= custom_icon('icon_play')
= icon('caret-down', 'aria-hidden' => 'true')
%ul.dropdown-menu.dropdown-menu-align-right
......
......@@ -13,7 +13,7 @@
Pipeline
= link_to "##{pipeline.id}", namespace_project_pipeline_path(pipeline.project.namespace, pipeline.project, pipeline.id), class: "monospace"
with
= pluralize pipeline.statuses.count(:id), "build"
= pluralize pipeline.statuses.count(:id), "job"
- if pipeline.ref
for
= link_to pipeline.ref, namespace_project_commits_path(pipeline.project.namespace, pipeline.project, pipeline.ref), class: "monospace"
......@@ -44,7 +44,7 @@
%thead
%tr
%th Status
%th Build ID
%th Job ID
%th Name
%th
- if pipeline.project.build_coverage_enabled?
......
......@@ -5,7 +5,7 @@
- unless diff_file.submodule?
.file-actions.hidden-xs
- if blob_text_viewable?(blob)
= link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip btn-file-option', title: "Toggle comments for this file", disabled: @diff_notes_disabled do
= link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip', title: "Toggle comments for this file", disabled: @diff_notes_disabled do
= icon('comment')
\
- if editable_diff?(diff_file)
......
......@@ -63,7 +63,7 @@
.row
.col-md-9.project-feature.nested
= feature_fields.label :builds_access_level, "Builds", class: 'label-light'
= feature_fields.label :builds_access_level, "Pipelines", class: 'label-light'
%span.help-block Submit, test and deploy your changes before merge
.col-md-3
= project_feature_access_select(:builds_access_level)
......@@ -181,13 +181,13 @@
%p
The following items will NOT be exported:
%ul
%li Build traces and artifacts
%li Job traces and artifacts
%li LFS objects
%li Container registry images
%li CI variables
%li Any encrypted tokens
%hr
- if can? current_user, :archive_project, @project
%hr
.row.prepend-top-default
.col-lg-3
%h4.warning-title.prepend-top-0
......
......@@ -32,8 +32,8 @@
%tr
%th ID
%th Commit
%th Build
%th
%th Job
%th Created
%th.hidden-xs
= render @deployments
......
%h4 Build charts
%h4 Pipelines charts
%p
&nbsp;
%span.cgreen
......@@ -11,19 +11,19 @@
.prepend-top-default
%p.light
Builds for last week
Jobs for last week
(#{date_from_to(Date.today - 7.days, Date.today)})
%canvas#weekChart{ height: 200 }
.prepend-top-default
%p.light
Builds for last month
Jobs for last month
(#{date_from_to(Date.today - 30.days, Date.today)})
%canvas#monthChart{ height: 200 }
.prepend-top-default
%p.light
Builds for last year
Jobs for last year
%canvas#yearChart.padded{ height: 250 }
- [:week, :month, :year].each do |scope|
......
......@@ -8,5 +8,5 @@
'@click' => "onClickResolveModeButton(file, 'edit')",
type: 'button' }
Edit inline
%a.btn.view-file.btn-file-option{ ":href" => "file.blobPath" }
%a.btn.view-file{ ":href" => "file.blobPath" }
View file @{{conflictsData.shortCommitSha}}
......@@ -10,7 +10,7 @@
= ci_label_for_status(status)
for
= succeed "." do
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace"
= link_to @pipeline.short_sha, namespace_project_commit_path(@merge_request.source_project.namespace, @merge_request.source_project, @pipeline.sha), class: "monospace js-commit-link"
%span.ci-coverage
- elsif @merge_request.has_ci?
......@@ -21,7 +21,7 @@
.ci_widget{ class: "ci-#{status} ci-status-icon-#{status}", style: "display:none" }
= ci_icon_for_status(status)
%span
CI build
CI job
= ci_label_for_status(status)
for
- commit = @merge_request.diff_head_commit
......
......@@ -16,14 +16,18 @@
gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.status : ''}",
ci_message: {
normal: "Build {{status}} for \"{{title}}\"",
preparing: "{{status}} build for \"{{title}}\""
normal: "Job {{status}} for \"{{title}}\"",
preparing: "{{status}} job for \"{{title}}\""
},
ci_enable: #{@project.ci_service ? "true" : "false"},
ci_title: {
preparing: "{{status}} build",
normal: "Build {{status}}"
preparing: "{{status}} job",
normal: "Job {{status}}"
},
ci_sha: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.short_sha : ''}",
ci_pipeline: #{@merge_request.head_pipeline.try(:id).to_json},
commits_path: "#{project_commits_path(@project)}",
pipeline_path: "#{project_pipelines_path(@project)}",
pipelines_path: "#{pipelines_namespace_project_merge_request_path(@project.namespace, @project, @merge_request)}"
};
......
......@@ -35,10 +35,10 @@
The source branch will be removed.
- elsif @merge_request.can_remove_source_branch?(current_user)
.accept-control.checkbox
= label_tag :should_remove_source_branch, class: "remove_source_checkbox" do
= label_tag :should_remove_source_branch, class: "merge-param-checkbox" do
= check_box_tag :should_remove_source_branch
Remove source branch
.accept-control.right
.accept-control
= link_to "#", class: "modify-merge-commit-link js-toggle-button" do
= icon('edit')
Modify commit message
......
%h4
= icon('exclamation-triangle')
The build for this merge request failed
The job for this merge request failed
%p
Please retry the build or push a new commit to fix the failure.
Please retry the job or push a new commit to fix the failure.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment