Commit fb6d7df3 authored by Johann Pardanaud's avatar Johann Pardanaud

Merge branch 'master' into avatar-cropping

Conflicts:
	app/models/user.rb
parents 78588cfc 7cc4b739
......@@ -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
spec:api:ruby21:
image: ruby:2.1
only:
- master
script:
- RAILS_ENV=test SIMPLECOV=true bundle exec rake spec:api
cache:
key: "ruby21"
paths:
- vendor
tags:
- ruby
- mysql
spinach:ruby21:
spec:models: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: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
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
......
......@@ -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()
......
$ ->
$('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 } }
)
@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()
else
uiBox.find("ul.projects-list li").each (index) ->
name = $(this).find(filterSelector).text()
@filter_results: ($element) ->
terms = $element.val()
filterSelector = $element.data('filter-selector') || 'span.filter-title'
if name.toLowerCase().search(terms.toLowerCase()) == -1
$(this).hide()
else
$(this).show()
uiBox.find("ul.projects-list li.bottom").hide()
if not terms
$(".projects-list li").show()
$('.gl-pagination').show()
else
$(".projects-list li").each (index) ->
$this = $(this)
name = $this.find(filterSelector).text()
if name.toLowerCase().indexOf(terms.toLowerCase()) == -1
$this.hide()
else
$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
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
......
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
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
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,11 +11,12 @@ 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")
end
@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)
@milestones = @milestones.page(params[:page]).per(PER_PAGE)
......
class Projects::RunnerProjectsController < Projects::ApplicationController
before_action :authorize_admin_project!
before_action :authorize_admin_build!
layout 'project_settings'
......
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'
......
class Projects::TriggersController < Projects::ApplicationController
before_action :authorize_admin_project!
before_action :authorize_admin_build!
layout 'project_settings'
......
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
......
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)
......@@ -69,7 +69,7 @@ module IssuesHelper
end
end
def issue_button_visibility(issue, closed)
def issue_button_visibility(issue, closed)
return 'hidden' if issue.closed? == closed
end
......
......@@ -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"
......@@ -32,9 +20,9 @@ module NavHelper
end
def page_gutter_class
if current_path?('merge_requests#show') ||
current_path?('merge_requests#diffs') ||
current_path?('merge_requests#commits') ||
if current_path?('merge_requests#show') ||
current_path?('merge_requests#diffs') ||
current_path?('merge_requests#commits') ||
current_path?('issues#show')
if cookies[:collapsed_gutter] == 'true'
"page-gutter right-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,7 +59,11 @@ class Repository
# This method return true if repository contains some content visible in project page.
#
def has_visible_content?
raw_repository.branch_count > 0
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')
......@@ -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,20 +230,39 @@ 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
branches.each do |branch|
cache.expire(:"diverging_commit_counts_#{branch.name}")
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
cache_keys.each do |key|
cache.expire(key)
......@@ -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
......
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
......
# 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
......
.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'
......
$('.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
......
.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
......
- if projects.any?
.public-projects
.projects-list-holder
= render 'shared/projects/list', projects: projects
- else
.nothing-here-block
......
.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
= icon('plus')
New Project
.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
......
- 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)
- 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
......
- 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)
......
- 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, '&rarr;')
......
......@@ -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
......
.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
......
%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
&nbsp;
= 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};
......
- 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,14 +29,15 @@
= link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do
= sort_title_oldest_updated
- 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')
Fork
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do
= icon('code-fork fw')
Fork
- 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')
Fork
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'btn btn-new' do
= icon('code-fork fw')
Fork
.projects-list-holder
......
......@@ -46,8 +46,8 @@
Edited
= time_ago_with_tooltip(@issue.updated_at, placement: 'bottom', html_class: 'issue_edited_ago')
.merge-requests
= render 'merge_requests'
.merge-requests
= render 'merge_requests'
.content-block
= render 'votes/votes_block', votable: @issue
......@@ -57,4 +57,4 @@
.issuable-discussion
= render 'projects/issues/discussion'
= render 'shared/issuable/sidebar', issuable: @issue
\ No newline at end of file
= render 'shared/issuable/sidebar', issuable: @issue
%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
......
- 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"}.
<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>
......@@ -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"
......
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,
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment