Commit 1984697b authored by Kamil Trzcinski's avatar Kamil Trzcinski

Merge remote-tracking branch 'origin/master' into improve-pipeline-processing

parents 4ccf39cd ded2b367
image: "ruby:2.1" image: "ruby:2.3"
cache: cache:
key: "ruby21" key: "ruby-23"
paths: paths:
- vendor/apt - vendor/apt
- vendor/ruby - vendor/ruby
...@@ -138,57 +138,57 @@ spinach 7 10: *spinach-knapsack ...@@ -138,57 +138,57 @@ spinach 7 10: *spinach-knapsack
spinach 8 10: *spinach-knapsack spinach 8 10: *spinach-knapsack
spinach 9 10: *spinach-knapsack spinach 9 10: *spinach-knapsack
# Execute all testing suites against Ruby 2.3 # Execute all testing suites against Ruby 2.1
.ruby-23: &ruby-23 .ruby-21: &ruby-21
image: "ruby:2.3" image: "ruby:2.1"
<<: *use-db <<: *use-db
only: only:
- master - master
cache: cache:
key: "ruby-23" key: "ruby21"
paths: paths:
- vendor/apt - vendor/apt
- vendor/ruby - vendor/ruby
.rspec-knapsack-ruby23: &rspec-knapsack-ruby23 .rspec-knapsack-ruby21: &rspec-knapsack-ruby21
<<: *rspec-knapsack <<: *rspec-knapsack
<<: *ruby-23 <<: *ruby-21
.spinach-knapsack-ruby23: &spinach-knapsack-ruby23 .spinach-knapsack-ruby21: &spinach-knapsack-ruby21
<<: *spinach-knapsack <<: *spinach-knapsack
<<: *ruby-23 <<: *ruby-21
rspec 0 20 ruby23: *rspec-knapsack-ruby23 rspec 0 20 ruby21: *rspec-knapsack-ruby21
rspec 1 20 ruby23: *rspec-knapsack-ruby23 rspec 1 20 ruby21: *rspec-knapsack-ruby21
rspec 2 20 ruby23: *rspec-knapsack-ruby23 rspec 2 20 ruby21: *rspec-knapsack-ruby21
rspec 3 20 ruby23: *rspec-knapsack-ruby23 rspec 3 20 ruby21: *rspec-knapsack-ruby21
rspec 4 20 ruby23: *rspec-knapsack-ruby23 rspec 4 20 ruby21: *rspec-knapsack-ruby21
rspec 5 20 ruby23: *rspec-knapsack-ruby23 rspec 5 20 ruby21: *rspec-knapsack-ruby21
rspec 6 20 ruby23: *rspec-knapsack-ruby23 rspec 6 20 ruby21: *rspec-knapsack-ruby21
rspec 7 20 ruby23: *rspec-knapsack-ruby23 rspec 7 20 ruby21: *rspec-knapsack-ruby21
rspec 8 20 ruby23: *rspec-knapsack-ruby23 rspec 8 20 ruby21: *rspec-knapsack-ruby21
rspec 9 20 ruby23: *rspec-knapsack-ruby23 rspec 9 20 ruby21: *rspec-knapsack-ruby21
rspec 10 20 ruby23: *rspec-knapsack-ruby23 rspec 10 20 ruby21: *rspec-knapsack-ruby21
rspec 11 20 ruby23: *rspec-knapsack-ruby23 rspec 11 20 ruby21: *rspec-knapsack-ruby21
rspec 12 20 ruby23: *rspec-knapsack-ruby23 rspec 12 20 ruby21: *rspec-knapsack-ruby21
rspec 13 20 ruby23: *rspec-knapsack-ruby23 rspec 13 20 ruby21: *rspec-knapsack-ruby21
rspec 14 20 ruby23: *rspec-knapsack-ruby23 rspec 14 20 ruby21: *rspec-knapsack-ruby21
rspec 15 20 ruby23: *rspec-knapsack-ruby23 rspec 15 20 ruby21: *rspec-knapsack-ruby21
rspec 16 20 ruby23: *rspec-knapsack-ruby23 rspec 16 20 ruby21: *rspec-knapsack-ruby21
rspec 17 20 ruby23: *rspec-knapsack-ruby23 rspec 17 20 ruby21: *rspec-knapsack-ruby21
rspec 18 20 ruby23: *rspec-knapsack-ruby23 rspec 18 20 ruby21: *rspec-knapsack-ruby21
rspec 19 20 ruby23: *rspec-knapsack-ruby23 rspec 19 20 ruby21: *rspec-knapsack-ruby21
spinach 0 10 ruby23: *spinach-knapsack-ruby23 spinach 0 10 ruby21: *spinach-knapsack-ruby21
spinach 1 10 ruby23: *spinach-knapsack-ruby23 spinach 1 10 ruby21: *spinach-knapsack-ruby21
spinach 2 10 ruby23: *spinach-knapsack-ruby23 spinach 2 10 ruby21: *spinach-knapsack-ruby21
spinach 3 10 ruby23: *spinach-knapsack-ruby23 spinach 3 10 ruby21: *spinach-knapsack-ruby21
spinach 4 10 ruby23: *spinach-knapsack-ruby23 spinach 4 10 ruby21: *spinach-knapsack-ruby21
spinach 5 10 ruby23: *spinach-knapsack-ruby23 spinach 5 10 ruby21: *spinach-knapsack-ruby21
spinach 6 10 ruby23: *spinach-knapsack-ruby23 spinach 6 10 ruby21: *spinach-knapsack-ruby21
spinach 7 10 ruby23: *spinach-knapsack-ruby23 spinach 7 10 ruby21: *spinach-knapsack-ruby21
spinach 8 10 ruby23: *spinach-knapsack-ruby23 spinach 8 10 ruby21: *spinach-knapsack-ruby21
spinach 9 10 ruby23: *spinach-knapsack-ruby23 spinach 9 10 ruby21: *spinach-knapsack-ruby21
# Other generic tests # Other generic tests
......
...@@ -5,6 +5,8 @@ v 8.11.0 (unreleased) ...@@ -5,6 +5,8 @@ v 8.11.0 (unreleased)
- Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres) - Fix don't pass a local variable called `i` to a partial. !20510 (herminiotorres)
- Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres) - Fix rename `add_users_into_project` and `projects_ids`. !20512 (herminiotorres)
- Fix the title of the toggle dropdown button. !5515 (herminiotorres) - Fix the title of the toggle dropdown button. !5515 (herminiotorres)
- Rename `markdown_preview` routes to `preview_markdown`. (Christopher Bartz)
- Update to Ruby 2.3.1. !4948
- Improve diff performance by eliminating redundant checks for text blobs - Improve diff performance by eliminating redundant checks for text blobs
- Ensure that branch names containing escapable characters (e.g. %20) aren't unescaped indiscriminately. !5770 (ewiltshi) - Ensure that branch names containing escapable characters (e.g. %20) aren't unescaped indiscriminately. !5770 (ewiltshi)
- Convert switch icon into icon font (ClemMakesApps) - Convert switch icon into icon font (ClemMakesApps)
...@@ -22,6 +24,7 @@ v 8.11.0 (unreleased) ...@@ -22,6 +24,7 @@ v 8.11.0 (unreleased)
- Cache highlighted diff lines for merge requests - Cache highlighted diff lines for merge requests
- Pre-create all builds for a Pipeline when the new Pipeline is created !5295 - Pre-create all builds for a Pipeline when the new Pipeline is created !5295
- Fix of 'Commits being passed to custom hooks are already reachable when using the UI' - Fix of 'Commits being passed to custom hooks are already reachable when using the UI'
- Show member roles to all users on members page
- Fix awardable button mutuality loading spinners (ClemMakesApps) - Fix awardable button mutuality loading spinners (ClemMakesApps)
- Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable - Add support for using RequestStore within Sidekiq tasks via SIDEKIQ_REQUEST_STORE env variable
- Optimize maximum user access level lookup in loading of notes - Optimize maximum user access level lookup in loading of notes
...@@ -101,6 +104,7 @@ v 8.11.0 (unreleased) ...@@ -101,6 +104,7 @@ v 8.11.0 (unreleased)
- Fix importing GitLab projects with an invalid MR source project - Fix importing GitLab projects with an invalid MR source project
- Sort folders with submodules in Files view !5521 - Sort folders with submodules in Files view !5521
- Each `File::exists?` replaced to `File::exist?` because of deprecate since ruby version 2.2.0 - Each `File::exists?` replaced to `File::exist?` because of deprecate since ruby version 2.2.0
- Print urls to create (or view) merge requests after git push !5542 (Scott Le)
v 8.10.5 v 8.10.5
- Add a data migration to fix some missing timestamps in the members table. !5670 - Add a data migration to fix some missing timestamps in the members table. !5670
......
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'rails', '4.2.7' gem 'rails', '4.2.7.1'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
# Responders respond_to and respond_with # Responders respond_to and respond_with
......
...@@ -3,34 +3,34 @@ GEM ...@@ -3,34 +3,34 @@ GEM
specs: specs:
RedCloth (4.3.2) RedCloth (4.3.2)
ace-rails-ap (4.0.2) ace-rails-ap (4.0.2)
actionmailer (4.2.7) actionmailer (4.2.7.1)
actionpack (= 4.2.7) actionpack (= 4.2.7.1)
actionview (= 4.2.7) actionview (= 4.2.7.1)
activejob (= 4.2.7) activejob (= 4.2.7.1)
mail (~> 2.5, >= 2.5.4) mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
actionpack (4.2.7) actionpack (4.2.7.1)
actionview (= 4.2.7) actionview (= 4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
rack (~> 1.6) rack (~> 1.6)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
actionview (4.2.7) actionview (4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
builder (~> 3.1) builder (~> 3.1)
erubis (~> 2.7.0) erubis (~> 2.7.0)
rails-dom-testing (~> 1.0, >= 1.0.5) rails-dom-testing (~> 1.0, >= 1.0.5)
rails-html-sanitizer (~> 1.0, >= 1.0.2) rails-html-sanitizer (~> 1.0, >= 1.0.2)
activejob (4.2.7) activejob (4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
globalid (>= 0.3.0) globalid (>= 0.3.0)
activemodel (4.2.7) activemodel (4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
builder (~> 3.1) builder (~> 3.1)
activerecord (4.2.7) activerecord (4.2.7.1)
activemodel (= 4.2.7) activemodel (= 4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
arel (~> 6.0) arel (~> 6.0)
activerecord-session_store (1.0.0) activerecord-session_store (1.0.0)
actionpack (>= 4.0, < 5.1) actionpack (>= 4.0, < 5.1)
...@@ -38,7 +38,7 @@ GEM ...@@ -38,7 +38,7 @@ GEM
multi_json (~> 1.11, >= 1.11.2) multi_json (~> 1.11, >= 1.11.2)
rack (>= 1.5.2, < 3) rack (>= 1.5.2, < 3)
railties (>= 4.0, < 5.1) railties (>= 4.0, < 5.1)
activesupport (4.2.7) activesupport (4.2.7.1)
i18n (~> 0.7) i18n (~> 0.7)
json (~> 1.7, >= 1.7.7) json (~> 1.7, >= 1.7.7)
minitest (~> 5.1) minitest (~> 5.1)
...@@ -289,7 +289,7 @@ GEM ...@@ -289,7 +289,7 @@ GEM
omniauth (~> 1.0) omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1) pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.3) rubyntlm (~> 0.3)
globalid (0.3.6) globalid (0.3.7)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
gollum-grit_adapter (1.0.1) gollum-grit_adapter (1.0.1)
gitlab-grit (~> 2.7, >= 2.7.1) gitlab-grit (~> 2.7, >= 2.7.1)
...@@ -518,16 +518,16 @@ GEM ...@@ -518,16 +518,16 @@ GEM
rack rack
rack-test (0.6.3) rack-test (0.6.3)
rack (>= 1.0) rack (>= 1.0)
rails (4.2.7) rails (4.2.7.1)
actionmailer (= 4.2.7) actionmailer (= 4.2.7.1)
actionpack (= 4.2.7) actionpack (= 4.2.7.1)
actionview (= 4.2.7) actionview (= 4.2.7.1)
activejob (= 4.2.7) activejob (= 4.2.7.1)
activemodel (= 4.2.7) activemodel (= 4.2.7.1)
activerecord (= 4.2.7) activerecord (= 4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
bundler (>= 1.3.0, < 2.0) bundler (>= 1.3.0, < 2.0)
railties (= 4.2.7) railties (= 4.2.7.1)
sprockets-rails sprockets-rails
rails-deprecated_sanitizer (1.0.3) rails-deprecated_sanitizer (1.0.3)
activesupport (>= 4.2.0.alpha) activesupport (>= 4.2.0.alpha)
...@@ -537,9 +537,9 @@ GEM ...@@ -537,9 +537,9 @@ GEM
rails-deprecated_sanitizer (>= 1.0.1) rails-deprecated_sanitizer (>= 1.0.1)
rails-html-sanitizer (1.0.3) rails-html-sanitizer (1.0.3)
loofah (~> 2.0) loofah (~> 2.0)
railties (4.2.7) railties (4.2.7.1)
actionpack (= 4.2.7) actionpack (= 4.2.7.1)
activesupport (= 4.2.7) activesupport (= 4.2.7.1)
rake (>= 0.8.7) rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0) thor (>= 0.18.1, < 2.0)
rainbow (2.1.0) rainbow (2.1.0)
...@@ -914,7 +914,7 @@ DEPENDENCIES ...@@ -914,7 +914,7 @@ DEPENDENCIES
rack-attack (~> 4.3.1) rack-attack (~> 4.3.1)
rack-cors (~> 0.4.0) rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1) rack-oauth2 (~> 1.2.1)
rails (= 4.2.7) rails (= 4.2.7.1)
rails-deprecated_sanitizer (~> 1.0.3) rails-deprecated_sanitizer (~> 1.0.3)
rainbow (~> 2.1.0) rainbow (~> 2.1.0)
rblineprof (~> 0.3.6) rblineprof (~> 0.3.6)
......
/*= require markdown_preview */ /*= require preview_markdown */
(function() { (function() {
this.DropzoneInput = (function() { this.DropzoneInput = (function() {
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
}; };
MarkdownPreview.prototype.renderMarkdown = function(text, success) { MarkdownPreview.prototype.renderMarkdown = function(text, success) {
if (!window.markdown_preview_path) { if (!window.preview_markdown_path) {
return; return;
} }
if (text === this.ajaxCache.text) { if (text === this.ajaxCache.text) {
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
} }
return $.ajax({ return $.ajax({
type: 'POST', type: 'POST',
url: window.markdown_preview_path, url: window.preview_markdown_path,
data: { data: {
text: text text: text
}, },
......
...@@ -91,7 +91,7 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -91,7 +91,7 @@ class Projects::WikisController < Projects::ApplicationController
) )
end end
def markdown_preview def preview_markdown
text = params[:text] text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user) ext = Gitlab::ReferenceExtractor.new(@project, current_user)
......
...@@ -238,7 +238,7 @@ class ProjectsController < Projects::ApplicationController ...@@ -238,7 +238,7 @@ class ProjectsController < Projects::ApplicationController
} }
end end
def markdown_preview def preview_markdown
text = params[:text] text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user) ext = Gitlab::ReferenceExtractor.new(@project, current_user)
......
...@@ -6,12 +6,6 @@ module MembersHelper ...@@ -6,12 +6,6 @@ module MembersHelper
"#{action}_#{member.type.underscore}".to_sym "#{action}_#{member.type.underscore}".to_sym
end end
def default_show_roles(member)
can?(current_user, action_member_permission(:update, member), member) ||
can?(current_user, action_member_permission(:destroy, member), member) ||
can?(current_user, action_member_permission(:admin, member), member.source)
end
def remove_member_message(member, user: nil) def remove_member_message(member, user: nil)
user = current_user if defined?(current_user) user = current_user if defined?(current_user)
......
...@@ -104,6 +104,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -104,6 +104,7 @@ class MergeRequest < ActiveRecord::Base
scope :from_project, ->(project) { where(source_project_id: project.id) } scope :from_project, ->(project) { where(source_project_id: project.id) }
scope :merged, -> { with_state(:merged) } scope :merged, -> { with_state(:merged) }
scope :closed_and_merged, -> { with_states(:closed, :merged) } scope :closed_and_merged, -> { with_states(:closed, :merged) }
scope :from_source_branches, ->(branches) { where(source_branch: branches) }
scope :join_project, -> { joins(:target_project) } scope :join_project, -> { joins(:target_project) }
scope :references_project, -> { references(:target_project) } scope :references_project, -> { references(:target_project) }
......
module MergeRequests
class GetUrlsService < BaseService
attr_reader :project
def initialize(project)
@project = project
end
def execute(changes)
branches = get_branches(changes)
merge_requests_map = opened_merge_requests_from_source_branches(branches)
branches.map do |branch|
existing_merge_request = merge_requests_map[branch]
if existing_merge_request
url_for_existing_merge_request(existing_merge_request)
else
url_for_new_merge_request(branch)
end
end
end
private
def opened_merge_requests_from_source_branches(branches)
merge_requests = MergeRequest.from_project(project).opened.from_source_branches(branches)
merge_requests.inject({}) do |hash, mr|
hash[mr.source_branch] = mr
hash
end
end
def get_branches(changes)
changes_list = Gitlab::ChangesList.new(changes)
changes_list.map do |change|
next unless Gitlab::Git.branch_ref?(change[:ref])
Gitlab::Git.branch_name(change[:ref])
end.compact
end
def url_for_new_merge_request(branch_name)
merge_request_params = { source_branch: branch_name }
url = Gitlab::Routing.url_helpers.new_namespace_project_merge_request_url(project.namespace, project, merge_request: merge_request_params)
{ branch_name: branch_name, url: url, new_merge_request: true }
end
def url_for_existing_merge_request(merge_request)
target_project = merge_request.target_project
url = Gitlab::Routing.url_helpers.namespace_project_merge_request_url(target_project.namespace, target_project, merge_request)
{ branch_name: merge_request.source_branch, url: url, new_merge_request: false }
end
end
end
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
- content_for :scripts_body_top do - content_for :scripts_body_top do
- project = @target_project || @project - project = @target_project || @project
- if @project_wiki && @page - if @project_wiki && @page
- markdown_preview_path = namespace_project_wiki_markdown_preview_path(project.namespace, project, @page.slug) - preview_markdown_path = namespace_project_wiki_preview_markdown_path(project.namespace, project, @page.slug)
- else - else
- markdown_preview_path = markdown_preview_namespace_project_path(project.namespace, project) - preview_markdown_path = preview_markdown_namespace_project_path(project.namespace, project)
- if current_user - if current_user
:javascript :javascript
window.project_uploads_path = "#{namespace_project_uploads_path project.namespace,project}"; window.project_uploads_path = "#{namespace_project_uploads_path project.namespace,project}";
window.markdown_preview_path = "#{markdown_preview_path}"; window.preview_markdown_path = "#{preview_markdown_path}";
- content_for :scripts_body do - content_for :scripts_body do
= render "layouts/init_auto_complete" if current_user = render "layouts/init_auto_complete" if current_user
......
- show_roles = local_assigns.fetch(:show_roles, default_show_roles(member)) - show_roles = local_assigns.fetch(:show_roles, true)
- show_controls = local_assigns.fetch(:show_controls, true) - show_controls = local_assigns.fetch(:show_controls, true)
- user = member.user - user = member.user
......
...@@ -468,7 +468,7 @@ Rails.application.routes.draw do ...@@ -468,7 +468,7 @@ Rails.application.routes.draw do
post :unarchive post :unarchive
post :housekeeping post :housekeeping
post :toggle_star post :toggle_star
post :markdown_preview post :preview_markdown
post :export post :export
post :remove_export post :remove_export
post :generate_new_export post :generate_new_export
...@@ -672,7 +672,7 @@ Rails.application.routes.draw do ...@@ -672,7 +672,7 @@ Rails.application.routes.draw do
get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID get '/wikis/*id', to: 'wikis#show', as: 'wiki', constraints: WIKI_SLUG_ID
delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID delete '/wikis/*id', to: 'wikis#destroy', constraints: WIKI_SLUG_ID
put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID put '/wikis/*id', to: 'wikis#update', constraints: WIKI_SLUG_ID
post '/wikis/*id/markdown_preview', to: 'wikis#markdown_preview', constraints: WIKI_SLUG_ID, as: 'wiki_markdown_preview' post '/wikis/*id/preview_markdown', to: 'wikis#preview_markdown', constraints: WIKI_SLUG_ID, as: 'wiki_preview_markdown'
end end
resource :repository, only: [:create] do resource :repository, only: [:create] do
......
...@@ -108,8 +108,7 @@ Then select 'Internet Site' and press enter to confirm the hostname. ...@@ -108,8 +108,7 @@ Then select 'Internet Site' and press enter to confirm the hostname.
## 2. Ruby ## 2. Ruby
_**Note:** The current supported Ruby version is 2.1.x. Ruby 2.2 and 2.3 are _**Note:** The current supported Ruby versions are 2.1.x and 2.3.x. 2.3.x is preferred, and support for 2.1.x will be dropped in the future.
currently not supported._
The use of Ruby version managers such as [RVM], [rbenv] or [chruby] with GitLab The use of Ruby version managers such as [RVM], [rbenv] or [chruby] with GitLab
in production, frequently leads to hard to diagnose problems. For example, in production, frequently leads to hard to diagnose problems. For example,
...@@ -124,9 +123,9 @@ Remove the old Ruby 1.8 if present: ...@@ -124,9 +123,9 @@ Remove the old Ruby 1.8 if present:
Download Ruby and compile it: Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby mkdir /tmp/ruby && cd /tmp/ruby
curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.1/ruby-2.1.8.tar.gz curl --remote-name --progress https://cache.ruby-lang.org/pub/ruby/2.3/ruby-2.3.1.tar.gz
echo 'c7e50159357afd87b13dc5eaf4ac486a70011149 ruby-2.1.8.tar.gz' | shasum -c - && tar xzf ruby-2.1.8.tar.gz echo 'c39b4001f7acb4e334cb60a0f4df72d434bef711 ruby-2.3.1.tar.gz' | shasum -c - && tar xzf ruby-2.3.1.tar.gz
cd ruby-2.1.8 cd ruby-2.3.1
./configure --disable-install-rdoc ./configure --disable-install-rdoc
make make
sudo make install sudo make install
...@@ -591,13 +590,13 @@ for the changes to take effect. ...@@ -591,13 +590,13 @@ for the changes to take effect.
If you'd like to connect to a Redis server on a non-standard port or on a different host, you can configure its connection string via the `config/resque.yml` file. If you'd like to connect to a Redis server on a non-standard port or on a different host, you can configure its connection string via the `config/resque.yml` file.
# example # example
production: production:
url: redis://redis.example.tld:6379 url: redis://redis.example.tld:6379
If you want to connect the Redis server via socket, then use the "unix:" URL scheme and the path to the Redis socket file in the `config/resque.yml` file. If you want to connect the Redis server via socket, then use the "unix:" URL scheme and the path to the Redis socket file in the `config/resque.yml` file.
# example # example
production: production:
url: unix:/path/to/redis/socket url: unix:/path/to/redis/socket
### Custom SSH Connection ### Custom SSH Connection
......
...@@ -6,13 +6,17 @@ You accept and agree to the following terms and conditions for Your present and ...@@ -6,13 +6,17 @@ You accept and agree to the following terms and conditions for Your present and
"You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with GitLab B.V.. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"Contribution" shall mean the code, documentation or other original works of authorship expressly identified in Schedule B, as well as any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution." "Contribution" shall mean the code, documentation or other original works of authorship, including any modifications or additions to an existing work, that is submitted by You to GitLab B.V. for inclusion in, or documentation of, any of the products owned or managed by GitLab B.V. (the "Work"). For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to GitLab B.V. or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, GitLab B.V. for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as "Not a Contribution."
2. Grant of Copyright License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works. 2. Grant of Copyright License.
3. Grant of Patent License. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare derivative works of, publicly display, publicly perform, sublicense, and distribute Your Contributions and such derivative works.
4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation designated on Schedule A below (or in a subsequent written modification to that Schedule) is authorized to submit Contributions on behalf of the Corporation. 3. Grant of Patent License.
Subject to the terms and conditions of this Agreement, You hereby grant to GitLab B.V. and to recipients of software distributed by GitLab B.V. a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed.
4. You represent that You are legally entitled to grant the above license. You represent further that each employee of the Corporation is authorized to submit Contributions on behalf of the Corporation, but excluding employees that are designated in writing by You as "Not authorized to submit Contributions on behalf of [name of corporation here]."
5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). 5. You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others).
...@@ -20,6 +24,6 @@ You accept and agree to the following terms and conditions for Your present and ...@@ -20,6 +24,6 @@ You accept and agree to the following terms and conditions for Your present and
7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]". 7. Should You wish to submit work that is not Your original creation, You may submit it to GitLab B.V. separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as "Submitted on behalf of a third-party: [named here]".
8. It is your responsibility to notify GitLab B.V. when any change is required to the list of designated employees authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V.. 8. It is your responsibility to notify GitLab B.V. when any change is required to the designation of employees not authorized to submit Contributions on behalf of the Corporation, or to the Corporation's Point of Contact with GitLab B.V..
This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office. This text is licensed under the [Creative Commons Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/) and the original source is the Google Open Source Programs Office.
...@@ -46,7 +46,7 @@ sudo -u git -H git checkout 8-11-stable-ee ...@@ -46,7 +46,7 @@ sudo -u git -H git checkout 8-11-stable-ee
```bash ```bash
cd /home/git/gitlab-shell cd /home/git/gitlab-shell
sudo -u git -H git fetch --all --tags sudo -u git -H git fetch --all --tags
sudo -u git -H git checkout v3.2.1 sudo -u git -H git checkout v3.3.3
``` ```
### 5. Update gitlab-workhorse ### 5. Update gitlab-workhorse
......
...@@ -24,14 +24,6 @@ Feature: Explore Groups ...@@ -24,14 +24,6 @@ Feature: Explore Groups
Then I should see project "Internal" items Then I should see project "Internal" items
And I should not see project "Enterprise" items And I should not see project "Enterprise" items
Scenario: I should see group's members as user
Given group "TestGroup" has internal project "Internal"
And "John Doe" is owner of group "TestGroup"
When I sign in as a user
And I visit group "TestGroup" members page
Then I should see group member "John Doe"
And I should not see member roles
Scenario: I should see group with private, internal and public projects as visitor Scenario: I should see group with private, internal and public projects as visitor
Given group "TestGroup" has internal project "Internal" Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community" Given group "TestGroup" has public project "Community"
...@@ -56,14 +48,6 @@ Feature: Explore Groups ...@@ -56,14 +48,6 @@ Feature: Explore Groups
And I should not see project "Internal" items And I should not see project "Internal" items
And I should not see project "Enterprise" items And I should not see project "Enterprise" items
Scenario: I should see group's members as visitor
Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community"
And "John Doe" is owner of group "TestGroup"
When I visit group "TestGroup" members page
Then I should see group member "John Doe"
And I should not see member roles
Scenario: I should see group with private, internal and public projects as user Scenario: I should see group with private, internal and public projects as user
Given group "TestGroup" has internal project "Internal" Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community" Given group "TestGroup" has public project "Community"
...@@ -91,15 +75,6 @@ Feature: Explore Groups ...@@ -91,15 +75,6 @@ Feature: Explore Groups
And I should see project "Internal" items And I should see project "Internal" items
And I should not see project "Enterprise" items And I should not see project "Enterprise" items
Scenario: I should see group's members as user
Given group "TestGroup" has internal project "Internal"
Given group "TestGroup" has public project "Community"
And "John Doe" is owner of group "TestGroup"
When I sign in as a user
And I visit group "TestGroup" members page
Then I should see group member "John Doe"
And I should not see member roles
Scenario: I should see group with public project in public groups area Scenario: I should see group with public project in public groups area
Given group "TestGroup" has public project "Community" Given group "TestGroup" has public project "Community"
When I visit the public groups area When I visit the public groups area
......
...@@ -62,10 +62,6 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps ...@@ -62,10 +62,6 @@ class Spinach::Features::ExploreGroups < Spinach::FeatureSteps
expect(page).to have_content "John Doe" expect(page).to have_content "John Doe"
end end
step 'I should not see member roles' do
expect(body).not_to match(%r{owner|developer|reporter|guest}i)
end
protected protected
def group_has_project(groupname, projectname, visibility_level) def group_has_project(groupname, projectname, visibility_level)
......
...@@ -74,6 +74,10 @@ module API ...@@ -74,6 +74,10 @@ module API
response response
end end
get "/merge_request_urls" do
::MergeRequests::GetUrlsService.new(project).execute(params[:changes])
end
# #
# Discover user by ssh key # Discover user by ssh key
# #
......
module Gitlab
class ChangesList
include Enumerable
attr_reader :raw_changes
def initialize(changes)
@raw_changes = changes.kind_of?(String) ? changes.lines : changes
end
def each(&block)
changes.each(&block)
end
def changes
@changes ||= begin
@raw_changes.map do |change|
next if change.blank?
oldrev, newrev, ref = change.strip.split(' ')
{ oldrev: oldrev, newrev: newrev, ref: ref }
end.compact
end
end
end
end
...@@ -4,8 +4,8 @@ module Gitlab ...@@ -4,8 +4,8 @@ module Gitlab
attr_reader :user_access, :project attr_reader :user_access, :project
def initialize(change, user_access:, project:) def initialize(change, user_access:, project:)
@oldrev, @newrev, @ref = change.split(' ') @oldrev, @newrev, @ref = change.values_at(:oldrev, :newrev, :ref)
@branch_name = branch_name(@ref) @branch_name = Gitlab::Git.branch_name(@ref)
@user_access = user_access @user_access = user_access
@project = project @project = project
end end
...@@ -47,7 +47,7 @@ module Gitlab ...@@ -47,7 +47,7 @@ module Gitlab
end end
def tag_checks def tag_checks
tag_ref = tag_name(@ref) tag_ref = Gitlab::Git.tag_name(@ref)
if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project) if tag_ref && protected_tag?(tag_ref) && user_access.cannot_do_action?(:admin_project)
"You are not allowed to change existing tags on this project." "You are not allowed to change existing tags on this project."
...@@ -73,24 +73,6 @@ module Gitlab ...@@ -73,24 +73,6 @@ module Gitlab
def matching_merge_request? def matching_merge_request?
Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match? Checks::MatchingMergeRequest.new(@newrev, @branch_name, @project).match?
end end
def branch_name(ref)
ref = @ref.to_s
if Gitlab::Git.branch_ref?(ref)
Gitlab::Git.ref_name(ref)
else
nil
end
end
def tag_name(ref)
ref = @ref.to_s
if Gitlab::Git.tag_ref?(ref)
Gitlab::Git.ref_name(ref)
else
nil
end
end
end end
end end
end end
...@@ -9,6 +9,24 @@ module Gitlab ...@@ -9,6 +9,24 @@ module Gitlab
ref.gsub(/\Arefs\/(tags|heads)\//, '') ref.gsub(/\Arefs\/(tags|heads)\//, '')
end end
def branch_name(ref)
ref = ref.to_s
if self.branch_ref?(ref)
self.ref_name(ref)
else
nil
end
end
def tag_name(ref)
ref = ref.to_s
if self.tag_ref?(ref)
self.ref_name(ref)
else
nil
end
end
def tag_ref?(ref) def tag_ref?(ref)
ref.start_with?(TAG_REF_PREFIX) ref.start_with?(TAG_REF_PREFIX)
end end
......
...@@ -76,10 +76,10 @@ module Gitlab ...@@ -76,10 +76,10 @@ module Gitlab
return build_status_object(false, "A repository for this project does not exist yet.") return build_status_object(false, "A repository for this project does not exist yet.")
end end
changes = changes.lines if changes.kind_of?(String) changes_list = Gitlab::ChangesList.new(changes)
# Iterate over all changes to find if user allowed all of them to be applied # Iterate over all changes to find if user allowed all of them to be applied
changes.map(&:strip).reject(&:blank?).each do |change| changes_list.each do |change|
status = change_access_check(change) status = change_access_check(change)
unless status.allowed? unless status.allowed?
# If user does not have access to make at least one change - cancel all push # If user does not have access to make at least one change - cancel all push
......
...@@ -9,54 +9,6 @@ describe MembersHelper do ...@@ -9,54 +9,6 @@ describe MembersHelper do
it { expect(action_member_permission(:admin, group_member)).to eq :admin_group_member } it { expect(action_member_permission(:admin, group_member)).to eq :admin_group_member }
end end
describe '#default_show_roles' do
let(:user) { double }
let(:member) { build(:project_member) }
before do
allow(helper).to receive(:current_user).and_return(user)
allow(helper).to receive(:can?).with(user, :update_project_member, member).and_return(false)
allow(helper).to receive(:can?).with(user, :destroy_project_member, member).and_return(false)
allow(helper).to receive(:can?).with(user, :admin_project_member, member.source).and_return(false)
end
context 'when the current cannot update, destroy or admin the passed member' do
it 'returns false' do
expect(helper.default_show_roles(member)).to be_falsy
end
end
context 'when the current can update the passed member' do
before do
allow(helper).to receive(:can?).with(user, :update_project_member, member).and_return(true)
end
it 'returns true' do
expect(helper.default_show_roles(member)).to be_truthy
end
end
context 'when the current can destroy the passed member' do
before do
allow(helper).to receive(:can?).with(user, :destroy_project_member, member).and_return(true)
end
it 'returns true' do
expect(helper.default_show_roles(member)).to be_truthy
end
end
context 'when the current can admin the passed member source' do
before do
allow(helper).to receive(:can?).with(user, :admin_project_member, member.source).and_return(true)
end
it 'returns true' do
expect(helper.default_show_roles(member)).to be_truthy
end
end
end
describe '#remove_member_message' do describe '#remove_member_message' do
let(:requester) { build(:user) } let(:requester) { build(:user) }
let(:project) { create(:project) } let(:project) { create(:project) }
......
require "spec_helper"
describe Gitlab::ChangesList do
let(:valid_changes_string) { "\n000000 570e7b2 refs/heads/my_branch\nd14d6c 6fd24d refs/heads/master" }
let(:invalid_changes) { 1 }
context 'when changes is a valid string' do
let(:changes_list) { Gitlab::ChangesList.new(valid_changes_string) }
it 'splits elements by newline character' do
expect(changes_list).to contain_exactly({
oldrev: "000000",
newrev: "570e7b2",
ref: "refs/heads/my_branch"
}, {
oldrev: "d14d6c",
newrev: "6fd24d",
ref: "refs/heads/master"
})
end
it 'behaves like a list' do
expect(changes_list.first).to eq({
oldrev: "000000",
newrev: "570e7b2",
ref: "refs/heads/my_branch"
})
end
end
end
...@@ -275,6 +275,24 @@ describe API::API, api: true do ...@@ -275,6 +275,24 @@ describe API::API, api: true do
end end
end end
describe 'GET /internal/merge_request_urls' do
let(:repo_name) { "#{project.namespace.name}/#{project.path}" }
let(:changes) { URI.escape("#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch") }
before do
project.team << [user, :developer]
get api("/internal/merge_request_urls?project=#{repo_name}&changes=#{changes}"), secret_token: secret_token
end
it 'returns link to create new merge request' do
expect(json_response).to match [{
"branch_name" => "new_branch",
"url" => "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch",
"new_merge_request" => true
}]
end
end
def pull(key, project, protocol = 'ssh') def pull(key, project, protocol = 'ssh')
post( post(
api("/internal/allowed"), api("/internal/allowed"),
......
...@@ -60,7 +60,7 @@ end ...@@ -60,7 +60,7 @@ end
# project GET /:id(.:format) projects#show # project GET /:id(.:format) projects#show
# PUT /:id(.:format) projects#update # PUT /:id(.:format) projects#update
# DELETE /:id(.:format) projects#destroy # DELETE /:id(.:format) projects#destroy
# markdown_preview_project POST /:id/markdown_preview(.:format) projects#markdown_preview # preview_markdown_project POST /:id/preview_markdown(.:format) projects#preview_markdown
describe ProjectsController, 'routing' do describe ProjectsController, 'routing' do
it 'to #create' do it 'to #create' do
expect(post('/projects')).to route_to('projects#create') expect(post('/projects')).to route_to('projects#create')
...@@ -91,9 +91,9 @@ describe ProjectsController, 'routing' do ...@@ -91,9 +91,9 @@ describe ProjectsController, 'routing' do
expect(delete('/gitlab/gitlabhq')).to route_to('projects#destroy', namespace_id: 'gitlab', id: 'gitlabhq') expect(delete('/gitlab/gitlabhq')).to route_to('projects#destroy', namespace_id: 'gitlab', id: 'gitlabhq')
end end
it 'to #markdown_preview' do it 'to #preview_markdown' do
expect(post('/gitlab/gitlabhq/markdown_preview')).to( expect(post('/gitlab/gitlabhq/preview_markdown')).to(
route_to('projects#markdown_preview', namespace_id: 'gitlab', id: 'gitlabhq') route_to('projects#preview_markdown', namespace_id: 'gitlab', id: 'gitlabhq')
) )
end end
end end
......
require "spec_helper"
describe MergeRequests::GetUrlsService do
let(:project) { create(:project, :public) }
let(:service) { MergeRequests::GetUrlsService.new(project) }
let(:source_branch) { "my_branch" }
let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=#{source_branch}" }
let(:show_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/#{merge_request.iid}" }
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/#{source_branch}" }
describe "#execute" do
shared_examples 'new_merge_request_link' do
it 'returns url to create new merge request' do
result = service.execute(changes)
expect(result).to match([{
branch_name: source_branch,
url: new_merge_request_url,
new_merge_request: true
}])
end
end
shared_examples 'show_merge_request_url' do
it 'returns url to view merge request' do
result = service.execute(changes)
expect(result).to match([{
branch_name: source_branch,
url: show_merge_request_url,
new_merge_request: false
}])
end
end
context 'pushing one completely new branch' do
let(:changes) { new_branch_changes }
it_behaves_like 'new_merge_request_link'
end
context 'pushing to existing branch but no merge request' do
let(:changes) { existing_branch_changes }
it_behaves_like 'new_merge_request_link'
end
context 'pushing to existing branch and merge request opened' do
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'show_merge_request_url'
end
context 'pushing to existing branch and merge request is reopened' do
let!(:merge_request) { create(:merge_request, :reopened, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'show_merge_request_url'
end
context 'pushing to existing branch from forked project' do
let(:user) { create(:user) }
let!(:forked_project) { Projects::ForkService.new(project, user).execute }
let!(:merge_request) { create(:merge_request, source_project: forked_project, target_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
# Source project is now the forked one
let(:service) { MergeRequests::GetUrlsService.new(forked_project) }
it_behaves_like 'show_merge_request_url'
end
context 'pushing to existing branch and merge request is closed' do
let!(:merge_request) { create(:merge_request, :closed, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'new_merge_request_link'
end
context 'pushing to existing branch and merge request is merged' do
let!(:merge_request) { create(:merge_request, :merged, source_project: project, source_branch: source_branch) }
let(:changes) { existing_branch_changes }
it_behaves_like 'new_merge_request_link'
end
context 'pushing new branch and existing branch (with merge request created) at once' do
let!(:merge_request) { create(:merge_request, source_project: project, source_branch: "existing_branch") }
let(:new_branch_changes) { "#{Gitlab::Git::BLANK_SHA} 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/new_branch" }
let(:existing_branch_changes) { "d14d6c0abdd253381df51a723d58691b2ee1ab08 570e7b2abdd848b95f2f578043fc23bd6f6fd24d refs/heads/existing_branch" }
let(:changes) { "#{new_branch_changes}\n#{existing_branch_changes}" }
let(:new_merge_request_url) { "http://localhost/#{project.namespace.name}/#{project.path}/merge_requests/new?merge_request%5Bsource_branch%5D=new_branch" }
it 'returns 2 urls for both creating new and showing merge request' do
result = service.execute(changes)
expect(result).to match([{
branch_name: "new_branch",
url: new_merge_request_url,
new_merge_request: true
}, {
branch_name: "existing_branch",
url: show_merge_request_url,
new_merge_request: false
}])
end
end
end
end
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