Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into fix/import-url-validator

# Conflicts:
#	spec/models/project_spec.rb
This commit is contained in:
James Lopez 2016-06-30 14:37:48 +02:00
commit 67f59ebd50
414 changed files with 1873 additions and 778 deletions

View File

@ -18,6 +18,7 @@ variables:
SIMPLECOV: "true"
USE_DB: "true"
USE_BUNDLE_INSTALL: "true"
GIT_DEPTH: "20"
before_script:
- source ./scripts/prepare_build.sh

View File

@ -1,4 +1,6 @@
require: rubocop-rspec
require:
- rubocop-rspec
- ./rubocop/rubocop
AllCops:
TargetRubyVersion: 2.1
@ -532,11 +534,11 @@ Style/SingleLineMethods:
# Use spaces after colons.
Style/SpaceAfterColon:
Enabled: false
Enabled: true
# Use spaces after commas.
Style/SpaceAfterComma:
Enabled: false
Enabled: true
# Do not put a space between a method name and the opening parenthesis in a
# method definition.

View File

@ -1,23 +1,56 @@
Please view this file on the master branch, on stable branches it's out of date.
v 8.10.0 (unreleased)
- Fix commit builds API, return all builds for all pipelines for given commit. !4849
- Replace Haml with Hamlit to make view rendering faster. !3666
- Refactor repository paths handling to allow multiple git mount points
- Add Application Setting to configure default Repository Path for new projects
- Wrap code blocks on Activies and Todos page. !4783 (winniehell)
- Align flash messages with left side of page content !4959 (winniehell)
- Display last commit of deleted branch in push events !4699 (winniehell)
- Add Sidekiq queue duration to transaction metrics.
- Let Workhorse serve format-patch diffs
- Make images fit to the size of the viewport !4810
- Fix check for New Branch button on Issue page !4630 (winniehell)
- Fix MR-auto-close text added to description. !4836
- Fix pagination when sorting by columns with lots of ties (like priority)
- Exclude email check from the standard health check
- Fix changing issue state columns in milestone view
- Add notification settings dropdown for groups
- Fix user creation with stronger minimum password requirements !4054 (nathan-pmt)
- PipelinesFinder uses git cache data
- Check for conflicts with existing Project's wiki path when creating a new project.
- Remove unused front-end variable -> default_issues_tracker
- Add API endpoint for a group issues !4520 (mahcsig)
- Add Bugzilla integration !4930 (iamtjg)
- Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w)
- Set import_url validation to be more strict
v 8.9.3 (unreleased)
- Add basic system information like memory and disk usage to the admin panel
v 8.9.4 (unreleased)
- Fixes middle click and double request when navigating through the file browser !4891
- Add sub nav to file page view
v 8.9.3
- Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963
- Fix rendering of commit notes. !4953
- Resolve "Pin should show up at 1280px min". !4947
- Switched mobile button icons to ellipsis and angle. !4944
- Correctly returns todo ID after creating todo. !4941
- Better debugging for memory killer middleware. !4936
- Remove duplicate new page btn from edit wiki. !4904
- Use clock_gettime for all performance timestamps. !4899
- Use memorized tags array when searching tags by name. !4859
- Fixed avatar alignment in new MR view. !4901
- Removed fade when filtering results. !4932
- Fix missing avatar on system notes. !4954
- Reduce overhead and optimize ProjectTeam#max_member_access performance. !4973
- Use update_columns to by_pass all the dirty code on active_record. !4985
- Decreased min width of screen to 1280px for pinned sidebar
- Fix encrypted data backwards compatibility after upgrading attr_encrypted gem
- Update mobile button icons to be more inline with typical UI paradigms
v 8.9.2
- Fix visibility of snippets when searching.
@ -68,6 +101,8 @@ v 8.9.1
- Remove duplicate 'New Page' button on edit wiki page
v 8.9.0
v 8.9.0 (unreleased)
- Fix group visibility form layout in application settings
- Fix builds API response not including commit data
- Fix error when CI job variables key specified but not defined
- Fix pipeline status when there are no builds in pipeline
@ -163,6 +198,7 @@ v 8.9.0
- Add Application Setting to configure Container Registry token expire delay (default 5min)
- Cache assigned issue and merge request counts in sidebar nav
- Use Knapsack only in CI environment
- Updated project creation page to match new UI #2542
- Cache project build count in sidebar nav
- Add milestone expire date to the right sidebar
- Manually mark a issue or merge request as a todo
@ -218,6 +254,10 @@ v 8.9.0
- Add tooltip to pin/unpin navbar
- Add new sub nav style to Wiki and Graphs sub navigation
v 8.8.6
- Fix visibility of snippets when searching.
- Update omniauth-saml to 1.6.0 !4951
v 8.8.5
- Import GitHub repositories respecting the API rate limit !4166
- Fix todos page throwing errors when you have a project pending deletion !4300
@ -348,6 +388,10 @@ v 8.8.0
- When creating a .gitignore file a dropdown with templates will be provided
- Shows the issue/MR list search/filter form and corrects the mobile styling for guest users. #17562
v 8.7.8
- Fix visibility of snippets when searching.
- Update omniauth-saml to 1.6.0 !4951
v 8.7.7
- Fix import by `Any Git URL` broken if the URL contains a space
- Prevent unauthorized access to other projects build traces

View File

@ -1 +1 @@
3.0.0
3.1.0

View File

@ -1 +1 @@
0.7.5
0.7.7

View File

@ -91,6 +91,7 @@ gem 'fog-core', '~> 1.40'
gem 'fog-local', '~> 0.3'
gem 'fog-google', '~> 0.3'
gem 'fog-openstack', '~> 0.1'
gem 'fog-rackspace', '~> 0.1.1'
# for aws storage
gem "unf", '~> 0.1.4'
@ -346,3 +347,6 @@ gem "paranoia", "~> 2.0"
# Health check
gem 'health_check', '~> 1.5.1'
# System information
gem 'vmstat', '~> 2.1.0'

View File

