Merge branch 'master' into avatar-cropping
Conflicts: app/models/user.rb
This commit is contained in:
commit
fb6d7df347
139
.gitlab-ci.yml
139
.gitlab-ci.yml
|
@ -5,6 +5,11 @@ services:
|
|||
- postgres:latest
|
||||
- redis:latest
|
||||
|
||||
cache:
|
||||
key: "ruby22"
|
||||
paths:
|
||||
- vendor
|
||||
|
||||
variables:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: "1"
|
||||
|
||||
|
@ -137,23 +142,145 @@ bundler:audit:
|
|||
|
||||
# Ruby 2.1 jobs
|
||||
|
||||
spec:ruby21:
|
||||
spec:feature:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake assets:precompile 2>/dev/null
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:feature
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
only:
|
||||
- master
|
||||
|
||||
spinach:ruby21:
|
||||
spec:api:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:models:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:models
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:lib:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:lib
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:services:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:services
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spec:benchmark:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test bundle exec rake spec:benchmark
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
allow_failure: true
|
||||
|
||||
spec:other:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:other
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spinach:project:half:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:half
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spinach:project:rest:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:project:rest
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
spinach:other:ruby21:
|
||||
image: ruby:2.1
|
||||
only:
|
||||
- master
|
||||
script:
|
||||
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spinach:other
|
||||
cache:
|
||||
key: "ruby21"
|
||||
paths:
|
||||
- vendor
|
||||
tags:
|
||||
- ruby
|
||||
- mysql
|
||||
|
||||
|
|
29
CHANGELOG
29
CHANGELOG
|
@ -1,45 +1,73 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.5.0 (unreleased)
|
||||
- Fix duplicate "me" in tooltip of the "thumbsup" awards Emoji (Stan Hu)
|
||||
- Cache various Repository methods to improve performance (Yorick Peterse)
|
||||
- Fix duplicated branch creation/deletion Web hooks/service notifications when using Web UI (Stan Hu)
|
||||
- Ensure rake tasks that don't need a DB connection can be run without one
|
||||
- Update New Relic gem to 3.14.1.311 (Stan Hu)
|
||||
- Add "visibility" flag to GET /projects api endpoint
|
||||
- Add an option to supply root email through an environmental variable (Koichiro Mikami)
|
||||
- Ignore binary files in code search to prevent Error 500 (Stan Hu)
|
||||
- Render sanitized SVG images (Stan Hu)
|
||||
- Support download access by PRIVATE-TOKEN header (Stan Hu)
|
||||
- Upgrade gitlab_git to 7.2.23 to fix commit message mentions in first branch push
|
||||
- Add option to include the sender name in body of Notify email (Jason Lee)
|
||||
- New UI for pagination
|
||||
- Don't prevent sign out when 2FA enforcement is enabled and user hasn't yet
|
||||
set it up
|
||||
- API: Added "merge_requests/:merge_request_id/closes_issues" (Gal Schlezinger)
|
||||
- Fix diff comments loaded by AJAX to load comment with diff in discussion tab
|
||||
- Fix relative links in other markup formats (Ben Boeckel)
|
||||
- Whitelist raw "abbr" elements when parsing Markdown (Benedict Etzel)
|
||||
- Fix label links for a merge request pointing to issues list
|
||||
- Don't vendor minified JS
|
||||
- Increase project import timeout to 15 minutes
|
||||
- Be more permissive with email address validation: it only has to contain a single '@'
|
||||
- Display 404 error on group not found
|
||||
- Track project import failure
|
||||
- Support Two-factor Authentication for LDAP users
|
||||
- Display database type and version in Administration dashboard
|
||||
- Allow limited Markdown in Broadcast Messages
|
||||
- Fix visibility level text in admin area (Zeger-Jan van de Weg)
|
||||
- Warn admin during OAuth of granting admin rights (Zeger-Jan van de Weg)
|
||||
- Update the ExternalIssue regex pattern (Blake Hitchcock)
|
||||
- Remember user's inline/side-by-side diff view preference in a cookie (Kirill Katsnelson)
|
||||
- Optimized performance of finding issues to be closed by a merge request
|
||||
- Add `avatar_url`, `description`, `git_ssh_url`, `git_http_url`, `path_with_namespace`
|
||||
and `default_branch` in `project` in push, issue, merge-request and note webhooks data (Kirill Zaitsev)
|
||||
- Deprecate the `ssh_url` in favor of `git_ssh_url` and `http_url` in favor of `git_http_url`
|
||||
in `project` for push, issue, merge-request and note webhooks data (Kirill Zaitsev)
|
||||
- Deprecate the `repository` key in push, issue, merge-request and note webhooks data, use `project` instead (Kirill Zaitsev)
|
||||
- API: Expose MergeRequest#merge_status (Andrei Dziahel)
|
||||
- Revert "Add IP check against DNSBLs at account sign-up"
|
||||
- Actually use the `skip_merges` option in Repository#commits (Tony Chu)
|
||||
- Fix API to keep request parameters in Link header (Michael Potthoff)
|
||||
- Deprecate API "merge_request/:merge_request_id/comments". Use "merge_requests/:merge_request_id/notes" instead
|
||||
- Deprecate API "merge_request/:merge_request_id/...". Use "merge_requests/:merge_request_id/..." instead
|
||||
- Prevent parse error when name of project ends with .atom and prevent path issues
|
||||
- Mark inline difference between old and new paths when a file is renamed
|
||||
- Support Akismet spam checking for creation of issues via API (Stan Hu)
|
||||
- API: Allow to set or update a merge-request's milestone (Kirill Skachkov)
|
||||
- Improve UI consistency between projects and groups lists
|
||||
- Add sort dropdown to dashboard projects page
|
||||
- Fixed logo animation on Safari (Roman Rott)
|
||||
- Hide remove source branch button when the MR is merged but new commits are pushed (Zeger-Jan van de Weg)
|
||||
- In seach autocomplete show only groups and projects you are member of
|
||||
- Don't process cross-reference notes from forks
|
||||
- Fix: init.d script not working on OS X
|
||||
- Faster snippet search
|
||||
- Title for milestones should be unique (Zeger-Jan van de Weg)
|
||||
- Validate correctness of maximum attachment size application setting
|
||||
- Replaces "Create merge request" link with one to the "Merge Request" when one exists
|
||||
- Fix CI builds badge, add a new link to builds badge, deprecate the old one
|
||||
- Fix broken link to project in build notification emails
|
||||
|
||||
v 8.4.4
|
||||
- Update omniauth-saml gem to 1.4.2
|
||||
- Prevent long-running backup tasks from timing out the database connection
|
||||
- Add a Project setting to allow guests to view build logs (defaults to true)
|
||||
- Sort project milestones by due date including issue editor (Oliver Rogers / Orih)
|
||||
|
||||
v 8.4.3
|
||||
- Increase lfs_objects size column to 8-byte integer to allow files larger
|
||||
|
@ -375,6 +403,7 @@ v 8.1.0
|
|||
- Improved performance of the trending projects page
|
||||
- Remove CI migration task
|
||||
- Improved performance of finding projects by their namespace
|
||||
- Add assignee data to Issuables' hook_data (Bram Daams)
|
||||
- Fix bug where transferring a project would result in stale commit links (Stan Hu)
|
||||
- Fix build trace updating
|
||||
- Include full path of source and target branch names in New Merge Request page (Stan Hu)
|
||||
|
|
|
@ -364,6 +364,7 @@ corresponding merge request should be updated to have the following:
|
|||
|
||||
This makes it easier for release managers to keep track of what still has to be
|
||||
merged and where changes have to be merged into.
|
||||
Like all merge requests the target should be master so all bugfixes are in master.
|
||||
|
||||
## Definition of done
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
0.6.3
|
||||
0.6.4
|
||||
|
|
4
Gemfile
4
Gemfile
|
@ -21,7 +21,7 @@ gem "pg", '~> 0.18.2', group: :postgres
|
|||
gem 'devise', '~> 3.5.4'
|
||||
gem 'devise-async', '~> 0.9.0'
|
||||
gem 'doorkeeper', '~> 2.2.0'
|
||||
gem 'omniauth', '~> 1.2.2'
|
||||
gem 'omniauth', '~> 1.3.1'
|
||||
gem 'omniauth-azure-oauth2', '~> 0.0.6'
|
||||
gem 'omniauth-bitbucket', '~> 0.0.2'
|
||||
gem 'omniauth-cas3', '~> 1.1.2'
|
||||
|
@ -108,7 +108,7 @@ gem 'rouge', '~> 1.10.1'
|
|||
|
||||
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
|
||||
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
|
||||
gem 'nokogiri', '1.6.7.2'
|
||||
gem 'nokogiri', '~> 1.6.7', '>= 1.6.7.2'
|
||||
|
||||
# Diffs
|
||||
gem 'diffy', '~> 3.0.3'
|
||||
|
|
|
@ -492,9 +492,9 @@ GEM
|
|||
rack (~> 1.2)
|
||||
octokit (3.8.0)
|
||||
sawyer (~> 0.6.0, >= 0.5.3)
|
||||
omniauth (1.2.2)
|
||||
omniauth (1.3.1)
|
||||
hashie (>= 1.2, < 4)
|
||||
rack (~> 1.0)
|
||||
rack (>= 1.0, < 3)
|
||||
omniauth-azure-oauth2 (0.0.6)
|
||||
jwt (~> 1.0)
|
||||
omniauth (~> 1.0)
|
||||
|
@ -961,11 +961,11 @@ DEPENDENCIES
|
|||
mysql2 (~> 0.3.16)
|
||||
nested_form (~> 0.3.2)
|
||||
net-ssh (~> 3.0.1)
|
||||
nokogiri (= 1.6.7.2)
|
||||
nokogiri (~> 1.6.7, >= 1.6.7.2)
|
||||
nprogress-rails (~> 0.1.6.7)
|
||||
oauth2 (~> 1.0.0)
|
||||
octokit (~> 3.8.0)
|
||||
omniauth (~> 1.2.2)
|
||||
omniauth (~> 1.3.1)
|
||||
omniauth-azure-oauth2 (~> 0.0.6)
|
||||
omniauth-bitbucket (~> 0.0.2)
|
||||
omniauth-cas3 (~> 1.1.2)
|
||||
|
|
|
@ -12,19 +12,6 @@ class @Admin
|
|||
e.preventDefault()
|
||||
$('.js-toggle-colors-container').toggle()
|
||||
|
||||
$('input#broadcast_message_color').on 'input', ->
|
||||
previewColor = $(@).val()
|
||||
$('div.broadcast-message-preview').css('background-color', previewColor)
|
||||
|
||||
$('input#broadcast_message_font').on 'input', ->
|
||||
previewColor = $(@).val()
|
||||
$('div.broadcast-message-preview').css('color', previewColor)
|
||||
|
||||
$('textarea#broadcast_message_message').on 'input', ->
|
||||
previewMessage = $(@).val()
|
||||
previewMessage = "Your message here" if previewMessage.trim() == ''
|
||||
$('div.broadcast-message-preview span').text(previewMessage)
|
||||
|
||||
$('.log-tabs a').click (e) ->
|
||||
e.preventDefault()
|
||||
$(this).tab('show')
|
||||
|
|
|
@ -49,10 +49,11 @@ class @AwardsHandler
|
|||
counter.text(parseInt(counter.text()) - 1)
|
||||
emojiIcon.removeClass("active")
|
||||
@removeMeFromAuthorList(emoji)
|
||||
else if emoji =="thumbsup" || emoji == "thumbsdown"
|
||||
else if emoji == "thumbsup" || emoji == "thumbsdown"
|
||||
emojiIcon.tooltip("destroy")
|
||||
counter.text(0)
|
||||
emojiIcon.removeClass("active")
|
||||
@removeMeFromAuthorList(emoji)
|
||||
else
|
||||
emojiIcon.tooltip("destroy")
|
||||
emojiIcon.remove()
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
$ ->
|
||||
$('input#broadcast_message_color').on 'input', ->
|
||||
previewColor = $(@).val()
|
||||
$('div.broadcast-message-preview').css('background-color', previewColor)
|
||||
|
||||
$('input#broadcast_message_font').on 'input', ->
|
||||
previewColor = $(@).val()
|
||||
$('div.broadcast-message-preview').css('color', previewColor)
|
||||
|
||||
previewPath = $('textarea#broadcast_message_message').data('preview-path')
|
||||
|
||||
$('textarea#broadcast_message_message').on 'input', ->
|
||||
message = $(@).val()
|
||||
|
||||
if message == ''
|
||||
$('.js-broadcast-message-preview').text("Your message here")
|
||||
else
|
||||
$.ajax(
|
||||
url: previewPath
|
||||
type: "POST"
|
||||
data: { broadcast_message: { message: message } }
|
||||
)
|
|
@ -1,10 +1,11 @@
|
|||
@Dashboard =
|
||||
init: ->
|
||||
$(".projects-list-filter").off('keyup')
|
||||
this.initSearch()
|
||||
|
||||
initSearch: ->
|
||||
@timer = null
|
||||
$("#project-filter-form-field").on('keyup', ->
|
||||
$(".projects-list-filter").on('keyup', ->
|
||||
clearTimeout(@timer)
|
||||
@timer = setTimeout(Dashboard.filterResults, 500)
|
||||
)
|
||||
|
@ -13,8 +14,8 @@
|
|||
$('.projects-list-holder').fadeTo(250, 0.5)
|
||||
|
||||
form = null
|
||||
form = $("#project-filter-form")
|
||||
search = $("#project-filter-form-field").val()
|
||||
form = $("form#project-filter-form")
|
||||
search = $(".projects-list-filter").val()
|
||||
project_filter_url = form.attr('action') + '?' + form.serialize()
|
||||
|
||||
$.ajax
|
||||
|
@ -24,7 +25,7 @@
|
|||
complete: ->
|
||||
$('.projects-list-holder').fadeTo(250, 1)
|
||||
success: (data) ->
|
||||
$('div.projects-list-holder').replaceWith(data.html)
|
||||
$('.projects-list-holder').replaceWith(data.html)
|
||||
# Change url so if user reload a page - search results are saved
|
||||
history.replaceState {page: project_filter_url}, document.title, project_filter_url
|
||||
dataType: "json"
|
||||
|
|
|
@ -16,6 +16,8 @@ class Dispatcher
|
|||
shortcut_handler = null
|
||||
|
||||
switch page
|
||||
when 'explore:projects:index', 'explore:projects:starred', 'explore:projects:trending'
|
||||
Dashboard.init()
|
||||
when 'projects:issues:index'
|
||||
Issues.init()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
|
|
|
@ -44,6 +44,7 @@ $(document).on('page:fetch', start)
|
|||
$(document).on('page:change', stop)
|
||||
|
||||
$ ->
|
||||
# Make logo clickable
|
||||
# Make logo clickable as part of a workaround for Safari visited
|
||||
# link behaviour (See !2690).
|
||||
$('#logo').on 'click', ->
|
||||
$('#js-shortcuts-home').get(0).click()
|
||||
|
|
|
@ -3,22 +3,24 @@ class @ProjectsList
|
|||
$(".projects-list .js-expand").on 'click', (e) ->
|
||||
e.preventDefault()
|
||||
list = $(this).closest('.projects-list')
|
||||
list.find("li").show()
|
||||
list.find("li.bottom").hide()
|
||||
|
||||
$(".projects-list-filter").keyup ->
|
||||
terms = $(this).val()
|
||||
uiBox = $('div.projects-list-holder')
|
||||
filterSelector = $(this).data('filter-selector') || 'span.filter-title'
|
||||
$("#filter_projects").on 'keyup', ->
|
||||
ProjectsList.filter_results($("#filter_projects"))
|
||||
|
||||
if terms == "" || terms == undefined
|
||||
uiBox.find("ul.projects-list li").show()
|
||||
@filter_results: ($element) ->
|
||||
terms = $element.val()
|
||||
filterSelector = $element.data('filter-selector') || 'span.filter-title'
|
||||
|
||||
if not terms
|
||||
$(".projects-list li").show()
|
||||
$('.gl-pagination').show()
|
||||
else
|
||||
uiBox.find("ul.projects-list li").each (index) ->
|
||||
name = $(this).find(filterSelector).text()
|
||||
$(".projects-list li").each (index) ->
|
||||
$this = $(this)
|
||||
name = $this.find(filterSelector).text()
|
||||
|
||||
if name.toLowerCase().search(terms.toLowerCase()) == -1
|
||||
$(this).hide()
|
||||
if name.toLowerCase().indexOf(terms.toLowerCase()) == -1
|
||||
$this.hide()
|
||||
else
|
||||
$(this).show()
|
||||
uiBox.find("ul.projects-list li.bottom").hide()
|
||||
$this.show()
|
||||
$('.gl-pagination').hide()
|
||||
|
|
|
@ -55,6 +55,16 @@
|
|||
@extend .alert-warning;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
|
||||
> div, p {
|
||||
display: inline;
|
||||
margin: 0;
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.broadcast-message-preview {
|
||||
|
|
|
@ -80,6 +80,10 @@
|
|||
display: inline-block;
|
||||
}
|
||||
|
||||
.select2-container span {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.issuable-count {
|
||||
|
||||
}
|
||||
|
@ -88,6 +92,10 @@
|
|||
margin-left: 20px;
|
||||
border-left: 1px solid $border-gray-light;
|
||||
padding-left: 10px;
|
||||
|
||||
&:hover {
|
||||
color: $gray-darkest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -192,6 +200,10 @@
|
|||
.btn {
|
||||
background: $gray-normal;
|
||||
border: 1px solid $border-gray-normal;
|
||||
&:hover {
|
||||
background: $gray-dark;
|
||||
border: 1px solid $border-gray-dark;
|
||||
}
|
||||
}
|
||||
|
||||
&.right-sidebar-collapsed {
|
||||
|
@ -223,6 +235,19 @@
|
|||
display: block;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.btn-clipboard {
|
||||
border: none;
|
||||
|
||||
&:hover {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
i {
|
||||
color: #999999;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -81,6 +81,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
|||
:sentry_dsn,
|
||||
:akismet_enabled,
|
||||
:akismet_api_key,
|
||||
:email_author_in_body,
|
||||
restricted_visibility_levels: [],
|
||||
import_sources: []
|
||||
)
|
||||
|
|
|
@ -36,6 +36,10 @@ class Admin::BroadcastMessagesController < Admin::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
@message = broadcast_message_params[:message]
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def finder
|
||||
|
|
|
@ -164,7 +164,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def git_not_found!
|
||||
render html: "errors/git_not_found", layout: "errors", status: 404
|
||||
render "errors/git_not_found.html", layout: "errors", status: 404
|
||||
end
|
||||
|
||||
def method_missing(method_sym, *arguments, &block)
|
||||
|
|
|
@ -3,52 +3,5 @@ module Ci
|
|||
def self.railtie_helpers_paths
|
||||
"app/helpers/ci"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authorize_access_project!
|
||||
unless can?(current_user, :read_project, project)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def authorize_manage_builds!
|
||||
unless can?(current_user, :manage_builds, project)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def authenticate_admin!
|
||||
return render_404 unless current_user.is_admin?
|
||||
end
|
||||
|
||||
def authorize_manage_project!
|
||||
unless can?(current_user, :admin_project, project)
|
||||
return page_404
|
||||
end
|
||||
end
|
||||
|
||||
def page_404
|
||||
render file: "#{Rails.root}/public/404.html", status: 404, layout: false
|
||||
end
|
||||
|
||||
def default_headers
|
||||
headers['X-Frame-Options'] = 'DENY'
|
||||
headers['X-XSS-Protection'] = '1; mode=block'
|
||||
end
|
||||
|
||||
# JSON for infinite scroll via Pager object
|
||||
def pager_json(partial, count)
|
||||
html = render_to_string(
|
||||
partial,
|
||||
layout: false,
|
||||
formats: [:html]
|
||||
)
|
||||
|
||||
render json: {
|
||||
html: html,
|
||||
count: count
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
module Ci
|
||||
class ProjectsController < Ci::ApplicationController
|
||||
before_action :project, except: [:index]
|
||||
before_action :authenticate_user!, except: [:index, :build, :badge]
|
||||
before_action :authorize_access_project!, except: [:index, :badge]
|
||||
before_action :project
|
||||
before_action :authorize_read_project!, except: [:badge]
|
||||
before_action :no_cache, only: [:badge]
|
||||
protect_from_forgery
|
||||
|
||||
|
@ -13,9 +12,13 @@ module Ci
|
|||
|
||||
# Project status badge
|
||||
# Image with build status for sha or ref
|
||||
#
|
||||
# This action in DEPRECATED, this is here only for backwards compatibility
|
||||
# with projects migrated from GitLab CI.
|
||||
#
|
||||
def badge
|
||||
return render_404 unless @project
|
||||
image = Ci::ImageForBuildService.new.execute(@project, params)
|
||||
|
||||
send_file image.path, filename: image.name, disposition: 'inline', type:"image/svg+xml"
|
||||
end
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
|
|||
@projects = @projects.search(terms)
|
||||
end
|
||||
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE) if terms.blank?
|
||||
@last_push = current_user.recent_push
|
||||
|
||||
respond_to do |format|
|
||||
|
@ -41,7 +41,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController
|
|||
@projects = @projects.search(terms)
|
||||
end
|
||||
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE) if terms.blank?
|
||||
@last_push = current_user.recent_push
|
||||
@groups = []
|
||||
|
||||
|
|
|
@ -6,19 +6,49 @@ class Explore::ProjectsController < Explore::ApplicationController
|
|||
@projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
|
||||
@projects = @projects.non_archived
|
||||
@projects = @projects.search(params[:search]) if params[:search].present?
|
||||
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
@projects = @projects.sort(@sort = params[:sort])
|
||||
@projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.includes(:namespace).page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def trending
|
||||
@projects = TrendingProjectsFinder.new.execute(current_user)
|
||||
@projects = @projects.non_archived
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def starred
|
||||
@projects = ProjectsFinder.new.execute(current_user)
|
||||
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
@projects = @projects.reorder('star_count DESC')
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json do
|
||||
render json: {
|
||||
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -14,7 +14,7 @@ class GroupsController < Groups::ApplicationController
|
|||
|
||||
# Load group projects
|
||||
before_action :load_projects, except: [:index, :new, :create, :projects, :edit, :update, :autocomplete]
|
||||
before_action :event_filter, only: :show
|
||||
before_action :event_filter, only: [:show, :events]
|
||||
|
||||
layout :determine_layout
|
||||
|
||||
|
@ -41,14 +41,16 @@ class GroupsController < Groups::ApplicationController
|
|||
def show
|
||||
@last_push = current_user.recent_push if current_user
|
||||
@projects = @projects.includes(:namespace)
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE)
|
||||
@projects = @projects.search(params[:filter_projects]) if params[:filter_projects].present?
|
||||
@projects = @projects.page(params[:page]).per(PER_PAGE) if params[:filter_projects].blank?
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
|
||||
format.json do
|
||||
load_events
|
||||
pager_json("events/_events", @events.count)
|
||||
render json: {
|
||||
html: view_to_html_string("dashboard/projects/_projects", locals: { projects: @projects })
|
||||
}
|
||||
end
|
||||
|
||||
format.atom do
|
||||
|
@ -58,6 +60,15 @@ class GroupsController < Groups::ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def events
|
||||
respond_to do |format|
|
||||
format.json do
|
||||
load_events
|
||||
pager_json("events/_events", @events.count)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def edit
|
||||
end
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Projects::ArtifactsController < Projects::ApplicationController
|
||||
layout 'project'
|
||||
before_action :authorize_read_build_artifacts!
|
||||
before_action :authorize_read_build!
|
||||
|
||||
def download
|
||||
unless artifacts_file.file_storage?
|
||||
|
@ -43,14 +43,4 @@ class Projects::ArtifactsController < Projects::ApplicationController
|
|||
def artifacts_file
|
||||
@artifacts_file ||= build.artifacts_file
|
||||
end
|
||||
|
||||
def authorize_read_build_artifacts!
|
||||
unless can?(current_user, :read_build_artifacts, @project)
|
||||
if current_user.nil?
|
||||
return authenticate_user!
|
||||
else
|
||||
return render_404
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
class Projects::BadgesController < Projects::ApplicationController
|
||||
def build
|
||||
respond_to do |format|
|
||||
format.html { render_404 }
|
||||
format.svg do
|
||||
image = Ci::ImageForBuildService.new.execute(project, ref: params[:ref])
|
||||
send_file(image.path, filename: image.name, disposition: 'inline', type: 'image/svg+xml')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,9 +1,8 @@
|
|||
class Projects::BuildsController < Projects::ApplicationController
|
||||
before_action :build, except: [:index, :cancel_all]
|
||||
|
||||
before_action :authorize_manage_builds!, except: [:index, :show, :status]
|
||||
|
||||
layout "project"
|
||||
before_action :authorize_read_build!, except: [:cancel, :cancel_all, :retry]
|
||||
before_action :authorize_update_build!, except: [:index, :show, :status]
|
||||
layout 'project'
|
||||
|
||||
def index
|
||||
@scope = params[:scope]
|
||||
|
@ -23,7 +22,6 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
|
||||
def cancel_all
|
||||
@project.builds.running_or_pending.each(&:cancel)
|
||||
|
||||
redirect_to namespace_project_builds_path(project.namespace, project)
|
||||
end
|
||||
|
||||
|
@ -46,20 +44,18 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
build = Ci::Build.retry(@build)
|
||||
|
||||
redirect_to build_path(build)
|
||||
end
|
||||
|
||||
def status
|
||||
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
|
||||
end
|
||||
|
||||
def cancel
|
||||
@build.cancel
|
||||
|
||||
redirect_to build_path(@build)
|
||||
end
|
||||
|
||||
def status
|
||||
render json: @build.to_json(only: [:status, :id, :sha, :coverage], methods: :sha)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def build
|
||||
|
@ -69,10 +65,4 @@ class Projects::BuildsController < Projects::ApplicationController
|
|||
def build_path(build)
|
||||
namespace_project_build_path(build.project.namespace, build.project, build)
|
||||
end
|
||||
|
||||
def authorize_manage_builds!
|
||||
unless can?(current_user, :manage_builds, project)
|
||||
return render_404
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,15 +4,13 @@
|
|||
class Projects::CommitController < Projects::ApplicationController
|
||||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!, except: [:cancel_builds]
|
||||
before_action :authorize_manage_builds!, only: [:cancel_builds]
|
||||
before_action :authorize_download_code!, except: [:cancel_builds, :retry_builds]
|
||||
before_action :authorize_update_build!, only: [:cancel_builds, :retry_builds]
|
||||
before_action :authorize_read_commit_status!, only: [:builds]
|
||||
before_action :commit
|
||||
before_action :authorize_manage_builds!, only: [:cancel_builds, :retry_builds]
|
||||
before_action :define_show_vars, only: [:show, :builds]
|
||||
|
||||
def show
|
||||
return git_not_found! unless @commit
|
||||
|
||||
apply_diff_view_cookie!
|
||||
|
||||
@line_notes = commit.notes.inline
|
||||
|
@ -68,6 +66,8 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
end
|
||||
|
||||
def define_show_vars
|
||||
return git_not_found! unless commit
|
||||
|
||||
if params[:w].to_i == 1
|
||||
@diffs = commit.diffs({ ignore_whitespace_change: true })
|
||||
else
|
||||
|
@ -79,10 +79,4 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
|
||||
@statuses = ci_commit.statuses if ci_commit
|
||||
end
|
||||
|
||||
def authorize_manage_builds!
|
||||
unless can?(current_user, :manage_builds, project)
|
||||
return render_404
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,6 +21,9 @@ class Projects::CommitsController < Projects::ApplicationController
|
|||
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
|
||||
group(:commit_id).count
|
||||
|
||||
@merge_request = @project.merge_requests.opened.
|
||||
find_by(source_project: @project, source_branch: @ref, target_branch: @repository.root_ref)
|
||||
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.json { pager_json("projects/commits/_commits", @commits.size) }
|
||||
|
|
|
@ -4,24 +4,23 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
before_action :authorize_download_code!
|
||||
before_action :assign_ref_vars, only: [:index, :show]
|
||||
before_action :merge_request, only: [:index, :show]
|
||||
|
||||
def index
|
||||
@ref = Addressable::URI.unescape(params[:to])
|
||||
end
|
||||
|
||||
def show
|
||||
base_ref = Addressable::URI.unescape(params[:from])
|
||||
@ref = head_ref = Addressable::URI.unescape(params[:to])
|
||||
diff_options = { ignore_whitespace_change: true } if params[:w] == '1'
|
||||
|
||||
compare_result = CompareService.new.
|
||||
execute(@project, head_ref, @project, base_ref, diff_options)
|
||||
execute(@project, @head_ref, @project, @base_ref, diff_options)
|
||||
|
||||
if compare_result
|
||||
@commits = Commit.decorate(compare_result.commits, @project)
|
||||
@diffs = compare_result.diffs
|
||||
@commit = @project.commit(head_ref)
|
||||
@base_commit = @project.merge_base_commit(base_ref, head_ref)
|
||||
@commit = @project.commit(@head_ref)
|
||||
@base_commit = @project.merge_base_commit(@base_ref, @head_ref)
|
||||
@diff_refs = [@base_commit, @commit]
|
||||
@line_notes = []
|
||||
end
|
||||
|
@ -31,4 +30,16 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
redirect_to namespace_project_compare_path(@project.namespace, @project,
|
||||
params[:from], params[:to])
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign_ref_vars
|
||||
@base_ref = Addressable::URI.unescape(params[:from])
|
||||
@ref = @head_ref = Addressable::URI.unescape(params[:to])
|
||||
end
|
||||
|
||||
def merge_request
|
||||
@merge_request ||= @project.merge_requests.opened.
|
||||
find_by(source_project: @project, source_branch: @head_ref, target_branch: @base_ref)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,10 +11,11 @@ class Projects::MilestonesController < Projects::ApplicationController
|
|||
respond_to :html
|
||||
|
||||
def index
|
||||
@milestones = case params[:state]
|
||||
when 'all'; @project.milestones.order("state, due_date DESC")
|
||||
when 'closed'; @project.milestones.closed.order("due_date DESC")
|
||||
else @project.milestones.active.order("due_date ASC")
|
||||
@milestones =
|
||||
case params[:state]
|
||||
when 'all' then @project.milestones.reorder(due_date: :desc, title: :asc)
|
||||
when 'closed' then @project.milestones.closed.reorder(due_date: :desc, title: :asc)
|
||||
else @project.milestones.active.reorder(due_date: :asc, title: :asc)
|
||||
end
|
||||
|
||||
@milestones = @milestones.includes(:project)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Projects::RunnerProjectsController < Projects::ApplicationController
|
||||
before_action :authorize_admin_project!
|
||||
before_action :authorize_admin_build!
|
||||
|
||||
layout 'project_settings'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Projects::RunnersController < Projects::ApplicationController
|
||||
before_action :authorize_admin_build!
|
||||
before_action :set_runner, only: [:edit, :update, :destroy, :pause, :resume, :show]
|
||||
before_action :authorize_admin_project!
|
||||
|
||||
layout 'project_settings'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Projects::TriggersController < Projects::ApplicationController
|
||||
before_action :authorize_admin_project!
|
||||
before_action :authorize_admin_build!
|
||||
|
||||
layout 'project_settings'
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
class Projects::VariablesController < Projects::ApplicationController
|
||||
before_action :authorize_admin_project!
|
||||
before_action :authorize_admin_build!
|
||||
|
||||
layout 'project_settings'
|
||||
|
||||
|
|
|
@ -227,6 +227,7 @@ class ProjectsController < ApplicationController
|
|||
:issues_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :default_branch,
|
||||
:wiki_enabled, :visibility_level, :import_url, :last_activity_at, :namespace_id, :avatar,
|
||||
:builds_enabled, :build_allow_git_fetch, :build_timeout_in_minutes, :build_coverage_regex,
|
||||
:public_builds,
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -212,8 +212,7 @@ module ApplicationHelper
|
|||
file_content
|
||||
end
|
||||
else
|
||||
GitHub::Markup.render(file_name, file_content).
|
||||
force_encoding(file_content.encoding).html_safe
|
||||
other_markup(file_name, file_content)
|
||||
end
|
||||
rescue RuntimeError
|
||||
simple_format(file_content)
|
||||
|
@ -281,76 +280,6 @@ module ApplicationHelper
|
|||
end
|
||||
end
|
||||
|
||||
def issuable_link_next(project,issuable)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
namespace_project_issue_path(project.namespace, project, next_issuable_for(project, issuable.id).try(:iid))
|
||||
elsif current_controller?(:merge_requests)
|
||||
namespace_project_merge_request_path(project.namespace, project, next_issuable_for(project, issuable.id).try(:iid))
|
||||
end
|
||||
end
|
||||
|
||||
def issuable_link_prev(project,issuable)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
namespace_project_issue_path(project.namespace, project, prev_issuable_for(project, issuable.id).try(:iid))
|
||||
elsif current_controller?(:merge_requests)
|
||||
namespace_project_merge_request_path(project.namespace, project, prev_issuable_for(project, issuable.id).try(:iid))
|
||||
end
|
||||
end
|
||||
|
||||
def issuable_count(entity, project)
|
||||
if project.nil?
|
||||
0
|
||||
elsif current_controller?(:issues)
|
||||
project.issues.send(entity).count
|
||||
elsif current_controller?(:merge_requests)
|
||||
project.merge_requests.send(entity).count
|
||||
end
|
||||
end
|
||||
|
||||
def next_issuable_for(project, id)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
project.issues.where("id > ?", id).last
|
||||
elsif current_controller?(:merge_requests)
|
||||
project.merge_requests.where("id > ?", id).last
|
||||
end
|
||||
end
|
||||
|
||||
def has_next_issuable?(project, id)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
project.issues.where("id > ?", id).last
|
||||
elsif current_controller?(:merge_requests)
|
||||
project.merge_requests.where("id > ?", id).last
|
||||
end
|
||||
end
|
||||
|
||||
def prev_issuable_for(project, id)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
project.issues.where("id < ?", id).first
|
||||
elsif current_controller?(:merge_requests)
|
||||
project.merge_requests.where("id < ?", id).first
|
||||
end
|
||||
end
|
||||
|
||||
def has_prev_issuable?(project, id)
|
||||
if project.nil?
|
||||
nil
|
||||
elsif current_controller?(:issues)
|
||||
project.issues.where("id < ?", id).first
|
||||
elsif current_controller?(:merge_requests)
|
||||
project.merge_requests.where("id < ?", id).first
|
||||
end
|
||||
end
|
||||
|
||||
def state_filters_text_for(entity, project)
|
||||
titles = {
|
||||
opened: "Open"
|
||||
|
|
|
@ -3,7 +3,7 @@ module BroadcastMessagesHelper
|
|||
return unless message.present?
|
||||
|
||||
content_tag :div, class: 'broadcast-message', style: broadcast_message_style(message) do
|
||||
icon('bullhorn') << ' ' << message.message
|
||||
icon('bullhorn') << ' ' << render_broadcast_message(message.message)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -31,4 +31,8 @@ module BroadcastMessagesHelper
|
|||
'Pending'
|
||||
end
|
||||
end
|
||||
|
||||
def render_broadcast_message(message)
|
||||
Banzai.render(message, pipeline: :broadcast_message).html_safe
|
||||
end
|
||||
end
|
||||
|
|
|
@ -78,6 +78,21 @@ module GitlabMarkdownHelper
|
|||
)
|
||||
end
|
||||
|
||||
def other_markup(file_name, text)
|
||||
Gitlab::OtherMarkup.render(
|
||||
file_name,
|
||||
text,
|
||||
project: @project,
|
||||
current_user: (current_user if defined?(current_user)),
|
||||
|
||||
# RelativeLinkFilter
|
||||
project_wiki: @project_wiki,
|
||||
requested_path: @path,
|
||||
ref: @ref,
|
||||
commit: @commit
|
||||
)
|
||||
end
|
||||
|
||||
# Return the first line of +text+, up to +max_chars+, after parsing the line
|
||||
# as Markdown. HTML tags in the parsed output are not counted toward the
|
||||
# +max_chars+ limit. If the length limit falls within a tag's contents, then
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
module IssuablesHelper
|
||||
|
||||
def sidebar_gutter_toggle_icon
|
||||
sidebar_gutter_collapsed? ? icon('angle-double-left') : icon('angle-double-right')
|
||||
end
|
||||
|
||||
def sidebar_gutter_collapsed_class
|
||||
"right-sidebar-#{sidebar_gutter_collapsed? ? 'collapsed' : 'expanded'}"
|
||||
end
|
||||
|
||||
def issuables_count(issuable)
|
||||
base_issuable_scope(issuable).maximum(:iid)
|
||||
end
|
||||
|
||||
def next_issuable_for(issuable)
|
||||
base_issuable_scope(issuable).where('iid > ?', issuable.iid).last
|
||||
end
|
||||
|
||||
def prev_issuable_for(issuable)
|
||||
base_issuable_scope(issuable).where('iid < ?', issuable.iid).first
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sidebar_gutter_collapsed?
|
||||
cookies[:collapsed_gutter] == 'true'
|
||||
end
|
||||
|
||||
def base_issuable_scope(issuable)
|
||||
issuable.project.send(issuable.class.table_name).send(issuable_state_scope(issuable))
|
||||
end
|
||||
|
||||
def issuable_state_scope(issuable)
|
||||
issuable.open? ? :opened : :closed
|
||||
end
|
||||
|
||||
end
|
|
@ -44,14 +44,14 @@ module IssuesHelper
|
|||
end
|
||||
|
||||
def bulk_update_milestone_options
|
||||
milestones = project_active_milestones.to_a
|
||||
milestones = @project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
|
||||
milestones.unshift(Milestone::None)
|
||||
|
||||
options_from_collection_for_select(milestones, 'id', 'title', params[:milestone_id])
|
||||
end
|
||||
|
||||
def milestone_options(object)
|
||||
milestones = object.project.milestones.active.to_a
|
||||
milestones = object.project.milestones.active.reorder(due_date: :asc, title: :asc).to_a
|
||||
milestones.unshift(Milestone::None)
|
||||
|
||||
options_from_collection_for_select(milestones, 'id', 'title', object.milestone_id)
|
||||
|
|
|
@ -3,18 +3,6 @@ module NavHelper
|
|||
cookies[:collapsed_nav] == 'true'
|
||||
end
|
||||
|
||||
def sidebar_gutter_collapsed_class
|
||||
if cookies[:collapsed_gutter] == 'true'
|
||||
"right-sidebar-collapsed"
|
||||
else
|
||||
"right-sidebar-expanded"
|
||||
end
|
||||
end
|
||||
|
||||
def sidebar_gutter_collapsed?
|
||||
cookies[:collapsed_gutter] == 'true'
|
||||
end
|
||||
|
||||
def nav_sidebar_class
|
||||
if nav_menu_collapsed?
|
||||
"sidebar-collapsed"
|
||||
|
|
|
@ -98,10 +98,6 @@ module ProjectsHelper
|
|||
project_nav_tabs.include? name
|
||||
end
|
||||
|
||||
def project_active_milestones
|
||||
@project.milestones.active.order("due_date, title ASC")
|
||||
end
|
||||
|
||||
def project_for_deploy_key(deploy_key)
|
||||
if deploy_key.projects.include?(@project)
|
||||
@project
|
||||
|
@ -141,7 +137,7 @@ module ProjectsHelper
|
|||
nav_tabs << :merge_requests
|
||||
end
|
||||
|
||||
if project.builds_enabled? && can?(current_user, :read_build, project)
|
||||
if can?(current_user, :read_build, project)
|
||||
nav_tabs << :builds
|
||||
end
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ module SnippetsHelper
|
|||
# surrounding code.
|
||||
#
|
||||
# @returns Array, unique and sorted.
|
||||
def matching_lines(lined_content, surrounding_lines)
|
||||
def matching_lines(lined_content, surrounding_lines, query)
|
||||
used_lines = []
|
||||
lined_content.each_with_index do |line, line_number|
|
||||
used_lines.concat bounded_line_numbers(
|
||||
|
@ -51,9 +51,9 @@ module SnippetsHelper
|
|||
# surrounding_lines() worth of unmatching lines.
|
||||
#
|
||||
# @returns a hash with {snippet_object, snippet_chunks:{data,start_line}}
|
||||
def chunk_snippet(snippet, surrounding_lines = 3)
|
||||
def chunk_snippet(snippet, query, surrounding_lines = 3)
|
||||
lined_content = snippet.content.split("\n")
|
||||
used_lines = matching_lines(lined_content, surrounding_lines)
|
||||
used_lines = matching_lines(lined_content, surrounding_lines, query)
|
||||
|
||||
snippet_chunk = []
|
||||
snippet_chunks = []
|
||||
|
|
|
@ -3,26 +3,27 @@ module Emails
|
|||
def build_fail_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
|
||||
add_project_headers
|
||||
add_build_headers
|
||||
headers['X-GitLab-Build-Status'] = "failed"
|
||||
add_build_headers('failed')
|
||||
mail(to: to, subject: subject("Build failed for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
def build_success_email(build_id, to)
|
||||
@build = Ci::Build.find(build_id)
|
||||
@project = @build.project
|
||||
|
||||
add_project_headers
|
||||
add_build_headers
|
||||
headers['X-GitLab-Build-Status'] = "success"
|
||||
add_build_headers('success')
|
||||
mail(to: to, subject: subject("Build success for #{@project.name}", @build.short_sha))
|
||||
end
|
||||
|
||||
private
|
||||
def add_build_headers
|
||||
|
||||
def add_build_headers(status)
|
||||
headers['X-GitLab-Build-Id'] = @build.id
|
||||
headers['X-GitLab-Build-Ref'] = @build.ref
|
||||
headers['X-GitLab-Build-Status'] = status.to_s
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,17 +5,18 @@ class Ability
|
|||
return [] unless user.is_a?(User)
|
||||
return [] if user.blocked?
|
||||
|
||||
case subject.class.name
|
||||
when "Project" then project_abilities(user, subject)
|
||||
when "Issue" then issue_abilities(user, subject)
|
||||
when "Note" then note_abilities(user, subject)
|
||||
when "ProjectSnippet" then project_snippet_abilities(user, subject)
|
||||
when "PersonalSnippet" then personal_snippet_abilities(user, subject)
|
||||
when "MergeRequest" then merge_request_abilities(user, subject)
|
||||
when "Group" then group_abilities(user, subject)
|
||||
when "Namespace" then namespace_abilities(user, subject)
|
||||
when "GroupMember" then group_member_abilities(user, subject)
|
||||
when "ProjectMember" then project_member_abilities(user, subject)
|
||||
case subject
|
||||
when CommitStatus then commit_status_abilities(user, subject)
|
||||
when Project then project_abilities(user, subject)
|
||||
when Issue then issue_abilities(user, subject)
|
||||
when Note then note_abilities(user, subject)
|
||||
when ProjectSnippet then project_snippet_abilities(user, subject)
|
||||
when PersonalSnippet then personal_snippet_abilities(user, subject)
|
||||
when MergeRequest then merge_request_abilities(user, subject)
|
||||
when Group then group_abilities(user, subject)
|
||||
when Namespace then namespace_abilities(user, subject)
|
||||
when GroupMember then group_member_abilities(user, subject)
|
||||
when ProjectMember then project_member_abilities(user, subject)
|
||||
else []
|
||||
end.concat(global_abilities(user))
|
||||
end
|
||||
|
@ -25,6 +26,8 @@ class Ability
|
|||
case true
|
||||
when subject.is_a?(PersonalSnippet)
|
||||
anonymous_personal_snippet_abilities(subject)
|
||||
when subject.is_a?(CommitStatus)
|
||||
anonymous_commit_status_abilities(subject)
|
||||
when subject.is_a?(Project) || subject.respond_to?(:project)
|
||||
anonymous_project_abilities(subject)
|
||||
when subject.is_a?(Group) || subject.respond_to?(:group)
|
||||
|
@ -52,16 +55,26 @@ class Ability
|
|||
:read_project_member,
|
||||
:read_merge_request,
|
||||
:read_note,
|
||||
:read_build,
|
||||
:read_commit_status,
|
||||
:download_code
|
||||
]
|
||||
|
||||
# Allow to read builds by anonymous user if guests are allowed
|
||||
rules << :read_build if project.public_builds?
|
||||
|
||||
rules - project_disabled_features_rules(project)
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def anonymous_commit_status_abilities(subject)
|
||||
rules = anonymous_project_abilities(subject.project)
|
||||
# If subject is Ci::Build which inherits from CommitStatus filter the abilities
|
||||
rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
|
||||
rules
|
||||
end
|
||||
|
||||
def anonymous_group_abilities(subject)
|
||||
group = if subject.is_a?(Group)
|
||||
subject
|
||||
|
@ -113,6 +126,9 @@ class Ability
|
|||
|
||||
if project.public? || project.internal?
|
||||
rules.push(*public_project_rules)
|
||||
|
||||
# Allow to read builds for internal projects
|
||||
rules << :read_build if project.public_builds?
|
||||
end
|
||||
|
||||
if project.owner == user || user.admin?
|
||||
|
@ -134,7 +150,8 @@ class Ability
|
|||
def public_project_rules
|
||||
@public_project_rules ||= project_guest_rules + [
|
||||
:download_code,
|
||||
:fork_project
|
||||
:fork_project,
|
||||
:read_commit_status,
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -149,7 +166,6 @@ class Ability
|
|||
:read_project_member,
|
||||
:read_merge_request,
|
||||
:read_note,
|
||||
:read_build,
|
||||
:create_project,
|
||||
:create_issue,
|
||||
:create_note
|
||||
|
@ -158,24 +174,26 @@ class Ability
|
|||
|
||||
def project_report_rules
|
||||
@project_report_rules ||= project_guest_rules + [
|
||||
:create_commit_status,
|
||||
:read_commit_statuses,
|
||||
:read_build_artifacts,
|
||||
:download_code,
|
||||
:fork_project,
|
||||
:create_project_snippet,
|
||||
:update_issue,
|
||||
:admin_issue,
|
||||
:admin_label
|
||||
:admin_label,
|
||||
:read_commit_status,
|
||||
:read_build,
|
||||
]
|
||||
end
|
||||
|
||||
def project_dev_rules
|
||||
@project_dev_rules ||= project_report_rules + [
|
||||
:admin_merge_request,
|
||||
:create_commit_status,
|
||||
:update_commit_status,
|
||||
:create_build,
|
||||
:update_build,
|
||||
:create_merge_request,
|
||||
:create_wiki,
|
||||
:manage_builds,
|
||||
:push_code
|
||||
]
|
||||
end
|
||||
|
@ -201,7 +219,9 @@ class Ability
|
|||
:admin_merge_request,
|
||||
:admin_note,
|
||||
:admin_wiki,
|
||||
:admin_project
|
||||
:admin_project,
|
||||
:admin_commit_status,
|
||||
:admin_build
|
||||
]
|
||||
end
|
||||
|
||||
|
@ -240,6 +260,10 @@ class Ability
|
|||
rules += named_abilities('wiki')
|
||||
end
|
||||
|
||||
unless project.builds_enabled
|
||||
rules += named_abilities('build')
|
||||
end
|
||||
|
||||
rules
|
||||
end
|
||||
|
||||
|
@ -376,6 +400,22 @@ class Ability
|
|||
rules
|
||||
end
|
||||
|
||||
def commit_status_abilities(user, subject)
|
||||
rules = project_abilities(user, subject.project)
|
||||
# If subject is Ci::Build which inherits from CommitStatus filter the abilities
|
||||
rules = filter_build_abilities(rules) if subject.is_a?(Ci::Build)
|
||||
rules
|
||||
end
|
||||
|
||||
def filter_build_abilities(rules)
|
||||
# If we can't read build we should also not have that
|
||||
# ability when looking at this in context of commit_status
|
||||
%w(read create update admin).each do |rule|
|
||||
rules.delete(:"#{rule}_commit_status") unless rules.include?(:"#{rule}_build")
|
||||
end
|
||||
rules
|
||||
end
|
||||
|
||||
def abilities
|
||||
@abilities ||= begin
|
||||
abilities = Six.new
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
# metrics_port :integer default(8089)
|
||||
# sentry_enabled :boolean default(FALSE)
|
||||
# sentry_dsn :string
|
||||
# email_author_in_body :boolean default(FALSE)
|
||||
#
|
||||
|
||||
class ApplicationSetting < ActiveRecord::Base
|
||||
|
@ -70,8 +71,8 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
url: true
|
||||
|
||||
validates :admin_notification_email,
|
||||
allow_blank: true,
|
||||
email: true
|
||||
email: true,
|
||||
allow_blank: true
|
||||
|
||||
validates :two_factor_grace_period,
|
||||
numericality: { greater_than_or_equal_to: 0 }
|
||||
|
@ -92,6 +93,10 @@ class ApplicationSetting < ActiveRecord::Base
|
|||
presence: true,
|
||||
if: :akismet_enabled
|
||||
|
||||
validates :max_attachment_size,
|
||||
presence: true,
|
||||
numericality: { only_integer: true, greater_than: 0 }
|
||||
|
||||
validates_each :restricted_visibility_levels do |record, attr, value|
|
||||
unless value.nil?
|
||||
value.each do |level|
|
||||
|
|
|
@ -126,17 +126,17 @@ module Issuable
|
|||
end
|
||||
|
||||
def to_hook_data(user)
|
||||
{
|
||||
hook_data = {
|
||||
object_kind: self.class.name.underscore,
|
||||
user: user.hook_attrs,
|
||||
repository: {
|
||||
name: project.name,
|
||||
url: project.url_to_repo,
|
||||
description: project.description,
|
||||
homepage: project.web_url
|
||||
},
|
||||
object_attributes: hook_attrs
|
||||
project: project.hook_attrs,
|
||||
object_attributes: hook_attrs,
|
||||
# DEPRECATED
|
||||
repository: project.hook_attrs.slice(:name, :url, :description, :homepage)
|
||||
}
|
||||
hook_data.merge!(assignee: assignee.hook_attrs) if assignee
|
||||
|
||||
hook_data
|
||||
end
|
||||
|
||||
def label_names
|
||||
|
|
|
@ -15,7 +15,7 @@ class Email < ActiveRecord::Base
|
|||
belongs_to :user
|
||||
|
||||
validates :user_id, presence: true
|
||||
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
|
||||
validates :email, presence: true, uniqueness: true, email: true
|
||||
validate :unique_email, if: ->(email) { email.email_changed? }
|
||||
|
||||
before_validation :cleanup_email
|
||||
|
|
|
@ -39,7 +39,6 @@ class Member < ActiveRecord::Base
|
|||
if: :invite?
|
||||
},
|
||||
email: {
|
||||
strict_mode: true,
|
||||
allow_nil: true
|
||||
},
|
||||
uniqueness: {
|
||||
|
|
|
@ -137,6 +137,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
scope :by_milestone, ->(milestone) { where(milestone_id: milestone) }
|
||||
scope :in_projects, ->(project_ids) { where("source_project_id in (:project_ids) OR target_project_id in (:project_ids)", project_ids: project_ids) }
|
||||
scope :of_projects, ->(ids) { where(target_project_id: ids) }
|
||||
scope :opened, -> { with_state(:opened) }
|
||||
scope :merged, -> { with_state(:merged) }
|
||||
scope :closed, -> { with_state(:closed) }
|
||||
scope :closed_and_merged, -> { with_states(:closed, :merged) }
|
||||
|
@ -240,7 +241,7 @@ class MergeRequest < ActiveRecord::Base
|
|||
return unless unchecked?
|
||||
|
||||
can_be_merged =
|
||||
project.repository.can_be_merged?(source_sha, target_branch)
|
||||
!broken? && project.repository.can_be_merged?(source_sha, target_branch)
|
||||
|
||||
if can_be_merged
|
||||
mark_as_mergeable
|
||||
|
|
|
@ -34,7 +34,7 @@ class Milestone < ActiveRecord::Base
|
|||
scope :closed, -> { with_state(:closed) }
|
||||
scope :of_projects, ->(ids) { where(project_id: ids) }
|
||||
|
||||
validates :title, presence: true
|
||||
validates :title, presence: true, uniqueness: { scope: :project_id }
|
||||
validates :project, presence: true
|
||||
|
||||
strip_attributes :title
|
||||
|
|
|
@ -342,7 +342,7 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(path_with_namespace, nil, self)
|
||||
@repository ||= Repository.new(path_with_namespace, self)
|
||||
end
|
||||
|
||||
def commit(id = 'HEAD')
|
||||
|
@ -738,11 +738,20 @@ class Project < ActiveRecord::Base
|
|||
def hook_attrs
|
||||
{
|
||||
name: name,
|
||||
ssh_url: ssh_url_to_repo,
|
||||
http_url: http_url_to_repo,
|
||||
description: description,
|
||||
web_url: web_url,
|
||||
avatar_url: avatar_url,
|
||||
git_ssh_url: ssh_url_to_repo,
|
||||
git_http_url: http_url_to_repo,
|
||||
namespace: namespace.name,
|
||||
visibility_level: visibility_level
|
||||
visibility_level: visibility_level,
|
||||
path_with_namespace: path_with_namespace,
|
||||
default_branch: default_branch,
|
||||
# Backward compatibility
|
||||
homepage: web_url,
|
||||
url: url_to_repo,
|
||||
ssh_url: ssh_url_to_repo,
|
||||
http_url: http_url_to_repo
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -790,6 +799,8 @@ class Project < ActiveRecord::Base
|
|||
def change_head(branch)
|
||||
# Cached divergent commit counts are based on repository head
|
||||
repository.expire_branch_cache
|
||||
repository.expire_root_ref_cache
|
||||
|
||||
gitlab_shell.update_repository_head(self.path_with_namespace, branch)
|
||||
reload_default_branch
|
||||
end
|
||||
|
|
|
@ -112,7 +112,7 @@ class PushoverService < Service
|
|||
priority: priority,
|
||||
title: "#{project.name_with_namespace}",
|
||||
message: message,
|
||||
url: data[:repository][:homepage],
|
||||
url: data[:project][:web_url],
|
||||
url_title: "See project #{project.name_with_namespace}"
|
||||
}
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ class ProjectWiki
|
|||
end
|
||||
|
||||
def repository
|
||||
Repository.new(path_with_namespace, default_branch, @project)
|
||||
Repository.new(path_with_namespace, @project)
|
||||
end
|
||||
|
||||
def default_branch
|
||||
|
|
|
@ -15,7 +15,7 @@ class Repository
|
|||
Gitlab::Popen.popen(%W(find #{repository_downloads_path} -not -path #{repository_downloads_path} -mmin +120 -delete))
|
||||
end
|
||||
|
||||
def initialize(path_with_namespace, default_branch = nil, project = nil)
|
||||
def initialize(path_with_namespace, project)
|
||||
@path_with_namespace = path_with_namespace
|
||||
@project = project
|
||||
end
|
||||
|
@ -44,7 +44,9 @@ class Repository
|
|||
end
|
||||
|
||||
def empty?
|
||||
raw_repository.empty?
|
||||
return @empty unless @empty.nil?
|
||||
|
||||
@empty = cache.fetch(:empty?) { raw_repository.empty? }
|
||||
end
|
||||
|
||||
#
|
||||
|
@ -57,8 +59,12 @@ class Repository
|
|||
# This method return true if repository contains some content visible in project page.
|
||||
#
|
||||
def has_visible_content?
|
||||
return @has_visible_content unless @has_visible_content.nil?
|
||||
|
||||
@has_visible_content = cache.fetch(:has_visible_content?) do
|
||||
raw_repository.branch_count > 0
|
||||
end
|
||||
end
|
||||
|
||||
def commit(id = 'HEAD')
|
||||
return nil unless raw_repository
|
||||
|
@ -78,7 +84,8 @@ class Repository
|
|||
offset: offset,
|
||||
# --follow doesn't play well with --skip. See:
|
||||
# https://gitlab.com/gitlab-org/gitlab-ce/issues/3574#note_3040520
|
||||
follow: false
|
||||
follow: false,
|
||||
skip_merges: skip_merges
|
||||
}
|
||||
|
||||
commits = Gitlab::Git::Commit.where(options)
|
||||
|
@ -199,12 +206,6 @@ class Repository
|
|||
readme version contribution_guide changelog license)
|
||||
end
|
||||
|
||||
def branch_cache_keys
|
||||
branches.map do |branch|
|
||||
:"diverging_commit_counts_#{branch.name}"
|
||||
end
|
||||
end
|
||||
|
||||
def build_cache
|
||||
cache_keys.each do |key|
|
||||
unless cache.exist?(key)
|
||||
|
@ -229,18 +230,37 @@ class Repository
|
|||
@branches = nil
|
||||
end
|
||||
|
||||
def expire_cache
|
||||
def expire_cache(branch_name = nil)
|
||||
cache_keys.each do |key|
|
||||
cache.expire(key)
|
||||
end
|
||||
|
||||
expire_branch_cache
|
||||
expire_branch_cache(branch_name)
|
||||
end
|
||||
|
||||
def expire_branch_cache
|
||||
def expire_branch_cache(branch_name = nil)
|
||||
# When we push to the root branch we have to flush the cache for all other
|
||||
# branches as their statistics are based on the commits relative to the
|
||||
# root branch.
|
||||
if !branch_name || branch_name == root_ref
|
||||
branches.each do |branch|
|
||||
cache.expire(:"diverging_commit_counts_#{branch.name}")
|
||||
end
|
||||
# In case a commit is pushed to a non-root branch we only have to flush the
|
||||
# cache for said branch.
|
||||
else
|
||||
cache.expire(:"diverging_commit_counts_#{branch_name}")
|
||||
end
|
||||
end
|
||||
|
||||
def expire_root_ref_cache
|
||||
cache.expire(:root_ref)
|
||||
@root_ref = nil
|
||||
end
|
||||
|
||||
def expire_has_visible_content_cache
|
||||
cache.expire(:has_visible_content?)
|
||||
@has_visible_content = nil
|
||||
end
|
||||
|
||||
def rebuild_cache
|
||||
|
@ -480,7 +500,7 @@ class Repository
|
|||
end
|
||||
|
||||
def root_ref
|
||||
@root_ref ||= raw_repository.root_ref
|
||||
@root_ref ||= cache.fetch(:root_ref) { raw_repository.root_ref }
|
||||
end
|
||||
|
||||
def commit_dir(user, path, message, branch)
|
||||
|
|
|
@ -151,16 +151,8 @@ class User < ActiveRecord::Base
|
|||
# Validations
|
||||
#
|
||||
validates :name, presence: true
|
||||
|
||||
[:avatar_crop_x, :avatar_crop_y, :avatar_crop_size].each do |field|
|
||||
validates field, numericality: { only_integer: true }, allow_blank: true
|
||||
end
|
||||
|
||||
# Note that a 'uniqueness' and presence check is provided by devise :validatable for email. We do not need to
|
||||
# duplicate that here as the validation framework will have duplicate errors in the event of a failure.
|
||||
validates :email, presence: true, email: { strict_mode: true }
|
||||
validates :notification_email, presence: true, email: { strict_mode: true }
|
||||
validates :public_email, presence: true, email: { strict_mode: true }, allow_blank: true, uniqueness: true
|
||||
validates :notification_email, presence: true, email: true
|
||||
validates :public_email, presence: true, uniqueness: true, email: true, allow_blank: true
|
||||
validates :bio, length: { maximum: 255 }, allow_blank: true
|
||||
validates :projects_limit, presence: true, numericality: { greater_than_or_equal_to: 0 }
|
||||
validates :username,
|
||||
|
@ -176,6 +168,10 @@ class User < ActiveRecord::Base
|
|||
validate :owns_public_email, if: ->(user) { user.public_email_changed? }
|
||||
validates :avatar, file_size: { maximum: 200.kilobytes.to_i }
|
||||
|
||||
[:avatar_crop_x, :avatar_crop_y, :avatar_crop_size].each do |field|
|
||||
validates field, numericality: { only_integer: true }, allow_blank: true
|
||||
end
|
||||
|
||||
before_validation :generate_password, on: :create
|
||||
before_validation :restricted_signup_domains, on: :create
|
||||
before_validation :sanitize_attrs
|
||||
|
|
|
@ -1,28 +1,23 @@
|
|||
module Ci
|
||||
class ImageForBuildService
|
||||
def execute(project, params)
|
||||
sha = params[:sha]
|
||||
sha ||=
|
||||
if params[:ref]
|
||||
project.commit(params[:ref]).try(:sha)
|
||||
end
|
||||
def execute(project, opts)
|
||||
sha = opts[:sha] || ref_sha(project, opts[:ref])
|
||||
|
||||
commit = project.ci_commits.ordered.find_by(sha: sha)
|
||||
image_name = image_for_commit(commit)
|
||||
|
||||
image_path = Rails.root.join('public/ci', image_name)
|
||||
|
||||
OpenStruct.new(
|
||||
path: image_path,
|
||||
name: image_name
|
||||
)
|
||||
OpenStruct.new(path: image_path, name: image_name)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ref_sha(project, ref)
|
||||
project.commit(ref).try(:sha) if ref
|
||||
end
|
||||
|
||||
def image_for_commit(commit)
|
||||
return 'build-unknown.svg' unless commit
|
||||
|
||||
'build-' + commit.status + ".svg"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -29,11 +29,7 @@ class CreateBranchService < BaseService
|
|||
end
|
||||
|
||||
if new_branch
|
||||
push_data = build_push_data(project, current_user, new_branch)
|
||||
|
||||
project.execute_hooks(push_data.dup, :push_hooks)
|
||||
project.execute_services(push_data.dup, :push_hooks)
|
||||
|
||||
# GitPushService handles execution of services and hooks for branch pushes
|
||||
success(new_branch)
|
||||
else
|
||||
error('Invalid reference name')
|
||||
|
|
|
@ -25,11 +25,7 @@ class DeleteBranchService < BaseService
|
|||
end
|
||||
|
||||
if repository.rm_branch(current_user, branch_name)
|
||||
push_data = build_push_data(branch)
|
||||
|
||||
project.execute_hooks(push_data.dup, :push_hooks)
|
||||
project.execute_services(push_data.dup, :push_hooks)
|
||||
|
||||
# GitPushService handles execution of services and hooks for branch pushes
|
||||
success('Branch was removed')
|
||||
else
|
||||
error('Failed to remove branch')
|
||||
|
|
|
@ -18,18 +18,23 @@ class GitPushService
|
|||
def execute(project, user, oldrev, newrev, ref)
|
||||
@project, @user = project, user
|
||||
|
||||
project.repository.expire_cache
|
||||
branch_name = Gitlab::Git.ref_name(ref)
|
||||
|
||||
project.repository.expire_cache(branch_name)
|
||||
|
||||
if push_remove_branch?(ref, newrev)
|
||||
project.repository.expire_has_visible_content_cache
|
||||
|
||||
@push_commits = []
|
||||
elsif push_to_new_branch?(ref, oldrev)
|
||||
project.repository.expire_has_visible_content_cache
|
||||
|
||||
# Re-find the pushed commits.
|
||||
if is_default_branch?(ref)
|
||||
# Initial push to the default branch. Take the full history of that branch as "newly pushed".
|
||||
@push_commits = project.repository.commits(newrev)
|
||||
|
||||
# Ensure HEAD points to the default branch in case it is not master
|
||||
branch_name = Gitlab::Git.ref_name(ref)
|
||||
project.change_head(branch_name)
|
||||
|
||||
# Set protection on the default branch if configured
|
||||
|
|
|
@ -274,12 +274,15 @@ class SystemNoteService
|
|||
# Check if a cross reference to a noteable from a mentioner already exists
|
||||
#
|
||||
# This method is used to prevent multiple notes being created for a mention
|
||||
# when a issue is updated, for example.
|
||||
# when a issue is updated, for example. The method also calls notes_for_mentioner
|
||||
# to check if the mentioner is a commit, and return matches only on commit hash
|
||||
# instead of project + commit, to avoid repeated mentions from forks.
|
||||
#
|
||||
# noteable - Noteable object being referenced
|
||||
# mentioner - Mentionable object
|
||||
#
|
||||
# Returns Boolean
|
||||
|
||||
def self.cross_reference_exists?(noteable, mentioner)
|
||||
# Initial scope should be system notes of this noteable type
|
||||
notes = Note.system.where(noteable_type: noteable.class)
|
||||
|
@ -291,14 +294,20 @@ class SystemNoteService
|
|||
notes = notes.where(noteable_id: noteable.id)
|
||||
end
|
||||
|
||||
gfm_reference = mentioner.gfm_reference(noteable.project)
|
||||
notes = notes.where(note: cross_reference_note_content(gfm_reference))
|
||||
|
||||
notes.count > 0
|
||||
notes_for_mentioner(mentioner, noteable, notes).count > 0
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.notes_for_mentioner(mentioner, noteable, notes)
|
||||
if mentioner.is_a?(Commit)
|
||||
notes.where('note LIKE ?', "#{cross_reference_note_prefix}%#{mentioner.to_reference(nil)}")
|
||||
else
|
||||
gfm_reference = mentioner.gfm_reference(noteable.project)
|
||||
notes.where(note: cross_reference_note_content(gfm_reference))
|
||||
end
|
||||
end
|
||||
|
||||
def self.create_note(args = {})
|
||||
Note.create(args.merge(system: true))
|
||||
end
|
||||
|
|
|
@ -1,18 +1,5 @@
|
|||
# EmailValidator
|
||||
#
|
||||
# Based on https://github.com/balexand/email_validator
|
||||
#
|
||||
# Extended to use only strict mode with following allowed characters:
|
||||
# ' - apostrophe
|
||||
#
|
||||
# See http://www.remote.org/jochen/mail/info/chars.html
|
||||
#
|
||||
class EmailValidator < ActiveModel::EachValidator
|
||||
PATTERN = /\A\s*([-a-z0-9+._']{1,64})@((?:[-a-z0-9]+\.)+[a-z]{2,})\s*\z/i.freeze
|
||||
|
||||
def validate_each(record, attribute, value)
|
||||
unless value =~ PATTERN
|
||||
record.errors.add(attribute, options[:message] || :invalid)
|
||||
end
|
||||
record.errors.add(attribute, :invalid) unless value =~ Devise.email_regexp
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,6 +47,16 @@
|
|||
= f.label :version_check_enabled do
|
||||
= f.check_box :version_check_enabled
|
||||
Version check enabled
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :email_author_in_body do
|
||||
= f.check_box :email_author_in_body
|
||||
Include author name in notification email body
|
||||
.help-block
|
||||
Some email servers do not support overriding the email sender name.
|
||||
Enable this option to include the name of the author of the issue,
|
||||
merge request or comment in the email body instead.
|
||||
.form-group
|
||||
= f.label :admin_notification_email, class: 'control-label col-sm-2'
|
||||
.col-sm-10
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
.broadcast-message-preview{ style: broadcast_message_style(@broadcast_message) }
|
||||
= icon('bullhorn')
|
||||
%span= @broadcast_message.message || "Your message here"
|
||||
.js-broadcast-message-preview
|
||||
= render_broadcast_message(@broadcast_message.message.presence || "Your message here")
|
||||
|
||||
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal js-requires-input'} do |f|
|
||||
-if @broadcast_message.errors.any?
|
||||
|
@ -10,7 +11,9 @@
|
|||
.form-group
|
||||
= f.label :message, class: 'control-label'
|
||||
.col-sm-10
|
||||
= f.text_area :message, class: "form-control js-quick-submit", rows: 2, required: true
|
||||
= f.text_area :message, class: "form-control js-quick-submit js-autosize",
|
||||
required: true,
|
||||
data: { preview_path: preview_admin_broadcast_messages_path }
|
||||
.form-group.js-toggle-colors-container
|
||||
.col-sm-10.col-sm-offset-2
|
||||
= link_to 'Customize colors', '#', class: 'js-toggle-colors-link'
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
$('.js-broadcast-message-preview').html("#{j(render_broadcast_message(@message))}");
|
|
@ -4,7 +4,7 @@
|
|||
= ci_status_with_icon(build.status)
|
||||
|
||||
%td.build-link
|
||||
- if build.target_url
|
||||
- if can?(current_user, :read_build, project) && build.target_url
|
||||
= link_to build.target_url do
|
||||
%strong Build ##{build.id}
|
||||
- else
|
||||
|
@ -60,10 +60,10 @@
|
|||
|
||||
%td
|
||||
.pull-right
|
||||
- if current_user && can?(current_user, :read_build_artifacts, project) && build.artifacts?
|
||||
- if can?(current_user, :read_build, project) && build.artifacts?
|
||||
= link_to build.artifacts_download_url, title: 'Download artifacts' do
|
||||
%i.fa.fa-download
|
||||
- if current_user && can?(current_user, :manage_builds, build.project)
|
||||
- if can?(current_user, :update_build, build.project)
|
||||
- if build.active?
|
||||
- if build.cancel_url
|
||||
= link_to build.cancel_url, method: :post, title: 'Cancel' do
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
.nav-controls
|
||||
= form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
|
||||
= search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'project-filter-form-field form-control input-short', spellcheck: false, id: 'project-filter-form-field'
|
||||
= search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'project-filter-form-field form-control input-short projects-list-filter', spellcheck: false, id: 'project-filter-form-field'
|
||||
= render 'explore/projects/dropdown'
|
||||
- if current_user.can_create_project?
|
||||
= link_to new_project_path, class: 'btn btn-new' do
|
||||
|
|
|
@ -1,11 +1,3 @@
|
|||
.pull-left
|
||||
= form_tag explore_projects_filter_path, method: :get, class: 'form-inline form-tiny' do |f|
|
||||
.form-group
|
||||
= search_field_tag :search, params[:search], placeholder: "Filter by name", class: "form-control search-text-input", id: "projects_search", spellcheck: false
|
||||
= hidden_field_tag :sort, @sort
|
||||
.form-group
|
||||
= button_tag 'Search', class: "btn"
|
||||
|
||||
.pull-right.hidden-sm.hidden-xs
|
||||
- if current_user
|
||||
.dropdown.inline.append-right-10
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- if projects.any?
|
||||
.public-projects
|
||||
.projects-list-holder
|
||||
= render 'shared/projects/list', projects: projects
|
||||
- else
|
||||
.nothing-here-block
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
.projects-list-holder.prepend-top-default
|
||||
.input-group
|
||||
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'projects-list-filter form-control', spellcheck: false
|
||||
- if can? current_user, :create_projects, @group
|
||||
%span.input-group-btn
|
||||
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new' do
|
||||
.top-area
|
||||
.nav-controls
|
||||
= form_tag request.original_url, method: :get, class: 'project-filter-form', id: 'project-filter-form' do |f|
|
||||
= search_field_tag :filter_projects, params[:filter_projects], placeholder: 'Filter by name...', class: 'input-short project-filter-form-field form-control projects-list-filter', spellcheck: false, id: 'project-filter-form-field'
|
||||
- if current_user && current_user.can_create_project?
|
||||
= link_to new_project_path, class: 'btn btn-new' do
|
||||
= icon('plus')
|
||||
New Project
|
||||
|
||||
.projects-list-holder
|
||||
= render 'shared/projects/list', projects: @projects, projects_limit: 20, stars: false, skip_namespace: true
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
|
||||
= render 'shared/event_filter'
|
||||
|
||||
.content_list
|
||||
.content_list{data: {href: events_group_path}}
|
||||
= spinner
|
||||
|
||||
.tab-pane#projects
|
||||
|
|
|
@ -1,2 +1,5 @@
|
|||
- if current_application_settings.email_author_in_body
|
||||
%div
|
||||
#{link_to @note.author_name, user_url(@note.author)} wrote:
|
||||
%div
|
||||
= markdown(@note.note, pipeline: :email)
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
- content_for :header do
|
||||
%h1{style: "background: #c40834; color: #FFF; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;"}
|
||||
GitLab (build failed)
|
||||
|
||||
%h3
|
||||
Project:
|
||||
= link_to ci_project_url(@project) do
|
||||
= link_to namespace_project_url(@project.namespace, @project) do
|
||||
= @project.name
|
||||
|
||||
%p
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
%h3
|
||||
Project:
|
||||
= link_to ci_project_url(@project) do
|
||||
= link_to namespace_project_url(@project.namespace, @project) do
|
||||
= @project.name
|
||||
|
||||
%p
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
- if current_application_settings.email_author_in_body
|
||||
%div
|
||||
#{link_to @issue.author_name, user_url(@issue.author)} wrote:
|
||||
-if @issue.description
|
||||
= markdown(@issue.description, pipeline: :email)
|
||||
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
- if current_application_settings.email_author_in_body
|
||||
%div
|
||||
#{link_to @merge_request.author_name, user_url(@merge_request.author)} wrote:
|
||||
%p.details
|
||||
!= merge_path_description(@merge_request, '→')
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
= number_with_delimiter(@all_builds.finished.count(:id))
|
||||
|
||||
.nav-controls
|
||||
- if can?(current_user, :manage_builds, @project)
|
||||
- if can?(current_user, :update_build, @project)
|
||||
- if @all_builds.running_or_pending.any?
|
||||
= link_to 'Cancel running', cancel_all_namespace_project_builds_path(@project.namespace, @project),
|
||||
data: { confirm: 'Are you sure?' }, class: 'btn btn-danger', method: :post
|
||||
|
|
|
@ -89,8 +89,7 @@
|
|||
Test coverage
|
||||
%h1 #{@build.coverage}%
|
||||
|
||||
- if current_user && can?(current_user, :read_build_artifacts, @project) && @build.artifacts?
|
||||
|
||||
- if can?(current_user, :read_build, @project) && @build.artifacts?
|
||||
.build-widget.artifacts
|
||||
%h4.title Build artifacts
|
||||
.center
|
||||
|
@ -102,7 +101,7 @@
|
|||
.build-widget
|
||||
%h4.title
|
||||
Build ##{@build.id}
|
||||
- if current_user && can?(current_user, :manage_builds, @project)
|
||||
- if can?(current_user, :update_build, @project)
|
||||
.pull-right
|
||||
- if @build.cancel_url
|
||||
= link_to "Cancel", @build.cancel_url, class: 'btn btn-sm btn-danger', method: :post
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
.gray-content-block.middle-block
|
||||
.pull-right
|
||||
- if can?(current_user, :manage_builds, @ci_commit.project)
|
||||
- if can?(current_user, :update_build, @ci_commit.project)
|
||||
- if @ci_commit.builds.latest.failed.any?(&:retryable?)
|
||||
= link_to "Retry failed", retry_builds_namespace_project_commit_path(@ci_commit.project.namespace, @ci_commit.project, @ci_commit.sha), class: 'btn btn-grouped btn-primary', method: :post
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
%tr.commit_status
|
||||
%td.status
|
||||
- if commit_status.target_url
|
||||
- if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
|
||||
= link_to commit_status.target_url, class: "ci-status ci-#{commit_status.status}" do
|
||||
= ci_icon_for_status(commit_status.status)
|
||||
= commit_status.status
|
||||
|
@ -8,14 +8,14 @@
|
|||
= ci_status_with_icon(commit_status.status)
|
||||
|
||||
%td.commit_status-link
|
||||
- if commit_status.target_url
|
||||
- if can?(current_user, :read_commit_status, commit_status) && commit_status.target_url
|
||||
= link_to commit_status.target_url do
|
||||
%strong ##{commit_status.id}
|
||||
- else
|
||||
%strong ##{commit_status.id}
|
||||
|
||||
- if commit_status.show_warning?
|
||||
%i.fa.fa-warning.text-warning
|
||||
%i.fa.fa-warning.text-warning{data: { toggle: "tooltip" }, title: "This build is stuck, open it to know more"}
|
||||
|
||||
- if defined?(commit_sha) && commit_sha
|
||||
%td
|
||||
|
@ -66,10 +66,10 @@
|
|||
|
||||
%td
|
||||
.pull-right
|
||||
- if current_user && can?(current_user, :read_build_artifacts, commit_status.project) && commit_status.artifacts_download_url
|
||||
- if can?(current_user, :read_commit_status, commit_status) && commit_status.artifacts_download_url
|
||||
= link_to commit_status.artifacts_download_url, title: 'Download artifacts' do
|
||||
%i.fa.fa-download
|
||||
- if current_user && can?(current_user, :manage_builds, commit_status.project)
|
||||
- if can?(current_user, :update_commit_status, commit_status)
|
||||
- if commit_status.active?
|
||||
- if commit_status.cancel_url
|
||||
= link_to commit_status.cancel_url, method: :post, title: 'Cancel' do
|
||||
|
|
|
@ -11,7 +11,10 @@
|
|||
= render 'shared/ref_switcher', destination: 'commits'
|
||||
|
||||
.block-controls.hidden-xs.hidden-sm
|
||||
- if create_mr_button?(@repository.root_ref, @ref)
|
||||
- if @merge_request.present?
|
||||
.control
|
||||
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
|
||||
- elsif create_mr_button?(@repository.root_ref, @ref)
|
||||
.control
|
||||
= link_to create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' do
|
||||
= icon('plus')
|
||||
|
|
|
@ -13,12 +13,13 @@
|
|||
= text_field_tag :to, params[:to], class: "form-control", required: true
|
||||
|
||||
= button_tag "Compare", class: "btn btn-create commits-compare-btn"
|
||||
- if create_mr_button?
|
||||
- if @merge_request.present?
|
||||
= link_to "View Open Merge Request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'prepend-left-10 btn'
|
||||
- elsif create_mr_button?
|
||||
= link_to create_mr_path, class: 'prepend-left-10 btn' do
|
||||
= icon("plus")
|
||||
Create Merge Request
|
||||
|
||||
|
||||
:javascript
|
||||
var availableTags = #{@project.repository.ref_names.to_json};
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
- diff = diff_file.diff
|
||||
- file.load_all_data!(@project.repository)
|
||||
- if diff.renamed_file || diff.new_file || diff.deleted_file
|
||||
.image
|
||||
%span.wrap
|
||||
|
@ -6,6 +7,7 @@
|
|||
%img{src: "data:#{file.mime_type};base64,#{Base64.encode64(file.data)}"}
|
||||
%p.image-info= "#{number_to_human_size file.size}"
|
||||
- else
|
||||
- old_file.load_all_data!(@project.repository)
|
||||
.image
|
||||
%div.two-up.view
|
||||
%span.wrap
|
||||
|
|
|
@ -130,6 +130,7 @@
|
|||
%strong git fetch
|
||||
%br
|
||||
%span.descr Faster
|
||||
|
||||
.form-group
|
||||
= f.label :build_timeout_in_minutes, 'Timeout', class: 'control-label'
|
||||
.col-sm-10
|
||||
|
@ -158,6 +159,13 @@
|
|||
phpunit --coverage-text --colors=never (PHP) -
|
||||
%code ^\s*Lines:\s*\d+.\d+\%
|
||||
|
||||
.form-group
|
||||
.col-sm-offset-2.col-sm-10
|
||||
.checkbox
|
||||
= f.label :public_builds do
|
||||
= f.check_box :public_builds
|
||||
%strong Public builds
|
||||
.help-block Allow everyone to access builds for Public and Internal projects
|
||||
|
||||
%fieldset.features
|
||||
%legend
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
== #{pluralize(@all_forks.size, 'fork')}: #{full_count_title}
|
||||
|
||||
.nav-controls
|
||||
= search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control input-short',
|
||||
= search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter project-filter-form-field form-control input-short',
|
||||
spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' }
|
||||
|
||||
.dropdown
|
||||
|
@ -29,6 +29,7 @@
|
|||
= link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do
|
||||
= sort_title_oldest_updated
|
||||
|
||||
- if current_user && can?(current_user, :fork_project, @project)
|
||||
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
|
||||
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'btn btn-new' do
|
||||
= icon('code-fork fw')
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%article.file-holder.readme-holder
|
||||
.file-title
|
||||
= blob_icon readme.mode, readme.name
|
||||
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, readme.name)) do
|
||||
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@repository.root_ref, @path, readme.name)) do
|
||||
%strong
|
||||
= readme.name
|
||||
.file-content.wiki
|
||||
|
|
|
@ -3,9 +3,11 @@
|
|||
Secret Variables
|
||||
|
||||
%p.light
|
||||
These variables will be set to environment by the runner and will be hidden in the build log.
|
||||
These variables will be set to environment by the runner.
|
||||
%br
|
||||
So you can use them for passwords, secret keys or whatever you want.
|
||||
%br
|
||||
The value of the variable can be visible in build log if explicitly asked to do so.
|
||||
|
||||
%hr
|
||||
|
||||
|
|
|
@ -1,46 +1,50 @@
|
|||
- snippet_blob = chunk_snippet(snippet_blob, @search_term)
|
||||
- snippet = snippet_blob[:snippet_object]
|
||||
- snippet_chunks = snippet_blob[:snippet_chunks]
|
||||
|
||||
.search-result-row
|
||||
%span
|
||||
= snippet_blob[:snippet_object].title
|
||||
= snippet.title
|
||||
by
|
||||
= link_to user_snippets_path(snippet_blob[:snippet_object].author) do
|
||||
= image_tag avatar_icon(snippet_blob[:snippet_object].author_email), class: "avatar avatar-inline s16", alt: ''
|
||||
= snippet_blob[:snippet_object].author_name
|
||||
%span.light #{time_ago_with_tooltip(snippet_blob[:snippet_object].created_at)}
|
||||
= link_to user_snippets_path(snippet.author) do
|
||||
= image_tag avatar_icon(snippet.author_email), class: "avatar avatar-inline s16", alt: ''
|
||||
= snippet.author_name
|
||||
%span.light #{time_ago_with_tooltip(snippet.created_at)}
|
||||
%h4.snippet-title
|
||||
- snippet_path = reliable_snippet_path(snippet_blob[:snippet_object])
|
||||
- snippet_path = reliable_snippet_path(snippet)
|
||||
= link_to snippet_path do
|
||||
.file-holder
|
||||
.file-title
|
||||
%i.fa.fa-file
|
||||
%strong= snippet_blob[:snippet_object].file_name
|
||||
- if markup?(snippet_blob[:snippet_object].file_name)
|
||||
%strong= snippet.file_name
|
||||
- if markup?(snippet.file_name)
|
||||
.file-content.wiki
|
||||
- snippet_blob[:snippet_chunks].each do |snippet|
|
||||
- unless snippet[:data].empty?
|
||||
= render_markup(snippet_blob[:snippet_object].file_name, snippet[:data])
|
||||
- snippet_chunks.each do |chunk|
|
||||
- unless chunk[:data].empty?
|
||||
= render_markup(snippet.file_name, chunk[:data])
|
||||
- else
|
||||
.file-content.code
|
||||
.nothing-here-block Empty file
|
||||
- else
|
||||
.file-content.code.js-syntax-highlight
|
||||
.line-numbers
|
||||
- snippet_blob[:snippet_chunks].each do |snippet|
|
||||
- unless snippet[:data].empty?
|
||||
- snippet[:data].lines.to_a.size.times do |index|
|
||||
- offset = defined?(snippet[:start_line]) ? snippet[:start_line] : 1
|
||||
- snippet_chunks.each do |chunk|
|
||||
- unless chunk[:data].empty?
|
||||
- chunk[:data].lines.to_a.size.times do |index|
|
||||
- offset = defined?(chunk[:start_line]) ? chunk[:start_line] : 1
|
||||
- i = index + offset
|
||||
= link_to snippet_path+"#L#{i}", id: "L#{i}", rel: "#L#{i}", class: "diff-line-num" do
|
||||
%i.fa.fa-link
|
||||
= i
|
||||
- unless snippet == snippet_blob[:snippet_chunks].last
|
||||
- unless snippet == snippet_chunks.last
|
||||
%a.diff-line-num
|
||||
= "."
|
||||
%pre.code
|
||||
%code
|
||||
- snippet_blob[:snippet_chunks].each do |snippet|
|
||||
- unless snippet[:data].empty?
|
||||
= snippet[:data]
|
||||
- unless snippet == snippet_blob[:snippet_chunks].last
|
||||
- snippet_chunks.each do |chunk|
|
||||
- unless chunk[:data].empty?
|
||||
= chunk[:data]
|
||||
- unless chunk == snippet_chunks.last
|
||||
%a
|
||||
= "..."
|
||||
- else
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
%li
|
||||
If your HTTP repository is not publicly accessible, add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>.
|
||||
%li
|
||||
The import will time out after 4 minutes. For big repositories, use a clone/push combination.
|
||||
The import will time out after 15 minutes. For repositories that take longer, use a clone/push combination.
|
||||
%li
|
||||
To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/importing/migrating_from_svn.html"}.
|
||||
|
|
|
@ -1,21 +1,9 @@
|
|||
<svg width="36px" height="36px" viewBox="0 0 210 210" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="tanuki-logo">
|
||||
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
|
||||
<g id="logo" sketch:type="MSLayerGroup" transform="translate(0.000000, 10.000000)">
|
||||
<g id="Page-1" sketch:type="MSShapeGroup">
|
||||
<g id="Fill-1-+-Group-24">
|
||||
<g id="Group-24">
|
||||
<g id="Group">
|
||||
<path id="tanuki-right-ear" d="M12.2685,74.7342 L66.4215,74.7342 L43.1485,3.1092 C41.9515,-0.5768 36.7375,-0.5758 35.5405,3.1092 L12.2685,74.7342 L12.2685,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
|
||||
<path id="tanuki-right-cheek" d="M12.2685,74.7341 L12.2685,74.7341 L0.5265,110.8731 C-0.5445,114.1691 0.6285,117.7801 3.4325,119.8171 L105.0615,193.6551 L12.2685,74.7341 L12.2685,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
|
||||
<path id="tanuki-right-eye" d="M105.0614,193.6548 L66.4214,74.7338 L12.2684,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
|
||||
<path id="tanuki-nose" d="M105.0614,193.655 L105.0614,193.655 L143.7014,74.734 L66.4214,74.734 L105.0614,193.655 L105.0614,193.655 Z" fill="#E24329" class="tanuki-shape"></path>
|
||||
<path id="tanuki-left-eye" d="M105.0614,193.6548 L143.7014,74.7338 L197.8544,74.7338 L105.0614,193.6548 L105.0614,193.6548 Z" fill="#FC6D26" class="tanuki-shape"></path>
|
||||
<path id="tanuki-left-cheek" d="M197.8544,74.7341 L197.8544,74.7341 L209.5964,110.8731 C210.6674,114.1691 209.4944,117.7801 206.6904,119.8171 L105.0614,193.6551 L197.8544,74.7341 L197.8544,74.7341 Z" fill="#FCA326" class="tanuki-shape"></path>
|
||||
<path id="tanuki-left-ear" d="M197.8544,74.7342 L143.7014,74.7342 L166.9744,3.1092 C168.1714,-0.5768 173.3854,-0.5758 174.5824,3.1092 L197.8544,74.7342 L197.8544,74.7342 Z" fill="#E24329" class="tanuki-shape"></path>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<svg width="36" height="36" id="tanuki-logo">
|
||||
<path id="tanuki-right-ear" class="tanuki-shape" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
|
||||
<path id="tanuki-left-ear" class="tanuki-shape" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
|
||||
<path id="tanuki-nose" class="tanuki-shape" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>
|
||||
<path id="tanuki-right-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 11.38,14 2,14 6,25Z"/>
|
||||
<path id="tanuki-left-eye" class="tanuki-shape" fill="#fc6d26" d="M18,34.38 24.62,14 34,14 30,25Z"/>
|
||||
<path id="tanuki-right-cheek" class="tanuki-shape" fill="#fca326" d="M2 14L.1 20.16c-.18.565 0 1.2.5 1.56l17.42 12.66z"/>
|
||||
<path id="tanuki-left-cheek" class="tanuki-shape" fill="#fca326" d="M34 14l1.9 6.16c.18.565 0 1.2-.5 1.56L18 34.38z"/>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 846 B |
|
@ -4,21 +4,18 @@
|
|||
%span.issuable-count.pull-left
|
||||
= issuable.iid
|
||||
of
|
||||
= issuable_count(:all, @project)
|
||||
= issuables_count(issuable)
|
||||
%span.pull-right
|
||||
%a.gutter-toggle{href: '#'}
|
||||
- if sidebar_gutter_collapsed?
|
||||
= icon('angle-double-left')
|
||||
- else
|
||||
= icon('angle-double-right')
|
||||
= sidebar_gutter_toggle_icon
|
||||
.issuable-nav.pull-right.btn-group{role: 'group', "aria-label" => '...'}
|
||||
- if has_prev_issuable?(@project, issuable.id)
|
||||
= link_to 'Prev', issuable_link_prev(@project, issuable), class: 'btn btn-default prev-btn'
|
||||
- if prev_issuable = prev_issuable_for(issuable)
|
||||
= link_to 'Prev', [@project.namespace.becomes(Namespace), @project, prev_issuable], class: 'btn btn-default prev-btn'
|
||||
- else
|
||||
%a.btn.btn-default.disabled{href: '#'}
|
||||
Prev
|
||||
- if has_next_issuable?(@project, issuable.id)
|
||||
= link_to 'Next', issuable_link_next(@project, issuable), class: 'btn btn-default next-btn'
|
||||
- if next_issuable = next_issuable_for(issuable)
|
||||
= link_to 'Next', [@project.namespace.becomes(Namespace), @project, next_issuable], class: 'btn btn-default next-btn'
|
||||
- else
|
||||
%a.btn.btn-default.disabled{href: '#'}
|
||||
Next
|
||||
|
@ -118,7 +115,7 @@
|
|||
- project_ref = cross_project_reference(@project, issuable)
|
||||
.block.project-reference
|
||||
.sidebar-collapsed-icon
|
||||
= icon('clipboard')
|
||||
= clipboard_button(clipboard_text: project_ref)
|
||||
.title
|
||||
.cross-project-reference
|
||||
%span
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
#{projects_limit} of #{pluralize(projects.count, 'project')} displayed.
|
||||
= link_to '#', class: 'js-expand' do
|
||||
Show all
|
||||
= paginate projects, theme: "gitlab" if !projects.kind_of?(Array)
|
||||
= paginate projects, theme: "gitlab" if projects.respond_to? :total_pages
|
||||
- else
|
||||
%h3 No projects found
|
||||
|
||||
:javascript
|
||||
new ProjectsList();
|
||||
Dashboard.init();
|
||||
|
|
|
@ -31,7 +31,7 @@ module Gitlab
|
|||
config.encoding = "utf-8"
|
||||
|
||||
# Configure sensitive parameters which will be filtered from the log file.
|
||||
config.filter_parameters.push(:password, :password_confirmation, :private_token, :otp_attempt)
|
||||
config.filter_parameters.push(:password, :password_confirmation, :private_token, :otp_attempt, :variables)
|
||||
|
||||
# Enable escaping HTML in JSON.
|
||||
config.active_support.escape_html_entities_in_json = true
|
||||
|
@ -52,17 +52,11 @@ module Gitlab
|
|||
|
||||
config.action_view.sanitized_allowed_protocols = %w(smb)
|
||||
|
||||
# Relative url support
|
||||
# Uncomment and customize the last line to run in a non-root path
|
||||
# WARNING: We recommend creating a FQDN to host GitLab in a root path instead of this.
|
||||
# Note that following settings need to be changed for this to work.
|
||||
# 1) In your application.rb file: config.relative_url_root = "/gitlab"
|
||||
# 2) In your gitlab.yml file: relative_url_root: /gitlab
|
||||
# 3) In your unicorn.rb: ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"
|
||||
# 4) In ../gitlab-shell/config.yml: gitlab_url: "http://127.0.0.1/gitlab"
|
||||
# 5) In lib/support/nginx/gitlab : do not use asset gzipping, remove block starting with "location ~ ^/(assets)/"
|
||||
#
|
||||
# To update the path, run: sudo -u git -H bundle exec rake assets:precompile RAILS_ENV=production
|
||||
# Relative URL support
|
||||
# WARNING: We recommend using an FQDN to host GitLab in a root path instead
|
||||
# of using a relative URL.
|
||||
# Documentation: http://doc.gitlab.com/ce/install/relative_url.html
|
||||
# Uncomment and customize the following line to run in a non-root path
|
||||
#
|
||||
# config.relative_url_root = "/gitlab"
|
||||
|
||||
|
|
|
@ -38,8 +38,12 @@ production: &base
|
|||
# Otherwise, ssh host will be set to the `host:` value above
|
||||
# ssh_host: ssh.host_example.com
|
||||
|
||||
# WARNING: See config/application.rb under "Relative url support" for the list of
|
||||
# other files that need to be changed for relative url support
|
||||
# Relative URL support
|
||||
# WARNING: We recommend using an FQDN to host GitLab in a root path instead
|
||||
# of using a relative URL.
|
||||
# Documentation: http://doc.gitlab.com/ce/install/relative_url.html
|
||||
# Uncomment and customize the following line to run in a non-root path
|
||||
#
|
||||
# relative_url_root: /gitlab
|
||||
|
||||
# Uncomment and customize if you can't use the default user to run GitLab (default: 'git')
|
||||
|
|
|
@ -12,7 +12,7 @@ if Rails.env.production?
|
|||
|
||||
ActionMailer::Base.smtp_settings = {
|
||||
address: "email.server.com",
|
||||
port: 456,
|
||||
port: 465,
|
||||
user_name: "smtp",
|
||||
password: "123456",
|
||||
domain: "gitlab.company.com",
|
||||
|
|
|
@ -227,7 +227,10 @@ Rails.application.routes.draw do
|
|||
get :test
|
||||
end
|
||||
|
||||
resources :broadcast_messages, only: [:index, :edit, :create, :update, :destroy]
|
||||
resources :broadcast_messages, only: [:index, :edit, :create, :update, :destroy] do
|
||||
post :preview, on: :collection
|
||||
end
|
||||
|
||||
resource :logs, only: [:show]
|
||||
resource :background_jobs, controller: 'background_jobs', only: [:show]
|
||||
|
||||
|
@ -349,6 +352,7 @@ Rails.application.routes.draw do
|
|||
get :issues
|
||||
get :merge_requests
|
||||
get :projects
|
||||
get :events
|
||||
end
|
||||
|
||||
scope module: :groups do
|
||||
|
@ -604,7 +608,7 @@ Rails.application.routes.draw do
|
|||
resource :variables, only: [:show, :update]
|
||||
resources :triggers, only: [:index, :create, :destroy]
|
||||
|
||||
resources :builds, only: [:index, :show] do
|
||||
resources :builds, only: [:index, :show], constraints: { id: /\d+/ } do
|
||||
collection do
|
||||
post :cancel_all
|
||||
end
|
||||
|
@ -693,6 +697,12 @@ Rails.application.routes.draw do
|
|||
end
|
||||
|
||||
resources :runner_projects, only: [:create, :destroy]
|
||||
resources :badges, only: [], path: 'badges/*ref',
|
||||
constraints: { ref: Gitlab::Regex.git_reference_regex } do
|
||||
collection do
|
||||
get :build, constraints: { format: /svg/ }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -10,9 +10,12 @@
|
|||
|
||||
# Note: If you change this file in a Merge Request, please also create a
|
||||
# Merge Request on https://gitlab.com/gitlab-org/omnibus-gitlab/merge_requests
|
||||
#
|
||||
# WARNING: See config/application.rb under "Relative url support" for the list of
|
||||
# other files that need to be changed for relative url support
|
||||
|
||||
# Relative URL support
|
||||
# WARNING: We recommend using an FQDN to host GitLab in a root path instead
|
||||
# of using a relative URL.
|
||||
# Documentation: http://doc.gitlab.com/ce/install/relative_url.html
|
||||
# Uncomment and customize the following line to run in a non-root path
|
||||
#
|
||||
# ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab"
|
||||
|
||||
|
|
|
@ -1,24 +1,13 @@
|
|||
class Gitlab::Seeder::Builds
|
||||
BUILD_STATUSES = %w(running pending success failed canceled)
|
||||
|
||||
def initialize(project)
|
||||
@project = project
|
||||
end
|
||||
|
||||
def seed!
|
||||
ci_commits.each do |ci_commit|
|
||||
build = Ci::Build.new(build_attributes_for(ci_commit))
|
||||
|
||||
artifacts_cache_file(artifacts_archive_path) do |file|
|
||||
build.artifacts_file = file
|
||||
end
|
||||
|
||||
artifacts_cache_file(artifacts_metadata_path) do |file|
|
||||
build.artifacts_metadata = file
|
||||
end
|
||||
|
||||
begin
|
||||
build.save!
|
||||
build_create!(ci_commit, name: 'test build 1')
|
||||
build_create!(ci_commit, status: 'success', name: 'test build 2')
|
||||
print '.'
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
print 'F'
|
||||
|
@ -36,6 +25,28 @@ class Gitlab::Seeder::Builds
|
|||
[]
|
||||
end
|
||||
|
||||
def build_create!(ci_commit, opts = {})
|
||||
attributes = build_attributes_for(ci_commit).merge(opts)
|
||||
build = Ci::Build.new(attributes)
|
||||
|
||||
if %w(success failed).include?(build.status)
|
||||
artifacts_cache_file(artifacts_archive_path) do |file|
|
||||
build.artifacts_file = file
|
||||
end
|
||||
|
||||
artifacts_cache_file(artifacts_metadata_path) do |file|
|
||||
build.artifacts_metadata = file
|
||||
end
|
||||
end
|
||||
|
||||
build.save!
|
||||
|
||||
if %w(running success failed).include?(build.status)
|
||||
# We need to set build trace after saving a build (id required)
|
||||
build.trace = FFaker::Lorem.paragraphs(6).join("\n\n")
|
||||
end
|
||||
end
|
||||
|
||||
def build_attributes_for(ci_commit)
|
||||
{ name: 'test build', commands: "$ build command",
|
||||
stage: 'test', stage_idx: 1, ref: 'master',
|
||||
|
@ -49,7 +60,7 @@ class Gitlab::Seeder::Builds
|
|||
end
|
||||
|
||||
def build_status
|
||||
BUILD_STATUSES.sample
|
||||
Ci::Build::AVAILABLE_STATUSES.sample
|
||||
end
|
||||
|
||||
def artifacts_archive_path
|
||||
|
|
|
@ -6,8 +6,10 @@ else
|
|||
expire_time = nil
|
||||
end
|
||||
|
||||
email = ENV['GITLAB_ROOT_EMAIL'].presence || 'admin@example.com'
|
||||
|
||||
admin = User.create(
|
||||
email: "admin@example.com",
|
||||
email: email,
|
||||
name: "Administrator",
|
||||
username: 'root',
|
||||
password: password,
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
class AddEmailAuthorInBodyToApplicationSettings < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :application_settings, :email_author_in_body, :boolean, default: false
|
||||
end
|
||||
end
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue