mirror of
https://github.com/wahyd4/gitlabhq.git
synced 2026-08-09 04:36:11 +10:00
Merge branch 'master' into dev-master
* master: (98 commits) Enable Style/EmptyLines cop, remove redundant ones Update CHANGELOG Cache results from jQuery selectors to retrieve namespace name Fix import button when import fail due the namespace already been taken Fix snippets comments not displayed Fix emoji paths in relative root configurations Exclude requesters from Project#members, Group#members and User#members Upgrade Thin from 1.6.1 to 1.7.0. Many squashed commits Cache autocomplete results Upgrade Sidekiq from 4.1.2 to 4.1.4. Upgrade seed-fu from 2.3.5 to 2.3.6 use has_many relationship with events Support creating a todo on issuables via API Expose target, filter by state as string Add todos API documentation and changelog Improve the request / withdraw access button Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab Groundwork for Kerberos SPNEGO (EE feature) Update CHANGELOG 8.9.5 for runners related fixes ...
This commit is contained in:
+7
-5
@@ -1,4 +1,6 @@
|
||||
require: rubocop-rspec
|
||||
require:
|
||||
- rubocop-rspec
|
||||
- ./rubocop/rubocop
|
||||
|
||||
AllCops:
|
||||
TargetRubyVersion: 2.1
|
||||
@@ -191,7 +193,7 @@ Style/EmptyLineBetweenDefs:
|
||||
|
||||
# Don't use several empty lines in a row.
|
||||
Style/EmptyLines:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# Keep blank lines around access modifiers.
|
||||
Style/EmptyLinesAroundAccessModifier:
|
||||
@@ -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.
|
||||
@@ -679,7 +681,7 @@ Style/UnlessElse:
|
||||
|
||||
# Checks for %W when interpolation is not needed.
|
||||
Style/UnneededCapitalW:
|
||||
Enabled: false
|
||||
Enabled: true
|
||||
|
||||
# TODO: Enable UnneededInterpolation Cop.
|
||||
# Checks for strings that are just an interpolated expression.
|
||||
|
||||
@@ -3,8 +3,12 @@ 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)
|
||||
- Apply the trusted_proxies config to the rack request object for use with rack_attack
|
||||
- Add Sidekiq queue duration to transaction metrics.
|
||||
- Let Workhorse serve format-patch diffs
|
||||
- Make images fit to the size of the viewport !4810
|
||||
@@ -14,17 +18,42 @@ v 8.10.0 (unreleased)
|
||||
- Exclude email check from the standard health check
|
||||
- Fix changing issue state columns in milestone view
|
||||
- Add notification settings dropdown for groups
|
||||
- Allow importing from Github using Personal Access Tokens. (Eric K Idema)
|
||||
- API: Todos !3188 (Robert Schilling)
|
||||
- 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.
|
||||
- Don't instantiate a git tree on Projects show default view
|
||||
- Remove unused front-end variable -> default_issues_tracker
|
||||
- Better caching of git calls on ProjectsController#show.
|
||||
- Add API endpoint for a group issues !4520 (mahcsig)
|
||||
- Add Bugzilla integration !4930 (iamtjg)
|
||||
- Metrics for Rouge::Plugins::Redcarpet and Rouge::Formatters::HTMLGitlab
|
||||
- Allow [ci skip] to be in any case and allow [skip ci]. !4785 (simon_w)
|
||||
- Add basic system information like memory and disk usage to the admin panel
|
||||
|
||||
v 8.9.4 (unreleased)
|
||||
- Ensure references to private repos aren't shown to logged-out users
|
||||
v 8.9.5 (unreleased)
|
||||
- Improve the request / withdraw access button. !4860
|
||||
- Fix assigning shared runners as admins. !4961
|
||||
- Show "locked" label for locked runners on runners admin. !4961
|
||||
- Fixes issues importing events in Import/Export. Import/Export version bumped to 0.1.1
|
||||
- Fix import button disabled when import process fail due to the namespace already been taken.
|
||||
|
||||
v 8.9.4
|
||||
- Fix privilege escalation issue with OAuth external users.
|
||||
- Ensure references to private repos aren't shown to logged-out users.
|
||||
- Fixed search field blur not removing focus. !4704
|
||||
- Resolve "Sub nav isn't showing on file view". !4890
|
||||
- Fixes middle click and double request when navigating through the file browser. !4891
|
||||
- Fixed URL on label button when filtering. !4897
|
||||
- Fixed commit avatar alignment. !4933
|
||||
- Do not show build retry link when build is active. !4967
|
||||
- Fix restore Rake task warning message output. !4980
|
||||
- Handle external issues in IssueReferenceFilter. !4988
|
||||
- Expiry date on pinned nav cookie. !5009
|
||||
- Updated breakpoint for sidebar pinning. !5019
|
||||
|
||||
v 8.9.3
|
||||
- Fix encrypted data backwards compatibility after upgrading attr_encrypted gem. !4963
|
||||
@@ -41,6 +70,7 @@ v 8.9.3
|
||||
- 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
|
||||
- Fix restore Rake task warning message output !4980
|
||||
|
||||
v 8.9.2
|
||||
- Fix visibility of snippets when searching.
|
||||
@@ -91,7 +121,6 @@ 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
|
||||
@@ -238,12 +267,17 @@ v 8.9.0 (unreleased)
|
||||
- Filter parameters for request_uri value on instrumented transactions.
|
||||
- Remove duplicated keys add UNIQUE index to keys fingerprint column
|
||||
- ExtractsPath get ref_names from repository cache, if not there access git.
|
||||
- Show a flash warning about the error detail of XHR requests which failed with status code 404 and 500
|
||||
- Cache user todo counts from TodoService
|
||||
- Ensure Todos counters doesn't count Todos for projects pending delete
|
||||
- Add left/right arrows horizontal navigation
|
||||
- Add tooltip to pin/unpin navbar
|
||||
- Add new sub nav style to Wiki and Graphs sub navigation
|
||||
|
||||
v 8.8.7
|
||||
- Fix privilege escalation issue with OAuth external users.
|
||||
- Ensure references to private repos aren't shown to logged-out users.
|
||||
|
||||
v 8.8.6
|
||||
- Fix visibility of snippets when searching.
|
||||
- Update omniauth-saml to 1.6.0 !4951
|
||||
@@ -378,6 +412,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.9
|
||||
- Fix privilege escalation issue with OAuth external users.
|
||||
- Ensure references to private repos aren't shown to logged-out users.
|
||||
|
||||
v 8.7.8
|
||||
- Fix visibility of snippets when searching.
|
||||
- Update omniauth-saml to 1.6.0 !4951
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.0
|
||||
3.1.0
|
||||
|
||||
@@ -251,7 +251,6 @@ group :development do
|
||||
gem 'brakeman', '~> 3.3.0', require: false
|
||||
|
||||
gem 'letter_opener_web', '~> 1.3.0'
|
||||
gem 'quiet_assets', '~> 1.0.2'
|
||||
gem 'rerun', '~> 0.11.0'
|
||||
gem 'bullet', require: false
|
||||
gem 'rblineprof', platform: :mri, require: false
|
||||
@@ -265,7 +264,7 @@ group :development do
|
||||
gem "sdoc", '~> 0.3.20'
|
||||
|
||||
# thin instead webrick
|
||||
gem 'thin', '~> 1.6.1'
|
||||
gem 'thin', '~> 1.7.0'
|
||||
end
|
||||
|
||||
group :development, :test do
|
||||
@@ -303,7 +302,6 @@ group :development, :test do
|
||||
gem 'rubocop', '~> 0.40.0', require: false
|
||||
gem 'rubocop-rspec', '~> 1.5.0', require: false
|
||||
gem 'scss_lint', '~> 0.47.0', require: false
|
||||
gem 'coveralls', '~> 0.8.2', require: false
|
||||
gem 'simplecov', '~> 0.11.0', require: false
|
||||
gem 'flog', require: false
|
||||
gem 'flay', require: false
|
||||
@@ -350,3 +348,4 @@ gem 'health_check', '~> 1.5.1'
|
||||
|
||||
# System information
|
||||
gem 'vmstat', '~> 2.1.0'
|
||||
gem 'sys-filesystem', '~> 1.1.6'
|
||||
|
||||
+17
-26
@@ -141,12 +141,6 @@ GEM
|
||||
colorize (0.7.7)
|
||||
concurrent-ruby (1.0.2)
|
||||
connection_pool (2.2.0)
|
||||
coveralls (0.8.13)
|
||||
json (~> 1.8)
|
||||
simplecov (~> 0.11.0)
|
||||
term-ansicolor (~> 1.3)
|
||||
thor (~> 0.19.1)
|
||||
tins (~> 1.6.0)
|
||||
crack (0.4.3)
|
||||
safe_yaml (~> 1.0.0)
|
||||
creole (0.5.0)
|
||||
@@ -505,8 +499,6 @@ GEM
|
||||
pry-rails (0.3.4)
|
||||
pry (>= 0.9.10)
|
||||
pyu-ruby-sasl (0.0.3.3)
|
||||
quiet_assets (1.0.3)
|
||||
railties (>= 3.1, < 5.0)
|
||||
rack (1.6.4)
|
||||
rack-accept (0.4.5)
|
||||
rack (>= 0.4)
|
||||
@@ -640,8 +632,8 @@ GEM
|
||||
sanitize (2.1.0)
|
||||
nokogiri (>= 1.4.4)
|
||||
sass (3.4.22)
|
||||
sass-rails (5.0.4)
|
||||
railties (>= 4.0.0, < 5.0)
|
||||
sass-rails (5.0.5)
|
||||
railties (>= 4.0.0, < 6)
|
||||
sass (~> 3.1)
|
||||
sprockets (>= 2.8, < 4.0)
|
||||
sprockets-rails (>= 2.0, < 4.0)
|
||||
@@ -655,9 +647,9 @@ GEM
|
||||
sdoc (0.3.20)
|
||||
json (>= 1.1.3)
|
||||
rdoc (~> 3.10)
|
||||
seed-fu (2.3.5)
|
||||
activerecord (>= 3.1, < 4.3)
|
||||
activesupport (>= 3.1, < 4.3)
|
||||
seed-fu (2.3.6)
|
||||
activerecord (>= 3.1)
|
||||
activesupport (>= 3.1)
|
||||
select2-rails (3.5.9.3)
|
||||
thor (~> 0.14)
|
||||
sentry-raven (1.1.0)
|
||||
@@ -668,10 +660,11 @@ GEM
|
||||
rack
|
||||
shoulda-matchers (2.8.0)
|
||||
activesupport (>= 3.0.0)
|
||||
sidekiq (4.1.2)
|
||||
sidekiq (4.1.4)
|
||||
concurrent-ruby (~> 1.0)
|
||||
connection_pool (~> 2.2, >= 2.2.0)
|
||||
redis (~> 3.2, >= 3.2.1)
|
||||
sinatra (>= 1.4.7)
|
||||
sidekiq-cron (0.4.0)
|
||||
redis-namespace (>= 1.5.2)
|
||||
rufus-scheduler (>= 2.0.24)
|
||||
@@ -682,8 +675,8 @@ GEM
|
||||
json (~> 1.8)
|
||||
simplecov-html (~> 0.10.0)
|
||||
simplecov-html (0.10.0)
|
||||
sinatra (1.4.6)
|
||||
rack (~> 1.4)
|
||||
sinatra (1.4.7)
|
||||
rack (~> 1.5)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (>= 1.3, < 3)
|
||||
six (0.2.0)
|
||||
@@ -706,10 +699,10 @@ GEM
|
||||
spring (>= 0.9.1)
|
||||
spring-commands-teaspoon (0.0.2)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (3.6.0)
|
||||
sprockets (3.6.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-rails (3.0.4)
|
||||
sprockets-rails (3.1.1)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
@@ -721,6 +714,8 @@ GEM
|
||||
activerecord (>= 4.1, < 5.1)
|
||||
state_machines-activemodel (>= 0.3.0)
|
||||
stringex (2.5.2)
|
||||
sys-filesystem (1.1.6)
|
||||
ffi
|
||||
systemu (2.6.5)
|
||||
task_list (1.0.2)
|
||||
html-pipeline
|
||||
@@ -729,14 +724,12 @@ GEM
|
||||
teaspoon-jasmine (2.2.0)
|
||||
teaspoon (>= 1.0.0)
|
||||
temple (0.7.7)
|
||||
term-ansicolor (1.3.2)
|
||||
tins (~> 1.0)
|
||||
test_after_commit (0.4.2)
|
||||
activerecord (>= 3.2)
|
||||
thin (1.6.4)
|
||||
thin (1.7.0)
|
||||
daemons (~> 1.0, >= 1.0.9)
|
||||
eventmachine (~> 1.0, >= 1.0.4)
|
||||
rack (~> 1.0)
|
||||
rack (>= 1, < 3)
|
||||
thor (0.19.1)
|
||||
thread_safe (0.3.5)
|
||||
tilt (2.0.5)
|
||||
@@ -751,7 +744,6 @@ GEM
|
||||
mime-types
|
||||
multi_json (~> 1.7)
|
||||
twitter-stream (~> 0.1)
|
||||
tins (1.6.0)
|
||||
turbolinks (2.5.3)
|
||||
coffee-rails
|
||||
twitter-stream (0.1.16)
|
||||
@@ -841,7 +833,6 @@ DEPENDENCIES
|
||||
chronic_duration (~> 0.10.6)
|
||||
coffee-rails (~> 4.1.0)
|
||||
connection_pool (~> 2.0)
|
||||
coveralls (~> 0.8.2)
|
||||
creole (~> 0.5.0)
|
||||
d3_rails (~> 3.5.0)
|
||||
database_cleaner (~> 1.4.0)
|
||||
@@ -928,7 +919,6 @@ DEPENDENCIES
|
||||
poltergeist (~> 1.9.0)
|
||||
premailer-rails (~> 1.9.0)
|
||||
pry-rails
|
||||
quiet_assets (~> 1.0.2)
|
||||
rack-attack (~> 4.3.1)
|
||||
rack-cors (~> 0.4.0)
|
||||
rack-oauth2 (~> 1.2.1)
|
||||
@@ -976,11 +966,12 @@ DEPENDENCIES
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
sprockets (~> 3.6.0)
|
||||
state_machines-activerecord (~> 0.4.0)
|
||||
sys-filesystem (~> 1.1.6)
|
||||
task_list (~> 1.0.2)
|
||||
teaspoon (~> 1.1.0)
|
||||
teaspoon-jasmine (~> 2.2.0)
|
||||
test_after_commit (~> 0.4.2)
|
||||
thin (~> 1.6.1)
|
||||
thin (~> 1.7.0)
|
||||
tinder (~> 1.10.0)
|
||||
turbolinks (~> 2.5.0)
|
||||
u2f (~> 0.2.1)
|
||||
|
||||
@@ -185,6 +185,15 @@ $ ->
|
||||
else
|
||||
buttons.enable()
|
||||
|
||||
$(document).ajaxError (e, xhrObj, xhrSetting, xhrErrorText) ->
|
||||
|
||||
if xhrObj.status is 401
|
||||
new Flash 'You need to be logged in.', 'alert'
|
||||
|
||||
else if xhrObj.status in [ 404, 500 ]
|
||||
new Flash 'Something went wrong on our end.', 'alert'
|
||||
|
||||
|
||||
# Show/Hide the profile menu when hovering the account box
|
||||
$('.account-box').hover -> $(@).toggleClass('hover')
|
||||
|
||||
@@ -260,8 +269,8 @@ $ ->
|
||||
new Aside()
|
||||
|
||||
# Sidenav pinning
|
||||
if $window.width() < 1280 and $.cookie('pin_nav') is 'true'
|
||||
$.cookie('pin_nav', 'false', { path: '/' })
|
||||
if $window.width() < 1024 and $.cookie('pin_nav') is 'true'
|
||||
$.cookie('pin_nav', 'false', { path: '/', expires: 365 * 10 })
|
||||
$('.page-with-sidebar')
|
||||
.toggleClass('page-sidebar-collapsed page-sidebar-expanded')
|
||||
.removeClass('page-sidebar-pinned')
|
||||
@@ -292,7 +301,7 @@ $ ->
|
||||
.toggleClass('header-collapsed header-expanded')
|
||||
|
||||
# Save settings
|
||||
$.cookie 'pin_nav', doPinNav, { path: '/' }
|
||||
$.cookie 'pin_nav', doPinNav, { path: '/', expires: 365 * 10 }
|
||||
|
||||
if $.cookie('pin_nav') is 'true' or doPinNav
|
||||
tooltipText = 'Unpin navigation'
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ window.GitLab ?= {}
|
||||
GitLab.GfmAutoComplete =
|
||||
dataLoading: false
|
||||
dataLoaded: false
|
||||
|
||||
cachedData: {}
|
||||
dataSource: ''
|
||||
|
||||
# Emoji
|
||||
@@ -55,7 +55,7 @@ GitLab.GfmAutoComplete =
|
||||
@setupAtWho()
|
||||
|
||||
if @dataSource
|
||||
if !@dataLoading
|
||||
if not @dataLoading and not @cachedData
|
||||
@dataLoading = true
|
||||
|
||||
# We should wait until initializations are done
|
||||
@@ -70,6 +70,8 @@ GitLab.GfmAutoComplete =
|
||||
@loadData(data)
|
||||
, 1000)
|
||||
|
||||
if @cachedData?
|
||||
@loadData(@cachedData)
|
||||
|
||||
setupAtWho: ->
|
||||
# Emoji
|
||||
@@ -205,6 +207,7 @@ GitLab.GfmAutoComplete =
|
||||
$.getJSON(dataSource)
|
||||
|
||||
loadData: (data) ->
|
||||
@cachedData = data
|
||||
@dataLoaded = true
|
||||
|
||||
# load members
|
||||
|
||||
@@ -7,13 +7,16 @@ class @ImporterStatus
|
||||
$('.js-add-to-import')
|
||||
.off 'click'
|
||||
.on 'click', (e) =>
|
||||
new_namespace = null
|
||||
$btn = $(e.currentTarget)
|
||||
$tr = $btn.closest('tr')
|
||||
$target_field = $tr.find('.import-target')
|
||||
$namespace_input = $target_field.find('input')
|
||||
id = $tr.attr('id').replace('repo_', '')
|
||||
if $tr.find('.import-target input').length > 0
|
||||
new_namespace = $tr.find('.import-target input').prop('value')
|
||||
$tr.find('.import-target').empty().append("#{new_namespace} / #{$tr.find('.import-target').data('project_name')}")
|
||||
new_namespace = null
|
||||
|
||||
if $namespace_input.length > 0
|
||||
new_namespace = $namespace_input.prop('value')
|
||||
$target_field.empty().append("#{new_namespace}/#{$target_field.data('project_name')}")
|
||||
|
||||
$btn
|
||||
.disable()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -16,4 +16,11 @@
|
||||
@extend .alert-danger;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.flash-notice, .flash-alert {
|
||||
.container-fluid.flash-text {
|
||||
background: transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,7 +125,8 @@
|
||||
border: 0;
|
||||
outline: 0;
|
||||
|
||||
&:hover {
|
||||
&:hover,
|
||||
&:focus {
|
||||
color: $gl-link-color;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,10 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.group-right-buttons {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container .title {
|
||||
padding-left: 15px !important;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ $gutter_collapsed_width: 62px;
|
||||
$gutter_width: 290px;
|
||||
$gutter_inner_width: 258px;
|
||||
$sidebar-transition-duration: .15s;
|
||||
$sidebar-breakpoint: 1280px;
|
||||
$sidebar-breakpoint: 1024px;
|
||||
|
||||
/*
|
||||
* UI elements
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -41,14 +41,17 @@
|
||||
}
|
||||
|
||||
.groups-cover-block {
|
||||
|
||||
.container-fluid {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.access-request-button {
|
||||
@include btn-gray;
|
||||
margin-right: 10px;
|
||||
text-transform: none;
|
||||
.group-right-buttons {
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
.btn {
|
||||
@include btn-gray;
|
||||
padding: 3px 10px;
|
||||
background-color: $background-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,18 +266,6 @@
|
||||
@media (max-width: $screen-md-max) {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.access-request-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 61px;
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
position: relative;
|
||||
bottom: 0;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $screen-md-max) {
|
||||
|
||||
@@ -101,7 +101,8 @@
|
||||
margin: 0;
|
||||
|
||||
.commit {
|
||||
padding: 0 0 0 55px;
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
|
||||
.commit-row-title {
|
||||
.commit-row-message {
|
||||
|
||||
@@ -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: []
|
||||
|
||||
@@ -10,6 +10,7 @@ class Admin::GroupsController < Admin::ApplicationController
|
||||
|
||||
def show
|
||||
@members = @group.members.order("access_level DESC").page(params[:members_page])
|
||||
@requesters = @group.requesters
|
||||
@projects = @group.projects.page(params[:projects_page])
|
||||
end
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ class Admin::HooksController < Admin::ApplicationController
|
||||
redirect_to admin_hooks_path
|
||||
end
|
||||
|
||||
|
||||
def test
|
||||
@hook = SystemHook.find(params[:hook_id])
|
||||
data = {
|
||||
|
||||
@@ -20,7 +20,8 @@ class Admin::ProjectsController < Admin::ApplicationController
|
||||
@group_members = @group.members.order("access_level DESC").page(params[:group_members_page])
|
||||
end
|
||||
|
||||
@project_members = @project.project_members.page(params[:project_members_page])
|
||||
@project_members = @project.members.page(params[:project_members_page])
|
||||
@requesters = @project.requesters
|
||||
end
|
||||
|
||||
def transfer
|
||||
|
||||
@@ -4,8 +4,6 @@ class Admin::RunnerProjectsController < Admin::ApplicationController
|
||||
def create
|
||||
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
|
||||
|
||||
return head(403) if @runner.is_shared? || @runner.locked?
|
||||
|
||||
runner_project = @runner.assign_to(@project, current_user)
|
||||
|
||||
if runner_project.persisted?
|
||||
|
||||
@@ -1,13 +1,59 @@
|
||||
class Admin::SystemInfoController < Admin::ApplicationController
|
||||
EXCLUDED_MOUNT_OPTIONS = [
|
||||
'nobrowse',
|
||||
'read-only',
|
||||
'ro'
|
||||
]
|
||||
|
||||
EXCLUDED_MOUNT_TYPES = [
|
||||
'autofs',
|
||||
'binfmt_misc',
|
||||
'cgroup',
|
||||
'debugfs',
|
||||
'devfs',
|
||||
'devpts',
|
||||
'devtmpfs',
|
||||
'efivarfs',
|
||||
'fuse.gvfsd-fuse',
|
||||
'fuseblk',
|
||||
'fusectl',
|
||||
'hugetlbfs',
|
||||
'mqueue',
|
||||
'proc',
|
||||
'pstore',
|
||||
'securityfs',
|
||||
'sysfs',
|
||||
'tmpfs',
|
||||
'tracefs',
|
||||
'vfat'
|
||||
]
|
||||
|
||||
def show
|
||||
system_info = Vmstat.snapshot
|
||||
mounts = Sys::Filesystem.mounts
|
||||
|
||||
@disks = []
|
||||
mounts.each do |mount|
|
||||
mount_options = mount.options.split(',')
|
||||
|
||||
next if (EXCLUDED_MOUNT_OPTIONS & mount_options).any?
|
||||
next if (EXCLUDED_MOUNT_TYPES & [mount.mount_type]).any?
|
||||
|
||||
begin
|
||||
disk = Sys::Filesystem.stat(mount.mount_point)
|
||||
@disks.push({
|
||||
bytes_total: disk.bytes_total,
|
||||
bytes_used: disk.bytes_used,
|
||||
disk_name: mount.name,
|
||||
mount_path: disk.path
|
||||
})
|
||||
rescue Sys::Filesystem::Error
|
||||
end
|
||||
end
|
||||
|
||||
@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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -10,7 +10,7 @@ module MembershipActions
|
||||
end
|
||||
|
||||
def approve_access_request
|
||||
@member = membershipable.members.request.find(params[:id])
|
||||
@member = membershipable.requesters.find(params[:id])
|
||||
|
||||
return render_403 unless can?(current_user, action_member_permission(:update, @member), @member)
|
||||
|
||||
@@ -20,7 +20,8 @@ module MembershipActions
|
||||
end
|
||||
|
||||
def leave
|
||||
@member = membershipable.members.find_by(user_id: current_user)
|
||||
@member = membershipable.members.find_by(user_id: current_user) ||
|
||||
membershipable.requesters.find_by(user_id: current_user)
|
||||
Members::DestroyService.new(@member, current_user).execute
|
||||
|
||||
source_type = @member.real_source_type.humanize(capitalize: false)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class ConfirmationsController < Devise::ConfirmationsController
|
||||
|
||||
def almost_there
|
||||
flash[:notice] = nil
|
||||
render layout: "devise_empty"
|
||||
|
||||
@@ -7,7 +7,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
def index
|
||||
@project = @group.projects.find(params[:project_id]) if params[:project_id]
|
||||
@members = @group.group_members
|
||||
@members = @members.non_pending unless can?(current_user, :admin_group, @group)
|
||||
@members = @members.non_invite unless can?(current_user, :admin_group, @group)
|
||||
|
||||
if params[:search].present?
|
||||
users = @group.users.search(params[:search]).to_a
|
||||
@@ -15,6 +15,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
end
|
||||
|
||||
@members = @members.order('access_level DESC').page(params[:page]).per(50)
|
||||
@requesters = @group.requesters if can?(current_user, :admin_group, @group)
|
||||
|
||||
@group_member = @group.group_members.new
|
||||
end
|
||||
@@ -34,7 +35,8 @@ class Groups::GroupMembersController < Groups::ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@group_member = @group.group_members.find(params[:id])
|
||||
@group_member = @group.members.find_by(id: params[:id]) ||
|
||||
@group.requesters.find_by(id: params[:id])
|
||||
|
||||
Members::DestroyService.new(@group_member, current_user).execute
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class Import::BaseController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def get_or_create_namespace
|
||||
|
||||
@@ -5,7 +5,6 @@ class Import::FogbugzController < Import::BaseController
|
||||
rescue_from Fogbugz::AuthenticationException, with: :fogbugz_unauthorized
|
||||
|
||||
def new
|
||||
|
||||
end
|
||||
|
||||
def callback
|
||||
@@ -22,7 +21,6 @@ class Import::FogbugzController < Import::BaseController
|
||||
end
|
||||
|
||||
def new_user_map
|
||||
|
||||
end
|
||||
|
||||
def create_user_map
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
class Import::GithubController < Import::BaseController
|
||||
before_action :verify_github_import_enabled
|
||||
before_action :github_auth, except: :callback
|
||||
before_action :github_auth, only: [:status, :jobs, :create]
|
||||
|
||||
rescue_from Octokit::Unauthorized, with: :github_unauthorized
|
||||
|
||||
helper_method :logged_in_with_github?
|
||||
|
||||
def new
|
||||
if logged_in_with_github?
|
||||
go_to_github_for_permissions
|
||||
elsif session[:github_access_token]
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
end
|
||||
|
||||
def callback
|
||||
session[:github_access_token] = client.get_token(params[:code])
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
|
||||
def personal_access_token
|
||||
session[:github_access_token] = params[:personal_access_token]
|
||||
redirect_to status_import_github_url
|
||||
end
|
||||
|
||||
def status
|
||||
@repos = client.repos
|
||||
@already_added_projects = current_user.created_projects.where(import_type: "github")
|
||||
@@ -57,10 +72,14 @@ class Import::GithubController < Import::BaseController
|
||||
end
|
||||
|
||||
def github_unauthorized
|
||||
go_to_github_for_permissions
|
||||
session[:github_access_token] = nil
|
||||
redirect_to new_import_github_url,
|
||||
alert: 'Access denied to your GitHub account.'
|
||||
end
|
||||
|
||||
private
|
||||
def logged_in_with_github?
|
||||
current_user.identities.exists?(provider: 'github')
|
||||
end
|
||||
|
||||
def access_params
|
||||
{ github_access_token: session[:github_access_token] }
|
||||
|
||||
@@ -44,5 +44,4 @@ class Import::GitoriousController < Import::BaseController
|
||||
def verify_gitorious_import_enabled
|
||||
render_404 unless gitorious_import_enabled?
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -3,7 +3,6 @@ class Import::GoogleCodeController < Import::BaseController
|
||||
before_action :user_map, only: [:new_user_map, :create_user_map]
|
||||
|
||||
def new
|
||||
|
||||
end
|
||||
|
||||
def callback
|
||||
@@ -34,7 +33,6 @@ class Import::GoogleCodeController < Import::BaseController
|
||||
end
|
||||
|
||||
def new_user_map
|
||||
|
||||
end
|
||||
|
||||
def create_user_map
|
||||
|
||||
@@ -5,7 +5,6 @@ class InvitesController < ApplicationController
|
||||
respond_to :html
|
||||
|
||||
def show
|
||||
|
||||
end
|
||||
|
||||
def accept
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
# This file should be identical in GitLab Community Edition and Enterprise Edition
|
||||
|
||||
class Projects::GitHttpController < Projects::ApplicationController
|
||||
include ActionController::HttpAuthentication::Basic
|
||||
include KerberosSpnegoHelper
|
||||
|
||||
attr_reader :user
|
||||
|
||||
# Git clients will not know what authenticity token to send along
|
||||
@@ -40,9 +45,12 @@ class Projects::GitHttpController < Projects::ApplicationController
|
||||
private
|
||||
|
||||
def authenticate_user
|
||||
return if project && project.public? && upload_pack?
|
||||
if project && project.public? && upload_pack?
|
||||
return # Allow access
|
||||
end
|
||||
|
||||
authenticate_or_request_with_http_basic do |login, password|
|
||||
if allow_basic_auth? && basic_auth_provided?
|
||||
login, password = user_name_and_password(request)
|
||||
auth_result = Gitlab::Auth.find_for_git_client(login, password, project: project, ip: request.ip)
|
||||
|
||||
if auth_result.type == :ci && upload_pack?
|
||||
@@ -53,8 +61,31 @@ class Projects::GitHttpController < Projects::ApplicationController
|
||||
@user = auth_result.user
|
||||
end
|
||||
|
||||
ci? || user
|
||||
if ci? || user
|
||||
return # Allow access
|
||||
end
|
||||
elsif allow_kerberos_spnego_auth? && spnego_provided?
|
||||
@user = find_kerberos_user
|
||||
|
||||
if user
|
||||
send_final_spnego_response
|
||||
return # Allow access
|
||||
end
|
||||
end
|
||||
|
||||
send_challenges
|
||||
render plain: "HTTP Basic: Access denied\n", status: 401
|
||||
end
|
||||
|
||||
def basic_auth_provided?
|
||||
has_basic_credentials?(request)
|
||||
end
|
||||
|
||||
def send_challenges
|
||||
challenges = []
|
||||
challenges << 'Basic realm="GitLab"' if allow_basic_auth?
|
||||
challenges << spnego_challenge if allow_kerberos_spnego_auth?
|
||||
headers['Www-Authenticate'] = challenges.join("\n") if challenges.any?
|
||||
end
|
||||
|
||||
def ensure_project_found!
|
||||
@@ -120,7 +151,7 @@ class Projects::GitHttpController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def render_not_found
|
||||
render text: 'Not Found', status: :not_found
|
||||
render plain: 'Not Found', status: :not_found
|
||||
end
|
||||
|
||||
def ci?
|
||||
|
||||
@@ -76,7 +76,6 @@ class Projects::IssuesController < Projects::ApplicationController
|
||||
render json: @issue.to_json(include: [:milestone, :labels])
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def create
|
||||
|
||||
@@ -7,7 +7,6 @@ class Projects::NetworkController < Projects::ApplicationController
|
||||
before_action :authorize_download_code!
|
||||
|
||||
def show
|
||||
|
||||
@url = namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))
|
||||
@commit_url = namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
|
||||
def index
|
||||
@project_members = @project.project_members
|
||||
@project_members = @project_members.non_pending unless can?(current_user, :admin_project, @project)
|
||||
@project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project)
|
||||
|
||||
if params[:search].present?
|
||||
users = @project.users.search(params[:search]).to_a
|
||||
@@ -19,7 +19,7 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
|
||||
if @group
|
||||
@group_members = @group.group_members
|
||||
@group_members = @group_members.non_pending unless can?(current_user, :admin_group, @group)
|
||||
@group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group)
|
||||
|
||||
if params[:search].present?
|
||||
users = @group.users.search(params[:search]).to_a
|
||||
@@ -29,6 +29,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
@group_members = @group_members.order('access_level DESC')
|
||||
end
|
||||
|
||||
@requesters = @project.requesters if can?(current_user, :admin_project, @project)
|
||||
|
||||
@project_member = @project.project_members.new
|
||||
@project_group_links = @project.project_group_links
|
||||
end
|
||||
@@ -48,7 +50,8 @@ class Projects::ProjectMembersController < Projects::ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@project_member = @project.project_members.find(params[:id])
|
||||
@project_member = @project.members.find_by(id: params[:id]) ||
|
||||
@project.requesters.find_by(id: params[:id])
|
||||
|
||||
Members::DestroyService.new(@project_member, current_user).execute
|
||||
|
||||
|
||||
@@ -6,8 +6,7 @@ class Projects::RunnerProjectsController < Projects::ApplicationController
|
||||
def create
|
||||
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
|
||||
|
||||
return head(403) if @runner.is_shared? || @runner.locked?
|
||||
return head(403) unless current_user.ci_authorized_runners.include?(@runner)
|
||||
return head(403) unless can?(current_user, :assign_runner, @runner)
|
||||
|
||||
path = runners_path(project)
|
||||
runner_project = @runner.assign_to(project, current_user)
|
||||
|
||||
@@ -54,7 +54,7 @@ class Projects::SnippetsController < Projects::ApplicationController
|
||||
|
||||
def show
|
||||
@note = @project.notes.new(noteable: @snippet)
|
||||
@notes = @snippet.notes.fresh
|
||||
@notes = Banzai::NoteRenderer.render(@snippet.notes.fresh, @project, current_user)
|
||||
@noteable = @snippet
|
||||
end
|
||||
|
||||
|
||||
@@ -124,5 +124,4 @@ class Projects::WikisController < Projects::ApplicationController
|
||||
def wiki_params
|
||||
params[:wiki].slice(:title, :content, :format, :message)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -4,7 +4,8 @@ class ProjectsController < Projects::ApplicationController
|
||||
before_action :authenticate_user!, except: [:show, :activity, :refs]
|
||||
before_action :project, except: [:new, :create]
|
||||
before_action :repository, except: [:new, :create]
|
||||
before_action :assign_ref_vars, :tree, only: [:show], if: :repo_exists?
|
||||
before_action :assign_ref_vars, only: [:show], if: :repo_exists?
|
||||
before_action :tree, only: [:show], if: :project_view_files?
|
||||
|
||||
# Authorize
|
||||
before_action :authorize_admin_project!, only: [:edit, :update, :housekeeping, :download_export, :export, :remove_export, :generate_new_export]
|
||||
@@ -303,6 +304,10 @@ class ProjectsController < Projects::ApplicationController
|
||||
project.repository_exists? && !project.empty_repo?
|
||||
end
|
||||
|
||||
def project_view_files?
|
||||
current_user && current_user.project_view == 'files'
|
||||
end
|
||||
|
||||
# Override extract_ref from ExtractsPath, which returns the branch and file path
|
||||
# for the blob/tree, which in this case is just the root of the default branch.
|
||||
# This way we avoid to access the repository.ref_names.
|
||||
|
||||
@@ -25,6 +25,7 @@ class TodosFinder
|
||||
def execute
|
||||
items = current_user.todos
|
||||
items = by_action_id(items)
|
||||
items = by_action(items)
|
||||
items = by_author(items)
|
||||
items = by_project(items)
|
||||
items = by_state(items)
|
||||
@@ -43,6 +44,18 @@ class TodosFinder
|
||||
params[:action_id]
|
||||
end
|
||||
|
||||
def to_action_id
|
||||
Todo::ACTION_NAMES.key(action.to_sym)
|
||||
end
|
||||
|
||||
def action?
|
||||
action.present? && to_action_id
|
||||
end
|
||||
|
||||
def action
|
||||
params[:action]
|
||||
end
|
||||
|
||||
def author?
|
||||
params[:author_id].present?
|
||||
end
|
||||
@@ -96,6 +109,14 @@ class TodosFinder
|
||||
params[:type]
|
||||
end
|
||||
|
||||
def by_action(items)
|
||||
if action?
|
||||
items = items.where(action: to_action_id)
|
||||
end
|
||||
|
||||
items
|
||||
end
|
||||
|
||||
def by_action_id(items)
|
||||
if action_id?
|
||||
items = items.where(action: action_id)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module EmailsHelper
|
||||
|
||||
# Google Actions
|
||||
# https://developers.google.com/gmail/markup/reference/go-to-action
|
||||
def email_action(url)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module IssuablesHelper
|
||||
|
||||
def sidebar_gutter_toggle_icon
|
||||
sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right')
|
||||
end
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
module KerberosSpnegoHelper
|
||||
def allow_basic_auth?
|
||||
true # different behavior in GitLab Enterprise Edition
|
||||
end
|
||||
|
||||
def allow_kerberos_spnego_auth?
|
||||
false # different behavior in GitLab Enterprise Edition
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
|
||||
@@ -12,6 +12,17 @@ module MembersHelper
|
||||
can?(current_user, action_member_permission(:admin, member), member.source)
|
||||
end
|
||||
|
||||
def can_see_request_access_button?(source)
|
||||
source_parent = source.respond_to?(:group) && source.group
|
||||
|
||||
return false if source_parent && source.group.members.exists?(user_id: current_user.id)
|
||||
return false if source_parent && source.group.requesters.exists?(user_id: current_user.id)
|
||||
return false if source.members.exists?(user_id: current_user.id)
|
||||
return true if source.requesters.exists?(user_id: current_user.id)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def remove_member_message(member, user: nil)
|
||||
user = current_user if defined?(current_user)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
module SearchHelper
|
||||
|
||||
def search_autocomplete_opts(term)
|
||||
return unless current_user
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
class Ability
|
||||
class << self
|
||||
# rubocop: disable Metrics/CyclomaticComplexity
|
||||
def allowed(user, subject)
|
||||
return anonymous_abilities(user, subject) if user.nil?
|
||||
return [] unless user.is_a?(User)
|
||||
@@ -19,6 +20,7 @@ class Ability
|
||||
when ProjectMember then project_member_abilities(user, subject)
|
||||
when User then user_abilities
|
||||
when ExternalIssue, Deployment, Environment then project_abilities(user, subject.project)
|
||||
when Ci::Runner then runner_abilities(user, subject)
|
||||
else []
|
||||
end.concat(global_abilities(user))
|
||||
end
|
||||
@@ -512,6 +514,18 @@ class Ability
|
||||
rules
|
||||
end
|
||||
|
||||
def runner_abilities(user, runner)
|
||||
if user.is_admin?
|
||||
[:assign_runner]
|
||||
elsif runner.is_shared? || runner.locked?
|
||||
[]
|
||||
elsif user.ci_authorized_runners.include?(runner)
|
||||
[:assign_runner]
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def user_abilities
|
||||
[:read_user]
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ module Ci
|
||||
end
|
||||
|
||||
def retryable?
|
||||
project.builds_enabled? && commands.present?
|
||||
project.builds_enabled? && commands.present? && complete?
|
||||
end
|
||||
|
||||
def retried?
|
||||
|
||||
@@ -58,7 +58,6 @@ module Issuable
|
||||
scope :references_project, -> { references(:project) }
|
||||
scope :non_archived, -> { join_project.where(projects: { archived: false }) }
|
||||
|
||||
|
||||
delegate :name,
|
||||
:email,
|
||||
to: :author,
|
||||
|
||||
+5
-4
@@ -6,15 +6,16 @@ class Group < Namespace
|
||||
include AccessRequestable
|
||||
include Referable
|
||||
|
||||
has_many :group_members, dependent: :destroy, as: :source, class_name: 'GroupMember'
|
||||
has_many :group_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember'
|
||||
alias_method :members, :group_members
|
||||
has_many :users, -> { where(members: { requested_at: nil }) }, through: :group_members
|
||||
|
||||
has_many :users, through: :group_members
|
||||
has_many :owners,
|
||||
-> { where(members: { requested_at: nil, access_level: Gitlab::Access::OWNER }) },
|
||||
-> { where(members: { access_level: Gitlab::Access::OWNER }) },
|
||||
through: :group_members,
|
||||
source: :user
|
||||
|
||||
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember'
|
||||
|
||||
has_many :project_group_links, dependent: :destroy
|
||||
has_many :shared_projects, through: :project_group_links, source: :project
|
||||
has_many :notification_settings, dependent: :destroy, as: :source
|
||||
|
||||
@@ -19,6 +19,8 @@ class Issue < ActiveRecord::Base
|
||||
belongs_to :project
|
||||
belongs_to :moved_to, class_name: 'Issue'
|
||||
|
||||
has_many :events, as: :target, dependent: :destroy
|
||||
|
||||
validates :project, presence: true
|
||||
|
||||
scope :cared, ->(user) { where(assignee_id: user) }
|
||||
|
||||
@@ -30,8 +30,6 @@ class Member < ActiveRecord::Base
|
||||
scope :invite, -> { where.not(invite_token: nil) }
|
||||
scope :non_invite, -> { where(invite_token: nil) }
|
||||
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) }
|
||||
|
||||
@@ -15,7 +15,6 @@ class ProjectMember < Member
|
||||
before_destroy :delete_member_todos
|
||||
|
||||
class << self
|
||||
|
||||
# Add users to project teams with passed access option
|
||||
#
|
||||
# access can be an integer representing a access code
|
||||
|
||||
@@ -12,6 +12,8 @@ class MergeRequest < ActiveRecord::Base
|
||||
|
||||
has_one :merge_request_diff, dependent: :destroy
|
||||
|
||||
has_many :events, as: :target, dependent: :destroy
|
||||
|
||||
serialize :merge_params, Hash
|
||||
|
||||
after_create :create_merge_request_diff, unless: :importing
|
||||
|
||||
@@ -17,6 +17,7 @@ class Milestone < ActiveRecord::Base
|
||||
has_many :labels, -> { distinct.reorder('labels.title') }, through: :issues
|
||||
has_many :merge_requests
|
||||
has_many :participants, -> { distinct.reorder('users.name') }, through: :issues, source: :assignee
|
||||
has_many :events, as: :target, dependent: :destroy
|
||||
|
||||
scope :active, -> { with_state(:active) }
|
||||
scope :closed, -> { with_state(:closed) }
|
||||
|
||||
+54
-39
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -21,6 +21,7 @@ class Note < ActiveRecord::Base
|
||||
belongs_to :updated_by, class_name: "User"
|
||||
|
||||
has_many :todos, dependent: :destroy
|
||||
has_many :events, as: :target, dependent: :destroy
|
||||
|
||||
delegate :gfm_reference, :local_reference, to: :noteable
|
||||
delegate :name, to: :project, prefix: true
|
||||
|
||||
+24
-5
@@ -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
|
||||
@@ -104,9 +108,13 @@ class Project < ActiveRecord::Base
|
||||
has_many :snippets, dependent: :destroy, class_name: 'ProjectSnippet'
|
||||
has_many :hooks, dependent: :destroy, class_name: 'ProjectHook'
|
||||
has_many :protected_branches, dependent: :destroy
|
||||
has_many :project_members, dependent: :destroy, as: :source, class_name: 'ProjectMember'
|
||||
|
||||
has_many :project_members, -> { where(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember'
|
||||
alias_method :members, :project_members
|
||||
has_many :users, -> { where(members: { requested_at: nil }) }, through: :project_members
|
||||
has_many :users, through: :project_members
|
||||
|
||||
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'ProjectMember'
|
||||
|
||||
has_many :deploy_keys_projects, dependent: :destroy
|
||||
has_many :deploy_keys, through: :deploy_keys_projects
|
||||
has_many :users_star_projects, dependent: :destroy
|
||||
@@ -165,6 +173,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
|
||||
@@ -376,6 +387,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
|
||||
@@ -842,12 +857,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
|
||||
|
||||
@@ -988,7 +1003,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
|
||||
@@ -1140,4 +1155,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
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class BugzillaService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
@@ -21,5 +20,4 @@ class BugzillaService < IssueTrackerService
|
||||
def to_param
|
||||
'bugzilla'
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class CustomIssueTrackerService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
@@ -31,5 +30,4 @@ class CustomIssueTrackerService < IssueTrackerService
|
||||
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url' }
|
||||
]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class DroneCiService < CiService
|
||||
|
||||
prop_accessor :drone_url, :token, :enable_ssl_verification
|
||||
|
||||
validates :drone_url, presence: true, url: true, if: :activated?
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class IssueTrackerService < Service
|
||||
|
||||
validates :project_url, :issues_url, :new_issue_url, presence: true, url: true, if: :activated?
|
||||
|
||||
default_value_for :category, 'issue_tracker'
|
||||
|
||||
@@ -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}"
|
||||
@@ -190,7 +190,6 @@ class JiraService < IssueTrackerService
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def auth
|
||||
require 'base64'
|
||||
Base64.urlsafe_encode64("#{self.username}:#{self.password}")
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
class RedmineService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
|
||||
@@ -22,12 +22,12 @@ class ProjectTeam
|
||||
end
|
||||
|
||||
def find_member(user_id)
|
||||
member = project.members.non_request.find_by(user_id: user_id)
|
||||
member = project.members.find_by(user_id: user_id)
|
||||
|
||||
# If user is not in project members
|
||||
# we should check for group membership
|
||||
if group && !member
|
||||
member = group.members.non_request.find_by(user_id: user_id)
|
||||
member = group.members.find_by(user_id: user_id)
|
||||
end
|
||||
|
||||
member
|
||||
@@ -137,10 +137,10 @@ class ProjectTeam
|
||||
def max_member_access(user_id)
|
||||
access = []
|
||||
|
||||
access += project.members.non_request.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
access += project.members.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
|
||||
if group
|
||||
access += group.members.non_request.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
access += group.members.where(user_id: user_id).has_access.pluck(:access_level)
|
||||
end
|
||||
|
||||
if project.invited_groups.any? && project.allowed_to_share_with_group?
|
||||
@@ -168,14 +168,14 @@ class ProjectTeam
|
||||
end
|
||||
|
||||
def fetch_members(level = nil)
|
||||
project_members = project.members.non_request
|
||||
group_members = group ? group.members.non_request : []
|
||||
project_members = project.members
|
||||
group_members = group ? group.members : []
|
||||
invited_members = []
|
||||
|
||||
if project.invited_groups.any? && project.allowed_to_share_with_group?
|
||||
project.project_group_links.each do |group_link|
|
||||
invited_group = group_link.group
|
||||
im = invited_group.members.non_request
|
||||
im = invited_group.members
|
||||
|
||||
if level
|
||||
int_level = GroupMember.access_level_roles[level.to_s.singularize.titleize]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -246,24 +246,26 @@ class Repository
|
||||
end
|
||||
end
|
||||
|
||||
# Keys for data that can be affected for any commit push.
|
||||
def cache_keys
|
||||
%i(size branch_names tag_names branch_count tag_count commit_count
|
||||
%i(size commit_count
|
||||
readme version contribution_guide changelog
|
||||
license_blob license_key gitignore)
|
||||
end
|
||||
|
||||
# Keys for data on branch/tag operations.
|
||||
def cache_keys_for_branches_and_tags
|
||||
%i(branch_names tag_names branch_count tag_count)
|
||||
end
|
||||
|
||||
def build_cache
|
||||
cache_keys.each do |key|
|
||||
(cache_keys + cache_keys_for_branches_and_tags).each do |key|
|
||||
unless cache.exist?(key)
|
||||
send(key)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def expire_gitignore
|
||||
cache.expire(:gitignore)
|
||||
end
|
||||
|
||||
def expire_tags_cache
|
||||
cache.expire(:tag_names)
|
||||
@tags = nil
|
||||
@@ -286,8 +288,6 @@ class Repository
|
||||
# This ensures this particular cache is flushed after the first commit to a
|
||||
# new repository.
|
||||
expire_emptiness_caches if empty?
|
||||
expire_branch_count_cache
|
||||
expire_tag_count_cache
|
||||
end
|
||||
|
||||
def expire_branch_cache(branch_name = nil)
|
||||
@@ -875,7 +875,6 @@ class Repository
|
||||
merge_base(ancestor_id, descendant_id) == ancestor_id
|
||||
end
|
||||
|
||||
|
||||
def search_files(query, ref)
|
||||
offset = 2
|
||||
args = %W(#{Gitlab.config.git.bin_path} grep -i -I -n --before-context #{offset} --after-context #{offset} -E -e #{Regexp.escape(query)} #{ref || root_ref})
|
||||
|
||||
@@ -4,6 +4,13 @@ class Todo < ActiveRecord::Base
|
||||
BUILD_FAILED = 3
|
||||
MARKED = 4
|
||||
|
||||
ACTION_NAMES = {
|
||||
ASSIGNED => :assigned,
|
||||
MENTIONED => :mentioned,
|
||||
BUILD_FAILED => :build_failed,
|
||||
MARKED => :marked
|
||||
}
|
||||
|
||||
belongs_to :author, class_name: "User"
|
||||
belongs_to :note
|
||||
belongs_to :project
|
||||
@@ -34,6 +41,10 @@ class Todo < ActiveRecord::Base
|
||||
action == BUILD_FAILED
|
||||
end
|
||||
|
||||
def action_name
|
||||
ACTION_NAMES[action]
|
||||
end
|
||||
|
||||
def body
|
||||
if note.present?
|
||||
note.note
|
||||
|
||||
+1
-2
@@ -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
|
||||
@@ -852,7 +852,6 @@ class User < ActiveRecord::Base
|
||||
projects.select(:id),
|
||||
groups.joins(:shared_projects).select(:project_id)]
|
||||
|
||||
|
||||
if min_access_level
|
||||
scope = { access_level: Gitlab::Access.values.select { |access| access >= min_access_level } }
|
||||
relations = [relations.shift] + relations.map { |relation| relation.where(members: scope) }
|
||||
|
||||
@@ -2,7 +2,6 @@ require_relative 'base_service'
|
||||
|
||||
class CreateReleaseService < BaseService
|
||||
def execute(tag_name, release_description)
|
||||
|
||||
repository = project.repository
|
||||
existing_tag = repository.find_tag(tag_name)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module Issues
|
||||
class BaseService < ::IssuableBaseService
|
||||
|
||||
def hook_data(issue, action)
|
||||
issue_data = issue.to_hook_data(current_user)
|
||||
issue_url = Gitlab::UrlBuilder.build(issue)
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module MergeRequests
|
||||
class BaseService < ::IssuableBaseService
|
||||
|
||||
def create_note(merge_request)
|
||||
SystemNoteService.change_status(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
|
||||
end
|
||||
|
||||
@@ -40,6 +40,5 @@ module MergeRequests
|
||||
error("Can't cancel the automatic merge", 406)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module Milestones
|
||||
class DestroyService < Milestones::BaseService
|
||||
def execute(milestone)
|
||||
|
||||
Milestone.transaction do
|
||||
update_params = { milestone: nil }
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module Projects
|
||||
class DownloadService < BaseService
|
||||
|
||||
WHITELIST = [
|
||||
/^[^.]+\.fogbugz.com$/
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
module Projects
|
||||
module ImportExport
|
||||
class ExportService < BaseService
|
||||
|
||||
def execute(_options = {})
|
||||
@shared = Gitlab::ImportExport::Shared.new(relative_path: File.join(project.path_with_namespace, 'work'))
|
||||
save_all
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -293,7 +293,6 @@ class SystemNoteService
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def self.cross_reference?(note_text)
|
||||
note_text.start_with?(cross_reference_note_prefix)
|
||||
end
|
||||
|
||||
@@ -2,7 +2,6 @@ require_relative 'base_service'
|
||||
|
||||
class UpdateReleaseService < BaseService
|
||||
def execute(tag_name, release_description)
|
||||
|
||||
repository = project.repository
|
||||
existing_tag = repository.find_tag(tag_name)
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module WikiPages
|
||||
class BaseService < ::BaseService
|
||||
|
||||
def hook_data(page, action)
|
||||
hook_data = {
|
||||
object_kind: page.class.name.underscore,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
- page_title "Background Jobs"
|
||||
= render 'admin/background_jobs/head'
|
||||
|
||||
%div{ class: (container_class) }
|
||||
%div{ class: container_class }
|
||||
%h3.page-title Background Jobs
|
||||
%p.light GitLab uses #{link_to "sidekiq", "http://sidekiq.org/"} library for async job processing
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- @no_container = true
|
||||
= render "admin/dashboard/head"
|
||||
|
||||
%div{ class: (container_class) }
|
||||
%div{ class: container_class }
|
||||
|
||||
.top-area
|
||||
%ul.nav-links
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
- @no_container = true
|
||||
= render "admin/dashboard/head"
|
||||
|
||||
%div{ class: (container_class) }
|
||||
%div{ class: container_class }
|
||||
.admin-dashboard.prepend-top-default
|
||||
.row
|
||||
.col-md-4
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user