@ -243,6 +243,11 @@ GEM
fog-core (>= 1.39)
fog-json (>= 1.0)
ipaddress (>= 0.8)
fog-rackspace (0.1.1)
fog-core (>= 1.35)
fog-json (>= 1.0)
fog-xml (>= 0.1)
ipaddress (>= 0.8)
fog-xml (0.1.2)
fog-core
nokogiri (~> 1.5, >= 1.5.11)
@ -780,6 +785,7 @@ GEM
coercible (~> 1.0)
descendants_tracker (~> 0.0, >= 0.0.3)
equalizer (~> 0.0, >= 0.0.9)
vmstat (2.1.0)
warden (1.2.6)
rack (>= 1.0)
web-console (2.3.0)
@ -857,6 +863,7 @@ DEPENDENCIES
fog-google (~> 0.3)
fog-local (~> 0.3)
fog-openstack (~> 0.1)
fog-rackspace (~> 0.1.1)
font-awesome-rails (~> 4.6.1)
foreman
fuubar (~> 2.0.0)
@ -984,6 +991,7 @@ DEPENDENCIES
unicorn-worker-killer (~> 0.4.2)
version_sorter (~> 2.0.0)
virtus (~> 1.0.1)
vmstat (~> 2.1.0)
web-console (~> 2.0)
webmock (~> 1.21.0)
wikicloth (= 0.8.1)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 695 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 870 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 167 B

After

Width:  |  Height:  |  Size: 167 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 KiB

After

Width:  |  Height:  |  Size: 257 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 674 KiB

After

Width:  |  Height:  |  Size: 673 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 809 B

After

Width:  |  Height:  |  Size: 631 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 495 B

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 621 B

After

Width:  |  Height:  |  Size: 621 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 942 B

After

Width:  |  Height:  |  Size: 939 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -199,7 +199,6 @@ $ ->
$('.header-content .header-logo').toggle()
$('.header-content .navbar-collapse').toggle()
$('.navbar-toggle').toggleClass('active')
$('.navbar-toggle i').toggleClass("fa-angle-right fa-angle-left")
# Show/hide comments on diff
$body.on "click", ".js-toggle-diff-comments", (e) ->
@ -261,7 +260,7 @@ $ ->
new Aside()
# Sidenav pinning
if $window.width() < 1440 and $.cookie('pin_nav') is 'true'
if $window.width() < 1280 and $.cookie('pin_nav') is 'true'
$.cookie('pin_nav', 'false', { path: '/' })
$('.page-with-sidebar')
.toggleClass('page-sidebar-collapsed page-sidebar-expanded')

View File

@ -84,6 +84,8 @@ class Dispatcher
new Activities()
when 'groups:show'
shortcut_handler = new ShortcutsNavigation()
new NotificationsForm()
new NotificationsDropdown()
when 'groups:group_members:index'
new GroupMembers()
new UsersSelect()

View File

@ -4,11 +4,19 @@ class @Flash
@flash.html("")
innerDiv = $('<div/>',
class: "flash-#{type}",
text: message
class: "flash-#{type}"
)
innerDiv.appendTo(".flash-container")
textDiv = $("<div/>",
class: "flash-text",
text: message
)
textDiv.appendTo(innerDiv)
if @flash.parent().hasClass('content-wrapper')
textDiv.addClass('container-fluid container-limited')
@flash.click -> $(@).fadeOut()
@flash.show()

View File

@ -186,6 +186,8 @@ class GitLabDropdown
@fullData = data
@parseData @fullData
@filter.input.trigger('keyup') if @options.filterable and @filter and @filter.input
}
# Init filterable
@ -218,6 +220,13 @@ class GitLabDropdown
@dropdown.on 'keyup', (e) =>
if e.which is 27 # Escape key
$('.dropdown-menu-close', @dropdown).trigger 'click'
@dropdown.on 'blur', 'a', (e) =>
if e.relatedTarget?
$relatedTarget = $(e.relatedTarget)
$dropdownMenu = $relatedTarget.closest('.dropdown-menu')
if $dropdownMenu.length is 0
@dropdown.removeClass('open')
if @dropdown.find(".dropdown-toggle-page").length
@dropdown.find(".dropdown-toggle-page, .dropdown-menu-back").on "click", (e) =>

View File

@ -59,13 +59,12 @@ issuable_created = false
filterResults: (form) =>
formData = form.serialize()
$('.issues-holder, .merge-requests-holder').css('opacity', '0.5')
formAction = form.attr('action')
issuesUrl = formAction
issuesUrl += ("#{if formAction.indexOf('?') < 0 then '?' else '&'}")
issuesUrl += formData
Turbolinks.visit(issuesUrl);
Turbolinks.visit(issuesUrl)
initChecks: ->
@issuableBulkActions = $('.bulk-update').data('bulkActions')

View File

@ -10,17 +10,41 @@
gl.text.selectedText = (text, textarea) ->
text.substring(textarea.selectionStart, textarea.selectionEnd)
gl.text.insertText = (textArea, text, tag, selected, wrap) ->
gl.text.lineBefore = (text, textarea) ->
split = text.substring(0, textarea.selectionStart).trim().split('\n')
split[split.length - 1]
gl.text.lineAfter = (text, textarea) ->
text.substring(textarea.selectionEnd).trim().split('\n')[0]
gl.text.blockTagText = (text, textArea, blockTag, selected) ->
lineBefore = @lineBefore(text, textArea)
lineAfter = @lineAfter(text, textArea)
if lineBefore is blockTag and lineAfter is blockTag
# To remove the block tag we have to select the line before & after
if blockTag?
textArea.selectionStart = textArea.selectionStart - (blockTag.length + 1)
textArea.selectionEnd = textArea.selectionEnd + (blockTag.length + 1)
selected
else
"#{blockTag}\n#{selected}\n#{blockTag}"
gl.text.insertText = (textArea, text, tag, blockTag, selected, wrap) ->
selectedSplit = selected.split('\n')
startChar = if not wrap and textArea.selectionStart > 0 then '\n' else ''
if selectedSplit.length > 1 and not wrap
insertText = selectedSplit.map((val) ->
if val.indexOf(tag) is 0
"#{val.replace(tag, '')}"
else
"#{tag}#{val}"
).join('\n')
if selectedSplit.length > 1 and (not wrap or blockTag?)
if blockTag?
insertText = @blockTagText(text, textArea, blockTag, selected)
else
insertText = selectedSplit.map((val) ->
if val.indexOf(tag) is 0
"#{val.replace(tag, '')}"
else
"#{tag}#{val}"
).join('\n')
else
insertText = "#{startChar}#{tag}#{selected}#{if wrap then tag else ' '}"
@ -51,7 +75,7 @@
textArea.setSelectionRange pos, pos
gl.text.updateText = (textArea, tag, wrap) ->
gl.text.updateText = (textArea, tag, blockTag, wrap) ->
$textArea = $(textArea)
oldVal = $textArea.val()
textArea = $textArea.get(0)
@ -59,7 +83,7 @@
selected = @selectedText(text, textArea)
$textArea.focus()
@insertText(textArea, text, tag, selected, wrap)
@insertText(textArea, text, tag, blockTag, selected, wrap)
gl.text.init = (form) ->
self = @
@ -70,6 +94,7 @@
self.updateText(
$this.closest('.md-area').find('textarea'),
$this.data('md-tag'),
$this.data('md-block'),
not $this.data('md-prepend')
)

View File

@ -171,22 +171,15 @@ class @SearchAutocomplete
}
bindEvents: ->
$(document).on 'click', @onDocumentClick
@searchInput.on 'keydown', @onSearchInputKeyDown
@searchInput.on 'keyup', @onSearchInputKeyUp
@searchInput.on 'click', @onSearchInputClick
@searchInput.on 'focus', @onSearchInputFocus
@searchInput.on 'blur', @onSearchInputBlur
@clearInput.on 'click', @onClearInputClick
@locationBadgeEl.on 'click', =>
@searchInput.focus()
onDocumentClick: (e) =>
# If clicking outside the search box
# And search input is not focused
# And we are not clicking inside a suggestion
if not $.contains(@dropdown[0], e.target) and @isFocused and not $(e.target).closest('.search-form').length
@onSearchInputBlur()
enableAutocomplete: ->
# No need to enable anything if user is not logged in
return if !gon.current_user_id
@ -287,8 +280,6 @@ class @SearchAutocomplete
value: @originalState._location
)
@dropdown.removeClass 'open'
badgePresent: ->
@locationBadgeEl.length

View File

@ -9,12 +9,12 @@ class @Shortcuts
onToggleHelp: (e) =>
e.preventDefault()
@toggleHelp(@enabledHelp)
Shortcuts.toggleHelp(@enabledHelp)
toggleMarkdownPreview: (e) =>
toggleMarkdownPreview: (e) ->
$(document).triggerHandler('markdown-preview:toggle', [e])
toggleHelp: (location) ->
@toggleHelp: (location) ->
$modal = $('#modal-shortcuts')
if $modal.length

View File

@ -5,9 +5,15 @@ class @TreeView
# Code browser tree slider
# Make the entire tree-item row clickable, but not if clicking another link (like a commit message)
$(".tree-content-holder .tree-item").on 'click', (e) ->
if (e.target.nodeName != "A")
path = $('.tree-item-file-name a', this).attr('href')
Turbolinks.visit(path)
$clickedEl = $(e.target)
path = $('.tree-item-file-name a', this).attr('href')
if not $clickedEl.is('a') and not $clickedEl.is('.str-truncated')
if e.metaKey or e.which is 2
e.preventDefault()
window.open path, '_blank'
else
Turbolinks.visit path
# Show the "Loading commit data" for only the first element
$('span.log_loading:first').removeClass('hide')

View File

@ -137,7 +137,7 @@
margin: 0;
font-size: 24px;
font-weight: normal;
margin-bottom: 5px;
margin-bottom: 10px;
color: #4c4e54;
font-size: 23px;
line-height: 1.1;

View File

@ -16,4 +16,11 @@
@extend .alert-danger;
margin: 0;
}
.flash-notice, .flash-alert {
.container-fluid.flash-text {
background: transparent;
}
}
}

View File

@ -125,7 +125,8 @@
border: 0;
outline: 0;
&:hover {
&:hover,
&:focus {
color: $gl-link-color;
}
}

View File

@ -21,9 +21,8 @@
.fa {
position: relative;
top: 3px;
font-size: 13px;
color: $btn-placeholder-gray;
top: 5px;
font-size: 18px;
}
}

View File

