Commit 44a45d87 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce-to-ee' into 'master'

CE upstream

See merge request !1360
parents 0f6d2ca8 e083313d
...@@ -284,7 +284,7 @@ bundler:audit: ...@@ -284,7 +284,7 @@ bundler:audit:
- master@gitlab/gitlabhq - master@gitlab/gitlabhq
- master@gitlab/gitlab-ee - master@gitlab/gitlab-ee
script: script:
- "bundle exec bundle-audit check --update --ignore OSVDB-115941 CVE-2016-6316 CVE-2016-6317" - "bundle exec bundle-audit check --update"
migration paths: migration paths:
stage: test stage: test
...@@ -405,6 +405,7 @@ pages: ...@@ -405,6 +405,7 @@ pages:
- public - public
only: only:
- master@gitlab-org/gitlab-ce - master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
# Insurance in case a gem needed by one of our releases gets yanked from # Insurance in case a gem needed by one of our releases gets yanked from
# rubygems.org in the future. # rubygems.org in the future.
......
...@@ -355,7 +355,7 @@ gem 'oauth2', '~> 1.2.0' ...@@ -355,7 +355,7 @@ gem 'oauth2', '~> 1.2.0'
gem 'paranoia', '~> 2.2' gem 'paranoia', '~> 2.2'
# Health check # Health check
gem 'health_check', '~> 2.2.0' gem 'health_check', '~> 2.6.0'
# System information # System information
gem 'vmstat', '~> 2.3.0' gem 'vmstat', '~> 2.3.0'
......
...@@ -371,7 +371,7 @@ GEM ...@@ -371,7 +371,7 @@ GEM
thor thor
tilt tilt
hashie (3.5.5) hashie (3.5.5)
health_check (2.2.1) health_check (2.6.0)
rails (>= 4.0) rails (>= 4.0)
hipchat (1.5.2) hipchat (1.5.2)
httparty httparty
...@@ -700,7 +700,7 @@ GEM ...@@ -700,7 +700,7 @@ GEM
sexp_processor (~> 4.1) sexp_processor (~> 4.1)
rubyntlm (0.5.2) rubyntlm (0.5.2)
rubypants (0.2.0) rubypants (0.2.0)
rubyzip (1.2.0) rubyzip (1.2.1)
rufus-scheduler (3.1.10) rufus-scheduler (3.1.10)
rugged (0.24.0) rugged (0.24.0)
safe_yaml (1.0.4) safe_yaml (1.0.4)
...@@ -939,7 +939,7 @@ DEPENDENCIES ...@@ -939,7 +939,7 @@ DEPENDENCIES
gssapi gssapi
haml_lint (~> 0.21.0) haml_lint (~> 0.21.0)
hamlit (~> 2.6.1) hamlit (~> 2.6.1)
health_check (~> 2.2.0) health_check (~> 2.6.0)
hipchat (~> 1.5.0) hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0) html-pipeline (~> 1.11.0)
html2text html2text
...@@ -1059,4 +1059,4 @@ DEPENDENCIES ...@@ -1059,4 +1059,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.14.4 1.14.5
...@@ -25,6 +25,9 @@ require('./lib/utils/common_utils'); ...@@ -25,6 +25,9 @@ require('./lib/utils/common_utils');
}, },
}, },
ReferenceFilter: { ReferenceFilter: {
'.tooltip'(el, text) {
return '';
},
'a.gfm:not([data-link=true])'(el, text) { 'a.gfm:not([data-link=true])'(el, text) {
return el.dataset.original || text; return el.dataset.original || text;
}, },
......
...@@ -25,6 +25,10 @@ require('./lib/utils/url_utility'); ...@@ -25,6 +25,10 @@ require('./lib/utils/url_utility');
isBound = true; isBound = true;
} }
if (gl.utils.getLocationHash()) {
this.highlightSelectedLine();
}
this.openAnchoredDiff(); this.openAnchoredDiff();
} }
...@@ -78,7 +82,7 @@ require('./lib/utils/url_utility'); ...@@ -78,7 +82,7 @@ require('./lib/utils/url_utility');
if (nothingHereBlock.length) { if (nothingHereBlock.length) {
const clickTarget = $('.js-file-title, .click-to-expand', diffFile); const clickTarget = $('.js-file-title, .click-to-expand', diffFile);
diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => {
this.highlighSelectedLine(); this.highlightSelectedLine();
if (cb) cb(); if (cb) cb();
}); });
} else if (cb) { } else if (cb) {
...@@ -94,7 +98,7 @@ require('./lib/utils/url_utility'); ...@@ -94,7 +98,7 @@ require('./lib/utils/url_utility');
} else { } else {
window.location.hash = hash; window.location.hash = hash;
} }
this.highlighSelectedLine(); this.highlightSelectedLine();
} }
diffViewType() { diffViewType() {
...@@ -108,7 +112,7 @@ require('./lib/utils/url_utility'); ...@@ -108,7 +112,7 @@ require('./lib/utils/url_utility');
return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10)); return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10));
} }
highlighSelectedLine() { highlightSelectedLine() {
const hash = gl.utils.getLocationHash(); const hash = gl.utils.getLocationHash();
const $diffFiles = $('.diff-file'); const $diffFiles = $('.diff-file');
$diffFiles.find('.hll').removeClass('hll'); $diffFiles.find('.hll').removeClass('hll');
......
...@@ -37,6 +37,9 @@ ...@@ -37,6 +37,9 @@
/* global WeightSelect */ /* global WeightSelect */
/* global AdminEmailSelect */ /* global AdminEmailSelect */
import GroupsList from './groups_list';
import ProjectsList from './projects_list';
const ShortcutsBlob = require('./shortcuts_blob'); const ShortcutsBlob = require('./shortcuts_blob');
const UserCallout = require('./user_callout'); const UserCallout = require('./user_callout');
...@@ -98,6 +101,18 @@ const UserCallout = require('./user_callout'); ...@@ -98,6 +101,18 @@ const UserCallout = require('./user_callout');
case 'dashboard:todos:index': case 'dashboard:todos:index':
new gl.Todos(); new gl.Todos();
break; break;
case 'dashboard:projects:index':
case 'dashboard:projects:starred':
case 'explore:projects:index':
case 'explore:projects:trending':
case 'explore:projects:starred':
case 'admin:projects:index':
new ProjectsList();
break;
case 'dashboard:groups:index':
case 'explore:groups:index':
new GroupsList();
break;
case 'projects:milestones:new': case 'projects:milestones:new':
case 'projects:milestones:edit': case 'projects:milestones:edit':
case 'projects:milestones:update': case 'projects:milestones:update':
...@@ -160,9 +175,6 @@ const UserCallout = require('./user_callout'); ...@@ -160,9 +175,6 @@ const UserCallout = require('./user_callout');
case 'dashboard:activity': case 'dashboard:activity':
new gl.Activities(); new gl.Activities();
break; break;
case 'dashboard:projects:starred':
new gl.Activities();
break;
case 'projects:commit:show': case 'projects:commit:show':
new Commit(); new Commit();
new gl.Diff(); new gl.Diff();
...@@ -205,6 +217,7 @@ const UserCallout = require('./user_callout'); ...@@ -205,6 +217,7 @@ const UserCallout = require('./user_callout');
shortcut_handler = new ShortcutsNavigation(); shortcut_handler = new ShortcutsNavigation();
new NotificationsForm(); new NotificationsForm();
new NotificationsDropdown(); new NotificationsDropdown();
new ProjectsList();
break; break;
case 'groups:group_members:index': case 'groups:group_members:index':
new gl.MemberExpirationDate(); new gl.MemberExpirationDate();
......
/**
* Makes search request for content when user types a value in the search input.
* Updates the html content of the page with the received one.
*/
export default class FilterableList {
constructor(form, filter, holder) {
this.filterForm = form;
this.listFilterElement = filter;
this.listHolderElement = holder;
}
initSearch() {
this.debounceFilter = _.debounce(this.filterResults.bind(this), 500);
this.listFilterElement.removeEventListener('input', this.debounceFilter);
this.listFilterElement.addEventListener('input', this.debounceFilter);
}
filterResults() {
const form = this.filterForm;
const filterUrl = `${form.getAttribute('action')}?${$(form).serialize()}`;
$(this.listHolderElement).fadeTo(250, 0.5);
return $.ajax({
url: form.getAttribute('action'),
data: $(form).serialize(),
type: 'GET',
dataType: 'json',
context: this,
complete() {
$(this.listHolderElement).fadeTo(250, 1);
},
success(data) {
this.listHolderElement.innerHTML = data.html;
// Change url so if user reload a page - search results are saved
return window.history.replaceState({
page: filterUrl,
}, document.title, filterUrl);
},
});
}
}
import FilterableList from './filterable_list';
/**
* Makes search request for groups when user types a value in the search input.
* Updates the html content of the page with the received one.
*/
export default class GroupsList {
constructor() {
const form = document.querySelector('form#group-filter-form');
const filter = document.querySelector('.js-groups-list-filter');
const holder = document.querySelector('.js-groups-list-holder');
if (form && filter && holder) {
const list = new FilterableList(form, filter, holder);
list.initSearch();
}
}
}
/* eslint-disable func-names, space-before-function-paren */
/*= require cropper */
(function() {
}).call(window);
...@@ -65,9 +65,10 @@ require('vendor/latinise'); ...@@ -65,9 +65,10 @@ require('vendor/latinise');
} }
}; };
gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) { gl.text.insertText = function(textArea, text, tag, blockTag, selected, wrap) {
var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine; var insertText, inserted, selectedSplit, startChar, removedLastNewLine, removedFirstNewLine, currentLineEmpty, lastNewLine;
removedLastNewLine = false; removedLastNewLine = false;
removedFirstNewLine = false; removedFirstNewLine = false;
currentLineEmpty = false;
// Remove the first newline // Remove the first newline
if (selected.indexOf('\n') === 0) { if (selected.indexOf('\n') === 0) {
...@@ -82,7 +83,17 @@ require('vendor/latinise'); ...@@ -82,7 +83,17 @@ require('vendor/latinise');
} }
selectedSplit = selected.split('\n'); selectedSplit = selected.split('\n');
startChar = !wrap && textArea.selectionStart > 0 ? '\n' : '';
if (!wrap) {
lastNewLine = textArea.value.substr(0, textArea.selectionStart).lastIndexOf('\n');
// Check whether the current line is empty or consists only of spaces(=handle as empty)
if (/^\s*$/.test(textArea.value.substring(lastNewLine, textArea.selectionStart))) {
currentLineEmpty = true;
}
}
startChar = !wrap && !currentLineEmpty && textArea.selectionStart > 0 ? '\n' : '';
if (selectedSplit.length > 1 && (!wrap || (blockTag != null))) { if (selectedSplit.length > 1 && (!wrap || (blockTag != null))) {
if (blockTag != null) { if (blockTag != null) {
...@@ -142,9 +153,8 @@ require('vendor/latinise'); ...@@ -142,9 +153,8 @@ require('vendor/latinise');
} }
}; };
gl.text.updateText = function(textArea, tag, blockTag, wrap) { gl.text.updateText = function(textArea, tag, blockTag, wrap) {
var $textArea, oldVal, selected, text; var $textArea, selected, text;
$textArea = $(textArea); $textArea = $(textArea);
oldVal = $textArea.val();
textArea = $textArea.get(0); textArea = $textArea.get(0);
text = $textArea.val(); text = $textArea.val();
selected = this.selectedText(text, textArea); selected = this.selectedText(text, textArea);
......
/* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */ /* eslint-disable no-useless-escape, max-len, quotes, no-var, no-underscore-dangle, func-names, space-before-function-paren, no-unused-vars, no-return-assign, object-shorthand, one-var, one-var-declaration-per-line, comma-dangle, consistent-return, class-methods-use-this, new-parens */
import 'vendor/cropper';
((global) => { ((global) => {
// Matches everything but the file name // Matches everything but the file name
const FILENAMEREGEX = /^.*[\\\/]/; const FILENAMEREGEX = /^.*[\\\/]/;
......
/* eslint-disable func-names, space-before-function-paren, object-shorthand, quotes, no-var, one-var, one-var-declaration-per-line, prefer-arrow-callback, consistent-return, no-unused-vars, camelcase, prefer-template, comma-dangle, max-len */ import FilterableList from './filterable_list';
(function() { /**
window.ProjectsList = { * Makes search request for projects when user types a value in the search input.
init: function() { * Updates the html content of the page with the received one.
$(".projects-list-filter").off('keyup'); */
this.initSearch(); export default class ProjectsList {
return this.initPagination(); constructor() {
}, const form = document.querySelector('form#project-filter-form');
initSearch: function() { const filter = document.querySelector('.js-projects-list-filter');
var debounceFilter, projectsListFilter; const holder = document.querySelector('.js-projects-list-holder');
projectsListFilter = $('.projects-list-filter');
debounceFilter = _.debounce(window.ProjectsList.filterResults, 500); if (form && filter && holder) {
return projectsListFilter.on('keyup', function(e) { const list = new FilterableList(form, filter, holder);
if (projectsListFilter.val() !== '') { list.initSearch();
return debounceFilter();
}
});
},
filterResults: function() {
var form, project_filter_url, search;
$('.projects-list-holder').fadeTo(250, 0.5);
form = null;
form = $("form#project-filter-form");
search = $(".projects-list-filter").val();
project_filter_url = form.attr('action') + '?' + form.serialize();
return $.ajax({
type: "GET",
url: form.attr('action'),
data: form.serialize(),
complete: function() {
return $('.projects-list-holder').fadeTo(250, 1);
},
success: function(data) {
$('.projects-list-holder').replaceWith(data.html);
return history.replaceState({
page: project_filter_url
// Change url so if user reload a page - search results are saved
}, document.title, project_filter_url);
},
dataType: "json"
});
},
initPagination: function() {
return $('.projects-list-holder .pagination').on('ajax:success', function(e, data) {
return $('.projects-list-holder').replaceWith(data.html);
});
} }
}; }
}).call(window); }
...@@ -16,9 +16,6 @@ require('./shortcuts'); ...@@ -16,9 +16,6 @@ require('./shortcuts');
Mousetrap.bind('g p', function() { Mousetrap.bind('g p', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-project');
}); });
Mousetrap.bind('g e', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-project-activity');
});
Mousetrap.bind('g f', function() { Mousetrap.bind('g f', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-tree'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-tree');
}); });
...@@ -31,9 +28,6 @@ require('./shortcuts'); ...@@ -31,9 +28,6 @@ require('./shortcuts');
Mousetrap.bind('g n', function() { Mousetrap.bind('g n', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-network'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-network');
}); });
Mousetrap.bind('g g', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-graphs');
});
Mousetrap.bind('g i', function() { Mousetrap.bind('g i', function() {
return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues'); return ShortcutsNavigation.findAndFollowLink('.shortcuts-issues');
}); });
......
...@@ -43,6 +43,8 @@ class UserCallout { ...@@ -43,6 +43,8 @@ class UserCallout {
this.userCalloutBody.append($template); this.userCalloutBody.append($template);
$template.find(closeButton).on('click', e => this.dismissCallout(e)); $template.find(closeButton).on('click', e => this.dismissCallout(e));
$template.find(userCalloutBtn).on('click', e => this.dismissCallout(e)); $template.find(userCalloutBtn).on('click', e => this.dismissCallout(e));
} else {
this.userCalloutBody.remove();
} }
} }
...@@ -50,7 +52,7 @@ class UserCallout { ...@@ -50,7 +52,7 @@ class UserCallout {
Cookies.set(USER_CALLOUT_COOKIE, 'true'); Cookies.set(USER_CALLOUT_COOKIE, 'true');
const $currentTarget = $(e.currentTarget); const $currentTarget = $(e.currentTarget);
if ($currentTarget.hasClass('close-user-callout')) { if ($currentTarget.hasClass('close-user-callout')) {
this.userCalloutBody.empty(); this.userCalloutBody.remove();
} }
} }
} }
......
...@@ -107,11 +107,12 @@ ...@@ -107,11 +107,12 @@
&.fa-spinner { &.fa-spinner {
font-size: 16px; font-size: 16px;
margin-top: -8px; margin-top: -3px;
} }
} }
.fa-chevron-down { .fa-chevron-down,
.fa-spinner {
position: absolute; position: absolute;
top: 11px; top: 11px;
right: 8px; right: 8px;
...@@ -196,6 +197,10 @@ ...@@ -196,6 +197,10 @@
&.is-focused { &.is-focused {
background-color: $dropdown-link-hover-bg; background-color: $dropdown-link-hover-bg;
text-decoration: none; text-decoration: none;
.badge {
background-color: darken($row-hover, 5%);
}
} }
&.dropdown-menu-empty-link { &.dropdown-menu-empty-link {
...@@ -232,6 +237,12 @@ ...@@ -232,6 +237,12 @@
padding: 5px 8px; padding: 5px 8px;
color: $gl-text-color-secondary; color: $gl-text-color-secondary;
} }
.badge {
position: absolute;
right: 8px;
top: 5px;
}
} }
.dropdown-menu-drop-up { .dropdown-menu-drop-up {
......
...@@ -149,14 +149,14 @@ header { ...@@ -149,14 +149,14 @@ header {
.header-logo { .header-logo {
display: inline-block; display: inline-block;
margin: 0 8px 0 3px; margin: 0 7px 0 2px;
position: relative; position: relative;
top: 7px; top: 10px;
transition-duration: .3s; transition-duration: .3s;
svg, svg,
img { img {
height: 36px; height: 28px;
} }
&:hover { &:hover {
......
...@@ -73,10 +73,6 @@ ...@@ -73,10 +73,6 @@
right: $gutter_collapsed_width; right: $gutter_collapsed_width;
} }
} }
&.with-overlay {
padding-right: $gutter_collapsed_width;
}
} }
.right-sidebar { .right-sidebar {
......
...@@ -155,7 +155,7 @@ ...@@ -155,7 +155,7 @@
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.event-item { .event-item {
padding-left: $gl-padding; padding-left: 0;
.event-title { .event-title {
white-space: normal; white-space: normal;
...@@ -169,8 +169,7 @@ ...@@ -169,8 +169,7 @@
.event-body { .event-body {
margin: 0; margin: 0;
border-left: 2px solid $events-body-border; padding-left: 0;
padding-left: 10px;
} }
.event-item-timestamp { .event-item-timestamp {
......
...@@ -279,7 +279,7 @@ table.u2f-registrations { ...@@ -279,7 +279,7 @@ table.u2f-registrations {
} }
.user-callout { .user-callout {
margin: 24px auto 0; margin: 0 auto;
.bordered-box { .bordered-box {
border: 1px solid $border-color; border: 1px solid $border-color;
...@@ -287,6 +287,7 @@ table.u2f-registrations { ...@@ -287,6 +287,7 @@ table.u2f-registrations {
} }
.landing { .landing {
margin-top: $gl-padding;
margin-bottom: $gl-padding; margin-bottom: $gl-padding;
.close { .close {
......
...@@ -182,7 +182,8 @@ input[type="checkbox"]:hover { ...@@ -182,7 +182,8 @@ input[type="checkbox"]:hover {
display: flex; display: flex;
} }
.search-field-holder { .search-field-holder,
.project-filter-form {
-webkit-flex: 1 0 auto; -webkit-flex: 1 0 auto;
flex: 1 0 auto; flex: 1 0 auto;
position: relative; position: relative;
...@@ -201,7 +202,8 @@ input[type="checkbox"]:hover { ...@@ -201,7 +202,8 @@ input[type="checkbox"]:hover {
pointer-events: none; pointer-events: none;
} }
.search-text-input { .search-text-input,
.project-filter-form-field {
padding-left: $gl-padding + 15px; padding-left: $gl-padding + 15px;
padding-right: $gl-padding + 15px; padding-right: $gl-padding + 15px;
} }
......
...@@ -178,3 +178,29 @@ ...@@ -178,3 +178,29 @@
margin-left: $btn-side-margin; margin-left: $btn-side-margin;
} }
} }
.repo-charts {
.sub-header {
margin: 20px 0;
}
.sub-header-block.border-top {
margin-top: 20px;
padding: 0;
border-top: 1px solid $white-dark;
border-bottom: none;
}
.commit-stats li {
font-size: 16px;
}
.tree-ref-header {
margin-bottom: 20px;
h4 {
margin: 0;
line-height: 36px;
}
}
}
class Admin::HealthCheckController < Admin::ApplicationController class Admin::HealthCheckController < Admin::ApplicationController
def show def show
@errors = HealthCheck::Utils.process_checks('standard') @errors = HealthCheck::Utils.process_checks(['standard'])
end end
end end
...@@ -14,6 +14,15 @@ class Admin::ProjectsController < Admin::ApplicationController ...@@ -14,6 +14,15 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.search(params[:name]) if params[:name].present? @projects = @projects.search(params[:name]) if params[:name].present?
@projects = @projects.sort(@sort = params[:sort]) @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]) @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page])
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("admin/projects/_projects", locals: { projects: @projects })
}
end
end
end end
def show def show
......
...@@ -126,10 +126,6 @@ class ApplicationController < ActionController::Base ...@@ -126,10 +126,6 @@ class ApplicationController < ActionController::Base
headers['X-XSS-Protection'] = '1; mode=block' headers['X-XSS-Protection'] = '1; mode=block'
headers['X-UA-Compatible'] = 'IE=edge' headers['X-UA-Compatible'] = 'IE=edge'
headers['X-Content-Type-Options'] = 'nosniff' headers['X-Content-Type-Options'] = 'nosniff'
# Enabling HSTS for non-standard ports would send clients to the wrong port
if Gitlab.config.gitlab.https && Gitlab.config.gitlab.port == 443
headers['Strict-Transport-Security'] = 'max-age=31536000'
end
end end
def validate_user_service_ticket! def validate_user_service_ticket!
......
module Ci
class ProjectsController < ::ApplicationController
before_action :project
before_action :no_cache, only: [:badge]
before_action :authorize_read_project!, except: [:badge, :index]
skip_before_action :authenticate_user!, only: [:badge]
protect_from_forgery
def index
redirect_to root_path
end
def show
# Temporary compatibility with CI badges pointing to CI project page
redirect_to namespace_project_path(project.namespace, project)
end
# Project status badge
# Image with build status for sha or ref
#
# This action in DEPRECATED, this is here only for backwards compatibility
# with projects migrated from GitLab CI.
#
def badge
return render_404 unless @project
image = Ci::ImageForBuildService.new.execute(@project, params)
send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml"
end
protected
def project
@project ||= Project.find_by(ci_id: params[:id].to_i)
end
def no_cache
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
def authorize_read_project!
return access_denied! unless can?(current_user, :read_project, project)
end
end
end
...@@ -4,10 +4,9 @@ module CreatesCommit ...@@ -4,10 +4,9 @@ module CreatesCommit
def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil) def create_commit(service, success_path:, failure_path:, failure_view: nil, success_notice: nil)
set_commit_variables set_commit_variables
start_branch = @mr_target_branch unless initial_commit?
commit_params = @commit_params.merge( commit_params = @commit_params.merge(
start_project: @mr_target_project, start_project: @mr_target_project,
start_branch: start_branch, start_branch: @mr_target_branch,
target_branch: @mr_source_branch target_branch: @mr_source_branch
) )
...@@ -17,12 +16,16 @@ module CreatesCommit ...@@ -17,12 +16,16 @@ module CreatesCommit
if result[:status] == :success if result[:status] == :success
update_flash_notice(success_notice) update_flash_notice(success_notice)
success_path = final_success_path(success_path)
respond_to do |format| respond_to do |format|
format.html { redirect_to final_success_path(success_path) } format.html { redirect_to success_path }
format.json { render json: { message: "success", filePath: final_success_path(success_path) } } format.json { render json: { message: "success", filePath: success_path } }
end end
else else
flash[:alert] = result[:message] flash[:alert] = result[:message]
failure_path = failure_path.call if failure_path.respond_to?(:call)
respond_to do |format| respond_to do |format|
format.html do format.html do
if failure_view if failure_view
...@@ -58,9 +61,13 @@ module CreatesCommit ...@@ -58,9 +61,13 @@ module CreatesCommit
end end
def final_success_path(success_path) def final_success_path(success_path)
return success_path unless create_merge_request? if create_merge_request?
merge_request_exists? ? existing_merge_request_path : new_merge_request_path
else
success_path = success_path.call if success_path.respond_to?(:call)
merge_request_exists? ? existing_merge_request_path : new_merge_request_path success_path
end
end end
def new_merge_request_path def new_merge_request_path
...@@ -92,47 +99,26 @@ module CreatesCommit ...@@ -92,47 +99,26 @@ module CreatesCommit
end end
def create_merge_request? def create_merge_request?
# XXX: Even if the field is set, if we're checking the same branch # Even if the field is set, if we're checking the same branch
# as the target branch in the same project, # as the target branch in the same project,
# we don't want to create a merge request. # we don't want to create a merge request.
params[:create_merge_request].present? && params[:create_merge_request].present? &&
(different_project? || @ref != @target_branch) (different_project? || @mr_target_branch != @mr_source_branch)
end end
# TODO: We should really clean this up
def set_commit_variables def set_commit_variables
@mr_source_project = if can?(current_user, :push_code, @project)
if can?(current_user, :push_code, @project) @mr_source_project = @project
# Edit file in this project @target_branch ||= @ref
@project else
else @mr_source_project = current_user.fork_of(@project)
# Merge request from fork to this project @target_branch ||= @mr_source_project.repository.next_branch('patch')
current_user.fork_of(@project) end
end
# Merge request to this project # Merge request to this project
@mr_target_project = @project @mr_target_project = @project
@mr_target_branch = @ref || @target_branch @mr_target_branch ||= @ref || @target_branch
@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 @mr_source_branch = @target_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
end end
...@@ -8,7 +8,7 @@ module FilterProjects ...@@ -8,7 +8,7 @@ module FilterProjects
extend ActiveSupport::Concern extend ActiveSupport::Concern
def filter_projects(projects) def filter_projects(projects)
projects = projects.search(params[:filter_projects]) if params[:filter_projects].present? projects = projects.search(params[:name]) if params[:name].present?
projects = projects.non_archived if params[:archived].blank? projects = projects.non_archived if params[:archived].blank?
projects = projects.personal(current_user) if params[:personal].present? && current_user projects = projects.personal(current_user) if params[:personal].present? && current_user
......
class Dashboard::GroupsController < Dashboard::ApplicationController class Dashboard::GroupsController < Dashboard::ApplicationController
def index def index
@group_members = current_user.group_members.includes(source: :route).page(params[:page]) @group_members = current_user.group_members.includes(source: :route).joins(:group)
@group_members = @group_members.merge(Group.search(params[:filter_groups])) if params[:filter_groups].present?
@group_members = @group_members.merge(Group.sort(@sort = params[:sort]))
@group_members = @group_members.page(params[:page])
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("dashboard/groups/_groups", locals: { group_members: @group_members })
}
end
end
end end
end end
class Explore::GroupsController < Explore::ApplicationController class Explore::GroupsController < Explore::ApplicationController
def index def index
@groups = GroupsFinder.new.execute(current_user) @groups = GroupsFinder.new.execute(current_user)
@groups = @groups.search(params[:search]) if params[:search].present? @groups = @groups.search(params[:filter_groups]) if params[:filter_groups].present?
@groups = @groups.sort(@sort = params[:sort]) @groups = @groups.sort(@sort = params[:sort])
@groups = @groups.page(params[:page]) @groups = @groups.page(params[:page])
respond_to do |format|
format.html
format.json do
render json: {
html: view_to_html_string("explore/groups/_groups", locals: { groups: @groups })
}
end
end
end end
end end
...@@ -108,7 +108,7 @@ class GroupsController < Groups::ApplicationController ...@@ -108,7 +108,7 @@ class GroupsController < Groups::ApplicationController
@projects = @projects.sorted_by_activity @projects = @projects.sorted_by_activity
@projects = filter_projects(@projects) @projects = filter_projects(@projects)
@projects = @projects.sort(@sort = params[:sort]) @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:filter_projects].blank? @projects = @projects.page(params[:page]) if params[:name].blank?
end end
def authorize_create_group! def authorize_create_group!
......
...@@ -24,7 +24,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -24,7 +24,7 @@ class Projects::BlobController < Projects::ApplicationController
def create def create
create_commit(Files::CreateService, success_notice: "The file has been successfully created.", create_commit(Files::CreateService, success_notice: "The file has been successfully created.",
success_path: namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)), success_path: -> { namespace_project_blob_path(@project.namespace, @project, File.join(@target_branch, @file_path)) },
failure_view: :new, failure_view: :new,
failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref)) failure_path: namespace_project_new_blob_path(@project.namespace, @project, @ref))
end end
...@@ -40,7 +40,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -40,7 +40,7 @@ class Projects::BlobController < Projects::ApplicationController
def update def update
@path = params[:file_path] if params[:file_path].present? @path = params[:file_path] if params[:file_path].present?
create_commit(Files::UpdateService, success_path: after_edit_path, create_commit(Files::UpdateService, success_path: -> { after_edit_path },
failure_view: :edit, failure_view: :edit,
failure_path: namespace_project_blob_path(@project.namespace, @project, @id)) failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
...@@ -62,7 +62,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -62,7 +62,7 @@ class Projects::BlobController < Projects::ApplicationController
def destroy def destroy
create_commit(Files::DestroyService, success_notice: "The file has been successfully deleted.", create_commit(Files::DestroyService, success_notice: "The file has been successfully deleted.",
success_path: namespace_project_tree_path(@project.namespace, @project, @target_branch), success_path: -> { namespace_project_tree_path(@project.namespace, @project, @target_branch) },
failure_view: :show, failure_view: :show,
failure_path: namespace_project_blob_path(@project.namespace, @project, @id)) failure_path: namespace_project_blob_path(@project.namespace, @project, @id))
end end
......
...@@ -51,23 +51,35 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -51,23 +51,35 @@ class Projects::CommitController < Projects::ApplicationController
def revert def revert
assign_change_commit_vars assign_change_commit_vars
return render_404 if @target_branch.blank? return render_404 if @start_branch.blank?
@target_branch = create_new_branch? ? @commit.revert_branch_name : @start_branch
@mr_target_branch = @start_branch
create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.", create_commit(Commits::RevertService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully reverted.",
success_path: successful_change_path, failure_path: failed_change_path) success_path: -> { successful_change_path }, failure_path: failed_change_path)
end end
def cherry_pick def cherry_pick
assign_change_commit_vars assign_change_commit_vars
return render_404 if @target_branch.blank? return render_404 if @start_branch.blank?
@target_branch = create_new_branch? ? @commit.cherry_pick_branch_name : @start_branch
@mr_target_branch = @start_branch
create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked.", create_commit(Commits::CherryPickService, success_notice: "The #{@commit.change_type_title(current_user)} has been successfully cherry-picked.",
success_path: successful_change_path, failure_path: failed_change_path) success_path: -> { successful_change_path }, failure_path: failed_change_path)
end end
private private
def create_new_branch?
params[:create_merge_request].present? || !can?(current_user, :push_code, @project)
end
def successful_change_path def successful_change_path
referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @target_branch) referenced_merge_request_url || namespace_project_commits_url(@project.namespace, @project, @target_branch)
end end
...@@ -78,7 +90,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -78,7 +90,7 @@ class Projects::CommitController < Projects::ApplicationController
def referenced_merge_request_url def referenced_merge_request_url
if merge_request = @commit.merged_merge_request(current_user) if merge_request = @commit.merged_merge_request(current_user)
namespace_project_merge_request_url(@project.namespace, @project, merge_request) namespace_project_merge_request_url(merge_request.target_project.namespace, merge_request.target_project, merge_request)
end end
end end
...@@ -94,7 +106,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -94,7 +106,7 @@ class Projects::CommitController < Projects::ApplicationController
@diffs = commit.diffs(opts) @diffs = commit.diffs(opts)
@notes_count = commit.notes.count @notes_count = commit.notes.count
@environment = EnvironmentsFinder.new(@project, current_user, commit: @commit).execute.last @environment = EnvironmentsFinder.new(@project, current_user, commit: @commit).execute.last
end end
...@@ -118,11 +130,7 @@ class Projects::CommitController < Projects::ApplicationController ...@@ -118,11 +130,7 @@ class Projects::CommitController < Projects::ApplicationController
end end
def assign_change_commit_vars def assign_change_commit_vars
@commit = project.commit(params[:id]) @start_branch = params[:start_branch]
@target_branch = params[:target_branch] @commit_params = { commit: @commit }
@commit_params = {
commit: @commit,
create_merge_request: params[:create_merge_request].present? || different_project?
}
end end
end end
...@@ -17,6 +17,25 @@ class Projects::GraphsController < Projects::ApplicationController ...@@ -17,6 +17,25 @@ class Projects::GraphsController < Projects::ApplicationController
end end
def commits def commits
redirect_to action: 'charts'
end
def languages
redirect_to action: 'charts'
end
def charts
get_commits
get_languages
end
def ci
redirect_to charts_namespace_project_pipelines_path(@project.namespace, @project)
end
private
def get_commits
@commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true) @commits = @project.repository.commits(@ref, limit: 2000, skip_merges: true)
@commits_graph = Gitlab::Graphs::Commits.new(@commits) @commits_graph = Gitlab::Graphs::Commits.new(@commits)
@commits_per_week_days = @commits_graph.commits_per_week_days @commits_per_week_days = @commits_graph.commits_per_week_days
...@@ -24,15 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController ...@@ -24,15 +43,7 @@ class Projects::GraphsController < Projects::ApplicationController
@commits_per_month = @commits_graph.commits_per_month @commits_per_month = @commits_graph.commits_per_month
end end
def ci def get_languages
@charts = {}
@charts[:week] = Ci::Charts::WeekChart.new(project)
@charts[:month] = Ci::Charts::MonthChart.new(project)
@charts[:year] = Ci::Charts::YearChart.new(project)
@charts[:build_times] = Ci::Charts::BuildTime.new(project)
end
def languages
@languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages @languages = Linguist::Repository.new(@repository.rugged, @repository.rugged.head.target_id).languages
total = @languages.map(&:last).sum total = @languages.map(&:last).sum
...@@ -52,8 +63,6 @@ class Projects::GraphsController < Projects::ApplicationController ...@@ -52,8 +63,6 @@ class Projects::GraphsController < Projects::ApplicationController
end end
end end
private
def fetch_graph def fetch_graph
@commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true) @commits = @project.repository.commits(@ref, limit: 6000, skip_merges: true)
@log = [] @log = []
......
class Projects::PipelinesController < Projects::ApplicationController class Projects::PipelinesController < Projects::ApplicationController
before_action :pipeline, except: [:index, :new, :create] before_action :pipeline, except: [:index, :new, :create, :charts]
before_action :commit, only: [:show, :builds] before_action :commit, only: [:show, :builds]
before_action :authorize_read_pipeline! before_action :authorize_read_pipeline!
before_action :authorize_create_pipeline!, only: [:new, :create] before_action :authorize_create_pipeline!, only: [:new, :create]
before_action :authorize_update_pipeline!, only: [:retry, :cancel] before_action :authorize_update_pipeline!, only: [:retry, :cancel]
before_action :builds_enabled, only: :charts
def index def index
@scope = params[:scope] @scope = params[:scope]
...@@ -92,6 +93,14 @@ class Projects::PipelinesController < Projects::ApplicationController ...@@ -92,6 +93,14 @@ class Projects::PipelinesController < Projects::ApplicationController
redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project) redirect_back_or_default default: namespace_project_pipelines_path(project.namespace, project)
end end
def charts
@charts = {}
@charts[:week] = Ci::Charts::WeekChart.new(project)
@charts[:month] = Ci::Charts::MonthChart.new(project)
@charts[:year] = Ci::Charts::YearChart.new(project)
@charts[:build_times] = Ci::Charts::BuildTime.new(project)
end
private private
def create_params def create_params
......
...@@ -170,7 +170,7 @@ module ApplicationHelper ...@@ -170,7 +170,7 @@ module ApplicationHelper
css_classes = short_format ? 'js-short-timeago' : 'js-timeago' css_classes = short_format ? 'js-short-timeago' : 'js-timeago'
css_classes << " #{html_class}" unless html_class.blank? css_classes << " #{html_class}" unless html_class.blank?
element = content_tag :time, time.to_s, element = content_tag :time, time.strftime("%b %d, %Y"),
class: css_classes, class: css_classes,
title: time.to_time.in_time_zone.to_s(:medium), title: time.to_time.in_time_zone.to_s(:medium),
datetime: time.to_time.getutc.iso8601, datetime: time.to_time.getutc.iso8601,
......
module ExploreHelper module ExploreHelper
def filter_projects_path(options = {}) def filter_projects_path(options = {})
exist_opts = { exist_opts = {
sort: params[:sort], sort: params[:sort] || @sort,
scope: params[:scope], scope: params[:scope],
group: params[:group], group: params[:group],
tag: params[:tag], tag: params[:tag],
visibility_level: params[:visibility_level], visibility_level: params[:visibility_level],
name: params[:name],
personal: params[:personal],
archived: params[:archived],
shared: params[:shared],
namespace_id: params[:namespace_id],
} }
options = exist_opts.merge(options) options = exist_opts.merge(options).delete_if { |key, value| value.blank? }
path = request.path request_path_with_options(options)
path << "?#{options.to_param}" end
path
def filter_groups_path(options = {})
request_path_with_options(options)
end end
def explore_controller? def explore_controller?
controller.class.name.split("::").first == "Explore" controller.class.name.split("::").first == "Explore"
end end
private
def request_path_with_options(options = {})
request.path + "?#{options.to_param}"
end
end end
module RssHelper
def rss_url_options
{ format: :atom, private_token: current_user.try(:private_token) }
end
end
...@@ -115,6 +115,7 @@ class Project < ActiveRecord::Base ...@@ -115,6 +115,7 @@ class Project < ActiveRecord::Base
has_one :external_wiki_service, dependent: :destroy has_one :external_wiki_service, dependent: :destroy
has_one :kubernetes_service, dependent: :destroy, inverse_of: :project has_one :kubernetes_service, dependent: :destroy, inverse_of: :project
has_one :index_status, dependent: :destroy has_one :index_status, dependent: :destroy
has_one :mock_ci_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
......
...@@ -94,7 +94,12 @@ class KubernetesService < DeploymentService ...@@ -94,7 +94,12 @@ class KubernetesService < DeploymentService
{ key: 'KUBE_TOKEN', value: token, public: false }, { key: 'KUBE_TOKEN', value: token, public: false },
{ key: 'KUBE_NAMESPACE', value: namespace, public: true } { key: 'KUBE_NAMESPACE', value: namespace, public: true }
] ]
variables << { key: 'KUBE_CA_PEM', value: ca_pem, public: true } if ca_pem.present?
if ca_pem.present?
variables << { key: 'KUBE_CA_PEM', value: ca_pem, public: true }
variables << { key: 'KUBE_CA_PEM_FILE', value: ca_pem, public: true, file: true }
end
variables variables
end end
......
...@@ -10,6 +10,7 @@ class Repository ...@@ -10,6 +10,7 @@ class Repository
attr_accessor :path_with_namespace, :project attr_accessor :path_with_namespace, :project
CommitError = Class.new(StandardError) CommitError = Class.new(StandardError)
CreateTreeError = Class.new(StandardError)
MIRROR_REMOTE = "upstream".freeze MIRROR_REMOTE = "upstream".freeze
MIRROR_GEO = "geo".freeze MIRROR_GEO = "geo".freeze
...@@ -897,17 +898,18 @@ class Repository ...@@ -897,17 +898,18 @@ class Repository
end end
def revert( def revert(
user, commit, branch_name, revert_tree_id = nil, user, commit, branch_name,
start_branch_name: nil, start_project: project) start_branch_name: nil, start_project: project)
revert_tree_id ||= check_revert_content(commit, branch_name)
return false unless revert_tree_id
GitOperationService.new(user, self).with_branch( GitOperationService.new(user, self).with_branch(
branch_name, branch_name,
start_branch_name: start_branch_name, start_branch_name: start_branch_name,
start_project: start_project) do |start_commit| start_project: start_project) do |start_commit|
revert_tree_id = check_revert_content(commit, start_commit.sha)
unless revert_tree_id
raise Repository::CreateTreeError.new('Failed to revert commit')
end
committer = user_to_committer(user) committer = user_to_committer(user)
Rugged::Commit.create(rugged, Rugged::Commit.create(rugged,
...@@ -920,17 +922,18 @@ class Repository ...@@ -920,17 +922,18 @@ class Repository
end end
def cherry_pick( def cherry_pick(
user, commit, branch_name, cherry_pick_tree_id = nil, user, commit, branch_name,
start_branch_name: nil, start_project: project) start_branch_name: nil, start_project: project)
cherry_pick_tree_id ||= check_cherry_pick_content(commit, branch_name)
return false unless cherry_pick_tree_id
GitOperationService.new(user, self).with_branch( GitOperationService.new(user, self).with_branch(
branch_name, branch_name,
start_branch_name: start_branch_name, start_branch_name: start_branch_name,
start_project: start_project) do |start_commit| start_project: start_project) do |start_commit|
cherry_pick_tree_id = check_cherry_pick_content(commit, start_commit.sha)
unless cherry_pick_tree_id
raise Repository::CreateTreeError.new('Failed to cherry-pick commit')
end
committer = user_to_committer(user) committer = user_to_committer(user)
Rugged::Commit.create(rugged, Rugged::Commit.create(rugged,
...@@ -954,9 +957,8 @@ class Repository ...@@ -954,9 +957,8 @@ class Repository
end end
end end
def check_revert_content(target_commit, branch_name) def check_revert_content(target_commit, source_sha)
source_sha = commit(branch_name).sha args = [target_commit.sha, source_sha]
args = [target_commit.sha, source_sha]
args << { mainline: 1 } if target_commit.merge_commit? args << { mainline: 1 } if target_commit.merge_commit?
revert_index = rugged.revert_commit(*args) revert_index = rugged.revert_commit(*args)
...@@ -968,9 +970,8 @@ class Repository ...@@ -968,9 +970,8 @@ class Repository
tree_id tree_id
end end
def check_cherry_pick_content(target_commit, branch_name) def check_cherry_pick_content(target_commit, source_sha)
source_sha = commit(branch_name).sha args = [target_commit.sha, source_sha]
args = [target_commit.sha, source_sha]
args << 1 if target_commit.merge_commit? args << 1 if target_commit.merge_commit?
cherry_pick_index = rugged.cherrypick_commit(*args) cherry_pick_index = rugged.cherrypick_commit(*args)
...@@ -1078,6 +1079,8 @@ class Repository ...@@ -1078,6 +1079,8 @@ class Repository
end end
def with_repo_branch_commit(start_repository, start_branch_name) def with_repo_branch_commit(start_repository, start_branch_name)
return yield(nil) if start_repository.empty_repo?
branch_name_or_sha = branch_name_or_sha =
if start_repository == self if start_repository == self
start_branch_name start_branch_name
......
...@@ -23,6 +23,7 @@ class User < ActiveRecord::Base ...@@ -23,6 +23,7 @@ class User < ActiveRecord::Base
default_value_for :can_create_team, false default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false default_value_for :hide_no_ssh_key, false
default_value_for :hide_no_password, false default_value_for :hide_no_password, false
default_value_for :project_view, :files
attr_encrypted :otp_secret, attr_encrypted :otp_secret,
key: Gitlab::Application.secrets.otp_key_base, key: Gitlab::Application.secrets.otp_key_base,
......
module Ci
class ImageForBuildService
def execute(project, opts)
ref = opts[:ref]
sha = opts[:sha] || ref_sha(project, ref)
pipelines = project.pipelines.where(sha: sha)
image_name = image_for_status(pipelines.latest_status(ref))
image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(path: image_path, name: image_name)
end
private
def ref_sha(project, ref)
project.commit(ref).try(:sha) if ref
end
def image_for_status(status)
status ||= 'unknown'
'build-' + status + ".svg"
end
end
end
module Ci module Ci
class RetryBuildService < ::BaseService class RetryBuildService < ::BaseService
CLONE_ATTRIBUTES = %i[pipeline project ref tag options commands name CLONE_ACCESSORS = %i[pipeline project ref tag options commands name
allow_failure stage stage_idx trigger_request allow_failure stage stage_idx trigger_request
yaml_variables when environment coverage_regex] yaml_variables when environment coverage_regex
.freeze description tag_list].freeze
REJECT_ATTRIBUTES = %i[id status user token coverage trace runner
artifacts_expire_at artifacts_file
artifacts_metadata artifacts_size
created_at updated_at started_at finished_at
queued_at erased_by erased_at].freeze
IGNORE_ATTRIBUTES = %i[type lock_version gl_project_id target_url
deploy job_id description].freeze
def execute(build) def execute(build)
reprocess(build).tap do |new_build| reprocess(build).tap do |new_build|
...@@ -31,7 +22,7 @@ module Ci ...@@ -31,7 +22,7 @@ module Ci
raise Gitlab::Access::AccessDeniedError raise Gitlab::Access::AccessDeniedError
end end
attributes = CLONE_ATTRIBUTES.map do |attribute| attributes = CLONE_ACCESSORS.map do |attribute|
[attribute, build.send(attribute)] [attribute, build.send(attribute)]
end end
......
...@@ -8,9 +8,9 @@ module Commits ...@@ -8,9 +8,9 @@ module Commits
@start_branch = params[:start_branch] @start_branch = params[:start_branch]
@target_branch = params[:target_branch] @target_branch = params[:target_branch]
@commit = params[:commit] @commit = params[:commit]
@create_merge_request = params[:create_merge_request].present?
check_push_permissions unless @create_merge_request check_push_permissions
commit commit
rescue Repository::CommitError, Gitlab::Git::Repository::InvalidBlobName, GitHooksService::PreReceiveError, rescue Repository::CommitError, Gitlab::Git::Repository::InvalidBlobName, GitHooksService::PreReceiveError,
ValidationError, ChangeError => ex ValidationError, ChangeError => ex
...@@ -26,34 +26,21 @@ module Commits ...@@ -26,34 +26,21 @@ module Commits
def commit_change(action) def commit_change(action)
raise NotImplementedError unless repository.respond_to?(action) raise NotImplementedError unless repository.respond_to?(action)
if @create_merge_request validate_target_branch if different_branch?
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
validate_target_branch(into) if @create_merge_request
repository.public_send( repository.public_send(
action, action,
current_user, current_user,
@commit, @commit,
into, @target_branch,
tree_id, start_project: @start_project,
start_project: @start_project, start_branch_name: @start_branch)
start_branch_name: @start_branch)
success success
else rescue Repository::CreateTreeError
error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title(current_user)} automatically. error_msg = "Sorry, we cannot #{action.to_s.dasherize} this #{@commit.change_type_title(current_user)} automatically.
A #{action.to_s.dasherize} may have already been performed with this #{@commit.change_type_title(current_user)}, or a more recent commit may have updated some of its content." A #{action.to_s.dasherize} may have already been performed with this #{@commit.change_type_title(current_user)}, or a more recent commit may have updated some of its content."
raise ChangeError, error_msg raise ChangeError, error_msg
end
end end
def check_push_permissions def check_push_permissions
...@@ -66,16 +53,17 @@ module Commits ...@@ -66,16 +53,17 @@ module Commits
true true
end end
def validate_target_branch(new_branch) def validate_target_branch
# Temporary branch exists and contains the change commit
return if repository.find_branch(new_branch)
result = ValidateNewBranchService.new(@project, current_user) result = ValidateNewBranchService.new(@project, current_user)
.execute(new_branch) .execute(@target_branch)
if result[:status] == :error if result[:status] == :error
raise ChangeError, "There was an error creating the source branch: #{result[:message]}" raise ChangeError, "There was an error creating the source branch: #{result[:message]}"
end end
end end
def different_branch?
@start_branch != @target_branch || @start_project != @project
end
end end
end end
...@@ -62,16 +62,12 @@ module Files ...@@ -62,16 +62,12 @@ module Files
raise_error("You are not allowed to push into this branch") raise_error("You are not allowed to push into this branch")
end end
unless project.empty_repo? if !@start_project.empty_repo? && !@start_project.repository.branch_exists?(@start_branch)
unless @start_project.repository.branch_exists?(@start_branch) raise ValidationError, 'You can only create or edit files when you are on a branch'
raise_error('You can only create or edit files when you are on a branch') end
end
if !project.empty_repo? && different_branch? && repository.branch_exists?(@branch_name)
if different_branch? raise ValidationError, "A branch called #{@branch_name} already exists. Switch to that branch in order to make changes"
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
end end
......
...@@ -56,12 +56,16 @@ class GitOperationService ...@@ -56,12 +56,16 @@ class GitOperationService
start_project: repository.project, start_project: repository.project,
&block) &block)
check_with_branch_arguments!( start_repository = start_project.repository
branch_name, start_branch_name, start_project) start_branch_name = nil if start_repository.empty_repo?
if start_branch_name && !start_repository.branch_exists?(start_branch_name)
raise ArgumentError, "Cannot find branch #{start_branch_name} in #{start_repository.path_with_namespace}"
end
update_branch_with_hooks(branch_name) do update_branch_with_hooks(branch_name) do
repository.with_repo_branch_commit( repository.with_repo_branch_commit(
start_project.repository, start_repository,
start_branch_name || branch_name, start_branch_name || branch_name,
&block) &block)
end end
...@@ -149,31 +153,4 @@ class GitOperationService ...@@ -149,31 +153,4 @@ class GitOperationService
repository.raw_repository.autocrlf = :input repository.raw_repository.autocrlf = :input
end end
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 end
...@@ -385,7 +385,6 @@ module SystemNoteService ...@@ -385,7 +385,6 @@ module SystemNoteService
# Returns Boolean # Returns Boolean
def cross_reference_disallowed?(noteable, mentioner) def cross_reference_disallowed?(noteable, mentioner)
return true if noteable.is_a?(ExternalIssue) && !noteable.project.jira_tracker_active? return true if noteable.is_a?(ExternalIssue) && !noteable.project.jira_tracker_active?
return true if noteable.is_a?(Issuable) && (noteable.try(:closed?) || noteable.try(:merged?))
return false unless mentioner.is_a?(MergeRequest) return false unless mentioner.is_a?(MergeRequest)
return false unless noteable.is_a?(Commit) return false unless noteable.is_a?(Commit)
......
.js-projects-list-holder
- if @projects.any?
%ul.projects-list.content-list
- @projects.each_with_index do |project|
%li.project-row
.controls
- if project.archived
%span.label.label-warning archived
%span.badge
= storage_counter(project.statistics.storage_size)
= link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn"
= link_to 'Delete', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-remove"
.title
= link_to [:admin, project.namespace.becomes(Namespace), project] do
.dash-project-avatar
.avatar-container.s40
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
%span.project-full-name
%span.namespace-name
- if project.namespace
= project.namespace.human_name
\/
%span.project-name.filter-title
= project.name
- if project.description.present?
.description
= markdown_field(project, :description)
= paginate @projects, theme: 'gitlab'
- else
.nothing-here-block No projects found
...@@ -7,40 +7,24 @@ ...@@ -7,40 +7,24 @@
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
.prepend-top-default .prepend-top-default
= form_tag admin_projects_path, method: :get do |f| .search-holder
.search-holder = render 'shared/projects/search_form', autofocus: true, icon: true
.search-field-holder .dropdown
= search_field_tag :name, params[:name], class: "form-control search-text-input js-search-input", id: "dashboard_search", autofocus: true, spellcheck: false, placeholder: 'Search by name' - toggle_text = 'Namespace'
- if params[:namespace_id].present?
- if params[:visibility_level].present? = hidden_field_tag :namespace_id, params[:namespace_id]
= hidden_field_tag 'visibility_level', params[:visibility_level] - namespace = Namespace.find(params[:namespace_id])
- toggle_text = "#{namespace.kind}: #{namespace.full_path}"
- if params[:sort].present? = dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { toggle_class: 'js-namespace-select large' })
= hidden_field_tag 'sort', params[:sort] .dropdown-menu.dropdown-select.dropdown-menu-align-right
= dropdown_title('Namespaces')
- if params[:personal].present? = dropdown_filter("Search for Namespace")
= hidden_field_tag 'visibility_level', 'true' = dropdown_content
= dropdown_loading
- if params[:archived].present? = render 'shared/projects/dropdown'
= hidden_field_tag 'archived', 'true' = link_to new_project_path, class: 'btn btn-new' do
New Project
= icon("search", class: "search-icon") = button_tag "Search", class: "btn btn-primary btn-search hide"
.dropdown
- toggle_text = 'Namespace'
- if params[:namespace_id].present?
- namespace = Namespace.find(params[:namespace_id])
- toggle_text = "#{namespace.kind}: #{namespace.full_path}"
= dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { toggle_class: 'js-namespace-select large' })
.dropdown-menu.dropdown-select.dropdown-menu-align-right
= dropdown_title('Namespaces')
= dropdown_filter("Search for Namespace")
= dropdown_content
= dropdown_loading
= render 'shared/projects/dropdown'
= link_to new_project_path, class: 'btn btn-new' do
New Project
= button_tag "Search", class: "btn btn-primary btn-search hide"
%ul.nav-links %ul.nav-links
- opts = params[:visibility_level].present? ? {} : { page: admin_projects_path } - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path }
...@@ -58,35 +42,4 @@ ...@@ -58,35 +42,4 @@
= link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do
Public Public
.projects-list-holder = render 'projects'
- if @projects.any?
%ul.projects-list.content-list
- @projects.each_with_index do |project|
%li.project-row
.controls
- if project.archived
%span.label.label-warning archived
%span.badge
= storage_counter(project.statistics.storage_size)
= link_to 'Edit', edit_namespace_project_path(project.namespace, project), id: "edit_#{dom_id(project)}", class: "btn"
= link_to 'Delete', [project.namespace.becomes(Namespace), project], data: { confirm: remove_project_message(project) }, method: :delete, class: "btn btn-remove"
.title
= link_to [:admin, project.namespace.becomes(Namespace), project] do
.dash-project-avatar
.avatar-container.s40
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
%span.project-full-name
%span.namespace-name
- if project.namespace
= project.namespace.human_name
\/
%span.project-name.filter-title
= project.name
- if project.description.present?
.description
= markdown_field(project, :description)
= paginate @projects, theme: 'gitlab'
- else
.nothing-here-block No projects found
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
.nav-block .nav-block
- if current_user .controls
.controls = link_to dashboard_projects_path(rss_url_options), class: 'btn rss-btn has-tooltip', title: 'Subscribe' do
= link_to dashboard_projects_path(:atom, { private_token: current_user.private_token }), class: 'btn rss-btn has-tooltip', title: 'Subscribe' do %i.fa.fa-rss
%i.fa.fa-rss
= render 'shared/event_filter' = render 'shared/event_filter'
.content_list .content_list
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
= nav_link(page: explore_groups_path) do = nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore groups' do = link_to explore_groups_path, title: 'Explore groups' do
Explore Groups Explore Groups
- if current_user.can_create_group? .nav-controls
.nav-controls = render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
= link_to new_group_path, class: "btn btn-new" do = link_to new_group_path, class: "btn btn-new" do
New Group New Group
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
Explore projects Explore projects
.nav-controls .nav-controls
= form_tag request.path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| = render 'shared/projects/search_form'
= search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'project-filter-form-field form-control input-short projects-list-filter', spellcheck: false, id: 'project-filter-form-field', tabindex: "2"
= render 'shared/projects/dropdown' = render 'shared/projects/dropdown'
- if current_user.can_create_project? - if current_user.can_create_project?
= link_to new_project_path, class: 'btn btn-new' do = link_to new_project_path, class: 'btn btn-new' do
......
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, dashboard_projects_url(rss_url_options), title: "All activity")
= auto_discovery_link_tag(:atom, dashboard_projects_url(format: :atom, private_token: current_user.private_token), title: "All activity")
- page_title "Activity" - page_title "Activity"
- header_title "Activity", activity_dashboard_path - header_title "Activity", activity_dashboard_path
......
.js-groups-list-holder
%ul.content-list
- @group_members.each do |group_member|
= render 'shared/groups/group', group: group_member.group, group_member: group_member
= paginate @group_members, theme: 'gitlab'
...@@ -5,9 +5,4 @@ ...@@ -5,9 +5,4 @@
- if @group_members.empty? - if @group_members.empty?
= render 'empty_state' = render 'empty_state'
- else - else
%ul.content-list = render 'groups'
- @group_members.each do |group_member|
- group = group_member.group
= render 'shared/groups/group', group: group, group_member: group_member
= paginate @group_members, theme: 'gitlab'
- page_title "Issues" - page_title "Issues"
- header_title "Issues", issues_dashboard_path(assignee_id: current_user.id) - header_title "Issues", issues_dashboard_path(assignee_id: current_user.id)
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
= auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{current_user.name} issues")
.top-area .top-area
= render 'shared/issuable/nav', type: :issues = render 'shared/issuable/nav', type: :issues
.nav-controls .nav-controls
- if current_user = link_to params.merge(rss_url_options), class: 'btn' do
= link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn' do = icon('rss')
= icon('rss') %span.icon-label
%span.icon-label Subscribe
Subscribe
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue" = render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
= render 'shared/issuable/filter', type: :issues = render 'shared/issuable/filter', type: :issues
......
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "Activity" xml.title "Activity"
xml.link href: dashboard_projects_url(format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: dashboard_projects_url(rss_url_options), rel: "self", type: "application/atom+xml"
xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html" xml.link href: dashboard_projects_url, rel: "alternate", type: "text/html"
xml.id dashboard_projects_url xml.id dashboard_projects_url
xml.updated @events[0].updated_at.xmlschema if @events[0] xml.updated @events[0].updated_at.xmlschema if @events[0]
......
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, dashboard_projects_url(rss_url_options), title: "All activity")
= auto_discovery_link_tag(:atom, dashboard_projects_url(format: :atom, private_token: current_user.private_token), title: "All activity")
- page_title "Projects" - page_title "Projects"
- header_title "Projects", dashboard_projects_path - header_title "Projects", dashboard_projects_path
.user-callout{ 'callout-svg' => custom_icon('icon_customization') } .user-callout{ 'callout-svg' => custom_icon('icon_customization') }
- if @projects.any? || params[:name]
- if @projects.any? || params[:filter_projects]
= render 'dashboard/projects_head' = render 'dashboard/projects_head'
- if @last_push - if @last_push
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
- if @projects.any? || params[:filter_projects] - if @projects.any? || params[:name]
= render 'projects' = render 'projects'
- else - else
= render "zero_authorized_projects" = render "zero_authorized_projects"
.js-groups-list-holder
%ul.content-list
- @groups.each do |group|
= render 'shared/groups/group', group: group
= paginate @groups, theme: 'gitlab'
.top-area
%ul.nav-links
= nav_link(page: explore_groups_path) do
= link_to explore_groups_path do
Explore Groups
.nav-controls
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
...@@ -5,41 +5,11 @@ ...@@ -5,41 +5,11 @@
= render 'dashboard/groups_head' = render 'dashboard/groups_head'
- else - else
= render 'explore/head' = render 'explore/head'
= render 'nav'
.row-content-block.clearfix - if @groups.present?
.pull-left = render 'groups'
= form_tag explore_groups_path, method: :get, class: 'form-inline form-tiny' do |f| - else
= hidden_field_tag :sort, @sort .nothing-here-block No public groups
.form-group
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "groups_search", spellcheck: false
.form-group
= button_tag 'Search', class: "btn btn-default"
.pull-right
.dropdown.inline
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to explore_groups_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to explore_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to explore_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to explore_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
%ul.content-list
- @groups.each do |group|
= render 'shared/groups/group', group: group
- unless @groups.present?
.nothing-here-block No public groups
= paginate @groups, theme: "gitlab" = paginate @groups, theme: "gitlab"
%ul.nav-links .top-area
= nav_link(page: [trending_explore_projects_path, explore_root_path]) do %ul.nav-links
= link_to trending_explore_projects_path do = nav_link(page: [trending_explore_projects_path, explore_root_path]) do
Trending = link_to trending_explore_projects_path do
= nav_link(page: starred_explore_projects_path) do Trending
= link_to starred_explore_projects_path do = nav_link(page: starred_explore_projects_path) do
Most stars = link_to starred_explore_projects_path do
= nav_link(page: explore_projects_path) do Most stars
= link_to explore_projects_path do = nav_link(page: explore_projects_path) do
All = link_to explore_projects_path do
All
.nav-controls
- unless current_user
= render 'shared/projects/search_form'
= render 'shared/projects/dropdown'
= render 'filter'
...@@ -6,10 +6,5 @@ ...@@ -6,10 +6,5 @@
- else - else
= render 'explore/head' = render 'explore/head'
.top-area = render 'explore/projects/nav'
= render 'explore/projects/nav'
.nav-controls
= render 'filter'
= render 'projects', projects: @projects = render 'projects', projects: @projects
...@@ -2,10 +2,9 @@ ...@@ -2,10 +2,9 @@
= render "events/event_last_push", event: @last_push = render "events/event_last_push", event: @last_push
.nav-block .nav-block
- if current_user .controls
.controls = link_to group_path(@group, rss_url_options), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do
= link_to group_path(@group, format: :atom, private_token: current_user.private_token), class: 'btn rss-btn has-tooltip' , title: 'Subscribe' do %i.fa.fa-rss
%i.fa.fa-rss
= render 'shared/event_filter' = render 'shared/event_filter'
.content_list .content_list
......
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
- page_title "Activity" - page_title "Activity"
= render 'groups/head' = render 'groups/head'
......
- page_title "Issues" - page_title "Issues"
= render "head_issues" = render "head_issues"
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues")
= auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{@group.name} issues")
- if group_issues(@group).exists? - if group_issues(@group).exists?
.top-area .top-area
= render 'shared/issuable/nav', type: :issues = render 'shared/issuable/nav', type: :issues
- if current_user .nav-controls
.nav-controls = link_to params.merge(rss_url_options), class: 'btn' do
= link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn' do = icon('rss')
= icon('rss') %span.icon-label
%span.icon-label Subscribe
Subscribe = render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
= render 'shared/issuable/filter', type: :issues = render 'shared/issuable/filter', type: :issues
......
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@group.name} activity" xml.title "#{@group.name} activity"
xml.link href: group_url(@group, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: group_url(@group, rss_url_options), rel: "self", type: "application/atom+xml"
xml.link href: group_url(@group), rel: "alternate", type: "text/html" xml.link href: group_url(@group), rel: "alternate", type: "text/html"
xml.id group_url(@group) xml.id group_url(@group)
xml.updated @events[0].updated_at.xmlschema if @events[0] xml.updated @events[0].updated_at.xmlschema if @events[0]
......
- @no_container = true - @no_container = true
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
= auto_discovery_link_tag(:atom, group_url(@group, format: :atom, private_token: current_user.private_token), title: "#{@group.name} activity")
= render 'groups/head' = render 'groups/head'
= render 'groups/home_panel' = render 'groups/home_panel'
...@@ -12,8 +11,7 @@ ...@@ -12,8 +11,7 @@
.top-area .top-area
= render 'groups/show_nav' = render 'groups/show_nav'
.nav-controls .nav-controls
= form_tag request.path, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f| = render 'shared/projects/search_form'
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
= render 'shared/projects/dropdown' = render 'shared/projects/dropdown'
- if can? current_user, :create_projects, @group - if can? current_user, :create_projects, @group
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
......
...@@ -128,12 +128,6 @@ ...@@ -128,12 +128,6 @@
.key p .key p
%td %td
Go to the project's home page Go to the project's home page
%tr
%td.shortcut
.key g
.key e
%td
Go to the project's activity feed
%tr %tr
%td.shortcut %td.shortcut
.key g .key g
...@@ -158,12 +152,6 @@ ...@@ -158,12 +152,6 @@
.key n .key n
%td %td
Go to network graph Go to network graph
%tr
%td.shortcut
.key g
.key g
%td
Go to graphs
%tr %tr
%td.shortcut %td.shortcut
.key g .key g
......
...@@ -24,12 +24,12 @@ ...@@ -24,12 +24,12 @@
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do = link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
%span %span
Issues Issues
(#{number_with_delimiter(cached_assigned_issuables_count(current_user, :issues, :opened))}) .badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :issues, :opened))
= nav_link(path: 'dashboard#merge_requests') do = nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do = link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
%span %span
Merge Requests Merge Requests
(#{number_with_delimiter(cached_assigned_issuables_count(current_user, :merge_requests, :opened))}) .badge= number_with_delimiter(cached_assigned_issuables_count(current_user, :merge_requests, :opened))
= nav_link(controller: 'dashboard/snippets') do = nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, title: 'Snippets' do = link_to dashboard_snippets_path, title: 'Snippets' do
%span %span
......
...@@ -21,40 +21,23 @@ ...@@ -21,40 +21,23 @@
.fade-right .fade-right
= icon('angle-right') = icon('angle-right')
%ul.nav-links.scrolling-tabs %ul.nav-links.scrolling-tabs
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do = nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do = link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
%span %span
Project Project
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
%span
Activity
- if project_nav_tab? :files - if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases network path_locks)) do = nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare repositories tags branches releases graphs network path_locks)) do
= link_to project_files_path(@project), title: 'Repository', class: 'shortcuts-tree' do = link_to project_files_path(@project), title: 'Repository', class: 'shortcuts-tree' do
%span %span
Repository Repository
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :environments, :cycle_analytics]) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span
Pipelines
- if project_nav_tab? :container_registry - if project_nav_tab? :container_registry
= nav_link(controller: %w(container_registry)) do = nav_link(controller: %w(container_registry)) do
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do = link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
%span %span
Registry Registry
- if project_nav_tab? :graphs
= nav_link(controller: %w(graphs)) do
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
%span
Graphs
- if project_nav_tab? :issues - if project_nav_tab? :issues
= nav_link(controller: [:issues, :labels, :milestones, :boards]) do = nav_link(controller: [:issues, :labels, :milestones, :boards]) do
= link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do = link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues', class: 'shortcuts-issues' do
...@@ -70,6 +53,12 @@ ...@@ -70,6 +53,12 @@
Merge Requests Merge Requests
%span.badge.count.merge_counter= number_with_delimiter(MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.count) %span.badge.count.merge_counter= number_with_delimiter(MergeRequestsFinder.new(current_user, project_id: @project.id).execute.opened.count)
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :environments]) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span
Pipelines
- if project_nav_tab? :wiki - if project_nav_tab? :wiki
= nav_link(controller: :wikis) do = nav_link(controller: :wikis) do
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do = link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
......
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/cropper.js')
= page_specific_javascript_bundle_tag('profile') = page_specific_javascript_bundle_tag('profile')
- @no_container = true - @no_container = true
= render "projects/head"
%div{ class: container_class } %div{ class: container_class }
.nav-block.activity-filter-block .nav-block.activity-filter-block
- if current_user .controls
.controls = link_to namespace_project_path(@project.namespace, @project, rss_url_options), title: "Subscribe", class: 'btn rss-btn has-tooltip' do
= link_to namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "Subscribe", class: 'btn rss-btn has-tooltip' do = icon('rss')
= icon('rss')
= render 'shared/event_filter' = render 'shared/event_filter'
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class }
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: 'Project home', class: 'shortcuts-project' do
%span
Home
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
%span
Activity
- if can?(current_user, :read_cycle_analytics, @project)
= nav_link(path: 'cycle_analytics#show') do
= link_to project_cycle_analytics_path(@project), title: 'Cycle Analytics', class: 'shortcuts-project-cycle-analytics' do
%span
Cycle Analytics
- case type.to_s - case type.to_s
- when 'revert' - when 'revert'
- label = 'Revert' - label = 'Revert'
- target_label = 'Revert in branch' - branch_label = 'Revert in branch'
- when 'cherry-pick' - when 'cherry-pick'
- label = 'Cherry-pick' - label = 'Cherry-pick'
- target_label = 'Pick into branch' - branch_label = 'Pick into branch'
.modal{ id: "modal-#{type}-commit" } .modal{ id: "modal-#{type}-commit" }
.modal-dialog .modal-dialog
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
.modal-body .modal-body
= form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "form-horizontal js-#{type}-form js-requires-input" do = form_tag [type.underscore, @project.namespace.becomes(Namespace), @project, commit], method: :post, remote: false, class: "form-horizontal js-#{type}-form js-requires-input" do
.form-group.branch .form-group.branch
= label_tag 'target_branch', target_label, class: 'control-label' = label_tag 'start_branch', branch_label, class: 'control-label'
.col-sm-10 .col-sm-10
= hidden_field_tag :target_branch, @project.default_branch, id: 'target_branch' = hidden_field_tag :start_branch, @project.default_branch, id: 'start_branch'
= dropdown_tag(@project.default_branch, options: { title: "Switch branch", filter: true, placeholder: "Search branches", toggle_class: 'js-project-refs-dropdown js-target-branch dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "target_branch", selected: @project.default_branch, target_branch: @project.default_branch, refs_url: namespace_project_branches_path(@project.namespace, @project), submit_form_on_click: false } }) = dropdown_tag(@project.default_branch, options: { title: "Switch branch", filter: true, placeholder: "Search branches", toggle_class: 'js-project-refs-dropdown js-target-branch dynamic', dropdown_class: 'dropdown-menu-selectable', data: { field_name: "start_branch", selected: @project.default_branch, start_branch: @project.default_branch, refs_url: namespace_project_branches_path(@project.namespace, @project), submit_form_on_click: false } })
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
.js-create-merge-request-container .js-create-merge-request-container
......
...@@ -11,14 +11,6 @@ ...@@ -11,14 +11,6 @@
= link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do = link_to namespace_project_commits_path(@project.namespace, @project, current_ref) do
Commits Commits
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
Network
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: current_ref) do
Compare
= nav_link(html_options: {class: branches_tab_class}) do = nav_link(html_options: {class: branches_tab_class}) do
= link_to namespace_project_branches_path(@project.namespace, @project) do = link_to namespace_project_branches_path(@project.namespace, @project) do
Branches Branches
...@@ -27,6 +19,22 @@ ...@@ -27,6 +19,22 @@
= link_to namespace_project_tags_path(@project.namespace, @project) do = link_to namespace_project_tags_path(@project.namespace, @project) do
Tags Tags
= nav_link(path: 'graphs#show') do
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref) do
Contributors
= nav_link(controller: %w(network)) do
= link_to namespace_project_network_path(@project.namespace, @project, current_ref) do
Graph
= nav_link(controller: :compare) do
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: current_ref) do
Compare
= nav_link(path: 'graphs#charts') do
= link_to charts_namespace_project_graph_path(@project.namespace, @project, current_ref) do
Charts
- if license_allows_file_locks? - if license_allows_file_locks?
= nav_link(controller: [:path_locks]) do = nav_link(controller: [:path_locks]) do
= link_to namespace_project_path_locks_path(@project.namespace, @project) do = link_to namespace_project_path_locks_path(@project.namespace, @project) do
......
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name}:#{@ref} commits" xml.title "#{@project.name}:#{@ref} commits"
xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref, rss_url_options), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html" xml.link href: namespace_project_commits_url(@project.namespace, @project, @ref), rel: "alternate", type: "text/html"
xml.id namespace_project_commits_url(@project.namespace, @project, @ref) xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
xml.updated @commits.first.committed_date.xmlschema if @commits.any? xml.updated @commits.first.committed_date.xmlschema if @commits.any?
......
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
- page_title "Commits", @ref - page_title "Commits", @ref
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits")
= content_for :sub_nav do = content_for :sub_nav do
= render "head" = render "head"
...@@ -27,10 +26,9 @@ ...@@ -27,10 +26,9 @@
.control .control
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
- if current_user && current_user.private_token .control
.control = link_to namespace_project_commits_path(@project.namespace, @project, @ref, rss_url_options), title: "Commits Feed", class: 'btn' do
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, { format: :atom, private_token: current_user.private_token }), title: "Commits Feed", class: 'btn' do = icon("rss")
= icon("rss")
= render 'projects/commits/mirror_status' = render 'projects/commits/mirror_status'
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('cycle_analytics') = page_specific_javascript_bundle_tag('cycle_analytics')
= render "projects/pipelines/head" = render "projects/head"
#cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } } #cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data - if @cycle_analytics_no_data
......
- @no_container = true - @no_container = true
- page_title "Commits", "Graphs" - page_title "Charts"
= render 'head' - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
= render "projects/commits/head"
%div{ class: container_class } .repo-charts{ class: container_class }
.sub-header-block %h4.sub-header
.tree-ref-holder Programming languages used in this repository
= render 'shared/ref_switcher', destination: 'graphs_commits'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
%p.lead .row
Commit statistics for .col-md-4
%strong= @ref %ul.bordered-list
#{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')} - @languages.each do |language|
%li
%span{ style: "color: #{language[:color]}" }
= icon('circle')
&nbsp;
= language[:label]
.pull-right
= language[:value]
\%
.col-md-8
%canvas#languages-chart{ height: 400 }
.repo-charts{ class: container_class }
.sub-header-block.border-top
.row.tree-ref-header
.col-md-6
%h4
Commit statistics for
%strong= @ref
#{@commits_graph.start_date.strftime('%b %d')} - #{@commits_graph.end_date.strftime('%b %d')}
.col-md-6
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'graphs_commits'
%ul.breadcrumb.repo-breadcrumb
= commits_breadcrumbs
.row .row
.col-md-6 .col-md-6
%ul %ul.commit-stats
%li %li
%p.lead Total:
%strong= @commits_graph.commits.size %strong #{@commits_graph.commits.size} commits
commits during
%strong= @commits_graph.duration
days
%li %li
%p.lead Average per day:
Average %strong #{@commits_graph.commit_per_day} commits
%strong= @commits_graph.commit_per_day
commits per day
%li %li
%p.lead Authors:
Contributed by %strong= @commits_graph.authors
%strong= @commits_graph.authors
authors
.col-md-6 .col-md-6
%div %div
%p.slead %p.slead
...@@ -40,15 +60,18 @@ ...@@ -40,15 +60,18 @@
%canvas#month-chart %canvas#month-chart
.row .row
.col-md-6 .col-md-6
%div
%p.slead
Commits per day hour (UTC)
%canvas#hour-chart
.col-md-6 .col-md-6
%div %div
%p.slead %p.slead
Commits per weekday Commits per weekday
%canvas#weekday-chart %canvas#weekday-chart
.row
.col-md-6
.col-md-6
%div
%p.slead
Commits per day hour (UTC)
%canvas#hour-chart
:javascript :javascript
var responsiveChart = function (selector, data) { var responsiveChart = function (selector, data) {
...@@ -93,3 +116,12 @@ ...@@ -93,3 +116,12 @@
var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json}); var monthData = chartData(#{@commits_per_month.keys.to_json}, #{@commits_per_month.values.to_json});
responsiveChart($('#month-chart'), monthData); responsiveChart($('#month-chart'), monthData);
var data = #{@languages.to_json};
var ctx = $("#languages-chart").get(0).getContext("2d");
var options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false
}
var myPieChart = new Chart(ctx).Pie(data, options);
- @no_container = true
- page_title "Languages", "Graphs"
= render 'head'
%div{ class: container_class }
.sub-header-block
.oneline
Programming languages used in this repository
.row
.col-md-8
%canvas#languages-chart{ height: 400 }
.col-md-4
%ul.bordered-list
- @languages.each do |language|
%li
%span{ style: "color: #{language[:color]}" }
= icon('circle')
&nbsp;
= language[:label]
.pull-right
= language[:value]
\%
:javascript
var data = #{@languages.to_json};
var ctx = $("#languages-chart").get(0).getContext("2d");
var options = {
scaleOverlay: true,
responsive: true,
maintainAspectRatio: false
}
var myPieChart = new Chart(ctx).Pie(data, options);
- @no_container = true - @no_container = true
- page_title "Contributors", "Graphs" - page_title "Contributors"
= render 'head' - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
= render 'projects/commits/head'
%div{ class: container_class } %div{ class: container_class }
.sub-header-block .sub-header-block
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
= nav_link(controller: :issues) do = nav_link(controller: :issues) do
= link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues' do = link_to namespace_project_issues_path(@project.namespace, @project), title: 'Issues' do
%span %span
Issues List
= nav_link(controller: :boards) do = nav_link(controller: :boards) do
= link_to namespace_project_boards_path(@project.namespace, @project), title: 'Board' do = link_to namespace_project_boards_path(@project.namespace, @project), title: 'Board' do
......
...@@ -10,17 +10,15 @@ ...@@ -10,17 +10,15 @@
= page_specific_javascript_bundle_tag('filtered_search') = page_specific_javascript_bundle_tag('filtered_search')
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
= auto_discovery_link_tag(:atom, url_for(params.merge(format: :atom, private_token: current_user.private_token)), title: "#{@project.name} issues")
- if project_issues(@project).exists? - if project_issues(@project).exists?
%div{ class: (container_class) } %div{ class: (container_class) }
.top-area .top-area
= render 'shared/issuable/nav', type: :issues = render 'shared/issuable/nav', type: :issues
.nav-controls .nav-controls
- if current_user = link_to params.merge(rss_url_options), class: 'btn append-right-10 has-tooltip', title: 'Subscribe' do
= link_to url_for(params.merge(format: :atom, private_token: current_user.private_token)), class: 'btn append-right-10 has-tooltip', title: 'Subscribe' do = icon('rss')
= icon('rss')
- if can? current_user, :create_issue, @project - if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, = link_to new_namespace_project_issue_path(@project.namespace,
@project, @project,
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
- @bulk_edit = can?(current_user, :admin_merge_request, @project) - @bulk_edit = can?(current_user, :admin_merge_request, @project)
- page_title "Merge Requests" - page_title "Merge Requests"
= render "projects/issues/head"
= render 'projects/last_push' = render 'projects/last_push'
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
......
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
= preserve do = preserve do
= markdown_field(@milestone, :description) = markdown_field(@milestone, :description)
- if @milestone.total_items_count(current_user).zero? - if can?(current_user, :read_issue, @project) && @milestone.total_items_count(current_user).zero?
.alert.alert-success.prepend-top-default .alert.alert-success.prepend-top-default
%span Assign some issues to this milestone. %span Assign some issues to this milestone.
- elsif @milestone.complete?(current_user) && @milestone.active? - elsif @milestone.complete?(current_user) && @milestone.active?
......
- page_title "Network", @ref - page_title "Graph", @ref
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/raphael.js') = page_specific_javascript_tag('lib/raphael.js')
= page_specific_javascript_bundle_tag('network') = page_specific_javascript_bundle_tag('network')
......
...@@ -4,25 +4,25 @@ ...@@ -4,25 +4,25 @@
.nav-links.sub-nav.scrolling-tabs{ class: ('build' if local_assigns.fetch(:build_subnav, false)) } .nav-links.sub-nav.scrolling-tabs{ class: ('build' if local_assigns.fetch(:build_subnav, false)) }
%ul{ class: (container_class) } %ul{ class: (container_class) }
- if project_nav_tab? :pipelines - if project_nav_tab? :pipelines
= nav_link(controller: :pipelines) do = nav_link(path: 'pipelines#index', controller: :pipelines) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do = link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span %span
Pipelines Pipelines
- if project_nav_tab? :builds - if project_nav_tab? :builds
= nav_link(controller: %w(builds)) do = nav_link(path: 'builds#index', controller: :builds) do
= link_to project_builds_path(@project), title: 'Jobs', class: 'shortcuts-builds' do = link_to project_builds_path(@project), title: 'Jobs', class: 'shortcuts-builds' do
%span %span
Jobs Jobs
- if project_nav_tab? :environments - if project_nav_tab? :environments
= nav_link(controller: %w(environments)) do = nav_link(path: 'environments#index', controller: :environments) do
= link_to project_environments_path(@project), title: 'Environments', class: 'shortcuts-environments' do = link_to project_environments_path(@project), title: 'Environments', class: 'shortcuts-environments' do
%span %span
Environments Environments
- if can?(current_user, :read_cycle_analytics, @project) - if @project.feature_available?(:builds, current_user) && !@project.empty_repo?
= nav_link(controller: %w(cycle_analytics)) do = nav_link(path: 'pipelines#charts') do
= link_to project_cycle_analytics_path(@project), title: 'Cycle Analytics' do = link_to charts_namespace_project_pipelines_path(@project.namespace, @project), title: 'Charts', class: 'shortcuts-pipelines-charts' do
%span %span
Cycle Analytics Charts
- @no_container = true - @no_container = true
- page_title "Continuous Integration", "Graphs" - page_title "Charts", "Pipelines"
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_d3')
= page_specific_javascript_bundle_tag('graphs')
= render 'head' = render 'head'
%div{ class: container_class } %div{ class: container_class }
...@@ -10,9 +13,9 @@ ...@@ -10,9 +13,9 @@
#charts.ci-charts #charts.ci-charts
.row .row
.col-md-6 .col-md-6
= render 'projects/graphs/ci/overall' = render 'projects/pipelines/charts/overall'
.col-md-6 .col-md-6
= render 'projects/graphs/ci/build_times' = render 'projects/pipelines/charts/build_times'
%hr %hr
= render 'projects/graphs/ci/builds' = render 'projects/pipelines/charts/builds'
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
xml.title "#{@project.name} activity" xml.title "#{@project.name} activity"
xml.link href: namespace_project_url(@project.namespace, @project, format: :atom, private_token: current_user.try(:private_token)), rel: "self", type: "application/atom+xml" xml.link href: namespace_project_url(@project.namespace, @project, rss_url_options), rel: "self", type: "application/atom+xml"
xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html" xml.link href: namespace_project_url(@project.namespace, @project), rel: "alternate", type: "text/html"
xml.id namespace_project_url(@project.namespace, @project) xml.id namespace_project_url(@project.namespace, @project)
xml.updated @events[0].updated_at.xmlschema if @events[0] xml.updated @events[0].updated_at.xmlschema if @events[0]
......
- @no_container = true - @no_container = true
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, rss_url_options), title: "#{@project.name} activity")
= auto_discovery_link_tag(:atom, namespace_project_path(@project.namespace, @project, format: :atom, private_token: current_user.private_token), title: "#{@project.name} activity")
= content_for :flash_message do = content_for :flash_message do
- if current_user && can?(current_user, :download_code, @project) - if current_user && can?(current_user, :download_code, @project)
...@@ -12,7 +11,8 @@ ...@@ -12,7 +11,8 @@
- if @project.above_size_limit? - if @project.above_size_limit?
= render 'above_size_limit_warning' = render 'above_size_limit_warning'
= render 'projects/last_push' = render "projects/head"
= render "projects/last_push"
= render "home_panel" = render "home_panel"
- if current_user && can?(current_user, :download_code, @project) - if current_user && can?(current_user, :download_code, @project)
......
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
- page_title @path.presence || "Files", @ref - page_title @path.presence || "Files", @ref
= content_for :meta_tags do = content_for :meta_tags do
- if current_user = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, format: :atom, private_token: current_user.private_token), title: "#{@project.name}:#{@ref} commits")
= render "projects/commits/head" = render "projects/commits/head"
= render 'projects/last_push' = render 'projects/last_push'
......
<svg width="36" height="36" class="tanuki-logo"> <svg width="28" height="28" class="tanuki-logo" viewBox="0 0 36 36">
<path class="tanuki-shape tanuki-left-ear" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/> <path class="tanuki-shape tanuki-left-ear" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
<path class="tanuki-shape tanuki-right-ear" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/> <path class="tanuki-shape tanuki-right-ear" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
<path class="tanuki-shape tanuki-nose" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/> <path class="tanuki-shape tanuki-nose" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>
......
.dropdown.inline
%button.dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-align-right
%li
= link_to filter_groups_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to filter_groups_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= link_to filter_groups_path(sort: sort_value_recently_updated) do
= sort_title_recently_updated
= link_to filter_groups_path(sort: sort_value_oldest_updated) do
= sort_title_oldest_updated
= form_tag request.path, method: :get, class: 'group-filter-form', id: 'group-filter-form' do |f|
= search_field_tag :filter_groups, params[:filter_groups], placeholder: 'Filter by name...', class: 'group-filter-form-field form-control input-short js-groups-list-filter', spellcheck: false, id: 'group-filter-form-field', tabindex: "2"
...@@ -6,14 +6,15 @@ ...@@ -6,14 +6,15 @@
.milestone-stats-and-buttons .milestone-stats-and-buttons
.milestone-stats .milestone-stats
%span.milestone-stat.with-drilldown - if !project || can?(current_user, :read_issue, project)
%strong= milestone.issues_visible_to_user(current_user).size %span.milestone-stat.with-drilldown
issues: %strong= milestone.issues_visible_to_user(current_user).size
%span.milestone-stat issues:
%strong= milestone.issues_visible_to_user(current_user).opened.size %span.milestone-stat
open and %strong= milestone.issues_visible_to_user(current_user).opened.size
%strong= milestone.issues_visible_to_user(current_user).closed.size open and
closed %strong= milestone.issues_visible_to_user(current_user).closed.size
closed
%span.milestone-stat.with-drilldown %span.milestone-stat.with-drilldown
%strong= milestone.merge_requests.size %strong= milestone.merge_requests.size
merge requests: merge requests:
...@@ -37,10 +38,12 @@ ...@@ -37,10 +38,12 @@
.milestone-progress-buttons .milestone-progress-buttons
%span.tab-issues-buttons %span.tab-issues-buttons
- if project && can?(current_user, :create_issue, project) - if project
= link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "btn", title: "New Issue" do - if can?(current_user, :create_issue, project)
New Issue = link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "btn", title: "New Issue" do
= link_to 'Browse Issues', milestones_browse_issuables_path(milestone, type: :issues), class: "btn" New Issue
- if can?(current_user, :read_issue, project)
= link_to 'Browse Issues', milestones_browse_issuables_path(milestone, type: :issues), class: "btn"
%span.tab-merge-requests-buttons.hidden %span.tab-merge-requests-buttons.hidden
= link_to 'Browse Merge Requests', milestones_browse_issuables_path(milestone, type: :merge_requests), class: "btn" = link_to 'Browse Merge Requests', milestones_browse_issuables_path(milestone, type: :merge_requests), class: "btn"
......
%ul.nav-links.no-top.no-bottom %ul.nav-links.no-top.no-bottom
%li.active - if milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
= link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do %li.active
Issues = link_to '#tab-issues', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
%span.badge= milestone.issues_visible_to_user(current_user).size Issues
%li %span.badge= milestone.issues_visible_to_user(current_user).size
= link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do %li
Merge Requests = link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do
%span.badge= milestone.merge_requests.size Merge Requests
%span.badge= milestone.merge_requests.size
- else
%li.active
= link_to '#tab-merge-requests', 'data-toggle' => 'tab', 'data-show' => '.tab-merge-requests-buttons' do
Merge Requests
%span.badge= milestone.merge_requests.size
%li %li
= link_to '#tab-participants', 'data-toggle' => 'tab' do = link_to '#tab-participants', 'data-toggle' => 'tab' do
Participants Participants
...@@ -20,10 +26,14 @@ ...@@ -20,10 +26,14 @@
- show_full_project_name = local_assigns.fetch(:show_full_project_name, false) - show_full_project_name = local_assigns.fetch(:show_full_project_name, false)
.tab-content.milestone-content .tab-content.milestone-content
.tab-pane.active#tab-issues - if milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
= render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user).include_associations, show_project_name: show_project_name, show_full_project_name: show_full_project_name .tab-pane.active#tab-issues
.tab-pane#tab-merge-requests = render 'shared/milestones/issues_tab', issues: milestone.issues_visible_to_user(current_user).include_associations, show_project_name: show_project_name, show_full_project_name: show_full_project_name
= render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name .tab-pane#tab-merge-requests
= render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name
- else
.tab-pane.active#tab-merge-requests
= render 'shared/milestones/merge_requests_tab', merge_requests: milestone.merge_requests, show_project_name: show_project_name, show_full_project_name: show_full_project_name
.tab-pane#tab-participants .tab-pane#tab-participants
= render 'shared/milestones/participants_tab', users: milestone.participants = render 'shared/milestones/participants_tab', users: milestone.participants
.tab-pane#tab-labels .tab-pane#tab-labels
......
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