Commit 7680ada3 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'ce_upsteram' into 'master'

CE upsteram



See merge request !48
parents b9e54481 3f6101aa
......@@ -6,6 +6,8 @@ v 8.1.0
v 8.0.1
v 8.1.0 (unreleased)
v 8.2.0 (unreleased)
- Force update refs/merge-requests/X/head upon a push to the source branch of a merge request (Stan Hu)
- Improved performance of finding users by one of their Email addresses
- Improved performance of replacing references in comments
- Show last project commit to default branch on project home page
- Highlight comment based on anchor in URL
......@@ -13,12 +15,43 @@ v 8.2.0 (unreleased)
- Improved performance of sorting milestone issues
- Allow users to select the Files view as default project view (Cristian Bica)
- Show "Empty Repository Page" for repository without branches (Artem V. Navrotskiy)
- Fix: Inability to reply to code comments in the MR view, if the MR comes from a fork
- Use git follow flag for commits page when retrieve history for file or directory
- Show merge request CI status on merge requests index page
- Extend yml syntax for only and except to support specifying repository path
- Fix: 500 error returned if destroy request without HTTP referer (Kazuki Shimizu)
- Remove deprecated CI events from project settings page
- Use issue editor as cross reference comment author when issue is edited with a new mention.
- [API] Add ability to fetch the commit ID of the last commit that actually touched a file
- Add "New file" link to dropdown on project page
- Include commit logs in project search
- Add "added", "modified" and "removed" properties to commit object in webhook
- Rename "Back to" links to "Go to" because its not always a case it point to place user come from
- Allow groups to appear in the search results if the group owner allows it
v 8.1.3
- Spread out runner contacted_at updates
- New design for user profile page
- Add Facebook authentication
v 8.1.1
- Fix cloning Wiki repositories via HTTP (Stan Hu)
- Add migration to remove satellites directory
- Fix specific runners visibility
- Fix 500 when editing CI service
- Require CI jobs to be named
- Fix CSS for runner status
- Fix CI badge
- Allow developer to manage builds
v 8.1.0
- Ensure MySQL CI limits DB migrations occur after the fields have been created (Stan Hu)
- Fix duplicate repositories in GitHub import page (Stan Hu)
- Redirect to a default path if HTTP_REFERER is not set (Stan Hu)
- Fix CSS for runner status
- Adds ability to create directories using the web editor (Ben Ford)
- Cleanup stuck CI builds
v 8.1.0 (unreleased)
- Send an email to admin email when a user is reported for spam (Jonathan Rochkind)
- Show notifications button when user is member of group rather than project (Grzegorz Bizon)
- Fix bug preventing mentioned issued from being closed when MR is merged using fast-forward merge.
......@@ -26,12 +59,11 @@ v 8.1.0
- Don't show "Add README" link in an empty repository if user doesn't have access to push (Stan Hu)
- Fix error preventing displaying of commit data for a directory with a leading dot (Stan Hu)
- Speed up load times of issue detail pages by roughly 1.5x
- Require CI jobs to be named
- Fix CI rendering regressions
- If a merge request is to close an issue, show this on the issue page (Zeger-Jan van de Weg)
- Add a system note and update relevant merge requests when a branch is deleted or re-added (Stan Hu)
- Make diff file view easier to use on mobile screens (Stan Hu)
- Improved performance of finding users by username or Email address
- Fix 500 when editing CI service
- Fix bug where merge request comments created by API would not trigger notifications (Stan Hu)
- Add support for creating directories from Files page (Stan Hu)
- Allow removing of project without confirmation when JavaScript is disabled (Stan Hu)
......
......@@ -83,6 +83,7 @@ If you can, please submit a merge request with the fix or improvements including
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submission
1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
1. Also have a look at the [shell command guidelines](doc/development/shell_commands.md) if your code reads or opens files, or handles paths to files on disk.
1. If your code creates new files on disk please read the [shared files guidelines](doc/development/shared_files.md).
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast.
Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as regressions requiring patch releases.
......
......@@ -19,6 +19,7 @@ gem 'devise-async', '~> 0.9.0'
gem 'doorkeeper', '~> 2.1.3'
gem 'omniauth', '~> 1.2.2'
gem 'omniauth-bitbucket', '~> 0.0.2'
gem 'omniauth-facebook', '~> 3.0.0'
gem 'omniauth-github', '~> 1.1.1'
gem 'omniauth-gitlab', '~> 1.0.0'
gem 'omniauth-google-oauth2', '~> 0.2.0'
......@@ -65,7 +66,7 @@ gem 'rack-cors', '~> 0.4.0', require: 'rack/cors'
# Format dates and times
# based on human-friendly examples
gem "stamp", '~> 0.5.0'
gem "stamp", '~> 0.6.0'
# Enumeration fields
gem 'enumerize', '~> 0.7.0'
......@@ -199,11 +200,11 @@ gem 'bootstrap-sass', '~> 3.0'
gem 'font-awesome-rails', '~> 4.2'
gem 'gitlab_emoji', '~> 0.1'
gem 'gon', '~> 5.0.0'
gem 'jquery-atwho-rails', '~> 1.0.0'
gem 'jquery-atwho-rails', '~> 1.3.2'
gem 'jquery-rails', '~> 3.1.3'
gem 'jquery-scrollto-rails', '~> 1.4.3'
gem 'jquery-ui-rails', '~> 4.2.1'
gem 'nprogress-rails', '~> 0.1.2.3'
gem 'nprogress-rails', '~> 0.1.6.7'
gem 'raphael-rails', '~> 2.1.2'
gem 'request_store', '~> 1.2.0'
gem 'select2-rails', '~> 3.5.9'
......
......@@ -357,7 +357,7 @@ GEM
ice_nine (0.11.1)
inflecto (0.0.2)
ipaddress (0.8.0)
jquery-atwho-rails (1.0.1)
jquery-atwho-rails (1.3.2)
jquery-rails (3.1.3)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
......@@ -409,7 +409,7 @@ GEM
newrelic_rpm (3.9.4.245)
nokogiri (1.6.6.2)
mini_portile (~> 0.6.0)
nprogress-rails (0.1.2.3)
nprogress-rails (0.1.6.7)
oauth (0.4.7)
oauth2 (1.0.0)
faraday (>= 0.8, < 0.10)
......@@ -426,6 +426,8 @@ GEM
multi_json (~> 1.7)
omniauth (~> 1.1)
omniauth-oauth (~> 1.0)
omniauth-facebook (3.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.1.2)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
......@@ -692,7 +694,7 @@ GEM
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (>= 2.8, < 4.0)
stamp (0.5.0)
stamp (0.6.0)
state_machine (1.2.0)
stringex (2.5.2)
systemu (2.6.5)
......@@ -845,7 +847,7 @@ DEPENDENCIES
hipchat (~> 1.5.0)
html-pipeline (~> 1.11.0)
httparty (~> 0.13.3)
jquery-atwho-rails (~> 1.0.0)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 3.1.3)
jquery-scrollto-rails (~> 1.4.3)
jquery-turbolinks (~> 2.0.1)
......@@ -860,11 +862,12 @@ DEPENDENCIES
net-ldap
newrelic-grape
newrelic_rpm (~> 3.9.4.245)
nprogress-rails (~> 0.1.2.3)
nprogress-rails (~> 0.1.6.7)
oauth2 (~> 1.0.0)
octokit (~> 3.7.0)
omniauth (~> 1.2.2)
omniauth-bitbucket (~> 0.0.2)
omniauth-facebook (~> 3.0.0)
omniauth-github (~> 1.1.1)
omniauth-gitlab (~> 1.0.0)
omniauth-google-oauth2 (~> 0.2.0)
......@@ -915,7 +918,7 @@ DEPENDENCIES
spring-commands-spinach (~> 1.0.0)
spring-commands-teaspoon (~> 0.0.2)
sprockets (~> 2.12.3)
stamp (~> 0.5.0)
stamp (~> 0.6.0)
state_machine (~> 1.2.0)
task_list (~> 1.0.2)
teaspoon (~> 1.0.0)
......
......@@ -115,3 +115,10 @@ We can only accept a merge request if all the tests are green. I've just
restarted the build. When the tests are still not passing after this restart and
you're sure that is does not have anything to do with your code changes, please
rebase with master to see if that solves the issue.
### Closing down the issue tracker on GitHub
We are currently in the process of closing down the issue tracker on GitHub, to
prevent duplication with the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
Since this is an older issue I'll be closing this for now. If you think this is
still an issue I encourage you to open it on the [GitLab.com issue tracker][https://gitlab.com/gitlab-org/gitlab-ce/issues].
No preview for this file type
File mode changed from 100755 to 100644
No preview for this file type
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
File mode changed from 100755 to 100644
......@@ -11,10 +11,10 @@ class @EditBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
return false
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
editModePanes = $(".js-edit-mode-pane")
editModeLinks = $(".js-edit-mode a")
......
......@@ -11,10 +11,10 @@ class @NewBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
return false
# Before a form submission, move the content from the Ace editor into the
# submitted textarea
$('form').submit ->
$("#file-content").val(editor.getValue())
editor: ->
return @editor
......@@ -25,7 +25,7 @@ class @Calendar
30
]
legendCellPadding: 3
cellSize: $('.user-calendar').width() / 80
cellSize: $('.user-calendar').width() / 73
onClick: (date, count) ->
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
$.ajax
......
......@@ -31,7 +31,7 @@ class CiBuild
$('#build-trace code').html build.trace_html
$('#build-trace code').append '<i class="fa fa-refresh fa-spin"/>'
@checkAutoscroll()
else
else if build.status != build_status
Turbolinks.visit build_url
, 4000
......
#= require clipboard
$ ->
clipboard = new Clipboard '.js-clipboard-trigger',
text: (trigger) ->
$target = $(trigger.nextElementSibling || trigger.previousElementSibling)
$target.data('clipboard-text') || $target.text().trim()
clipboard.on 'success', (e) ->
$(e.trigger).
tooltip(trigger: 'manual', placement: 'auto bottom', title: 'Copied!').
tooltip('show')
# Clear the selection and blur the trigger so it loses its border
e.clearSelection()
$(e.trigger).blur()
# Manually hide the tooltip after 1 second
setTimeout(->
$(e.trigger).tooltip('hide')
, 1000)
......@@ -100,7 +100,7 @@
}
.cover-desc {
padding: 0 $gl-padding;
padding: 0 $gl-padding 3px;
color: $gl-text-color;
}
......
......@@ -180,3 +180,7 @@
}
}
}
.btn-clipboard {
border: none;
}
......@@ -396,6 +396,36 @@ table {
}
}
.center-middle-menu {
@include nav-menu;
padding: 0;
text-align: center;
margin: -$gl-padding;
margin-top: 0;
margin-bottom: 0;
height: 58px;
border-bottom: 1px solid $border-color;
li {
&:after {
content: "|";
color: $border-gray-light;
}
&:last-child {
&:after {
content: none;
}
}
> a {
display: inline-block;
text-transform: uppercase;
font-size: 13px;
}
}
}
.dropzone .dz-preview .dz-progress {
border-color: $border-color !important;
}
......
......@@ -137,6 +137,7 @@
&:hover, &:active, &:focus {
text-decoration: none;
outline: none;
}
}
......
......@@ -33,6 +33,8 @@
}
li.commit {
list-style: none;
.commit-row-title {
font-size: $list-font-size;
line-height: 20px;
......
......@@ -50,7 +50,7 @@
.editor-file-name {
.new-file-name {
display: inline-block;
width: 200px;
width: 450px;
}
.form-control {
......
......@@ -88,3 +88,16 @@
padding: 13px 0;
}
}
.cross-project-reference {
text-align: center;
width: 100%;
.slead {
padding: 5px;
}
span, button {
background-color: $background-color;
}
}
......@@ -205,6 +205,15 @@
#modal_merge_info .modal-dialog {
width: 600px;
.btn-clipboard {
@extend .pull-right;
margin-right: 18px;
margin-top: 5px;
position: absolute;
right: 0;
}
}
.mr-source-target {
......
......@@ -53,3 +53,25 @@
float: right;
font-size: 12px;
}
.profile-link-holder {
display: inline;
&:after {
content: "\00B7";
padding: 0px 6px;
font-weight: bold;
}
&:last-child {
&:after {
content: "";
padding: 0;
}
}
a {
color: $blue-dark;
text-decoration: none;
}
}
......@@ -59,13 +59,8 @@ class ApplicationController < ActionController::Base
end
def authenticate_user!(*args)
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
if current_application_settings.home_page_url.present? &&
current_application_settings.home_page_url.chomp('/') != Gitlab.config.gitlab['url'].chomp('/')
if current_user.nil? && root_path == request.path
redirect_to current_application_settings.home_page_url and return
end
if redirect_to_home_page_url?
redirect_to current_application_settings.home_page_url and return
end
super(*args)
......@@ -352,4 +347,17 @@ class ApplicationController < ActionController::Base
def git_import_enabled?
current_application_settings.import_sources.include?('git')
end
def redirect_to_home_page_url?
# If user is not signed-in and tries to access root_path - redirect him to landing page
# Don't redirect to the default URL to prevent endless redirections
return false unless current_application_settings.home_page_url.present?
home_page_url = current_application_settings.home_page_url.chomp('/')
root_urls = [Gitlab.config.gitlab['url'].chomp('/'), root_url.chomp('/')]
return false if root_urls.include?(home_page_url)
current_user.nil? && root_path == request.path
end
end
......@@ -17,6 +17,7 @@ module Ci
@projects = @projects.where(gitlab_id: @gl_projects.select(:id))
end
@projects = @projects.where("ci_projects.id NOT IN (?)", @runner.projects.pluck(:id)) if @runner.projects.any?
@projects = @projects.joins(:gl_project)
@projects = @projects.page(params[:page]).per(30)
end
......
......@@ -8,14 +8,6 @@ module Ci
private
def authenticate_public_page!
unless project.public
authenticate_user!
return access_denied! unless can?(current_user, :read_project, gl_project)
end
end
def authenticate_token!
unless project.valid_token?(params[:token])
return head(403)
......
module Ci
class EventsController < Ci::ApplicationController
EVENTS_PER_PAGE = 50
before_action :authenticate_user!
before_action :project
before_action :authorize_manage_project!
layout 'ci/project'
def index
@events = project.events.order("created_at DESC").page(params[:page]).per(EVENTS_PER_PAGE)
end
private
def project
@project ||= Ci::Project.find(params[:project_id])
end
end
end
......@@ -4,8 +4,6 @@ module Ci
before_action :project
before_action :authorize_manage_project!
layout 'ci/project'
def create
@runner = Ci::Runner.find(params[:runner_project][:runner_id])
......
......@@ -4,12 +4,12 @@ class GroupsController < Groups::ApplicationController
before_action :group, except: [:new, :create]
# Authorize
before_action :authorize_read_group!, except: [:show, :new, :create]
before_action :authorize_read_group!, except: [:show, :new, :create, :autocomplete]
before_action :authorize_admin_group!, only: [:edit, :update, :destroy, :projects]
before_action :authorize_create_group!, only: [:new, :create]
# Load group projects
before_action :load_projects, except: [:new, :create, :projects, :edit, :update]
before_action :load_projects, except: [:new, :create, :projects, :edit, :update, :autocomplete]
before_action :event_filter, only: :show
layout :determine_layout
......@@ -135,7 +135,7 @@ class GroupsController < Groups::ApplicationController
end
def group_params
params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock, :share_with_group_lock)
params.require(:group).permit(:name, :description, :path, :avatar, :membership_lock, :share_with_group_lock, :public)
end
def load_events
......
......@@ -161,7 +161,7 @@ class Projects::BlobController < Projects::ApplicationController
if params[:file].present?
params[:file_name] = params[:file].original_filename
end
File.join(@path, File.basename(params[:file_name]))
File.join(@path, params[:file_name])
else
@path
end
......
......@@ -2,23 +2,24 @@ class Projects::BuildsController < Projects::ApplicationController
before_action :ci_project
before_action :build, except: [:index, :cancel_all]
before_action :authorize_admin_project!, except: [:index, :show, :status]
before_action :authorize_manage_builds!, except: [:index, :show, :status]
layout "project"
def index
@scope = params[:scope]
@all_builds = project.ci_builds
@builds = @all_builds.order('created_at DESC')
@builds =
case @scope
when 'all'
@all_builds
@builds
when 'finished'
@all_builds.finished
@builds.finished
else
@all_builds.running_or_pending
@builds.running_or_pending.reverse_order
end
@builds = @builds.order('created_at DESC').page(params[:page]).per(30)
@builds = @builds.page(params[:page]).per(30)
end
def cancel_all
......@@ -73,4 +74,10 @@ class Projects::BuildsController < Projects::ApplicationController
def build_path(build)
namespace_project_build_path(build.gl_project.namespace, build.gl_project, build)
end
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return page_404
end
end
end
......@@ -4,7 +4,8 @@
class Projects::CommitController < Projects::ApplicationController
# Authorize
before_action :require_non_empty_project
before_action :authorize_download_code!
before_action :authorize_download_code!, except: [:cancel_builds]
before_action :authorize_manage_builds!, only: [:cancel_builds]
before_action :commit
def show
......@@ -55,4 +56,12 @@ class Projects::CommitController < Projects::ApplicationController
def commit
@commit ||= @project.commit(params[:id])
end
private
def authorize_manage_builds!
unless can?(current_user, :manage_builds, project)
return page_404
end
end
end
......@@ -12,7 +12,7 @@ class Projects::CommitsController < Projects::ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset)
@note_counts = Note.where(commit_id: @commits.map(&:id)).
@note_counts = project.notes.where(commit_id: @commits.map(&:id)).
group(:commit_id).count
respond_to do |format|
......
......@@ -6,11 +6,10 @@ class Projects::RunnersController < Projects::ApplicationController
layout 'project_settings'
def index
@runners = @ci_project.runners.order('id DESC')
@specific_runners =
Ci::Runner.specific.includes(:runner_projects).
where(Ci::RunnerProject.table_name => { project_id: current_user.authorized_projects } ).
where.not(id: @runners).order("#{Ci::Runner.table_name}.id DESC").page(params[:page]).per(20)
@runners = @ci_project.runners.ordered
@specific_runners = current_user.ci_authorized_runners.
where.not(id: @ci_project.runners).
ordered.page(params[:page]).per(20)
@shared_runners = Ci::Runner.shared.active
@shared_runners_count = @shared_runners.count(:all)
end
......
class ProjectsController < ApplicationController
include ExtractsPath
prepend_before_filter :render_go_import, only: [:show]
prepend_before_action :render_go_import, only: [:show]
skip_before_action :authenticate_user!, only: [:show, :activity]
before_action :project, except: [:new, :create]
before_action :repository, except: [:new, :create]
......@@ -124,11 +124,7 @@ class ProjectsController < ApplicationController
::Projects::DestroyService.new(@project, current_user, {}).execute
flash[:alert] = "Project '#{@project.name}' was deleted."
if request.referer.include?('/admin')
redirect_to admin_namespaces_projects_path
else
redirect_to dashboard_projects_path
end
redirect_back_or_default(default: dashboard_projects_path, options: {})
rescue Projects::DestroyService::DestroyError => ex
redirect_to edit_project_path(@project), alert: ex.message
end
......
......@@ -23,8 +23,8 @@ class SearchController < ApplicationController
@search_results =
if @project
unless %w(blobs notes issues merge_requests milestones wiki_blobs).
include?(@scope)
unless %w(blobs notes issues merge_requests milestones wiki_blobs
commits).include?(@scope)
@scope = 'blobs'
end
......
......@@ -6,33 +6,34 @@ class GroupsFinder
private
def all_groups(current_user)
if current_user
if current_user.authorized_groups.any?
# User has access to groups
#
# Return only:
# groups with public projects
# groups with internal projects
# groups with joined projects
#
group_ids = Project.public_and_internal_only.pluck(:namespace_id) +
current_user.authorized_groups.pluck(:id)
Group.where(id: group_ids)
else
# User has no group membership
#
# Return only:
# groups with public projects
# groups with internal projects
#
Group.where(id: Project.public_and_internal_only.pluck(:namespace_id))
end
else
# Not authenticated
#
# Return only:
# groups with public projects
Group.where(id: Project.public_only.pluck(:namespace_id))
end
group_ids = if current_user
if current_user.authorized_groups.any?
# User has access to groups
#
# Return only:
# groups with public projects
# groups with internal projects
# groups with joined projects
#
Project.public_and_internal_only.pluck(:namespace_id) +
current_user.authorized_groups.pluck(:id)
else
# User has no group membership
#
# Return only:
# groups with public projects
# groups with internal projects
#
Project.public_and_internal_only.pluck(:namespace_id)
end
else
# Not authenticated
#
# Return only:
# groups with public projects
Project.public_only.pluck(:namespace_id)
end
Group.where("public IS TRUE OR id IN(?)", group_ids)
end
end
module AuthHelper
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2).freeze
PROVIDERS_WITH_ICONS = %w(twitter github gitlab bitbucket google_oauth2 facebook).freeze
FORM_BASED_PROVIDERS = [/\Aldap/, 'kerberos', 'crowd'].freeze
def ldap_enabled?
......
......@@ -42,4 +42,13 @@ module CiStatusHelper
icon(icon_name)
end
def render_ci_status(ci_commit)
link_to ci_status_path(ci_commit),
class: "c#{ci_status_color(ci_commit)}",
title: "Build status: #{ci_commit.status}",
data: { toggle: 'tooltip', placement: 'left' } do
ci_status_icon(ci_commit)
end
end
end
module ClipboardHelper
def clipboard_button
content_tag :button,
icon('clipboard'),
class: 'btn btn-xs btn-clipboard js-clipboard-trigger',
type: :button
end
end
......@@ -70,7 +70,7 @@ module SearchHelper
# Autocomplete results for the current user's groups
def groups_autocomplete(term, limit = 5)
current_user.authorized_groups.search(term).limit(limit).map do |group|
GroupsFinder.new.execute(current_user).search(term).limit(limit).map do |group|
{
label: "group: #{search_result_sanitize(group.name)}",
url: group_path(group)
......
......@@ -187,7 +187,7 @@ module Ci
end
def config_processor
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file)
@config_processor ||= Ci::GitlabCiYamlProcessor.new(ci_yaml_file, gl_project.path_with_namespace)
rescue Ci::GitlabCiYamlProcessor::ValidationError => e
save_yaml_error(e.message)
nil
......
......@@ -99,6 +99,7 @@ module Ci
def ordered_by_last_commit_date
last_commit_subquery = "(SELECT gl_project_id, MAX(committed_at) committed_at FROM #{Ci::Commit.table_name} GROUP BY gl_project_id)"
joins("LEFT JOIN #{last_commit_subquery} AS last_commit ON #{Ci::Project.table_name}.gitlab_id = last_commit.gl_project_id").
joins(:gl_project).
order("CASE WHEN last_commit.committed_at IS NULL THEN 1 ELSE 0 END, last_commit.committed_at DESC")
end
end
......
......@@ -27,9 +27,5 @@ module Ci
def human_status
status
end
def last_commit_for_ref(ref)
commits.where(ref: ref).last
end
end
end
......@@ -36,6 +36,7 @@ module Ci
scope :active, ->() { where(active: true) }
scope :paused, ->() { where(active: false) }
scope :online, ->() { where('contacted_at > ?', LAST_CONTACT_TIME) }
scope :ordered, ->() { order(id: :desc) }
acts_as_taggable
......
......@@ -20,7 +20,6 @@ class CommitStatus < ActiveRecord::Base
scope :latest, -> { where(id: unscope(:select).select('max(id)').group(:name, :ref)) }
scope :ordered, -> { order(:ref, :stage_idx, :name) }
scope :for_ref, ->(ref) { where(ref: ref) }
scope :running_or_pending, -> { where(status: [:running, :pending]) }
state_machine :status, initial: :pending do
event :run do
......
......@@ -8,12 +8,12 @@ module Sortable
included do
# By default all models should be ordered
# by created_at field starting from newest
default_scope { order(created_at: :desc, id: :desc) }
default_scope { order(id: :desc) }
scope :order_created_desc, -> { reorder(created_at: :desc, id: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc, id: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc, id: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc, id: :asc) }
scope :order_created_desc, -> { reorder(created_at: :desc) }
scope :order_created_asc, -> { reorder(created_at: :asc) }
scope :order_updated_desc, -> { reorder(updated_at: :desc) }
scope :order_updated_asc, -> { reorder(updated_at: :asc) }
scope :order_name_asc, -> { reorder(name: :asc) }
scope :order_name_desc, -> { reorder(name: :desc) }
end
......
......@@ -128,7 +128,7 @@ class Group < Namespace
end
def public_profile?
projects.public_only.any?
self.public || projects.public_only.any?
end
# NOTE: Backwards compatibility with old ldap situation
......
......@@ -163,11 +163,11 @@ class MergeRequest < ActiveRecord::Base
def last_commit
merge_request_diff ? merge_request_diff.last_commit : compare_commits.last
end
end
def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end
end
def last_commit_short_sha
last_commit.short_id
......@@ -261,7 +261,7 @@ class MergeRequest < ActiveRecord::Base
Note.where(
"(project_id = :target_project_id AND noteable_type = 'MergeRequest' AND noteable_id = :mr_id) OR" +
"(project_id = :source_project_id AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
"((project_id = :source_project_id OR project_id = :target_project_id) AND noteable_type = 'Commit' AND commit_id IN (:commit_ids))",
mr_id: id,
commit_ids: commit_ids,
target_project_id: target_project_id,
......@@ -542,4 +542,10 @@ class MergeRequest < ActiveRecord::Base
def rebase_in_progress?
File.exist?(rebase_dir_path)
end
def ci_commit
if last_commit
source_project.ci_commit(last_commit.id)
end
end
end
......@@ -67,13 +67,16 @@ class Repository
end
def commits(ref, path = nil, limit = nil, offset = nil, skip_merges = false)
commits = Gitlab::Git::Commit.where(
options = {
repo: raw_repository,
ref: ref,
path: path,
limit: limit,
offset: offset,
)
follow: path.present?
}
commits = Gitlab::Git::Commit.where(options)
commits = Commit.decorate(commits, @project) if commits.present?
commits
end
......@@ -84,6 +87,15 @@ class Repository
commits
end
def find_commits_by_message(query)
# Limited to 1000 commits for now, could be parameterized?
args = %W(#{Gitlab.config.git.bin_path} log --pretty=%H --max-count 1000 --grep=#{query})
git_log_results = Gitlab::Popen.popen(args, path_to_repo).first.lines.map(&:chomp)
commits = git_log_results.map { |c| commit(c) }
commits
end
def find_branch(name)
branches.find { |branch| branch.name == name }
end
......@@ -284,7 +296,7 @@ class Repository
end
def last_commit_for_path(sha, path)
args = %W(git rev-list --max-count=1 #{sha} -- #{path})
args = %W(#{Gitlab.config.git.bin_path} rev-list --max-count=1 #{sha} -- #{path})
sha = Gitlab::Popen.popen(args, path_to_repo).first.strip
commit(sha)
end
......@@ -335,7 +347,7 @@ class Repository
end
def branch_names_contains(sha)
args = %W(git branch --contains #{sha})
args = %W(#{Gitlab.config.git.bin_path} branch --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
......@@ -352,7 +364,7 @@ class Repository
end
def tag_names_contains(sha)
args = %W(git tag --contains #{sha})
args = %W(#{Gitlab.config.git.bin_path} tag --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
if names.respond_to?(:split)
......@@ -505,7 +517,7 @@ class Repository
def search_files(query, ref)
offset = 2
args = %W(git grep -i -n --before-context #{offset} --after-context #{offset} #{query} #{ref || root_ref})
args = %W(#{Gitlab.config.git.bin_path} grep -i -n --before-context #{offset} --after-context #{offset} -e #{query} #{ref || root_ref})
Gitlab::Popen.popen(args, path_to_repo).first.scrub.split(/^--$/)
end
......@@ -537,7 +549,7 @@ class Repository
end
def fetch_ref(source_path, source_ref, target_ref)
args = %W(git fetch #{source_path} #{source_ref}:#{target_ref})
args = %W(#{Gitlab.config.git.bin_path} fetch -f #{source_path} #{source_ref}:#{target_ref})
Gitlab::Popen.popen(args, path_to_repo)
end
......
......@@ -238,21 +238,16 @@ class User < ActiveRecord::Base
# Find a User by their primary email or any associated secondary email
def find_by_any_email(email)
user_table = arel_table
email_table = Email.arel_table
sql = 'SELECT *
FROM users
WHERE id IN (
SELECT id FROM users WHERE email = :email
UNION
SELECT emails.user_id FROM emails WHERE email = :email
)
LIMIT 1;'
# Use ARel to build a query:
query = user_table.
# SELECT "users".* FROM "users"
project(user_table[Arel.star]).
# LEFT OUTER JOIN "emails"
join(email_table, Arel::Nodes::OuterJoin).
# ON "users"."id" = "emails"."user_id"
on(user_table[:id].eq(email_table[:user_id])).
# WHERE ("user"."email" = '<email>' OR "emails"."email" = '<email>')
where(user_table[:email].eq(email).or(email_table[:email].eq(email)))
find_by_sql(query.to_sql).first
User.find_by_sql([sql, { email: email }]).first
end
def existing_member?(email)
......@@ -429,16 +424,18 @@ class User < ActiveRecord::Base
end
end
def authorized_projects_id
@authorized_projects_id ||= begin
project_ids = personal_projects.pluck(:id)
project_ids.push(*groups_projects.pluck(:id))
project_ids.push(*projects.pluck(:id).uniq)
project_ids.push(*groups.joins(:shared_projects).pluck(:project_id))
end
end
# Projects user has access to
def authorized_projects
@authorized_projects ||= begin
project_ids = personal_projects.pluck(:id)
project_ids.push(*groups_projects.pluck(:id))
project_ids.push(*projects.pluck(:id).uniq)
project_ids.push(*groups.joins(:shared_projects).pluck(:project_id))
Project.where(id: project_ids)
end
@authorized_projects ||= Project.where(id: authorized_projects_id)
end
def owned_projects
......@@ -801,11 +798,14 @@ class User < ActiveRecord::Base
end
def ci_authorized_projects
@ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects)
@ci_authorized_projects ||= Ci::Project.where(gitlab_id: authorized_projects_id)
end
def ci_authorized_runners
Ci::Runner.specific.includes(:runner_projects).
where(ci_runner_projects: { project_id: ci_authorized_projects } )
@ci_authorized_runners ||= begin
runner_ids = Ci::RunnerProject.joins(:project).
where(ci_projects: { gitlab_id: authorized_projects_id }).select(:runner_id)
Ci::Runner.specific.where(id: runner_ids)
end
end
end
module Ci
class ImageForBuildService
def execute(project, params)
image_name =
if params[:sha]
commit = project.commits.find_by(sha: params[:sha])
image_for_commit(commit)
elsif params[:ref]
commit = project.last_commit_for_ref(params[:ref])
image_for_commit(commit)
else
'build-unknown.svg'
sha = params[:sha]
sha ||=
if params[:ref]
project.gl_project.commit(params[:ref]).try(:sha)
end
commit = project.commits.ordered.find_by(sha: sha)
image_name = image_for_commit(commit)
image_path = Rails.root.join('public/ci', image_name)
OpenStruct.new(
......
......@@ -5,5 +5,16 @@ module Files
def commit
repository.commit_dir(current_user, @file_path, @commit_message, @target_branch)
end
def validate
super
unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error(
'Your changes could not be committed, because the file path ' +
Gitlab::Regex.file_path_regex_message
)
end
end
end
end
......@@ -9,12 +9,17 @@ module Files
def validate
super
file_name = File.basename(@file_path)
if @file_path =~ Gitlab::Regex.directory_traversal_regex
raise_error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.directory_traversal_regex_message
)
end
unless file_name =~ Gitlab::Regex.file_name_regex
unless @file_path =~ Gitlab::Regex.file_path_regex
raise_error(
'Your changes could not be committed, because the file name ' +
Gitlab::Regex.file_name_regex_message
Gitlab::Regex.file_path_regex_message
)
end
......
......@@ -35,7 +35,7 @@ module Issues
create_title_change_note(issue, issue.previous_changes['title'].first)
end
issue.create_new_cross_references!
issue.create_new_cross_references!(current_user)
execute_hooks(issue, 'update')
end
......
......@@ -59,7 +59,7 @@ module MergeRequests
merge_request.mark_as_unchecked
end
merge_request.create_new_cross_references!
merge_request.create_new_cross_references!(current_user)
execute_hooks(merge_request, 'update')
end
......
......@@ -4,7 +4,7 @@ module Notes
return note unless note.editable?
note.update_attributes(params.merge(updated_by: current_user))
note.create_new_cross_references!
note.create_new_cross_references!(current_user)
note.reset_events_cache
note
......
......@@ -94,8 +94,6 @@ module Projects
@project.team << [current_user, :master, current_user]
end
@project.update_column(:last_activity_at, @project.created_at)
if @project.import?
@project.import_start
end
......
%p.lead
To register new runner visit #{link_to 'this page ', ci_runners_path}
To register a new runner visit #{link_to 'this page ', ci_runners_path}
.row
.col-md-8
......
%p.lead
%span To register new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
%span To register a new runner you should enter the following registration token. With this token the runner will request a unique runner token and use that for future communication.
%code #{GitlabCi::REGISTRATION_TOKEN}
.bs-callout
......@@ -21,7 +21,7 @@
\- run builds from assigned projects
%li
%span.label.label-danger paused
\- runner will not receive any new build
\- runner will not receive any new builds
.append-bottom-20.clearfix
.pull-left
......
......@@ -13,13 +13,13 @@
- if @runner.shared?
.bs-callout.bs-callout-success
%h4 This runner will process build from ALL UNASSIGNED projects
%h4 This runner will process builds from ALL UNASSIGNED projects
%p
If you want runners to build only specific projects, enable them in the table below.
Keep in mind that this is a one way transition.
- else
.bs-callout.bs-callout-info
%h4 This runner will process build only from ASSIGNED projects
%h4 This runner will process builds only from ASSIGNED projects
%p You can't make this a shared runner.
%hr
= form_for @runner, url: ci_admin_runner_path(@runner), html: { class: 'form-horizontal' } do |f|
......@@ -53,13 +53,14 @@
%th
- @runner.runner_projects.each do |runner_project|
- project = runner_project.project
%tr.alert-info
%td
%strong
= project.name
%td
.pull-right
= link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
- if project.gl_project
%tr.alert-info
%td
%strong
= project.name
%td
.pull-right
= link_to 'Disable', [:ci, :admin, project, runner_project], method: :delete, class: 'btn btn-danger btn-xs'
%table.table
%thead
......@@ -103,21 +104,26 @@
%th Finished at
- @builds.each do |build|
- gl_project = build.gl_project
%tr.build
%td.id
- gl_project = build.project.gl_project
= link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
- if gl_project
= link_to namespace_project_build_path(gl_project.namespace, gl_project, build) do
= build.id
- else
= build.id
%td.status
= ci_status_with_icon(build.status)
%td.status
= build.project.name
- if gl_project
= gl_project.name_with_namespace
%td.build-link
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
- if gl_project
= link_to ci_status_path(build.commit) do
%strong #{build.commit.short_sha}
%td.timestamp
- if build.finished_at
......
%h3.page-title Events
.table-holder
%table.table
%thead
%tr
%th User ID
%th Description
%th When
- @events.each do |event|
%tr
%td
= event.user_id
%td
= event.description
%td.light
= time_ago_in_words event.updated_at
ago
= paginate @events
......@@ -17,7 +17,7 @@
%td #{stage.capitalize} Job - #{build[:name]}
%td
%pre
= simple_format build[:script]
= simple_format build[:commands]
%br
%b Tag list:
......@@ -28,6 +28,11 @@
%br
%b Refs except:
= build[:except] && build[:except].join(", ")
%br
%b When:
= build[:when]
- if build[:allow_failure]
%b Allowed to fail
-else
%p
......
.login-block
%h2 Login using GitLab account
%p.light
Make sure you have account on GitLab server
Make sure you have an account on the GitLab server
= link_to GitlabCi.config.gitlab_server.url, GitlabCi.config.gitlab_server.url, no_turbolink
%hr
= link_to "Login with GitLab", auth_ci_user_sessions_path(state: params[:state]), no_turbolink.merge( class: 'btn btn-login btn-success' )
......@@ -43,6 +43,15 @@
= f.check_box :share_with_group_lock
%span.descr Prevent sharing a project with another group within this group
.form-group
%hr
= f.label :public, class: 'control-label' do
Public
.col-sm-10
.checkbox
= f.check_box :public
%span.descr Make this group public (even if there is no any public project inside this group)
.form-actions
= f.submit 'Save group', class: "btn btn-save"
......
......@@ -11,6 +11,8 @@
= hidden_field_tag :scope, 'merge_requests'
- elsif current_controller?(:wikis)
= hidden_field_tag :scope, 'wiki_blobs'
- elsif current_controller?(:commits)
= hidden_field_tag :scope, 'commits'
- else
= hidden_field_tag :search_code, true
......
!!! 5
%html{ lang: "en"}
= render 'layouts/head'
%body{class: "ci-body #{user_application_theme}", 'data-page' => body_data_page}
- header_title @project.name, ci_project_path(@project)
- if current_user
= render "layouts/header/default", title: header_title
- else
= render "layouts/header/public", title: header_title
= render 'layouts/ci/page', sidebar: 'nav_project'
%ul.nav.nav-sidebar
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to dashboard
Go to dashboard
%li.separate-item
......
%ul.nav.nav-sidebar
= nav_link do
= link_to group_path(@group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
= link_to group_path(@group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to group
Go to group
%li.separate-item
......
%ul.nav.nav-sidebar
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to dashboard
Go to dashboard
%li.separate-item
......
%ul.nav.nav-sidebar
- if @project.group
= nav_link do
= link_to group_path(@project.group), title: 'Back to group', data: {placement: 'right'}, class: 'back-link' do
= link_to group_path(@project.group), title: 'Go to group', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to group
Go to group
- else
= nav_link do
= link_to root_path, title: 'Back to dashboard', data: {placement: 'right'}, class: 'back-link' do
= link_to root_path, title: 'Go to dashboard', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to dashboard
Go to dashboard
%li.separate-item
......
%ul.nav.nav-sidebar
= nav_link do
= link_to project_path(@project), title: 'Back to project', data: {placement: 'right'}, class: 'back-link' do
= link_to project_path(@project), title: 'Go to project', data: {placement: 'right'}, class: 'back-link' do
= icon('caret-square-o-left fw')
%span
Back to project
Go to project
%li.separate-item
......@@ -81,8 +81,3 @@
= icon('share fw')
%span
CI Services
= nav_link path: 'events#index' do
= link_to ci_project_events_path(@project.gitlab_ci_project) do
= icon('book fw')
%span
CI Events
......@@ -155,7 +155,7 @@
- if @builds.present?
.build-widget
%h4.title #{pluralize(@builds.count, "other build")} for #{@build.short_sha}:
%h4.title #{pluralize(@builds.count(:id), "other build")} for #{@build.short_sha}:
%table.table.builds
- @builds.each_with_index do |build, i|
%tr.build
......
......@@ -20,6 +20,10 @@
New snippet
- if can?(current_user, :push_code, @project)
%li.divider
%li
= link_to namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'), title: 'New file' do
= icon('file fw')
New file
%li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do
= icon('code-fork fw')
......
......@@ -102,7 +102,7 @@
%code \(\d+.\d+\%\) covered
%li
pytest-cov (Python) -
%code \d+\%$
%code \d+\%\s*$
......
......@@ -5,4 +5,4 @@
You can add Specific runner for this project on Runners page
- if current_user.admin
or add Shared runner for whole application in admin are.
or add Shared runner for whole application in admin area.
......@@ -18,10 +18,10 @@
.pull-right
- if ci_commit
= link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}" do
= ci_status_icon(ci_commit)
= render_ci_status(ci_commit)
&nbsp;
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
= clipboard_button
= link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id", data: {clipboard_text: commit.id}
.notes_count
- if note_count > 0
......
......@@ -17,8 +17,10 @@
- @participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.col-md-3
%span.slead.has_tooltip{title: 'Cross-project reference'}
= cross_project_reference(@project, @issue)
.input-group.cross-project-reference
%span.slead.has_tooltip{title: 'Cross-project reference'}
= cross_project_reference(@project, @issue)
= clipboard_button
.row
%section.col-md-9
......
- if @project.labels.size == 0
$('.labels').load(document.URL + ' .light-well').hide().fadeIn(1000)
$('.labels').load(document.URL + ' .nothing-here-block').hide().fadeIn(1000)
......@@ -14,8 +14,8 @@
= render @labels
= paginate @labels, theme: 'gitlab'
- else
.light-well
.nothing-here-block
- if can? current_user, :admin_label, @project
.nothing-here-block Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
Create first label or #{link_to 'generate', generate_namespace_project_labels_path(@project.namespace, @project), method: :post} default set of labels
- else
.nothing-here-block No labels created
No labels created
- ci_commit = merge_request.ci_commit
%li{ class: mr_css_classes(merge_request) }
.merge-request-title
%span.merge-request-title-text
......@@ -6,6 +7,8 @@
- merge_request.labels.each do |label|
= link_to_label(label, project: merge_request.project)
.pull-right.light
- if ci_commit
= render_ci_status(ci_commit)
- if merge_request.merged?
%span
%i.fa.fa-check
......
......@@ -3,11 +3,12 @@
.modal-content
.modal-header
%a.close{href: "#", "data-dismiss" => "modal"} ×
%h3 Check out, review and merge locally
%h3 Check out, review, and merge locally
.modal-body
%p
%strong Step 1.
%strong Step 1.
Fetch and check out the branch for this merge request
= clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
......@@ -24,6 +25,7 @@
%p
%strong Step 3.
Merge the branch and fix any conflicts that come up
= clipboard_button
%pre.dark
- if @merge_request.for_fork?
:preserve
......@@ -36,6 +38,7 @@
%p
%strong Step 4.
Push the result of the merge to GitLab
= clipboard_button
%pre.dark
:preserve
git push origin #{h @merge_request.target_branch}
......
- ci_commit = @merge_request.source_project.ci_commit(@merge_request.source_sha)
- ci_commit = @merge_request.ci_commit
- if ci_commit
- status = ci_commit.status
.mr-widget-heading
......
......@@ -42,6 +42,13 @@
Wiki
%span.badge
= @search_results.wiki_blobs_count
%li{class: ("active" if @scope == 'commits')}
= link_to search_filter_path(scope: 'commits') do
= icon('history fw')
%span
Commits
%span.badge
= @search_results.commits_count
- elsif @show_snippets
%li{class: ("active" if @scope == 'snippet_blobs')}
......
.search-result-row
= render 'projects/commits/commit', project: @project, commit: commit
......@@ -21,9 +21,7 @@
.project-controls
- if ci && !project.empty_repo? && project.commit
- if ci_commit = project.ci_commit(project.commit.sha)
= link_to ci_status_path(ci_commit), class: "c#{ci_status_color(ci_commit)}",
title: "Build status: #{ci_commit.status}", data: {toggle: 'tooltip', placement: 'left'} do
= ci_status_icon(ci_commit)
= render_ci_status(ci_commit)
&nbsp;
- if stars
%span
......
= link_to new_snippet_path, class: 'btn btn-grouped new-snippet-link', title: "New Snippet" do
= icon('plus')
New Snippet
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
- if can?(current_user, :update_personal_snippet, @snippet)
= link_to edit_snippet_path(@snippet), class: "btn btn-grouped snippable-edit" do
= icon('pencil-square-o')
Edit
- if can?(current_user, :admin_personal_snippet, @snippet)
= link_to snippet_path(@snippet), method: :delete, data: { confirm: "Are you sure?" }, class: "btn btn-grouped btn-remove", title: 'Delete Snippet' do
= icon('trash-o')
Delete
- if local_assigns.has_key?(:contributed_projects) && contributed_projects.present?
.panel.panel-default.contributed-projects
.panel-heading Projects contributed to
= render 'shared/projects/list',
projects: contributed_projects.sort_by(&:star_count).reverse,
projects_limit: 5, stars: true, avatar: false
- if local_assigns.has_key?(:projects) && projects.present?
.panel.panel-default
.panel-heading Personal projects
= render 'shared/projects/list',
projects: projects.sort_by(&:star_count).reverse,
projects_limit: 10, stars: true, avatar: false
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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