@ -1,5 +1,6 @@
.page-with-sidebar {
padding-top: $header-height;
padding-bottom: 25px;
transition: padding $sidebar-transition-duration;
.sidebar-wrapper {

View File

@ -7,7 +7,7 @@ $gutter_collapsed_width: 62px;
$gutter_width: 290px;
$gutter_inner_width: 258px;
$sidebar-transition-duration: .15s;
$sidebar-breakpoint: 1440px;
$sidebar-breakpoint: 1280px;
/*
* UI elements

View File

@ -83,11 +83,7 @@
position: relative;
@media (min-width: $screen-sm-min) {
padding-left: 20px;
.commit-info-block {
padding-left: 44px;
}
padding-left: 46px;
}
&:not(:last-child) {
@ -102,9 +98,7 @@
.avatar {
position: absolute;
top: 10px;
left: 16px;
margin-left: -46px;
}
.item-title {

View File

@ -48,11 +48,7 @@
.access-request-button {
@include btn-gray;
position: absolute;
right: 16px;
bottom: 32px;
padding: 3px 10px;
margin-right: 10px;
text-transform: none;
background-color: $background-color;
}
}

View File

@ -264,8 +264,15 @@
margin-bottom: 4px;
}
.item-title {
@media (min-width: $screen-sm-min) {
width: 49%;
}
}
.avatar {
margin-left: 0;
left: 0;
top: 2px;
}
.commit-row-info {

View File

@ -41,6 +41,10 @@ ul.notes {
.timeline-icon {
.avatar {
visibility: hidden;
.discussion-body & {
visibility: visible;
}
}
}
}

View File

@ -13,10 +13,53 @@
.new_project,
.edit-project {
fieldset.features {
.control-label {
fieldset {
&.features .control-label {
font-weight: normal;
}
.form-group {
margin-bottom: 5px;
}
&> .form-group {
padding-left: 0;
}
}
.help-block {
margin-bottom: 10px;
}
.project-path {
padding-right: 0;
.form-control {
border-radius: $border-radius-base;
}
}
.input-group > div {
&:last-child {
padding-right: 0;
}
}
@media (max-width: $screen-xs-max) {
.input-group > div {
margin-bottom: 14px;
&:last-child {
margin-bottom: 0;
}
}
fieldset > .form-group:first-child {
padding-right: 0;
}
}
.input-group-addon {
&.static-namespace {
height: 35px;
border-radius: 3px;
border: 1px solid #e5e5e5;
}
&+ .select2 a {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
@ -365,10 +408,28 @@ a.deploy-project-label {
}
}
.project-import .btn {
float: left;
margin-bottom: 10px;
margin-right: 10px;
.project-import {
.form-group {
margin-bottom: 0;
}
.import-buttons {
padding-left: 0;
display: -webkit-flex;
display: flex;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
.btn {
margin-right: 10px;
padding: 8px 12px;
}
&> div {
margin-bottom: 14px;
padding-left: 0;
&:last-child {
margin-bottom: 0;
}
}
}
}
.project-stats {

View File

@ -101,7 +101,8 @@
margin: 0;
.commit {
padding: 0 0 0 55px;
padding-top: 0;
padding-bottom: 0;
.commit-row-title {
.commit-row-message {

View File

@ -109,6 +109,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:metrics_packet_size,
:send_user_confirmation_email,
:container_registry_token_expire_delay,
:repository_storage,
restricted_visibility_levels: [],
import_sources: [],
disabled_oauth_sign_in_sources: []

View File

@ -0,0 +1,13 @@
class Admin::SystemInfoController < Admin::ApplicationController
def show
system_info = Vmstat.snapshot
@cpus = system_info.cpus.length
@mem_used = system_info.memory.active_bytes
@mem_total = system_info.memory.total_bytes
@disk_used = system_info.disks[0].used_bytes
@disk_total = system_info.disks[0].total_bytes
end
end

View File

@ -25,7 +25,7 @@ module Ci
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"
send_file image.path, filename: image.name, disposition: 'inline', type: "image/svg+xml"
end
protected

View File

@ -37,15 +37,12 @@ class GroupsController < Groups::ApplicationController
end
def show
@last_push = current_user.recent_push if current_user
if current_user
@last_push = current_user.recent_push
@notification_setting = current_user.notification_settings_for(group)
end
@projects = @projects.includes(:namespace)
@projects = @projects.sorted_by_activity
@projects = filter_projects(@projects)
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:filter_projects].blank?
@shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user)
setup_projects
respond_to do |format|
format.html
@ -97,6 +94,16 @@ class GroupsController < Groups::ApplicationController
protected
def setup_projects
@projects = @projects.includes(:namespace)
@projects = @projects.sorted_by_activity
@projects = filter_projects(@projects)
@projects = @projects.sort(@sort = params[:sort])
@projects = @projects.page(params[:page]) if params[:filter_projects].blank?
@shared_projects = GroupProjectsFinder.new(group, only_shared: true).execute(current_user)
end
def authorize_create_group!
unless can?(current_user, :create_group, nil)
return render_404

View File

@ -2,11 +2,9 @@ class NotificationSettingsController < ApplicationController
before_action :authenticate_user!
def create
project = Project.find(params[:project][:id])
return render_404 unless can_read?(resource)
return render_404 unless can?(current_user, :read_project, project)
@notification_setting = current_user.notification_settings_for(project)
@notification_setting = current_user.notification_settings_for(resource)
@saved = @notification_setting.update_attributes(notification_setting_params)
render_response
@ -21,6 +19,22 @@ class NotificationSettingsController < ApplicationController
private
def resource
@resource ||=
if params[:project_id].present?
Project.find(params[:project_id])
elsif params[:namespace_id].present?
Group.find(params[:namespace_id])
end
end
def can_read?(resource)
ability_name = resource.class.name.downcase
ability_name = "read_#{ability_name}".to_sym
can?(current_user, ability_name, resource)
end
def render_response
render json: {
html: view_to_html_string("shared/notifications/_button", notification_setting: @notification_setting),

View File

@ -59,7 +59,13 @@ class Projects::MergeRequestsController < Projects::ApplicationController
respond_to do |format|
format.html
format.json { render json: @merge_request }
format.patch { render text: @merge_request.to_patch }
format.patch do
headers.store(*Gitlab::Workhorse.send_git_patch(@project.repository,
@merge_request.diff_base_commit.id,
@merge_request.last_commit.id))
headers['Content-Disposition'] = 'inline'
head :ok
end
format.diff do
return render_404 unless @merge_request.diff_refs

View File

@ -29,10 +29,10 @@ class PipelinesFinder
end
def branches
project.repository.branches.map(&:name)
project.repository.branch_names
end
def tags
project.repository.tags.map(&:name)
project.repository.tag_names
end
end

View File

@ -78,4 +78,12 @@ module ApplicationSettingsHelper
end
end
end
def repository_storage_options_for_select
options = Gitlab.config.repositories.storages.map do |name, path|
["#{name} - #{path}", name]
end
options_for_select(options, @application_setting.repository_storage)
end
end

View File

@ -69,7 +69,7 @@ module DropdownsHelper
def dropdown_filter(placeholder, search_id: nil)
content_tag :div, class: "dropdown-input" do
filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder
filter_output = search_field_tag search_id, nil, class: "dropdown-input-field", placeholder: placeholder, autocomplete: 'off'
filter_output << icon('search', class: "dropdown-input-search")
filter_output << icon('times', class: "dropdown-input-clear js-dropdown-input-clear", role: "button")

View File

@ -34,10 +34,7 @@ module LabelsHelper
# Returns a String
def link_to_label(label, project: nil, type: :issue, tooltip: true, css_class: nil, &block)
project ||= @project || label.project
link = send("namespace_project_#{type.to_s.pluralize}_path",
project.namespace,
project,
label_name: [label.name])
link = label_filter_path(project, label, type: type)
if block_given?
link_to link, class: css_class, &block
@ -46,6 +43,13 @@ module LabelsHelper
end
end
def label_filter_path(project, label, type: issue)
send("namespace_project_#{type.to_s.pluralize}_path",
project.namespace,
project,
label_name: [label.name])
end
def project_label_names
@project.labels.pluck(:title)
end

View File

@ -69,4 +69,14 @@ module NotesHelper
button_tag 'Reply...', class: 'btn btn-text-field js-discussion-reply-button',
data: data, title: 'Add a reply'
end
def note_max_access_for_user(note)
@max_access_by_user_id ||= Hash.new do |hash, key|
project = key[:project]
hash[key] = project.team.human_max_access(key[:user_id])
end
full_key = { project: note.project, user_id: note.author_id }
@max_access_by_user_id[full_key]
end
end

View File

@ -72,6 +72,6 @@ module NotificationsHelper
# Create hidden field to send notification setting source to controller
def hidden_setting_source_input(notification_setting)
return unless notification_setting.source_type
hidden_field_tag "#{notification_setting.source_type.downcase}[id]", notification_setting.source_id
hidden_field_tag "#{notification_setting.source_type.downcase}_id", notification_setting.source_id
end
end

View File

@ -52,7 +52,7 @@ module PageLayoutHelper
raise ArgumentError, 'cannot provide more than two attributes' if map.length > 2
@page_card_attributes ||= {}
@page_card_attributes = map.reject { |_,v| v.blank? } if map.present?
@page_card_attributes = map.reject { |_, v| v.blank? } if map.present?
@page_card_attributes
end

View File

@ -15,7 +15,7 @@ module ProjectsHelper
def link_to_member_avatar(author, opts = {})
default_opts = { avatar: true, name: true, size: 16, author_class: 'author', title: ":name" }
opts = default_opts.merge(opts)
image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar]
end
def link_to_member(project, author, opts = {}, &block)
@ -27,7 +27,7 @@ module ProjectsHelper
author_html = ""
# Build avatar image tag
author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt:'') if opts[:avatar]
author_html << image_tag(avatar_icon(author, opts[:size]), width: opts[:size], class: "avatar avatar-inline #{"s#{opts[:size]}" if opts[:size]}", alt: '') if opts[:avatar]
# Build name span tag
if opts[:by_username]
@ -327,9 +327,9 @@ module ProjectsHelper
end
end
def sanitize_repo_path(message)
def sanitize_repo_path(project, message)
return '' unless message.present?
message.strip.gsub(Gitlab.config.gitlab_shell.repos_path.chomp('/'), "[REPOS PATH]")
message.strip.gsub(project.repository_storage_path.chomp('/'), "[REPOS PATH]")
end
end

View File

@ -55,6 +55,10 @@ class ApplicationSetting < ActiveRecord::Base
presence: true,
numericality: { only_integer: true, greater_than: 0 }
validates :repository_storage,
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
validates_each :restricted_visibility_levels do |record, attr, value|
unless value.nil?
value.each do |level|
@ -134,6 +138,7 @@ class ApplicationSetting < ActiveRecord::Base
disabled_oauth_sign_in_sources: [],
send_user_confirmation_email: false,
container_registry_token_expire_delay: 5,
repository_storage: 'default',
)
end

View File

@ -315,7 +315,7 @@ class Event < ActiveRecord::Base
def body?
if push?
push_with_commits?
push_with_commits? || rm_ref?
elsif note?
true
else

View File

@ -32,6 +32,7 @@ class Member < ActiveRecord::Base
scope :request, -> { where.not(requested_at: nil) }
scope :non_request, -> { where(requested_at: nil) }
scope :non_pending, -> { non_request.non_invite }
scope :has_access, -> { where('access_level > 0') }
scope :guests, -> { where(access_level: GUEST) }
scope :reporters, -> { where(access_level: REPORTER) }

View File

@ -319,13 +319,6 @@ class MergeRequest < ActiveRecord::Base
)
end
# Returns the commit as a series of email patches.
#
# see "git format-patch"
def to_patch
target_project.repository.format_patch(diff_base_commit.sha, source_sha)
end
def hook_attrs
attrs = {
source: source_project.try(:hook_attrs),

View File

@ -108,44 +108,46 @@ class MergeRequestDiff < ActiveRecord::Base
# Reload all commits related to current merge request from repo
# and save it as array of hashes in st_commits db field
def reload_commits
new_attributes = {}
commit_objects = unmerged_commits
if commit_objects.present?
self.st_commits = dump_commits(commit_objects)
new_attributes[:st_commits] = dump_commits(commit_objects)
end
save
update_columns_serialized(new_attributes)
end
# Reload diffs between branches related to current merge request from repo
# and save it as array of hashes in st_diffs db field
def reload_diffs
new_attributes = {}
new_diffs = []
if commits.size.zero?
self.state = :empty
new_attributes[:state] = :empty
else
diff_collection = unmerged_diffs
if diff_collection.overflow?
# Set our state to 'overflow' to make the #empty? and #collected?
# methods (generated by StateMachine) return false.
self.state = :overflow
new_attributes[:state] = :overflow
end
self.real_size = diff_collection.real_size
new_attributes[:real_size] = diff_collection.real_size
if diff_collection.any?
new_diffs = dump_diffs(diff_collection)
self.state = :collected
new_attributes[:state] = :collected
end
end
self.st_diffs = new_diffs
new_attributes[:st_diffs] = new_diffs
new_attributes[:base_commit_sha] = self.repository.merge_base(self.head, self.base)
self.base_commit_sha = self.repository.merge_base(self.head, self.base)
self.save
update_columns_serialized(new_attributes)
end
# Collect array of Git::Diff objects
@ -190,4 +192,29 @@ class MergeRequestDiff < ActiveRecord::Base
)
end
end
private
#
# #save or #update_attributes providing changes on serialized attributes do a lot of
# serialization and deserialization calls resulting in bad performance.
# Using #update_columns solves the problem with just one YAML.dump per serialized attribute that we provide.
# As a tradeoff we need to reload the current instance to properly manage time objects on those serialized
# attributes. So to keep the same behaviour as the attribute assignment we reload the instance.
# The difference is in the usage of
# #write_attribute= (#update_attributes) and #raw_write_attribute= (#update_columns)
#
# Ex:
#
# new_attributes[:st_commits].first.slice(:committed_date)
# => {:committed_date=>2014-02-27 11:01:38 +0200}
# YAML.load(YAML.dump(new_attributes[:st_commits].first.slice(:committed_date)))
# => {:committed_date=>2014-02-27 10:01:38 +0100}
#
def update_columns_serialized(new_attributes)
return unless new_attributes.any?
update_columns(new_attributes.merge(updated_at: current_time_from_proper_timezone))
reload
end
end

View File

@ -21,8 +21,10 @@ class Namespace < ActiveRecord::Base
delegate :name, to: :owner, allow_nil: true, prefix: true
after_create :ensure_dir_exist
after_update :move_dir, if: :path_changed?
# Save the storage paths before the projects are destroyed to use them on after destroy
before_destroy(prepend: true) { @old_repository_storage_paths = repository_storage_paths }
after_destroy :rm_dir
scope :root, -> { where('type IS NULL') }
@ -87,51 +89,35 @@ class Namespace < ActiveRecord::Base
owner_name
end
def ensure_dir_exist
gitlab_shell.add_namespace(path)
end
def rm_dir
# Move namespace directory into trash.
# We will remove it later async
new_path = "#{path}+#{id}+deleted"
if gitlab_shell.mv_namespace(path, new_path)
message = "Namespace directory \"#{path}\" moved to \"#{new_path}\""
Gitlab::AppLogger.info message
# Remove namespace directroy async with delay so
# GitLab has time to remove all projects first
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, new_path)
end
end
def move_dir
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(path_was)
if any_project_has_container_registry_tags?
raise Exception.new('Namespace cannot be moved, because at least one project has tags in container registry')
end
if gitlab_shell.mv_namespace(path_was, path)
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
# Move the namespace directory in all storages paths used by member projects
repository_storage_paths.each do |repository_storage_path|
# Ensure old directory exists before moving it
gitlab_shell.add_namespace(repository_storage_path, path_was)
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
send_update_instructions
rescue
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path)
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Exception.new('namespace directory cannot be moved')
end
else
# if we cannot move namespace directory we should rollback
# db changes in order to prevent out of sync between db and fs
raise Exception.new('namespace directory cannot be moved')
end
Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
# If repositories moved successfully we need to
# send update instructions to users.
# However we cannot allow rollback since we moved namespace dir
# So we basically we mute exceptions in next actions
begin
send_update_instructions
rescue
# Returning false does not rollback after_* transaction but gives
# us information about failing some of tasks
false
end
end
@ -152,4 +138,33 @@ class Namespace < ActiveRecord::Base
def find_fork_of(project)
projects.joins(:forked_project_link).find_by('forked_project_links.forked_from_project_id = ?', project.id)
end
private
def repository_storage_paths
# We need to get the storage paths for all the projects, even the ones that are
# pending delete. Unscoping also get rids of the default order, which causes
# problems with SELECT DISTINCT.
Project.unscoped do
projects.select('distinct(repository_storage)').to_a.map(&:repository_storage_path)
end
end
def rm_dir
# Remove the namespace directory in all storages paths used by member projects
@old_repository_storage_paths.each do |repository_storage_path|
# Move namespace directory into trash.
# We will remove it later async
new_path = "#{path}+#{id}+deleted"
if gitlab_shell.mv_namespace(repository_storage_path, path, new_path)
message = "Namespace directory \"#{path}\" moved to \"#{new_path}\""
Gitlab::AppLogger.info message
# Remove namespace directroy async with delay so
# GitLab has time to remove all projects first
GitlabShellWorker.perform_in(5.minutes, :rm_namespace, repository_storage_path, new_path)
end
end
end
end

View File

@ -54,7 +54,7 @@ module Network
@map = {}
@reserved = {}
@commits.each_with_index do |c,i|
@commits.each_with_index do |c, i|
c.time = i
days[i] = c.committed_date
@map[c.id] = c
@ -116,7 +116,7 @@ module Network
end
def commits_sort_by_ref
@commits.sort do |a,b|
@commits.sort do |a, b|
if include_ref?(a)
-1
elsif include_ref?(b)

View File

@ -24,8 +24,12 @@ class Project < ActiveRecord::Base
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :snippets_enabled, gitlab_config_features.snippets
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
default_value_for(:repository_storage) { current_application_settings.repository_storage }
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
after_create :ensure_dir_exist
after_save :ensure_dir_exist, if: :namespace_id_changed?
# set last_activity_at to the same as created_at
after_create :set_last_activity_at
def set_last_activity_at
@ -81,6 +85,7 @@ class Project < ActiveRecord::Base
has_one :jira_service, dependent: :destroy
has_one :redmine_service, dependent: :destroy
has_one :custom_issue_tracker_service, dependent: :destroy
has_one :bugzilla_service, dependent: :destroy
has_one :gitlab_issue_tracker_service, dependent: :destroy, inverse_of: :project
has_one :external_wiki_service, dependent: :destroy
@ -162,6 +167,9 @@ class Project < ActiveRecord::Base
validate :visibility_level_allowed_by_group
validate :visibility_level_allowed_as_fork
validate :check_wiki_path_conflict
validates :repository_storage,
presence: true,
inclusion: { in: ->(_object) { Gitlab.config.repositories.storages.keys } }
add_authentication_token_field :runners_token
before_save :ensure_runners_token
@ -373,6 +381,10 @@ class Project < ActiveRecord::Base
end
end
def repository_storage_path
Gitlab.config.repositories.storages[repository_storage]
end
def team
@team ||= ProjectTeam.new(self)
end
@ -841,12 +853,12 @@ class Project < ActiveRecord::Base
raise Exception.new('Project cannot be renamed, because tags are present in its container registry')
end
if gitlab_shell.mv_repository(old_path_with_namespace, new_path_with_namespace)
if gitlab_shell.mv_repository(repository_storage_path, old_path_with_namespace, new_path_with_namespace)
# If repository moved successfully we need to send update instructions to users.
# However we cannot allow rollback since we moved repository
# So we basically we mute exceptions in next actions
begin
gitlab_shell.mv_repository("#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
gitlab_shell.mv_repository(repository_storage_path, "#{old_path_with_namespace}.wiki", "#{new_path_with_namespace}.wiki")
send_move_instructions(old_path_with_namespace)
reset_events_cache
@ -987,7 +999,7 @@ class Project < ActiveRecord::Base
def create_repository
# Forked import is handled asynchronously
unless forked?
if gitlab_shell.add_repository(path_with_namespace)
if gitlab_shell.add_repository(repository_storage_path, path_with_namespace)
repository.after_create
true
else
@ -1139,4 +1151,8 @@ class Project < ActiveRecord::Base
_, status = Gitlab::Popen.popen(%W(find #{export_path} -not -path #{export_path} -delete))
status.zero?
end
def ensure_dir_exist
gitlab_shell.add_namespace(repository_storage_path, namespace.path)
end
end

View File

@ -0,0 +1,25 @@
class BugzillaService < IssueTrackerService
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
def title
if self.properties && self.properties['title'].present?
self.properties['title']
else
'Bugzilla'
end
end
def description
if self.properties && self.properties['description'].present?
self.properties['description']
else
'Bugzilla issue tracker'
end
end
def to_param
'bugzilla'
end
end

View File

@ -32,7 +32,4 @@ class CustomIssueTrackerService < IssueTrackerService
]
end
def initialize_properties
self.properties = {} if properties.nil?
end
end

View File

@ -106,7 +106,7 @@ class HipchatService < Service
else
message << "pushed to #{ref_type} <a href=\""\
"#{project.web_url}/commits/#{CGI.escape(ref)}\">#{ref}</a> "
message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/,'')}</a> "
message << "of <a href=\"#{project.web_url}\">#{project.name_with_namespace.gsub!(/\s/, '')}</a> "
message << "(<a href=\"#{project.web_url}/compare/#{before}...#{after}\">Compare changes</a>)"
push[:commits].take(MAX_COMMITS).each do |commit|

View File

@ -124,7 +124,7 @@ class JiraService < IssueTrackerService
def build_api_url_from_project_url
server = URI(project_url)
default_ports = [["http",80],["https",443]].include?([server.scheme,server.port])
default_ports = [["http", 80], ["https", 443]].include?([server.scheme, server.port])
server_url = "#{server.scheme}://#{server.host}"
server_url.concat(":#{server.port}") unless default_ports
"#{server_url}/rest/api/#{DEFAULT_API_VERSION}"

View File

@ -137,20 +137,10 @@ class ProjectTeam
def max_member_access(user_id)
access = []
project.members.non_request.each do |member|
if member.user_id == user_id
access << member.access_field if member.access_field
break
end
end
access += project.members.non_request.where(user_id: user_id).has_access.pluck(:access_level)
if group
group.members.non_request.each do |member|
if member.user_id == user_id
access << member.access_field if member.access_field
break
end
end
access += group.members.non_request.where(user_id: user_id).has_access.pluck(:access_level)
end
if project.invited_groups.any? && project.allowed_to_share_with_group?

View File

@ -159,7 +159,7 @@ class ProjectWiki
private
def init_repo(path_with_namespace)
gitlab_shell.add_repository(path_with_namespace)
gitlab_shell.add_repository(project.repository_storage_path, path_with_namespace)
end
def commit_details(action, message = nil, title = nil)
@ -173,7 +173,7 @@ class ProjectWiki
end
def path_to_repo
@path_to_repo ||= File.join(Gitlab.config.gitlab_shell.repos_path, "#{path_with_namespace}.git")
@path_to_repo ||= File.join(project.repository_storage_path, "#{path_with_namespace}.git")
end
def update_project_activity

View File

@ -39,7 +39,7 @@ class Repository
# Return absolute path to repository
def path_to_repo
@path_to_repo ||= File.expand_path(
File.join(Gitlab.config.gitlab_shell.repos_path, path_with_namespace + ".git")
File.join(@project.repository_storage_path, path_with_namespace + ".git")
)
end

View File

@ -170,6 +170,7 @@ class Service < ActiveRecord::Base
bamboo
buildkite
builds_email
bugzilla
campfire
custom_issue_tracker
drone_ci

View File

@ -764,7 +764,7 @@ class User < ActiveRecord::Base
unless email_domains.blank?
match_found = email_domains.any? do |domain|
escaped = Regexp.escape(domain).gsub('\*','.*?')
escaped = Regexp.escape(domain).gsub('\*', '.*?')
regexp = Regexp.new "^#{escaped}$", Regexp::IGNORECASE
email_domain = Mail::Address.new(self.email).domain
email_domain =~ regexp

View File

@ -51,13 +51,13 @@ module Projects
return true if params[:skip_repo] == true
# There is a possibility project does not have repository or wiki
return true unless gitlab_shell.exists?(path + '.git')
return true unless gitlab_shell.exists?(project.repository_storage_path, path + '.git')
new_path = removal_path(path)
if gitlab_shell.mv_repository(path, new_path)
if gitlab_shell.mv_repository(project.repository_storage_path, path, new_path)
log_info("Repository \"#{path}\" moved to \"#{new_path}\"")
GitlabShellWorker.perform_in(5.minutes, :remove_repository, new_path)
GitlabShellWorker.perform_in(5.minutes, :remove_repository, project.repository_storage_path, new_path)
else
false
end

View File

@ -24,7 +24,7 @@ module Projects
def execute
raise LeaseTaken unless try_obtain_lease
GitlabShellOneShotWorker.perform_async(:gc, @project.path_with_namespace)
GitlabShellOneShotWorker.perform_async(:gc, @project.repository_storage_path, @project.path_with_namespace)
ensure
Gitlab::Metrics.measure(:reset_pushes_since_gc) do
@project.update_column(:pushes_since_gc, 0)

View File

@ -42,7 +42,7 @@ module Projects
def import_repository
begin
gitlab_shell.import_repository(project.path_with_namespace, project.import_url)
gitlab_shell.import_repository(project.repository_storage_path, project.path_with_namespace, project.import_url)
rescue Gitlab::Shell::Error => e
raise Error, "Error importing repository #{project.import_url} into #{project.path_with_namespace} - #{e.message}"
end

View File

@ -50,12 +50,12 @@ module Projects
project.send_move_instructions(old_path)
# Move main repository
unless gitlab_shell.mv_repository(old_path, new_path)
unless gitlab_shell.mv_repository(project.repository_storage_path, old_path, new_path)
raise TransferError.new('Cannot move project')
end
# Move wiki repo also if present
gitlab_shell.mv_repository("#{old_path}.wiki", "#{new_path}.wiki")
gitlab_shell.mv_repository(project.repository_storage_path, "#{old_path}.wiki", "#{new_path}.wiki")
# clear project cached events
project.reset_events_cache

View File

@ -4,7 +4,7 @@ class LfsObjectUploader < CarrierWave::Uploader::Base
storage :file
def store_dir
"#{Gitlab.config.lfs.storage_path}/#{model.oid[0,2]}/#{model.oid[2,2]}"
"#{Gitlab.config.lfs.storage_path}/#{model.oid[0, 2]}/#{model.oid[2, 2]}"
end
def cache_dir

View File

@ -15,7 +15,7 @@
= f.label :default_snippet_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: ProjectSnippet.new)
.form-group.group-visibility-level-holder
.form-group.project-visibility-level-holder
= f.label :default_group_visibility, class: 'control-label col-sm-2'
.col-sm-10
= render('shared/visibility_radios', model_method: :default_group_visibility, form: f, selected_level: @application_setting.default_group_visibility, form_model: Group.new)
@ -310,6 +310,15 @@
.col-sm-10
= f.text_field :sentry_dsn, class: 'form-control'
%fieldset
%legend Repository Storage
.form-group
= f.label :repository_storage, 'Storage path for new projects', class: 'control-label col-sm-2'
.col-sm-10
= f.select :repository_storage, repository_storage_options_for_select, {}, class: 'form-control'
.help-block
You can manage the repository storage paths in your gitlab.yml configuration file
%fieldset
%legend Repository Checks
.form-group

View File

@ -1,5 +1,9 @@
.nav-links.sub-nav
%ul{ class: (container_class) }
= nav_link(controller: :system_info) do
= link_to admin_system_info_path, title: 'System Info' do
%span
System Info
= nav_link(controller: :background_jobs) do
= link_to admin_background_jobs_path, title: 'Background Jobs' do
%span

View File

@ -0,0 +1,22 @@
- @no_container = true
- page_title "System Info"
= render 'admin/background_jobs/head'
%div{ class: (container_class) }
.prepend-top-default
.row
.col-sm-4
.light-well
%h4 CPU
.data
%h1= "#{@cpus} cores"
.col-sm-4
.light-well
%h4 Memory
.data
%h1= "#{number_to_human_size(@mem_used)} / #{number_to_human_size(@mem_total)}"
.col-sm-4
.light-well
%h4 Disk
.data
%h1= "#{number_to_human_size(@disk_used)} / #{number_to_human_size(@disk_total)}"

View File

@ -1,3 +1,5 @@
- project = event.project
.event-title
%span.author_name= link_to_author event
%span.event_label.pushed #{event.action_name} #{event.ref_type}
@ -5,19 +7,18 @@
%strong= event.ref_name
- else
%strong
= link_to event.ref_name, namespace_project_commits_path(event.project.namespace, event.project, event.ref_name), title: h(event.target_title)
= link_to event.ref_name, namespace_project_commits_path(project.namespace, project, event.ref_name), title: h(event.target_title)
at
= link_to_project event.project
= link_to_project project
- if event.push_with_commits?
- project = event.project
.event-body
%ul.well-list.event_commits
- few_commits = event.commits[0...2]
- few_commits.each do |commit|
= render "events/commit", commit: commit, project: project, event: event
- create_mr = event.new_ref? && create_mr_button?(event.project.default_branch, event.ref_name, event.project)
- create_mr = event.new_ref? && create_mr_button?(project.default_branch, event.ref_name, project)
- if event.commits_count > 1
%li.commits-stat
- if event.commits_count > 2
@ -27,18 +28,26 @@
- from = event.commit_from
- from_label = truncate_sha(from)
- else
- from = event.project.default_branch
- from = project.default_branch
- from_label = from
= link_to namespace_project_compare_path(event.project.namespace, event.project, from: from, to: event.commit_to) do
= link_to namespace_project_compare_path(project.namespace, project, from: from, to: event.commit_to) do
Compare #{from_label}...#{truncate_sha(event.commit_to)}
- if create_mr
%span{"data-user-is" => event.author_id, "data-display" => "inline"}
or
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
= link_to create_mr_path(project.default_branch, event.ref_name, project) do
create a merge request
- elsif create_mr
%li.commits-stat{"data-user-is" => event.author_id}
= link_to create_mr_path(event.project.default_branch, event.ref_name, event.project) do
= link_to create_mr_path(project.default_branch, event.ref_name, project) do
Create Merge Request
- elsif event.rm_ref?
- repository = project.repository
- last_commit = repository.commit(event.commit_from)
- if last_commit
.event-body
%ul.well-list.event_commits
= render "events/commit", commit: last_commit, project: project, event: event

View File

@ -15,12 +15,17 @@
%span.visibility-icon.has-tooltip{ data: { container: 'body' }, title: visibility_icon_description(@group) }
= visibility_level_icon(@group.visibility_level, fw: false)
%span.hidden-xs
= render 'shared/notifications/button', notification_setting: @notification_setting
- if current_user
.pull-right
= render 'shared/members/access_request_buttons', source: @group
- if @group.description.present?
.cover-desc.description
= markdown(@group.description, pipeline: :description)
- if current_user
= render 'shared/members/access_request_buttons', source: @group
%div{ class: container_class }
.top-area

View File

@ -36,6 +36,6 @@
%ul.well-list
%li= link_to 'See our website for getting help', promo_url + '/getting-help/'
%li= link_to 'Use the search bar on the top of this page', '#', onclick: 'Shortcuts.focusSearch(event)'
%li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.showHelp(event)'
%li= link_to 'Use shortcuts', '#', onclick: 'Shortcuts.toggleHelp()'
%li= link_to 'Get a support subscription', 'https://about.gitlab.com/pricing/'
%li= link_to 'Compare GitLab editions', 'https://about.gitlab.com/features/#compare'

View File

@ -6,7 +6,7 @@
= icon('bars')
%button.navbar-toggle{type: 'button'}
%span.sr-only Toggle navigation
= icon('angle-left')
= icon('ellipsis-v')
.navbar-collapse.collapse
%ul.nav.navbar-nav

View File

@ -1,16 +1,16 @@
.scrolling-tabs-container{ class: nav_control_class }
= render 'layouts/nav/admin_settings'
.fade-left
= icon('arrow-left')
= icon('angle-left')
.fade-right
= icon('arrow-right')
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(controller: %w(dashboard admin projects users groups builds runners), html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
%span
Overview
= nav_link(controller: %w(background_jobs logs health_check)) do
= link_to admin_background_jobs_path, title: 'Monitoring' do
= nav_link(controller: %w(system_info background_jobs logs health_check)) do
= link_to admin_system_info_path, title: 'Monitoring' do
%span
Monitoring
= nav_link(controller: :broadcast_messages) do

View File

@ -1,9 +1,9 @@
.scrolling-tabs-container{ class: nav_control_class }
= render 'layouts/nav/group_settings'
.fade-left
= icon('arrow-left')
= icon('angle-left')
.fade-right
= icon('arrow-right')
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: 'Home' do

View File

@ -1,8 +1,8 @@
.scrolling-tabs-container
.fade-left
= icon('arrow-left')
= icon('angle-left')
.fade-right
= icon('arrow-right')
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile Settings' do

View File

@ -26,9 +26,9 @@
.scrolling-tabs-container{ class: nav_control_class }
.fade-left
= icon('arrow-left')
= icon('angle-left')
.fade-right
= icon('arrow-right')
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do

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