Commit fae2e540 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'master' of dev.gitlab.org:gitlab/gitlabhq into upstream-ce-6-8

Signed-off-by: default avatarDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>

Conflicts:
	CHANGELOG
	Gemfile.lock
	README.md
	VERSION
	app/assets/javascripts/application.js
	db/schema.rb
	doc/install/installation.md
	doc/update/4.2-to-5.0.md
	doc/update/5.0-to-5.1.md
	doc/update/5.1-to-5.2.md
	doc/update/5.2-to-5.3.md
	doc/update/5.4-to-6.0.md
	doc/update/6.0-to-6.1.md
	doc/update/6.0-to-6.7.md
	lib/gitlab/git_access.rb
parents 6d761461 5b123dbf
--color --drb --color
v6.7.2 v 6.8.0
- Ability to at mention users that are participating in issue and merge req. discussion
- Enabled GZip Compression for assets in example Nginx, make sure that Nginx is compiled with --with-http_gzip_static_module flag (this is default in Ubuntu)
- Make user search case-insensitive (Christopher Arnold)
- Remove omniauth-ldap nickname bug workaround
- Drop all tables before restoring a Postgres backup
- Make the repository downloads path configurable
- Create branches via API (sponsored by O'Reilly Media)
- Changed permission of gitlab-satellites directory not to be world accessible
- Protected branch does not allow force push
- Fix popen bug in `rake gitlab:satellites:create`
- Disable connection reaping for MySQL
- Allow oauth signup without email for twitter and github
- Fix faulty namespace names that caused 500 on user creation
- Option to disable standard login
- Clean old created archives from repository downloads directory
v 6.7.3
- Fix the merge notification email not being sent (Pierre de La Morinerie)
- Drop all tables before restoring a Postgres backup
- Remove yanked modernizr gem
v 6.7.2
- Fix upgrader script - Fix upgrader script
v6.7.1 v 6.7.1
- Fix GitLab CI integration - Fix GitLab CI integration
v 6.7.0 v 6.7.0
......
...@@ -24,12 +24,14 @@ Issues and merge requests should be in English and contain appropriate language ...@@ -24,12 +24,14 @@ Issues and merge requests should be in English and contain appropriate language
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/). To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/).
The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious bugs in the latest [stable or development release of GitLab](MAINTENANCE.md). The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md).
If something is missing but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request.
When submitting an issue please conform to the issue submission guidelines listed below. When submitting an issue please conform to the issue submission guidelines listed below.
Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose. Do not use the issue tracker for feature requests.
We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose.
Please keep feature requests as small and simple as possible, complex ones might be edited to make them small and simple.
Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there. Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
...@@ -63,10 +65,11 @@ If you can, please submit a merge request with the fix or improvements including ...@@ -63,10 +65,11 @@ If you can, please submit a merge request with the fix or improvements including
1. Add your changes to the [CHANGELOG](CHANGELOG) 1. Add your changes to the [CHANGELOG](CHANGELOG)
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits) 1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. Push the commit to your fork 1. Push the commit to your fork
1. Submit a merge request (MR) 1. Submit a merge request (MR) to the master branch
1. The MR title should describes the change you want to make 1. The MR title should describes the change you want to make
1. The MR description should give a motive for your change and the method you used to achieve it 1. The MR description should give a motive for your change and the method you used to achieve it
1. If the MR changes the UI it should include before and after screenshots 1. If the MR changes the UI it should include before and after screenshots
1. If the MR changes CSS classes please include the list of affected pages `grep css-class ./app -R`
1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR 1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feature requests](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
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. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
...@@ -77,6 +80,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c ...@@ -77,6 +80,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c
For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). Please ensure that your merge request meets the following contribution acceptance criteria. For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). Please ensure that your merge request meets the following contribution acceptance criteria.
**Please format your merge request description as follows:**
1. What does this MR do?
2. Are there points in the code the reviewer needs to double check?
3. Why was this MR needed?
4. What are the relevant issue numbers / [Feature requests](http://feedback.gitlab.com/)?
5. Screenshots (If appropiate)
## Contribution acceptance criteria ## Contribution acceptance criteria
1. The change is as small as possible (see the above paragraph for details) 1. The change is as small as possible (see the above paragraph for details)
......
...@@ -12,8 +12,6 @@ gem "rails", "~> 4.0.0" ...@@ -12,8 +12,6 @@ gem "rails", "~> 4.0.0"
gem "protected_attributes" gem "protected_attributes"
gem 'rails-observers' gem 'rails-observers'
gem 'actionpack-page_caching'
gem 'actionpack-action_caching'
# Default values for AR models # Default values for AR models
gem "default_value_for", "~> 3.0.0" gem "default_value_for", "~> 3.0.0"
...@@ -32,7 +30,7 @@ gem 'omniauth-github' ...@@ -32,7 +30,7 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", '~> 5.7.1' gem "gitlab_git", '~> 5.8'
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack' gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
...@@ -42,7 +40,7 @@ gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap" ...@@ -42,7 +40,7 @@ gem 'gitlab_omniauth-ldap', '1.0.4', require: "omniauth-ldap"
gem 'net-ldap' gem 'net-ldap'
# Git Wiki # Git Wiki
gem "gitlab-gollum-lib", "~> 1.1.0", require: 'gollum-lib' gem 'gollum-lib', '~> 3.0.0'
# Language detection # Language detection
gem "gitlab-linguist", "~> 3.0.0", require: "linguist" gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
...@@ -50,7 +48,7 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist" ...@@ -50,7 +48,7 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
# API # API
gem "grape", "~> 0.6.1" gem "grape", "~> 0.6.1"
# Replace with rubygems when nesteted entities get released # Replace with rubygems when nesteted entities get released
gem "grape-entity", "~> 0.4.1", ref: 'd904381c951e86250c3f44213b349a3dd8e83fb1', git: 'https://github.com/intridea/grape-entity.git' gem "grape-entity", "~> 0.4.2"
gem 'rack-cors', require: 'rack/cors' gem 'rack-cors', require: 'rack/cors'
# Email validation # Email validation
...@@ -73,7 +71,7 @@ gem "haml-rails" ...@@ -73,7 +71,7 @@ gem "haml-rails"
gem "carrierwave" gem "carrierwave"
# for aws storage # for aws storage
gem "fog", "~> 1.3.1", group: :aws gem "fog", "~> 1.14", group: :aws
# Authorization # Authorization
gem "six" gem "six"
...@@ -83,7 +81,7 @@ gem "seed-fu" ...@@ -83,7 +81,7 @@ gem "seed-fu"
# Markdown to HTML # Markdown to HTML
gem "redcarpet", "~> 2.2.2" gem "redcarpet", "~> 2.2.2"
gem "github-markup", "~> 0.7.4", require: 'github/markup', git: 'https://github.com/gitlabhq/markup.git', ref: '61ade389c1e1c159359338f570d18464a44ddbc4' gem "github-markup"
# Asciidoc to HTML # Asciidoc to HTML
gem "asciidoctor" gem "asciidoctor"
...@@ -103,7 +101,7 @@ gem "acts-as-taggable-on" ...@@ -103,7 +101,7 @@ gem "acts-as-taggable-on"
# Background jobs # Background jobs
gem 'slim' gem 'slim'
gem 'sinatra', require: nil gem 'sinatra', require: nil
gem 'sidekiq' gem 'sidekiq', '2.17.0'
# HTTP requests # HTTP requests
gem "httparty" gem "httparty"
...@@ -143,7 +141,7 @@ gem "d3_rails", "~> 3.1.4" ...@@ -143,7 +141,7 @@ gem "d3_rails", "~> 3.1.4"
gem "underscore-rails", "~> 1.4.4" gem "underscore-rails", "~> 1.4.4"
# Sanitize user input # Sanitize user input
gem "sanitize" gem "sanitize", '~> 2.0'
# Protect against bruteforcing # Protect against bruteforcing
gem "rack-attack" gem "rack-attack"
...@@ -218,7 +216,6 @@ group :development, :test do ...@@ -218,7 +216,6 @@ group :development, :test do
# PhantomJS driver for Capybara # PhantomJS driver for Capybara
gem 'poltergeist', '~> 1.4.1' gem 'poltergeist', '~> 1.4.1'
gem 'spork', '~> 1.0rc'
gem 'jasmine', '2.0.0.rc5' gem 'jasmine', '2.0.0.rc5'
gem "spring", '1.1.1' gem "spring", '1.1.1'
......
GIT
remote: https://github.com/gitlabhq/markup.git
revision: 61ade389c1e1c159359338f570d18464a44ddbc4
ref: 61ade389c1e1c159359338f570d18464a44ddbc4
specs:
github-markup (0.7.6)
GIT
remote: https://github.com/intridea/grape-entity.git
revision: d904381c951e86250c3f44213b349a3dd8e83fb1
ref: d904381c951e86250c3f44213b349a3dd8e83fb1
specs:
grape-entity (0.4.1)
activesupport
multi_json (>= 1.3.2)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
...@@ -27,10 +11,6 @@ GEM ...@@ -27,10 +11,6 @@ GEM
erubis (~> 2.7.0) erubis (~> 2.7.0)
rack (~> 1.5.2) rack (~> 1.5.2)
rack-test (~> 0.6.2) rack-test (~> 0.6.2)
actionpack-action_caching (1.1.0)
actionpack (>= 4.0.0, < 5.0)
actionpack-page_caching (1.0.2)
actionpack (>= 4.0.0, < 5)
activemodel (4.0.3) activemodel (4.0.3)
activesupport (= 4.0.3) activesupport (= 4.0.3)
builder (~> 3.1.0) builder (~> 3.1.0)
...@@ -54,7 +34,7 @@ GEM ...@@ -54,7 +34,7 @@ GEM
rake (>= 0.8.7) rake (>= 0.8.7)
arel (4.0.2) arel (4.0.2)
asciidoctor (0.1.4) asciidoctor (0.1.4)
atomic (1.1.14) atomic (1.1.16)
awesome_print (1.2.0) awesome_print (1.2.0)
axiom-types (0.0.5) axiom-types (0.0.5)
descendants_tracker (~> 0.0.1) descendants_tracker (~> 0.0.1)
...@@ -136,7 +116,7 @@ GEM ...@@ -136,7 +116,7 @@ GEM
erubis (2.7.0) erubis (2.7.0)
escape_utils (0.2.4) escape_utils (0.2.4)
eventmachine (1.0.3) eventmachine (1.0.3)
excon (0.13.4) excon (0.32.1)
execjs (2.0.2) execjs (2.0.2)
factory_girl (4.3.0) factory_girl (4.3.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
...@@ -149,16 +129,23 @@ GEM ...@@ -149,16 +129,23 @@ GEM
faraday (>= 0.7.4, < 0.9) faraday (>= 0.7.4, < 0.9)
ffaker (1.22.1) ffaker (1.22.1)
ffi (1.9.3) ffi (1.9.3)
fog (1.3.1) fog (1.21.0)
fog-brightbox
fog-core (~> 1.21, >= 1.21.1)
fog-json
nokogiri (~> 1.5, >= 1.5.11)
fog-brightbox (0.0.1)
fog-core
fog-json
fog-core (1.21.1)
builder builder
excon (~> 0.13.0) excon (~> 0.32)
formatador (~> 0.2.0) formatador (~> 0.2.0)
mime-types mime-types
multi_json (~> 1.0) net-scp (~> 1.1)
net-scp (~> 1.0.4)
net-ssh (>= 2.1.3) net-ssh (>= 2.1.3)
nokogiri (~> 1.5.0) fog-json (1.0.0)
ruby-hmac multi_json (~> 1.0)
font-awesome-rails (3.2.1.3) font-awesome-rails (3.2.1.3)
railties (>= 3.2, < 5.0) railties (>= 3.2, < 5.0)
foreman (0.63.0) foreman (0.63.0)
...@@ -169,35 +156,28 @@ GEM ...@@ -169,35 +156,28 @@ GEM
rugged (~> 0.19) rugged (~> 0.19)
gherkin-ruby (0.3.1) gherkin-ruby (0.3.1)
racc racc
github-markdown (0.5.5) github-markup (1.1.0)
gitlab-flowdock-git-hook (0.4.2.2) gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-gollum-lib (1.1.0)
github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0)
gitlab-grit (~> 2.6.1)
nokogiri (~> 1.5.9)
sanitize (~> 2.0.3)
stringex (~> 1.5.1)
gitlab-grack (2.0.0.pre) gitlab-grack (2.0.0.pre)
rack (~> 1.5.1) rack (~> 1.5.1)
gitlab-grit (2.6.4) gitlab-grit (2.6.5)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3)
gitlab-linguist (3.0.0) gitlab-linguist (3.0.0)
charlock_holmes (~> 0.6.6) charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4) escape_utils (~> 0.2.4)
mime-types (~> 1.19) mime-types (~> 1.19)
gitlab_emoji (0.0.1.1) gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1) emoji (~> 1.0.1)
gitlab_git (5.7.1) gitlab_git (5.8.0)
activesupport (~> 4.0.0) activesupport (~> 4.0)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6)
gitlab-grit (~> 2.6.1) gitlab-grit (~> 2.6)
gitlab-linguist (~> 3.0.0) gitlab-linguist (~> 3.0)
rugged (~> 0.19.0) rugged (~> 0.19.0)
gitlab_meta (6.0) gitlab_meta (6.0)
gitlab_omniauth-ldap (1.0.4) gitlab_omniauth-ldap (1.0.4)
...@@ -205,6 +185,13 @@ GEM ...@@ -205,6 +185,13 @@ GEM
omniauth (~> 1.0) omniauth (~> 1.0)
pyu-ruby-sasl (~> 0.0.3.1) pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.1.1) rubyntlm (~> 0.1.1)
gollum-lib (3.0.0)
github-markup (~> 1.1.0)
gitlab-grit (~> 2.6.5)
nokogiri (~> 1.6.1)
rouge (~> 1.3.3)
sanitize (~> 2.1.0)
stringex (~> 2.5.1)
gon (5.0.1) gon (5.0.1)
actionpack (>= 2.3.0) actionpack (>= 2.3.0)
json json
...@@ -218,6 +205,9 @@ GEM ...@@ -218,6 +205,9 @@ GEM
rack-accept rack-accept
rack-mount rack-mount
virtus (>= 1.0.0) virtus (>= 1.0.0)
grape-entity (0.4.2)
activesupport
multi_json (>= 1.3.2)
growl (1.0.3) growl (1.0.3)
guard (2.2.4) guard (2.2.4)
formatador (>= 0.2.4) formatador (>= 0.2.4)
...@@ -288,16 +278,18 @@ GEM ...@@ -288,16 +278,18 @@ GEM
treetop (~> 1.4.8) treetop (~> 1.4.8)
method_source (0.8.2) method_source (0.8.2)
mime-types (1.25.1) mime-types (1.25.1)
mini_portile (0.5.3)
minitest (4.7.5) minitest (4.7.5)
multi_json (1.8.4) multi_json (1.9.2)
multi_xml (0.5.5) multi_xml (0.5.5)
multipart-post (1.2.0) multipart-post (1.2.0)
mysql2 (0.3.11) mysql2 (0.3.11)
net-ldap (0.3.1) net-ldap (0.3.1)
net-scp (1.0.4) net-scp (1.1.2)
net-ssh (>= 1.99.1) net-ssh (>= 2.6.5)
net-ssh (2.7.0) net-ssh (2.8.0)
nokogiri (1.5.10) nokogiri (1.6.1)
mini_portile (~> 0.5.0)
nprogress-rails (0.1.2.3) nprogress-rails (0.1.2.3)
oauth (0.4.7) oauth (0.4.7)
oauth2 (0.8.1) oauth2 (0.8.1)
...@@ -414,6 +406,7 @@ GEM ...@@ -414,6 +406,7 @@ GEM
require_all (1.3.2) require_all (1.3.2)
rest-client (1.6.7) rest-client (1.6.7)
mime-types (>= 1.16) mime-types (>= 1.16)
rouge (1.3.3)
rspec (2.14.1) rspec (2.14.1)
rspec-core (~> 2.14.0) rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0) rspec-expectations (~> 2.14.0)
...@@ -429,12 +422,11 @@ GEM ...@@ -429,12 +422,11 @@ GEM
rspec-core (~> 2.14.0) rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0) rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0) rspec-mocks (~> 2.14.0)
ruby-hmac (0.4.0)
ruby-progressbar (1.2.0) ruby-progressbar (1.2.0)
rubyntlm (0.1.1) rubyntlm (0.1.1)
rugged (0.19.0) rugged (0.19.0)
safe_yaml (0.9.7) safe_yaml (0.9.7)
sanitize (2.0.6) sanitize (2.1.0)
nokogiri (>= 1.4.4) nokogiri (>= 1.4.4)
sass (3.2.12) sass (3.2.12)
sass-rails (4.0.1) sass-rails (4.0.1)
...@@ -482,7 +474,6 @@ GEM ...@@ -482,7 +474,6 @@ GEM
capybara (>= 2.0.0) capybara (>= 2.0.0)
railties (>= 3) railties (>= 3)
spinach (>= 0.4) spinach (>= 0.4)
spork (1.0.0rc4)
spring (1.1.1) spring (1.1.1)
spring-commands-rspec (1.0.1) spring-commands-rspec (1.0.1)
spring (>= 0.9.1) spring (>= 0.9.1)
...@@ -499,7 +490,7 @@ GEM ...@@ -499,7 +490,7 @@ GEM
sprockets (~> 2.8) sprockets (~> 2.8)
stamp (0.5.0) stamp (0.5.0)
state_machine (1.2.0) state_machine (1.2.0)
stringex (1.5.1) stringex (2.5.1)
temple (0.6.7) temple (0.6.7)
term-ansicolor (1.2.2) term-ansicolor (1.2.2)
tins (~> 0.8) tins (~> 0.8)
...@@ -512,8 +503,8 @@ GEM ...@@ -512,8 +503,8 @@ GEM
eventmachine (>= 1.0.0) eventmachine (>= 1.0.0)
rack (>= 1.0.0) rack (>= 1.0.0)
thor (0.18.1) thor (0.18.1)
thread_safe (0.1.3) thread_safe (0.3.1)
atomic atomic (>= 1.1.7, < 2)
tilt (1.4.1) tilt (1.4.1)
timers (1.1.0) timers (1.1.0)
tinder (1.9.3) tinder (1.9.3)
...@@ -535,7 +526,7 @@ GEM ...@@ -535,7 +526,7 @@ GEM
eventmachine (>= 0.12.8) eventmachine (>= 0.12.8)
http_parser.rb (~> 0.5.1) http_parser.rb (~> 0.5.1)
simple_oauth (~> 0.1.4) simple_oauth (~> 0.1.4)
tzinfo (0.3.38) tzinfo (0.3.39)
uglifier (2.3.2) uglifier (2.3.2)
execjs (>= 0.3.0) execjs (>= 0.3.0)
json (>= 1.8.0) json (>= 1.8.0)
...@@ -566,8 +557,6 @@ PLATFORMS ...@@ -566,8 +557,6 @@ PLATFORMS
DEPENDENCIES DEPENDENCIES
ace-rails-ap ace-rails-ap
actionpack-action_caching
actionpack-page_caching
acts-as-taggable-on acts-as-taggable-on
annotate (~> 2.6.0.beta2) annotate (~> 2.6.0.beta2)
asciidoctor asciidoctor
...@@ -590,22 +579,22 @@ DEPENDENCIES ...@@ -590,22 +579,22 @@ DEPENDENCIES
enumerize enumerize
factory_girl_rails factory_girl_rails
ffaker ffaker
fog (~> 1.3.1) fog (~> 1.14)
font-awesome-rails (~> 3.2) font-awesome-rails (~> 3.2)
foreman foreman
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
github-markup (~> 0.7.4)! github-markup
gitlab-flowdock-git-hook (~> 0.4.2) gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.1.0)
gitlab-grack (~> 2.0.0.pre) gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 3.0.0) gitlab-linguist (~> 3.0.0)
gitlab_emoji (~> 0.0.1.1) gitlab_emoji (~> 0.0.1.1)
gitlab_git (~> 5.7.1) gitlab_git (~> 5.8)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.4) gitlab_omniauth-ldap (= 1.0.4)
gollum-lib (~> 3.0.0)
gon (~> 5.0.0) gon (~> 5.0.0)
grape (~> 0.6.1) grape (~> 0.6.1)
grape-entity (~> 0.4.1)! grape-entity (~> 0.4.2)
growl growl
guard-rspec guard-rspec
guard-spinach guard-spinach
...@@ -645,21 +634,20 @@ DEPENDENCIES ...@@ -645,21 +634,20 @@ DEPENDENCIES
redcarpet (~> 2.2.2) redcarpet (~> 2.2.2)
redis-rails redis-rails
rspec-rails rspec-rails
sanitize sanitize (~> 2.0)
sass-rails sass-rails
sdoc sdoc
seed-fu seed-fu
select2-rails select2-rails
settingslogic settingslogic
shoulda-matchers (~> 2.1.0) shoulda-matchers (~> 2.1.0)
sidekiq sidekiq (= 2.17.0)
simplecov simplecov
sinatra sinatra
six six
slack-notifier (~> 0.2.0) slack-notifier (~> 0.2.0)
slim slim
spinach-rails spinach-rails
spork (~> 1.0rc)
spring (= 1.1.1) spring (= 1.1.1)
spring-commands-rspec (= 1.0.1) spring-commands-rspec (= 1.0.1)
spring-commands-spinach (= 1.0.0) spring-commands-spinach (= 1.0.0)
......
# A sample Guardfile # A sample Guardfile
# More info at https://github.com/guard/guard#readme # More info at https://github.com/guard/guard#readme
guard 'rspec', :version => 2, :all_on_start => false, :all_after_pass => false do guard 'rspec', cmd: "spring rspec", version: 2, all_on_start: false, all_after_pass: false do
watch(%r{^spec/.+_spec\.rb$}) watch(%r{^spec/.+_spec\.rb$})
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" } watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" } watch(%r{^lib/api/(.+)\.rb$}) { |m| "spec/requests/api/#{m[1]}_spec.rb" }
......
...@@ -7,24 +7,19 @@ Below we describe the contributing process to GitLab for two reasons. So that co ...@@ -7,24 +7,19 @@ Below we describe the contributing process to GitLab for two reasons. So that co
## Common actions ## Common actions
### Issue team ### Issue team
- Looks for issues without workflow labels and triages issue - Looks for issues without [workflow labels](#how-we-handle-issues) and triages issue
- Monitors merge requests - Closes invalid issues with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
- Closes invalid issues and merge requests with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.) - Asks for feedback from issue reporter ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
- Assigns appropriate [labels](#how-we-handle-issues) - Monitors all issues for feedback (but especially ones commented on since automatically watching them)
- Asks for feedback from issue reporter/merge request initiator ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
- Asks for feedback from the relevant developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
- Monitors all issues/merge requests for feedback (but especially ones commented on since automatically watching them):
- Closes issues with no feedback from the reporter for two weeks - Closes issues with no feedback from the reporter for two weeks
- Closes stale merge requests
### Development team ### Merge request officers
- Responds to issues and merge requests the issue team mentions them in - Responds to merge requests the issue team mentions them in and monitors for new merge requests
- Monitors for new issues in _Awaiting developer action/feedback_ with no developer activity (once a week) - Provides feedback to the merge request submitter to improve the merge request (style, tests, etc.)
- Monitors for new merge requests (at least once a week) - Mark merge requests 'ready-for-merge' when they meet the contribution guidelines
- Manages their work queue by looking at issues and merge requests assigned to them - Mention developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
- Close fixed issues (via commit messages or manually) - Closes merge requests with no feedback from the reporter for two weeks
- Be kind to people trying to contribute. Be aware that people can be a non-native or a native English speaker, they might not understand thing or they might be very sensitive to how your word things. Use emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
## Priorities of the issue team ## Priorities of the issue team
...@@ -63,6 +58,10 @@ If an issue is complex and needs the attention of a specific person, assignment ...@@ -63,6 +58,10 @@ If an issue is complex and needs the attention of a specific person, assignment
- Feature request (see copy & paste response: [Feature requests](#feature-requests)) - Feature request (see copy & paste response: [Feature requests](#feature-requests))
- Support (see copy & paste response: [Support requests and configuration questions](#support-requests-and-configuration-questions) - Support (see copy & paste response: [Support requests and configuration questions](#support-requests-and-configuration-questions)
## Be kind
Be kind to people trying to contribute. Be aware that people can be a non-native or a native English speaker, they might not understand thing or they might be very sensitive to how your word things. Use emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
## Copy & paste responses ## Copy & paste responses
### Improperly formatted issue ### Improperly formatted issue
...@@ -71,7 +70,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue ...@@ -71,7 +70,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue
### Feature requests ### Feature requests
Thanks for your interest in GitLab. We don't use the issue tracker for feature requests. Please use the [feature request forum](http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. Thank you for your interest in improving GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use the [feature request forum](http://feedback.gitlab.com/) for this purpose or create a merge request implementing this feature. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
### Issue report for old version ### Issue report for old version
...@@ -79,7 +78,7 @@ Thanks for the issue report but we only support issues for the latest stable ver ...@@ -79,7 +78,7 @@ Thanks for the issue report but we only support issues for the latest stable ver
### Support requests and configuration questions ### Support requests and configuration questions
Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the unofficial #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information. Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
### Code format ### Code format
......
web: bundle exec unicorn_rails -p $PORT -E development -c config/unicorn_development.rb web: bundle exec unicorn_rails -p ${PORT:="3000"} -E ${RAILS_ENV:="development"} -c ${UNICORN_CONFIG:="config/unicorn.rb"}
worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
...@@ -45,13 +45,11 @@ ...@@ -45,13 +45,11 @@
#### Official installation methods #### Official installation methods
* [GitLab packages](https://gitlab.com/subscribers/gitlab-ee/blob/master/doc/install/packages.md) These packages contain GitLab and all its depencies (Ruby, PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions. * [GitLab packages](https://www.gitlab.com/downloads/) **recommended** These packages contain GitLab and all its depencies (Ruby, PostgreSQL, Redis, Nginx, Unicorn, etc.). They are made with [omnibus-gitlab](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md) that also contains the installation instructions.
* [GitLab virtual machine images](https://www.gitlab.com/downloads/) contain an operating system and a preinstalled GitLab. They are made with [GitLab Packer](https://gitlab.com/gitlab-org/gitlab-packer/blob/master/README.md) that also contains the installation instructions.
* [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies. * [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies.
* [Manual installation guide](doc/install/installation.md) This guide to set up a production server offers detailed and complete step-by-step instructions. * [Manual installation guide](doc/install/installation.md) This guide to set up a production server on Ubuntu offers detailed and complete step-by-step instructions.
#### Third party one-click installers #### Third party one-click installers
...@@ -85,6 +83,10 @@ or by directly calling the script ...@@ -85,6 +83,10 @@ or by directly calling the script
### Run in development mode ### Run in development mode
Copy the example development unicorn configuration file
cp config/unicorn.rb.example.development config/unicorn.rb
Start it with [Foreman](https://github.com/ddollar/foreman) Start it with [Foreman](https://github.com/ddollar/foreman)
bundle exec foreman start -p 3000 bundle exec foreman start -p 3000
...@@ -96,14 +98,9 @@ or start each component separately ...@@ -96,14 +98,9 @@ or start each component separately
### Run the tests ### Run the tests
* Seed the database
bundle exec rake db:setup RAILS_ENV=test
bundle exec rake db:seed_fu RAILS_ENV=test
* Run all tests * Run all tests
bundle exec rake gitlab:test RAILS_ENV=test bundle exec rake test
* [RSpec](http://rspec.info/) unit and functional tests * [RSpec](http://rspec.info/) unit and functional tests
...@@ -118,38 +115,10 @@ or start each component separately ...@@ -118,38 +115,10 @@ or start each component separately
Single Spinach test: bundle exec spinach features/project/issues/milestones.feature Single Spinach test: bundle exec spinach features/project/issues/milestones.feature
### GitLab interfaces ### Documentation
* [GitLab API doc](doc/api/README.md) or see the [GitLab API website](http://api.gitlab.org/)
* [Rake tasks](doc/raketasks) including a [backup and restore procedure](doc/raketasks/backup_restore.md)
* [Directory structure](doc/install/structure.md)
* [Database installation](doc/install/databases.md)
* [Markdown specification](doc/markdown/markdown.md)
* [Security guide](doc/security/rack_attack.md) to throttle abusive requests All documentation can be found on [doc.gitlab.com/ce/](http://doc.gitlab.com/ce/).
### Getting help ### Getting help
* [Maintenance policy](MAINTENANCE.md) specifies what versions are supported. Please see [Getting help for GitLab](https://www.gitlab.com/getting-help/) on our website for the many options to get help.
* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) contains solutions to common problems.
* [Mailing list](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
* [Feature request forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
* [Contributing guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) describes how to submit merge requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
* [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
* [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
* [#gitlab IRC channel](http://www.freenode.net/) on Freenode to get in touch with other GitLab users and get help, it's managed by James Newton (newton), Drew Blessing (dblessing), and Sam Gleske (sag47).
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
6.7.0-ee 6.8.0.pre-ee
# This is a manifest file that'll be compiled into including all the files listed below.
# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
# be included in the compiled file accessible from http://example.com/assets/application.js
# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
# the compiled file.
#
#= require jquery
#= require jquery.ui.all
#= require jquery_ujs
#= require jquery.cookie
#= require jquery.endless-scroll
#= require jquery.highlight
#= require jquery.history
#= require jquery.waitforimages
#= require jquery.atwho
#= require jquery.scrollto
#= require jquery.blockUI
#= require turbolinks
#= require jquery.turbolinks
#= require bootstrap
#= require select2
#= require raphael
#= require g.raphael-min
#= require g.bar-min
#= require branch-graph
#= require highlightjs.min
#= require ace/ace
#= require d3
#= require underscore
#= require nprogress
#= require nprogress-turbolinks
#= require_tree .
window.slugify = (text) -> window.slugify = (text) ->
text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase() text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
......
...@@ -201,7 +201,7 @@ class BranchGraph ...@@ -201,7 +201,7 @@ class BranchGraph
stroke: @colors[commit.space] stroke: @colors[commit.space]
"stroke-width": 2 "stroke-width": 2
) )
r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20) r.image(gon.relative_url_root + commit.author.icon, avatar_box_x, avatar_box_y, 20, 20)
r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr( r.text(@offsetX + @unitSpace * @mspace + 35, y, commit.message.split("\n")[0]).attr(
"text-anchor": "start" "text-anchor": "start"
font: "14px Monaco, monospace" font: "14px Monaco, monospace"
...@@ -274,7 +274,7 @@ class BranchGraph ...@@ -274,7 +274,7 @@ class BranchGraph
Raphael::commitTooltip = (x, y, commit) -> Raphael::commitTooltip = (x, y, commit) ->
boxWidth = 300 boxWidth = 300
boxHeight = 200 boxHeight = 200
icon = @image(commit.author.icon, x, y, 20, 20) icon = @image(gon.relative_url_root + commit.author.icon, x, y, 20, 20)
nameText = @text(x + 25, y + 10, commit.author.name) nameText = @text(x + 25, y + 10, commit.author.name)
idText = @text(x, y + 35, commit.id) idText = @text(x, y + 35, commit.id)
messageText = @text(x, y + 50, commit.message) messageText = @text(x, y + 50, commit.message)
......
class CommitFile class CommitFile
constructor: (file) -> constructor: (file) ->
if $('.image', file).length if $('.image', file).length
new ImageFile(file) new ImageFile(file)
this.CommitFile = CommitFile @CommitFile = CommitFile
\ No newline at end of file
...@@ -125,4 +125,4 @@ class ImageFile ...@@ -125,4 +125,4 @@ class ImageFile
img.on 'load', => img.on 'load', =>
callback.call(this, domImg.naturalWidth, domImg.naturalHeight) callback.call(this, domImg.naturalWidth, domImg.naturalHeight)
this.ImageFile = ImageFile @ImageFile = ImageFile
\ No newline at end of file
...@@ -6,7 +6,6 @@ GitLab.GfmAutoComplete = ...@@ -6,7 +6,6 @@ GitLab.GfmAutoComplete =
dataSource: '' dataSource: ''
# Emoji # Emoji
Emoji: Emoji:
assetBase: ''
template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>' template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
# Team Members # Team Members
...@@ -27,7 +26,7 @@ GitLab.GfmAutoComplete = ...@@ -27,7 +26,7 @@ GitLab.GfmAutoComplete =
tpl: @Emoji.template tpl: @Emoji.template
callbacks: callbacks:
before_save: (emojis) => before_save: (emojis) =>
$.map emojis, (em) => name: em, insert: em+ ':', image: "#{@Emoji.assetBase}/#{em}.png" $.map emojis, (em) => name: em.name, insert: em.name+ ':', image: em.path
# Team Members # Team Members
input.atwho input.atwho
......
...@@ -58,6 +58,18 @@ class MergeRequest ...@@ -58,6 +58,18 @@ class MergeRequest
$('.automerge_widget.can_be_merged').hide() $('.automerge_widget.can_be_merged').hide()
$('.merge-in-progress').show() $('.merge-in-progress').show()
this.$('.remove_source_branch').on 'click', ->
$('.remove_source_branch_widget').hide()
$('.remove_source_branch_in_progress').show()
this.$(".remove_source_branch").on "ajax:success", (e, data, status, xhr) ->
location.reload()
this.$(".remove_source_branch").on "ajax:error", (e, data, status, xhr) =>
this.$('.remove_source_branch_widget').hide()
this.$('.remove_source_branch_in_progress').hide()
this.$('.remove_source_branch_widget.failed').show()
activateTab: (action) -> activateTab: (action) ->
this.$('.nav-tabs li').removeClass 'active' this.$('.nav-tabs li').removeClass 'active'
this.$('.tab-content').hide() this.$('.tab-content').hide()
...@@ -76,7 +88,21 @@ class MergeRequest ...@@ -76,7 +88,21 @@ class MergeRequest
showCiState: (state) -> showCiState: (state) ->
$('.ci_widget').hide() $('.ci_widget').hide()
$('.ci_widget.ci-' + state).show() allowed_states = ["failed", "running", "pending", "success"]
if state in allowed_states
$('.ci_widget.ci-' + state).show()
else
$('.ci_widget.ci-error').show()
switch state
when "success"
$('.mr-state-widget').addClass("panel-success")
when "failed"
$('.mr-state-widget').addClass("panel-danger")
when "running", "pending"
$('.mr-state-widget').addClass("panel-warning")
loadDiff: (event) -> loadDiff: (event) ->
$.ajax $.ajax
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
* This is a manifest file that'll automatically include all the stylesheets available in this directory * This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope. * the top of the compiled file, but it's generally better to create a new file per style scope.
*= require jquery.ui.gitlab *= require jquery.ui.datepicker
*= require jquery.ui.autocomplete
*= require jquery.atwho *= require jquery.atwho
*= require select2 *= require select2
*= require highlightjs.min *= require highlightjs.min
...@@ -43,6 +44,7 @@ ...@@ -43,6 +44,7 @@
@import "generic/forms.scss"; @import "generic/forms.scss";
@import "generic/selects.scss"; @import "generic/selects.scss";
@import "generic/highlight.scss"; @import "generic/highlight.scss";
@import "generic/jquery.scss";
/** /**
* Page specific styles (issues, projects etc): * Page specific styles (issues, projects etc):
......
...@@ -364,3 +364,7 @@ table { ...@@ -364,3 +364,7 @@ table {
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
.container .content { margin-top: 20px; } .container .content { margin-top: 20px; }
} }
.wiki .highlight, .note-body .highlight {
margin-bottom: 9px;
}
.ui-widget {
font-family: $regular_font;
font-size: $font-size-base;
&.ui-datepicker-inline {
border: 1px solid #DDD;
padding: 10px;
width: 270px;
.ui-datepicker-header {
background: #EEE;
border-color: #DDD;
}
.ui-datepicker-calendar td a {
padding: 5px;
text-align: center;
}
}
&.ui-autocomplete {
@include border-radius(0px);
border-color: #DDD;
padding: 0;
.ui-menu-item a {
color: #777;
&:hover {
background: $hover;
border-color: $primary_color;
@include border-radius(0px);
color: #333;
}
}
}
}
...@@ -13,6 +13,12 @@ ...@@ -13,6 +13,12 @@
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
border-bottom: 1px solid rgba(0, 0, 0, 0.05); border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:after {
content: " ";
display: table;
clear: both;
}
&.disabled { &.disabled {
color: #888; color: #888;
} }
...@@ -46,6 +52,12 @@ ...@@ -46,6 +52,12 @@
.author { color: #999; } .author { color: #999; }
.list-item-name {
float: left;
position: relative;
top: 3px;
}
p { p {
padding-top: 1px; padding-top: 1px;
margin: 0; margin: 0;
......
...@@ -88,9 +88,6 @@ a:focus { ...@@ -88,9 +88,6 @@ a:focus {
.wiki { .wiki {
@include md-typography; @include md-typography;
font-size: 14px;
line-height: 1.6;
/* Link to current header. */ /* Link to current header. */
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6 {
position: relative; position: relative;
...@@ -120,3 +117,11 @@ a:focus { ...@@ -120,3 +117,11 @@ a:focus {
.md { .md {
@include md-typography; @include md-typography;
} }
/**
* Textareas intended for GFM
*
*/
textarea.js-gfm-input {
font-family: $monospace_font;
}
...@@ -45,6 +45,7 @@ $pagination-active-bg: $bg_style_color; ...@@ -45,6 +45,7 @@ $pagination-active-bg: $bg_style_color;
@import "bootstrap/list-group"; @import "bootstrap/list-group";
@import "bootstrap/wells"; @import "bootstrap/wells";
@import "bootstrap/close"; @import "bootstrap/close";
@import "bootstrap/panels";
// Components w/ JavaScript // Components w/ JavaScript
@import "bootstrap/modals"; @import "bootstrap/modals";
......
This diff is collapsed.
/** Typo **/ /** Typo **/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
$regular_font: "Helvetica Neue", Helvetica, Arial, sans-serif;
...@@ -84,6 +84,9 @@ ...@@ -84,6 +84,9 @@
} }
@mixin md-typography { @mixin md-typography {
font-size: 14px;
line-height: 1.6;
img { img {
max-width: 100%; max-width: 100%;
} }
......
/* Generic print styles */
header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;}
.profiler-results {display: none;}
/* Styles targeted specifically at printing files */
.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;}
.file-title {display: none;}
.file-holder {border: none;}
.wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; }
.wiki h1 {font-size: 30px;}
.wiki h2 {font-size: 22px;}
.wiki h3 {font-size: 18px; font-weight: bold; }
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
} }
.project-row, .group-row { .project-row, .group-row {
padding: 10px 12px !important; padding: 8px 12px !important;
font-size: 14px; font-size: 14px;
line-height: 24px; line-height: 24px;
...@@ -113,6 +113,5 @@ ...@@ -113,6 +113,5 @@
float: left; float: left;
margin-right: 3px; margin-right: 3px;
color: #999; color: #999;
margin-bottom: 10px;
width: 16px; width: 16px;
} }
...@@ -62,6 +62,29 @@ ...@@ -62,6 +62,29 @@
font-size: 12px; font-size: 12px;
} }
} }
.text-file-parallel div {
display: inline-block;
padding-bottom: 16px;
}
.diff-side {
overflow-x: scroll;
width: 508px;
height: 700px;
}
.diff-side.diff-side-left{
overflow-y:hidden;
}
.diff-side table, td.diff-middle table {
height: 700px;
}
.diff-middle {
width: 114px;
vertical-align: top;
height: 700px;
overflow: hidden
}
.old_line, .new_line, .diff_line { .old_line, .new_line, .diff_line {
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
...@@ -125,8 +148,6 @@ ...@@ -125,8 +148,6 @@
} }
&.parallel { &.parallel {
display: table-cell; display: table-cell;
overflow: hidden;
width: 50%;
} }
} }
} }
......
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
} }
} }
padding: 14px 0px; padding: 12px 0px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
.event-title { .event-title {
color: #333; color: #333;
...@@ -63,6 +63,10 @@ ...@@ -63,6 +63,10 @@
color: #666; color: #666;
margin-top: 5px; margin-top: 5px;
.md {
font-size: 13px;
}
pre { pre {
border: none; border: none;
background: #f9f9f9; background: #f9f9f9;
......
...@@ -273,3 +273,9 @@ header { ...@@ -273,3 +273,9 @@ header {
} }
} }
} }
@media (max-width: $screen-xs-max) {
#nprogress .spinner {
right: 35px !important;
}
}
...@@ -44,10 +44,9 @@ ...@@ -44,10 +44,9 @@
.label-branch { .label-branch {
@include border-radius(4px); @include border-radius(4px);
padding: 3px 4px; padding: 2px 4px;
border: none; border: none;
font-size: 14px; background: #555;
background: #474D57;
color: #fff; color: #fff;
font-family: $monospace_font; font-family: $monospace_font;
font-weight: normal; font-weight: normal;
...@@ -95,3 +94,21 @@ ...@@ -95,3 +94,21 @@
.diff-file .reopen-mr-link { .diff-file .reopen-mr-link {
display: none; display: none;
} }
.mr-state-widget {
@include border-radius(0px);
.panel-heading {
@include border-radius(0px);
}
.panel-body {
h4 {
margin-top: 0px;
}
p:last-child {
margin-bottom: 0;
}
}
}
...@@ -27,11 +27,15 @@ ul.notes { ...@@ -27,11 +27,15 @@ ul.notes {
.discussion-last-update, .discussion-last-update,
.note-last-update { .note-last-update {
font-style: italic; &:before {
content: "\00b7";
}
font-size: 13px;
} }
.author { .author {
color: $style_color; color: #555;
font-weight: bold; font-weight: bold;
font-size: 14px;
&:hover { &:hover {
color: $primary_color; color: $primary_color;
} }
...@@ -90,10 +94,10 @@ ul.notes { ...@@ -90,10 +94,10 @@ ul.notes {
} }
.note-body { .note-body {
@include md-typography; @include md-typography;
margin-left: 45px; margin-left: 43px;
} }
.note-header { .note-header {
padding-bottom: 5px; padding-bottom: 3px;
} }
} }
......
...@@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base ...@@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
before_filter :default_headers before_filter :default_headers
before_filter :add_gon_variables before_filter :add_gon_variables
before_filter :configure_permitted_parameters, if: :devise_controller? before_filter :configure_permitted_parameters, if: :devise_controller?
before_filter :require_email, unless: :devise_controller?
protect_from_forgery protect_from_forgery
...@@ -235,4 +236,10 @@ class ApplicationController < ActionController::Base ...@@ -235,4 +236,10 @@ class ApplicationController < ActionController::Base
def hexdigest(string) def hexdigest(string)
Digest::SHA1.hexdigest string Digest::SHA1.hexdigest string
end end
def require_email
if current_user && current_user.temp_oauth_email?
redirect_to profile_path, notice: 'Please complete your profile with email address' and return
end
end
end end
...@@ -8,7 +8,7 @@ class Profiles::EmailsController < ApplicationController ...@@ -8,7 +8,7 @@ class Profiles::EmailsController < ApplicationController
def create def create
@email = current_user.emails.new(params[:email]) @email = current_user.emails.new(params[:email])
flash[:alert] = @email.errors.full_messages.first unless @email.save flash[:alert] = @email.errors.full_messages.first unless @email.save
redirect_to profile_emails_url redirect_to profile_emails_url
......
...@@ -3,6 +3,7 @@ class ProfilesController < ApplicationController ...@@ -3,6 +3,7 @@ class ProfilesController < ApplicationController
before_filter :user before_filter :user
before_filter :authorize_change_username!, only: :update_username before_filter :authorize_change_username!, only: :update_username
skip_before_filter :require_email, only: [:show, :update]
layout 'profile' layout 'profile'
......
...@@ -16,11 +16,7 @@ class Projects::BranchesController < Projects::ApplicationController ...@@ -16,11 +16,7 @@ class Projects::BranchesController < Projects::ApplicationController
end end
def create def create
@repository.add_branch(params[:branch_name], params[:ref]) CreateBranchService.new.execute(project, params[:branch_name], params[:ref], current_user)
if new_branch = @repository.find_branch(params[:branch_name])
Event.create_ref_event(@project, current_user, new_branch, 'add')
end
redirect_to project_branches_path(@project) redirect_to project_branches_path(@project)
end end
......
...@@ -18,7 +18,7 @@ class Projects::HooksController < Projects::ApplicationController ...@@ -18,7 +18,7 @@ class Projects::HooksController < Projects::ApplicationController
if @hook.valid? if @hook.valid?
redirect_to project_hooks_path(@project) redirect_to project_hooks_path(@project)
else else
@hooks = @project.hooks @hooks = @project.hooks.select(&:persisted?)
render :index render :index
end end
end end
......
...@@ -59,9 +59,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -59,9 +59,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def create def create
@issue = @project.issues.new(params[:issue]) @issue = Issues::CreateService.new(project, current_user, params[:issue]).execute
@issue.author = current_user
@issue.save
respond_to do |format| respond_to do |format|
format.html do format.html do
...@@ -76,8 +74,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -76,8 +74,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def update def update
@issue.update_attributes(params[:issue].merge(author_id_of_changes: current_user.id)) @issue = Issues::UpdateService.new(project, current_user, params[:issue]).execute(issue)
@issue.reset_events_cache
respond_to do |format| respond_to do |format|
format.js format.js
......
...@@ -76,10 +76,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -76,10 +76,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def create def create
@merge_request = MergeRequest.new(params[:merge_request])
@merge_request.author = current_user
@target_branches ||= [] @target_branches ||= []
if @merge_request.save @merge_request = MergeRequests::CreateService.new(project, current_user, params[:merge_request]).execute
if @merge_request.valid?
redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.' redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.'
else else
@source_project = @merge_request.source_project @source_project = @merge_request.source_project
...@@ -89,29 +89,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -89,29 +89,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def update def update
# If we close MergeRequest we want to ignore validation @merge_request = MergeRequests::UpdateService.new(project, current_user, params[:merge_request]).execute(@merge_request)
# so we can close broken one (Ex. fork project removed)
if params[:merge_request] == {"state_event"=>"close"}
@merge_request.allow_broken = true
if @merge_request.close
opts = { notice: 'Merge request was successfully closed.' }
else
opts = { alert: 'Failed to close merge request.' }
end
redirect_to [@merge_request.target_project, @merge_request], opts
return
end
# We dont allow change of source/target projects
# after merge request was created
params[:merge_request].delete(:source_project_id)
params[:merge_request].delete(:target_project_id)
if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
@merge_request.reset_events_cache
if @merge_request.valid?
respond_to do |format| respond_to do |format|
format.js format.js
format.html do format.html do
...@@ -231,20 +211,31 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -231,20 +211,31 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request_diff = @merge_request.merge_request_diff @merge_request_diff = @merge_request.merge_request_diff
@allowed_to_merge = allowed_to_merge? @allowed_to_merge = allowed_to_merge?
@show_merge_controls = @merge_request.open? && @commits.any? && @allowed_to_merge @show_merge_controls = @merge_request.open? && @commits.any? && @allowed_to_merge
@allowed_to_remove_source_branch = allowed_to_remove_source_branch?
@source_branch = @merge_request.source_project.repository.find_branch(@merge_request.source_branch).try(:name)
end end
def allowed_to_merge? def allowed_to_merge?
action = if project.protected_branch?(@merge_request.target_branch) allowed_to_push_code?(project, @merge_request.target_branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, @project)
end end
def invalid_mr def invalid_mr
# Render special view for MR with removed source or target branch # Render special view for MR with removed source or target branch
render 'invalid' render 'invalid'
end end
def allowed_to_remove_source_branch?
allowed_to_push_code?(@merge_request.source_project, @merge_request.source_branch) &&
!@merge_request.disallow_source_branch_removal?
end
def allowed_to_push_code?(project, branch)
action = if project.protected_branch?(branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, project)
end
end end
...@@ -38,7 +38,6 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -38,7 +38,6 @@ class Projects::MilestonesController < Projects::ApplicationController
def create def create
@milestone = @project.milestones.new(params[:milestone]) @milestone = @project.milestones.new(params[:milestone])
@milestone.author_id_of_changes = current_user.id
if @milestone.save if @milestone.save
redirect_to project_milestone_path(@project, @milestone) redirect_to project_milestone_path(@project, @milestone)
...@@ -48,7 +47,7 @@ class Projects::MilestonesController < Projects::ApplicationController ...@@ -48,7 +47,7 @@ class Projects::MilestonesController < Projects::ApplicationController
end end
def update def update
@milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id)) @milestone.update_attributes(params[:milestone])
respond_to do |format| respond_to do |format|
format.js format.js
......
...@@ -14,7 +14,9 @@ class Projects::RepositoriesController < Projects::ApplicationController ...@@ -14,7 +14,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
render_404 and return render_404 and return
end end
storage_path = Rails.root.join("tmp", "repositories") storage_path = Gitlab.config.gitlab.repository_downloads_path
@repository.clean_old_archives
file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase) file_path = @repository.archive_repo(params[:ref], storage_path, params[:format].downcase)
......
require 'project_wiki'
class Projects::WikisController < Projects::ApplicationController class Projects::WikisController < Projects::ApplicationController
before_filter :authorize_read_wiki! before_filter :authorize_read_wiki!
before_filter :authorize_write_wiki!, only: [:edit, :create, :history] before_filter :authorize_write_wiki!, only: [:edit, :create, :history]
before_filter :authorize_admin_wiki!, only: :destroy before_filter :authorize_admin_wiki!, only: :destroy
before_filter :load_gollum_wiki before_filter :load_project_wiki
def pages def pages
@wiki_pages = @gollum_wiki.pages @wiki_pages = @project_wiki.pages
end end
def show def show
@wiki = @gollum_wiki.find_page(params[:id], params[:version_id]) @page = @project_wiki.find_page(params[:id], params[:version_id])
if @wiki if @page
render 'show' render 'show'
else else
return render('empty') unless can?(current_user, :write_wiki, @project) return render('empty') unless can?(current_user, :write_wiki, @project)
@wiki = WikiPage.new(@gollum_wiki) @page = WikiPage.new(@project_wiki)
@wiki.title = params[:id] @page.title = params[:id]
render 'edit' render 'edit'
end end
end end
def edit def edit
@wiki = @gollum_wiki.find_page(params[:id]) @page = @project_wiki.find_page(params[:id])
end end
def update def update
@wiki = @gollum_wiki.find_page(params[:id]) @page = @project_wiki.find_page(params[:id])
return render('empty') unless can?(current_user, :write_wiki, @project) return render('empty') unless can?(current_user, :write_wiki, @project)
if @wiki.update(content, format, message) if @page.update(content, format, message)
redirect_to [@project, @wiki], notice: 'Wiki was successfully updated.' redirect_to [@project, @page], notice: 'Wiki was successfully updated.'
else else
render 'edit' render 'edit'
end end
end end
def create def create
@wiki = WikiPage.new(@gollum_wiki) @page = WikiPage.new(@project_wiki)
if @wiki.create(wiki_params) if @page.create(wiki_params)
redirect_to project_wiki_path(@project, @wiki), notice: 'Wiki was successfully updated.' redirect_to project_wiki_path(@project, @page), notice: 'Wiki was successfully updated.'
else else
render action: "edit" render action: "edit"
end end
end end
def history def history
@wiki = @gollum_wiki.find_page(params[:id]) @page = @project_wiki.find_page(params[:id])
redirect_to(project_wiki_path(@project, :home), notice: "Page not found") unless @wiki unless @page
redirect_to(project_wiki_path(@project, :home), notice: "Page not found")
end
end end
def destroy def destroy
@wiki = @gollum_wiki.find_page(params[:id]) @page = @project_wiki.find_page(params[:id])
@wiki.delete if @wiki @page.delete if @page
redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted" redirect_to project_wiki_path(@project, :home), notice: "Page was successfully deleted"
end end
...@@ -65,12 +70,12 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -65,12 +70,12 @@ class Projects::WikisController < Projects::ApplicationController
private private
def load_gollum_wiki def load_project_wiki
@gollum_wiki = GollumWiki.new(@project, current_user) @project_wiki = ProjectWiki.new(@project, current_user)
# Call #wiki to make sure the Wiki Repo is initialized # Call #wiki to make sure the Wiki Repo is initialized
@gollum_wiki.wiki @project_wiki.wiki
rescue GollumWiki::CouldNotCreateWikiError => ex rescue ProjectWiki::CouldNotCreateWikiError => ex
flash[:notice] = "Could not create Wiki Repository at this time. Please try again later." flash[:notice] = "Could not create Wiki Repository at this time. Please try again later."
redirect_to @project redirect_to @project
return false return false
...@@ -91,5 +96,4 @@ class Projects::WikisController < Projects::ApplicationController ...@@ -91,5 +96,4 @@ class Projects::WikisController < Projects::ApplicationController
def message def message
params[:wiki][:message] params[:wiki][:message]
end end
end end
...@@ -123,11 +123,20 @@ class ProjectsController < ApplicationController ...@@ -123,11 +123,20 @@ class ProjectsController < ApplicationController
end end
def autocomplete_sources def autocomplete_sources
note_type = params['type']
note_id = params['type_id']
participating = if note_type && note_id
participants_in(note_type, note_id)
else
[]
end
team_members = sorted(@project.team.members)
participants = team_members + participating
@suggestions = { @suggestions = {
emojis: Emoji.names, emojis: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } },
issues: @project.issues.select([:iid, :title, :description]), issues: @project.issues.select([:iid, :title, :description]),
mergerequests: @project.merge_requests.select([:iid, :title, :description]), mergerequests: @project.merge_requests.select([:iid, :title, :description]),
members: @project.team.members.sort_by(&:username).map { |user| { username: user.username, name: user.name } } members: participants.uniq
} }
respond_to do |format| respond_to do |format|
...@@ -162,4 +171,25 @@ class ProjectsController < ApplicationController ...@@ -162,4 +171,25 @@ class ProjectsController < ApplicationController
def user_layout def user_layout
current_user ? "projects" : "public_projects" current_user ? "projects" : "public_projects"
end end
def participants_in(type, id)
users = case type
when "Issue"
issue = @project.issues.find_by_iid(id)
issue ? issue.participants : []
when "MergeRequest"
merge_request = @project.merge_requests.find_by_iid(id)
merge_request ? merge_request.participants : []
when "Commit"
author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
User.where(id: author_ids)
else
[]
end
sorted(users)
end
def sorted(users)
users.uniq.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
end
end end
...@@ -47,9 +47,9 @@ class BaseFinder ...@@ -47,9 +47,9 @@ class BaseFinder
[] []
end end
elsif current_user && params[:authorized_only].presence elsif current_user && params[:authorized_only].presence
klass.of_projects(current_user.authorized_projects) klass.of_projects(current_user.authorized_projects).references(:project)
else else
klass.of_projects(Project.accessible_to(current_user)) klass.of_projects(Project.accessible_to(current_user)).references(:project)
end end
end end
......
...@@ -105,8 +105,80 @@ module CommitsHelper ...@@ -105,8 +105,80 @@ module CommitsHelper
branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
end end
def get_old_file(project, commit, diff) def parallel_diff_lines(project, commit, diff, file)
project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id old_file = project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
deleted_lines = {}
added_lines = {}
each_diff_line(diff, 0) do |line, type, line_code, line_new, line_old|
if type == "old"
deleted_lines[line_old] = { line_code: line_code, type: type, line: line }
elsif type == "new"
added_lines[line_new] = { line_code: line_code, type: type, line: line }
end
end
max_length = old_file ? old_file.sloc + added_lines.length : file.sloc
offset1 = 0
offset2 = 0
old_lines = []
new_lines = []
max_length.times do |line_index|
line_index1 = line_index - offset1
line_index2 = line_index - offset2
deleted_line = deleted_lines[line_index1 + 1]
added_line = added_lines[line_index2 + 1]
old_line = old_file.lines[line_index1] if old_file
new_line = file.lines[line_index2]
if deleted_line && added_line
elsif deleted_line
new_line = nil
offset2 += 1
elsif added_line
old_line = nil
offset1 += 1
end
old_lines[line_index] = DiffLine.new
new_lines[line_index] = DiffLine.new
# old
if line_index == 0 && diff.new_file
old_lines[line_index].type = :file_created
old_lines[line_index].content = 'File was created'
elsif deleted_line
old_lines[line_index].type = :deleted
old_lines[line_index].content = old_line
old_lines[line_index].num = line_index1 + 1
old_lines[line_index].code = deleted_line[:line_code]
elsif old_line
old_lines[line_index].type = :no_change
old_lines[line_index].content = old_line
old_lines[line_index].num = line_index1 + 1
else
old_lines[line_index].type = :added
end
# new
if line_index == 0 && diff.deleted_file
new_lines[line_index].type = :file_deleted
new_lines[line_index].content = "File was deleted"
elsif added_line
new_lines[line_index].type = :added
new_lines[line_index].num = line_index2 + 1
new_lines[line_index].content = new_line
new_lines[line_index].code = added_line[:line_code]
elsif new_line
new_lines[line_index].type = :no_change
new_lines[line_index].num = line_index2 + 1
new_lines[line_index].content = new_line
else
new_lines[line_index].type = :deleted
end
end
return old_lines, new_lines
end end
protected protected
......
...@@ -20,7 +20,7 @@ module MergeRequestsHelper ...@@ -20,7 +20,7 @@ module MergeRequestsHelper
target_project_id: target_project.id, target_project_id: target_project.id,
source_branch: event.branch_name, source_branch: event.branch_name,
target_branch: target_project.repository.root_ref, target_branch: target_project.repository.root_ref,
title: event.branch_name.titleize title: event.branch_name.titleize.humanize
} }
end end
......
...@@ -12,6 +12,8 @@ module SubmoduleHelper ...@@ -12,6 +12,8 @@ module SubmoduleHelper
if self_url?(url, project) if self_url?(url, project)
return project_path(project), project_tree_path(project, submodule_item.id) return project_path(project), project_tree_path(project, submodule_item.id)
elsif relative_self_url?(url)
relative_self_links(url, submodule_item.id)
elsif github_dot_com_url?(url) elsif github_dot_com_url?(url)
standard_links('github.com', project, submodule_item.id) standard_links('github.com', project, submodule_item.id)
elsif gitlab_dot_com_url?(url) elsif gitlab_dot_com_url?(url)
...@@ -36,8 +38,22 @@ module SubmoduleHelper ...@@ -36,8 +38,22 @@ module SubmoduleHelper
url == gitlab_shell.url_to_repo(project) url == gitlab_shell.url_to_repo(project)
end end
def relative_self_url?(url)
# (./)?(../repo.git) || (./)?(../../project/repo.git) )
url =~ /^((\.\/)?(\.\.\/))(?!(\.\.)|(.*\/)).*\.git\Z/ || url =~ /^((\.\/)?(\.\.\/){2})(?!(\.\.))([^\/]*)\/(?!(\.\.)|(.*\/)).*\.git\Z/
end
def standard_links(host, project, commit) def standard_links(host, project, commit)
base = [ 'https://', host, '/', project ].join('') base = [ 'https://', host, '/', project ].join('')
return base, [ base, '/tree/', commit ].join('') return base, [ base, '/tree/', commit ].join('')
end end
def relative_self_links(url, commit)
if url.scan(/(\.\.\/)/).size == 2
base = url[/([^\/]*\/[^\/]*)\.git/, 1]
else
base = [ @project.group.path, '/', url[/([^\/]*)\.git/, 1] ].join('')
end
return project_path(base), project_tree_path(base, commit)
end
end end
...@@ -29,11 +29,11 @@ module Emails ...@@ -29,11 +29,11 @@ module Emails
subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end end
def merged_merge_request_email(recipient_id, merge_request_id) def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@merge_request = MergeRequest.find(merge_request_id) @merge_request = MergeRequest.find(merge_request_id)
@project = @merge_request.project @project = @merge_request.project
@target_url = project_merge_request_url(@project, @merge_request) @target_url = project_merge_request_url(@project, @merge_request)
mail(from: sender(@merge_request.author_id_of_changes), mail(from: sender(updated_by_user_id),
to: recipient(recipient_id), to: recipient(recipient_id),
subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
end end
......
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
# Table name: broadcast_messages # Table name: broadcast_messages
# #
# id :integer not null, primary key # id :integer not null, primary key
# message :text default(""), not null # message :text not null
# starts_at :datetime # starts_at :datetime
# ends_at :datetime # ends_at :datetime
# alert_type :integer # alert_type :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# color :string(255) # color :string(255)
# font :string(255) # font :string(255)
# #
......
...@@ -37,8 +37,6 @@ module Issuable ...@@ -37,8 +37,6 @@ module Issuable
allow_nil: true, allow_nil: true,
prefix: true prefix: true
attr_accessor :author_id_of_changes
attr_mentionable :title, :description attr_mentionable :title, :description
end end
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer # user_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# key :text # key :text
# title :string(255) # title :string(255)
# type :string(255) # type :string(255)
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# id :integer not null, primary key # id :integer not null, primary key
# deploy_key_id :integer not null # deploy_key_id :integer not null
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# #
class DeployKeysProject < ActiveRecord::Base class DeployKeysProject < ActiveRecord::Base
......
class DiffLine
attr_accessor :type, :content, :num, :code
end
...@@ -2,10 +2,13 @@ ...@@ -2,10 +2,13 @@
# #
# Table name: emails # Table name: emails
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer not null
# email :string not null # email :string(255) not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime
#
class Email < ActiveRecord::Base class Email < ActiveRecord::Base
attr_accessible :email, :user_id attr_accessible :email, :user_id
...@@ -13,14 +16,15 @@ class Email < ActiveRecord::Base ...@@ -13,14 +16,15 @@ class Email < ActiveRecord::Base
# Relations # Relations
# #
belongs_to :user belongs_to :user
# #
# Validations # Validations
# #
validates :user_id, presence: true validates :user_id, presence: true
validates :email, presence: true, email: { strict_mode: true }, uniqueness: true validates :email, presence: true, email: { strict_mode: true }, uniqueness: true
validate :unique_email, if: ->(email) { email.email_changed? } validate :unique_email, if: ->(email) { email.email_changed? }
after_create :notify
before_validation :cleanup_email before_validation :cleanup_email
def cleanup_email def cleanup_email
...@@ -30,4 +34,8 @@ class Email < ActiveRecord::Base ...@@ -30,4 +34,8 @@ class Email < ActiveRecord::Base
def unique_email def unique_email
self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email) self.errors.add(:email, 'has already been taken') if User.exists?(email: self.email)
end end
end
\ No newline at end of file def notify
NotificationService.new.new_email(self)
end
end
...@@ -8,8 +8,8 @@ ...@@ -8,8 +8,8 @@
# title :string(255) # title :string(255)
# data :text # data :text
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# action :integer # action :integer
# author_id :integer # author_id :integer
# #
...@@ -47,14 +47,6 @@ class Event < ActiveRecord::Base ...@@ -47,14 +47,6 @@ class Event < ActiveRecord::Base
scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent } scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
class << self class << self
def determine_action(record)
if [Issue, MergeRequest].include? record.class
Event::CREATED
elsif record.kind_of? Note
Event::COMMENTED
end
end
def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads') def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
commit = project.repository.commit(ref.target) commit = project.repository.commit(ref.target)
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# id :integer not null, primary key # id :integer not null, primary key
# forked_to_project_id :integer not null # forked_to_project_id :integer not null
# forked_from_project_id :integer not null # forked_from_project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# #
class ForkedProjectLink < ActiveRecord::Base class ForkedProjectLink < ActiveRecord::Base
......
...@@ -6,10 +6,11 @@ ...@@ -6,10 +6,11 @@
# name :string(255) not null # name :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer # owner_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255)
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
# assignee_id :integer # assignee_id :integer
# author_id :integer # author_id :integer
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# position :integer default(0) # position :integer default(0)
# branch_name :string(255) # branch_name :string(255)
# description :text # description :text
...@@ -30,8 +30,7 @@ class Issue < ActiveRecord::Base ...@@ -30,8 +30,7 @@ class Issue < ActiveRecord::Base
scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) } scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
attr_accessible :title, :assignee_id, :position, :description, attr_accessible :title, :assignee_id, :position, :description,
:milestone_id, :label_list, :author_id_of_changes, :milestone_id, :label_list, :state_event
:state_event
acts_as_taggable_on :labels acts_as_taggable_on :labels
......
...@@ -4,8 +4,8 @@ ...@@ -4,8 +4,8 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer # user_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# key :text # key :text
# title :string(255) # title :string(255)
# type :string(255) # type :string(255)
...@@ -29,6 +29,10 @@ class Key < ActiveRecord::Base ...@@ -29,6 +29,10 @@ class Key < ActiveRecord::Base
delegate :name, :email, to: :user, prefix: true delegate :name, :email, to: :user, prefix: true
after_create :add_to_shell
after_create :notify_user
after_destroy :remove_from_shell
def strip_white_space def strip_white_space
self.key = key.strip unless key.blank? self.key = key.strip unless key.blank?
end end
...@@ -42,6 +46,26 @@ class Key < ActiveRecord::Base ...@@ -42,6 +46,26 @@ class Key < ActiveRecord::Base
"key-#{id}" "key-#{id}"
end end
def add_to_shell
GitlabShellWorker.perform_async(
:add_key,
shell_id,
key
)
end
def notify_user
NotificationService.new.new_key(self)
end
def remove_from_shell
GitlabShellWorker.perform_async(
:remove_key,
shell_id,
key,
)
end
private private
def generate_fingerpint def generate_fingerpint
......
...@@ -9,10 +9,8 @@ ...@@ -9,10 +9,8 @@
# author_id :integer # author_id :integer
# assignee_id :integer # assignee_id :integer
# title :string(255) # title :string(255)
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# st_commits :text(2147483647)
# st_diffs :text(2147483647)
# milestone_id :integer # milestone_id :integer
# state :string(255) # state :string(255)
# merge_status :string(255) # merge_status :string(255)
...@@ -38,7 +36,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -38,7 +36,7 @@ class MergeRequest < ActiveRecord::Base
delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :author_id_of_changes, :state_event, :description attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :state_event, :description
attr_accessor :should_remove_source_branch attr_accessor :should_remove_source_branch
...@@ -97,6 +95,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -97,6 +95,7 @@ class MergeRequest < ActiveRecord::Base
validates :target_project, presence: true validates :target_project, presence: true
validates :target_branch, presence: true validates :target_branch, presence: true
validate :validate_branches validate :validate_branches
validate :validate_fork
scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) } scope :of_group, ->(group) { where("source_project_id in (:group_project_ids) OR target_project_id in (:group_project_ids)", group_project_ids: group.project_ids) }
scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))", team_project_ids: team.project_ids, team_member_ids: team.member_ids) } scope :of_user_team, ->(team) { where("(source_project_id in (:team_project_ids) OR target_project_id in (:team_project_ids) AND assignee_id in (:team_member_ids))", team_project_ids: team.project_ids, team_member_ids: team.member_ids) }
...@@ -125,6 +124,22 @@ class MergeRequest < ActiveRecord::Base ...@@ -125,6 +124,22 @@ class MergeRequest < ActiveRecord::Base
end end
end end
def validate_fork
return true unless target_project && source_project
if target_project == source_project
true
else
# If source and target projects are different
# we should check if source project is actually a fork of target project
if source_project.forked_from?(target_project)
true
else
errors.add :base, "Source project is not a fork of target project"
end
end
end
def update_merge_request_diff def update_merge_request_diff
if source_branch_changed? || target_branch_changed? if source_branch_changed? || target_branch_changed?
reload_code reload_code
...@@ -193,7 +208,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -193,7 +208,7 @@ class MergeRequest < ActiveRecord::Base
end end
def disallow_source_branch_removal? def disallow_source_branch_removal?
(source_project.root_ref? source_branch) || for_fork? source_project.root_ref?(source_branch) || source_project.protected_branches.include?(source_branch)
end end
def project def project
......
# == Schema Information
#
# Table name: merge_request_diffs
#
# id :integer not null, primary key
# state :string(255) default("collected"), not null
# st_commits :text
# st_diffs :text
# merge_request_id :integer not null
# created_at :datetime
# updated_at :datetime
#
require Rails.root.join("app/models/commit") require Rails.root.join("app/models/commit")
class MergeRequestDiff < ActiveRecord::Base class MergeRequestDiff < ActiveRecord::Base
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
# project_id :integer not null # project_id :integer not null
# description :text # description :text
# due_date :date # due_date :date
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# state :string(255) # state :string(255)
# iid :integer # iid :integer
# #
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
class Milestone < ActiveRecord::Base class Milestone < ActiveRecord::Base
include InternalId include InternalId
attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes attr_accessible :title, :description, :due_date, :state_event
attr_accessor :author_id_of_changes
belongs_to :project belongs_to :project
has_many :issues has_many :issues
...@@ -89,6 +88,6 @@ class Milestone < ActiveRecord::Base ...@@ -89,6 +88,6 @@ class Milestone < ActiveRecord::Base
end end
def author_id def author_id
author_id_of_changes nil
end end
end end
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
# name :string(255) not null # name :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer # owner_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) # type :string(255)
# description :string(255) default(""), not null # description :string(255) default(""), not null
# avatar :string(255) # avatar :string(255)
......
...@@ -6,15 +6,15 @@ ...@@ -6,15 +6,15 @@
# note :text # note :text
# noteable_type :string(255) # noteable_type :string(255)
# author_id :integer # author_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# project_id :integer # project_id :integer
# attachment :string(255) # attachment :string(255)
# line_code :string(255) # line_code :string(255)
# commit_id :string(255) # commit_id :string(255)
# noteable_id :integer # noteable_id :integer
# st_diff :text
# system :boolean default(FALSE), not null # system :boolean default(FALSE), not null
# st_diff :text
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
...@@ -23,6 +23,8 @@ require 'file_size_validator' ...@@ -23,6 +23,8 @@ require 'file_size_validator'
class Note < ActiveRecord::Base class Note < ActiveRecord::Base
include Mentionable include Mentionable
default_value_for :system, false
attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id, attr_accessible :note, :noteable, :noteable_id, :noteable_type, :project_id,
:attachment, :line_code, :commit_id :attachment, :line_code, :commit_id
attr_mentionable :note attr_mentionable :note
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# title :string(255) # title :string(255)
# content :text(2147483647) # content :text
# author_id :integer not null # author_id :integer not null
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# file_name :string(255) # file_name :string(255)
# expires_at :datetime # expires_at :datetime
# private :boolean default(TRUE), not null # private :boolean default(TRUE), not null
......
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
# name :string(255) # name :string(255)
# path :string(255) # path :string(255)
# description :text # description :text
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# creator_id :integer # creator_id :integer
# issues_enabled :boolean default(TRUE), not null # issues_enabled :boolean default(TRUE), not null
# wall_enabled :boolean default(TRUE), not null # wall_enabled :boolean default(TRUE), not null
...@@ -18,9 +18,10 @@ ...@@ -18,9 +18,10 @@
# issues_tracker_id :string(255) # issues_tracker_id :string(255)
# snippets_enabled :boolean default(TRUE), not null # snippets_enabled :boolean default(TRUE), not null
# last_activity_at :datetime # last_activity_at :datetime
# imported :boolean default(FALSE), not null
# import_url :string(255) # import_url :string(255)
# visibility_level :integer default(0), not null # visibility_level :integer default(0), not null
# archived :boolean default(FALSE), not null
# import_status :string(255)
# #
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
...@@ -29,6 +30,11 @@ class Project < ActiveRecord::Base ...@@ -29,6 +30,11 @@ class Project < ActiveRecord::Base
extend Enumerize extend Enumerize
default_value_for :archived, false default_value_for :archived, false
default_value_for :issues_enabled, true
default_value_for :wall_enabled, true
default_value_for :merge_requests_enabled, true
default_value_for :wiki_enabled, true
default_value_for :snippets_enabled, true
ActsAsTaggableOn.strict_case_match = true ActsAsTaggableOn.strict_case_match = true
...@@ -244,7 +250,7 @@ class Project < ActiveRecord::Base ...@@ -244,7 +250,7 @@ class Project < ActiveRecord::Base
def check_limit def check_limit
unless creator.can_create_project? unless creator.can_create_project?
errors[:limit_reached] << ("Your own projects limit is #{creator.projects_limit}! Please contact administrator to increase it") errors[:limit_reached] << ("Your project limit is #{creator.projects_limit} projects! Please contact your administrator to increase it")
end end
rescue rescue
errors[:base] << ("Can't check your ability to create project") errors[:base] << ("Can't check your ability to create project")
...@@ -556,4 +562,8 @@ class Project < ActiveRecord::Base ...@@ -556,4 +562,8 @@ class Project < ActiveRecord::Base
gitlab_shell.update_repository_head(self.path_with_namespace, branch) gitlab_shell.update_repository_head(self.path_with_namespace, branch)
reload_default_branch reload_default_branch
end end
def forked_from?(project)
forked? && project == forked_from_project
end
end end
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# #
class ProjectHook < WebHook class ProjectHook < WebHook
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -11,10 +11,16 @@ class SlackMessage ...@@ -11,10 +11,16 @@ class SlackMessage
@username = params.fetch(:user_name) @username = params.fetch(:user_name)
end end
def compose def pretext
format(message) format(message)
end end
def attachments
return [] if new_branch? || removed_branch?
commit_message_attachments
end
private private
attr_reader :after attr_reader :after
...@@ -31,7 +37,7 @@ class SlackMessage ...@@ -31,7 +37,7 @@ class SlackMessage
elsif removed_branch? elsif removed_branch?
removed_branch_message removed_branch_message
else else
push_message << commit_messages push_message
end end
end end
...@@ -54,15 +60,20 @@ class SlackMessage ...@@ -54,15 +60,20 @@ class SlackMessage
def commit_messages def commit_messages
commits.each_with_object('') do |commit, str| commits.each_with_object('') do |commit, str|
str << compose_commit_message(commit) str << compose_commit_message(commit)
end end.chomp
end
def commit_message_attachments
[{ text: format(commit_messages), color: attachment_color }]
end end
def compose_commit_message(commit) def compose_commit_message(commit)
id = commit.fetch(:id)[0..5] author = commit.fetch(:author).fetch(:name)
id = commit.fetch(:id)[0..8]
message = commit.fetch(:message) message = commit.fetch(:message)
url = commit.fetch(:url) url = commit.fetch(:url)
"\n - #{message} ([#{id}](#{url}))" "[#{id}](#{url}): #{message} - #{author}\n"
end end
def new_branch? def new_branch?
...@@ -92,4 +103,8 @@ class SlackMessage ...@@ -92,4 +103,8 @@ class SlackMessage
def compare_link def compare_link
"[Compare changes](#{compare_url})" "[Compare changes](#{compare_url})"
end end
def attachment_color
'#345'
end
end end
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
...@@ -52,7 +53,8 @@ class SlackService < Service ...@@ -52,7 +53,8 @@ class SlackService < Service
notifier = Slack::Notifier.new(subdomain, token) notifier = Slack::Notifier.new(subdomain, token)
notifier.channel = room notifier.channel = room
notifier.ping(message.compose) notifier.username = 'GitLab'
notifier.ping(message.pretext, attachments: message.attachments)
end end
private private
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# title :string(255) # title :string(255)
# content :text(2147483647) # content :text
# author_id :integer not null # author_id :integer not null
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# file_name :string(255) # file_name :string(255)
# expires_at :datetime # expires_at :datetime
# private :boolean default(TRUE), not null # private :boolean default(TRUE), not null
......
class GollumWiki class ProjectWiki
include Gitlab::ShellAdapter include Gitlab::ShellAdapter
MARKUPS = { MARKUPS = {
...@@ -41,7 +41,7 @@ class GollumWiki ...@@ -41,7 +41,7 @@ class GollumWiki
def wiki def wiki
@wiki ||= begin @wiki ||= begin
Gollum::Wiki.new(path_to_repo) Gollum::Wiki.new(path_to_repo)
rescue Grit::NoSuchPathError rescue Gollum::NoSuchPathError
create_repo! create_repo!
end end
end end
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# id :integer not null, primary key # id :integer not null, primary key
# project_id :integer not null # project_id :integer not null
# name :string(255) not null # name :string(255) not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# #
class ProtectedBranch < ActiveRecord::Base class ProtectedBranch < ActiveRecord::Base
......
...@@ -215,4 +215,9 @@ class Repository ...@@ -215,4 +215,9 @@ class Repository
def last_commit_for_path(sha, path) def last_commit_for_path(sha, path)
commits(sha, path, 1).last commits(sha, path, 1).last
end end
# Remove archives older than 2 hours
def clean_old_archives
Gitlab::Popen.popen(%W(find #{Gitlab.config.gitlab.repository_downloads_path} -mmin +120 -delete))
end
end end
...@@ -7,12 +7,13 @@ ...@@ -7,12 +7,13 @@
# title :string(255) # title :string(255)
# token :string(255) # token :string(255)
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# active :boolean default(FALSE), not null # active :boolean default(FALSE), not null
# project_url :string(255) # project_url :string(255)
# subdomain :string(255) # subdomain :string(255)
# room :string(255) # room :string(255)
# recipients :text
# api_key :string(255) # api_key :string(255)
# #
......
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# #
class ServiceHook < WebHook class ServiceHook < WebHook
......
...@@ -4,11 +4,11 @@ ...@@ -4,11 +4,11 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# title :string(255) # title :string(255)
# content :text(2147483647) # content :text
# author_id :integer not null # author_id :integer not null
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# file_name :string(255) # file_name :string(255)
# expires_at :datetime # expires_at :datetime
# private :boolean default(TRUE), not null # private :boolean default(TRUE), not null
......
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# #
class SystemHook < WebHook class SystemHook < WebHook
......
...@@ -2,53 +2,59 @@ ...@@ -2,53 +2,59 @@
# #
# Table name: users # Table name: users
# #
# id :integer not null, primary key # id :integer not null, primary key
# email :string(255) default(""), not null # email :string(255) default(""), not null
# encrypted_password :string(255) default(""), not null # encrypted_password :string(255) default(""), not null
# reset_password_token :string(255) # reset_password_token :string(255)
# reset_password_sent_at :datetime # reset_password_sent_at :datetime
# remember_created_at :datetime # remember_created_at :datetime
# sign_in_count :integer default(0) # sign_in_count :integer default(0)
# current_sign_in_at :datetime # current_sign_in_at :datetime
# last_sign_in_at :datetime # last_sign_in_at :datetime
# current_sign_in_ip :string(255) # current_sign_in_ip :string(255)
# last_sign_in_ip :string(255) # last_sign_in_ip :string(255)
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# name :string(255) # name :string(255)
# admin :boolean default(FALSE), not null # admin :boolean default(FALSE), not null
# projects_limit :integer default(10) # projects_limit :integer default(10)
# skype :string(255) default(""), not null # skype :string(255) default(""), not null
# linkedin :string(255) default(""), not null # linkedin :string(255) default(""), not null
# twitter :string(255) default(""), not null # twitter :string(255) default(""), not null
# authentication_token :string(255) # authentication_token :string(255)
# theme_id :integer default(1), not null # theme_id :integer default(1), not null
# bio :string(255) # bio :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255) # extern_uid :string(255)
# provider :string(255) # provider :string(255)
# username :string(255) # username :string(255)
# can_create_group :boolean default(TRUE), not null # can_create_group :boolean default(TRUE), not null
# can_create_team :boolean default(TRUE), not null # can_create_team :boolean default(TRUE), not null
# state :string(255) # state :string(255)
# color_scheme_id :integer default(1), not null # color_scheme_id :integer default(1), not null
# notification_level :integer default(1), not null # notification_level :integer default(1), not null
# password_expires_at :datetime # password_expires_at :datetime
# created_by_id :integer # created_by_id :integer
# avatar :string(255) # last_credential_check_at :datetime
# confirmation_token :string(255) # avatar :string(255)
# confirmed_at :datetime # confirmation_token :string(255)
# confirmation_sent_at :datetime # confirmed_at :datetime
# unconfirmed_email :string(255) # confirmation_sent_at :datetime
# hide_no_ssh_key :boolean default(FALSE) # unconfirmed_email :string(255)
# website_url :string(255) default(""), not null # hide_no_ssh_key :boolean default(FALSE)
# website_url :string(255) default(""), not null
# #
require 'carrierwave/orm/activerecord' require 'carrierwave/orm/activerecord'
require 'file_size_validator' require 'file_size_validator'
class User < ActiveRecord::Base class User < ActiveRecord::Base
default_value_for :admin, false
default_value_for :can_create_group, true
default_value_for :can_create_team, false
default_value_for :hide_no_ssh_key, false
devise :database_authenticatable, :token_authenticatable, :lockable, :async, devise :database_authenticatable, :token_authenticatable, :lockable, :async,
:recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :confirmable, :registerable
...@@ -204,7 +210,7 @@ class User < ActiveRecord::Base ...@@ -204,7 +210,7 @@ class User < ActiveRecord::Base
end end
def search query def search query
where("name LIKE :query OR email LIKE :query OR username LIKE :query", query: "%#{query}%") where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
end end
def by_username_or_id(name_or_id) def by_username_or_id(name_or_id)
...@@ -463,4 +469,12 @@ class User < ActiveRecord::Base ...@@ -463,4 +469,12 @@ class User < ActiveRecord::Base
def all_ssh_keys def all_ssh_keys
keys.map(&:key) keys.map(&:key)
end end
def temp_oauth_email?
email =~ /\Atemp-email-for-oauth/
end
def generate_tmp_oauth_email
self.email = "temp-email-for-oauth-#{username}@gitlab.localhost"
end
end end
...@@ -6,8 +6,8 @@ ...@@ -6,8 +6,8 @@
# group_access :integer not null # group_access :integer not null
# group_id :integer not null # group_id :integer not null
# user_id :integer not null # user_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# notification_level :integer default(3), not null # notification_level :integer default(3), not null
# #
......
...@@ -5,8 +5,8 @@ ...@@ -5,8 +5,8 @@
# id :integer not null, primary key # id :integer not null, primary key
# user_id :integer not null # user_id :integer not null
# project_id :integer not null # project_id :integer not null
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# project_access :integer default(0), not null # project_access :integer default(0), not null
# notification_level :integer default(3), not null # notification_level :integer default(3), not null
# #
......
...@@ -5,13 +5,14 @@ ...@@ -5,13 +5,14 @@
# id :integer not null, primary key # id :integer not null, primary key
# url :string(255) # url :string(255)
# project_id :integer # project_id :integer
# created_at :datetime not null # created_at :datetime
# updated_at :datetime not null # updated_at :datetime
# type :string(255) default("ProjectHook") # type :string(255) default("ProjectHook")
# service_id :integer # service_id :integer
# push_events :boolean default(TRUE), not null # push_events :boolean default(TRUE), not null
# issues_events :boolean default(FALSE), not null # issues_events :boolean default(FALSE), not null
# merge_requests_events :boolean default(FALSE), not null # merge_requests_events :boolean default(FALSE), not null
# tag_push_events :boolean default(FALSE)
# #
class WebHook < ActiveRecord::Base class WebHook < ActiveRecord::Base
......
...@@ -19,7 +19,7 @@ class WikiPage ...@@ -19,7 +19,7 @@ class WikiPage
validates :title, presence: true validates :title, presence: true
validates :content, presence: true validates :content, presence: true
# The Gitlab GollumWiki instance. # The Gitlab ProjectWiki instance.
attr_reader :wiki attr_reader :wiki
# The raw Gollum::Page instance. # The raw Gollum::Page instance.
...@@ -118,7 +118,7 @@ class WikiPage ...@@ -118,7 +118,7 @@ class WikiPage
# :content - The raw markup content. # :content - The raw markup content.
# :format - Optional symbol representing the # :format - Optional symbol representing the
# content format. Can be any type # content format. Can be any type
# listed in the GollumWiki::MARKUPS # listed in the ProjectWiki::MARKUPS
# Hash. # Hash.
# :message - Optional commit message to set on # :message - Optional commit message to set on
# the new page. # the new page.
...@@ -135,7 +135,7 @@ class WikiPage ...@@ -135,7 +135,7 @@ class WikiPage
# #
# new_content - The raw markup content to replace the existing. # new_content - The raw markup content to replace the existing.
# format - Optional symbol representing the content format. # format - Optional symbol representing the content format.
# See GollumWiki::MARKUPS Hash for available formats. # See ProjectWiki::MARKUPS Hash for available formats.
# message - Optional commit message to set on the new version. # message - Optional commit message to set on the new version.
# #
# Returns the String SHA1 of the newly created page # Returns the String SHA1 of the newly created page
...@@ -181,5 +181,4 @@ class WikiPage ...@@ -181,5 +181,4 @@ class WikiPage
end end
@persisted @persisted
end end
end end
class ActivityObserver < BaseObserver
observe :issue, :note, :milestone
def after_create(record)
event_author_id = record.author_id
if record.kind_of?(Note)
# Skip system notes, like status changes and cross-references.
return true if record.system?
# Skip wall notes to prevent spamming of dashboard
return true if record.noteable_type.blank?
end
if event_author_id
create_event(record, Event.determine_action(record))
end
end
def after_close(record, transition)
create_event(record, Event::CLOSED)
end
def after_reopen(record, transition)
create_event(record, Event::REOPENED)
end
protected
def create_event(record, status)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
end
...@@ -3,6 +3,10 @@ class BaseObserver < ActiveRecord::Observer ...@@ -3,6 +3,10 @@ class BaseObserver < ActiveRecord::Observer
NotificationService.new NotificationService.new
end end
def event_service
EventCreateService.new
end
def log_info message def log_info message
Gitlab::AppLogger.info message Gitlab::AppLogger.info message
end end
......
class EmailObserver < BaseObserver
def after_create(email)
notification.new_email(email)
end
end
class IssueObserver < BaseObserver
def after_create(issue)
notification.new_issue(issue, current_user)
issue.create_cross_references!(issue.project, current_user)
execute_hooks(issue)
end
def after_close(issue, transition)
notification.close_issue(issue, current_user)
create_note(issue)
execute_hooks(issue)
end
def after_reopen(issue, transition)
create_note(issue)
execute_hooks(issue)
end
def after_update(issue)
if issue.is_being_reassigned?
notification.reassigned_issue(issue, current_user)
create_assignee_note(issue)
end
issue.notice_added_references(issue.project, current_user)
execute_hooks(issue)
end
protected
# Create issue note with service comment like 'Status changed to closed'
def create_note(issue)
Note.create_status_change_note(issue, issue.project, current_user, issue.state, current_commit)
end
def create_assignee_note(issue)
Note.create_assignee_change_note(issue, issue.project, current_user, issue.assignee)
end
def execute_hooks(issue)
issue.project.execute_hooks(issue.to_hook_data, :issue_hooks)
end
end
class KeyObserver < BaseObserver
def after_create(key)
GitlabShellWorker.perform_async(
:add_key,
key.shell_id,
key.key
)
notification.new_key(key)
end
def after_destroy(key)
GitlabShellWorker.perform_async(
:remove_key,
key.shell_id,
key.key,
)
end
end
class MergeRequestObserver < ActivityObserver
observe :merge_request
def after_create(merge_request)
if merge_request.author_id
create_event(merge_request, Event.determine_action(merge_request))
end
notification.new_merge_request(merge_request, current_user)
merge_request.create_cross_references!(merge_request.project, current_user)
execute_hooks(merge_request)
end
def after_close(merge_request, transition)
create_event(merge_request, Event::CLOSED)
notification.close_mr(merge_request, current_user)
create_note(merge_request)
execute_hooks(merge_request)
end
def after_reopen(merge_request, transition)
create_event(merge_request, Event::REOPENED)
create_note(merge_request)
execute_hooks(merge_request)
merge_request.reload_code
merge_request.mark_as_unchecked
end
def after_update(merge_request)
notification.reassigned_merge_request(merge_request, current_user) if merge_request.is_being_reassigned?
merge_request.notice_added_references(merge_request.project, current_user)
execute_hooks(merge_request)
end
def create_event(record, status)
Event.create(
project: record.target_project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
private
# Create merge request note with service comment like 'Status changed to closed'
def create_note(merge_request)
Note.create_status_change_note(merge_request, merge_request.target_project, current_user, merge_request.state, nil)
end
def execute_hooks(merge_request)
if merge_request.project
merge_request.project.execute_hooks(merge_request.to_hook_data, :merge_request_hooks)
end
end
end
class MilestoneObserver < BaseObserver
def after_create(milestone)
event_service.open_milestone(milestone, current_user)
end
def after_close(milestone, transition)
event_service.close_milestone(milestone, current_user)
end
def after_reopen(milestone, transition)
event_service.reopen_milestone(milestone, current_user)
end
end
...@@ -2,6 +2,12 @@ class NoteObserver < BaseObserver ...@@ -2,6 +2,12 @@ class NoteObserver < BaseObserver
def after_create(note) def after_create(note)
notification.new_note(note) notification.new_note(note)
# Skip system notes, like status changes and cross-references.
# Skip wall notes to prevent spamming of dashboard
if note.noteable_type.present? && !note.system
event_service.leave_note(note, current_user)
end
unless note.system? unless note.system?
# Create a cross-reference note if this Note contains GFM that names an # Create a cross-reference note if this Note contains GFM that names an
# issue, merge request, or commit. # issue, merge request, or commit.
......
...@@ -10,7 +10,7 @@ class UsersProjectObserver < BaseObserver ...@@ -10,7 +10,7 @@ class UsersProjectObserver < BaseObserver
end end
def after_update(users_project) def after_update(users_project)
notification.update_team_member(users_project) notification.update_team_member(users_project) if users_project.project_access_changed?
end end
def after_destroy(users_project) def after_destroy(users_project)
......
...@@ -16,4 +16,16 @@ class BaseService ...@@ -16,4 +16,16 @@ class BaseService
def can?(object, action, subject) def can?(object, action, subject)
abilities.allowed?(object, action, subject) abilities.allowed?(object, action, subject)
end end
def notification_service
NotificationService.new
end
def event_service
EventCreateService.new
end
def log_info message
Gitlab::AppLogger.info message
end
end end
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.
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.
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