Commit cfc4a2db authored by Franz-Robert van Vugt's avatar Franz-Robert van Vugt

Merge branch 'master' of https://github.com/gitlabhq/gitlabhq into patch-1

parents f03820eb fc5ac145
--color --drb --color
...@@ -19,10 +19,10 @@ rvm: ...@@ -19,10 +19,10 @@ rvm:
services: services:
- redis-server - redis-server
before_script: before_script:
- "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu"
- "cp config/database.yml.$DB config/database.yml" - "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml" - "cp config/gitlab.yml.example config/gitlab.yml"
- "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu"
script: "bundle exec rake $TASK --trace" script: "bundle exec rake $TASK --trace"
notifications: notifications:
email: false email: false
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)
v 6.7.2
- Fix upgrader script
v 6.7.1
- Fix GitLab CI integration
v 6.7.0 v 6.7.0
- Increased the example Nginx client_max_body_size from 5MB to 20MB, consider updating it manually on existing installations - Increased the example Nginx client_max_body_size from 5MB to 20MB, consider updating it manually on existing installations
- Add support for Gemnasium as a Project Service (Olivier Gonzalez) - Add support for Gemnasium as a Project Service (Olivier Gonzalez)
...@@ -9,6 +20,7 @@ v 6.7.0 ...@@ -9,6 +20,7 @@ v 6.7.0
- Show contribution guide link for new issue form (Jeroen van Baarsen) - Show contribution guide link for new issue form (Jeroen van Baarsen)
- Fix CI status for merge requests from fork - Fix CI status for merge requests from fork
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard) - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
- New page load indicator that includes a spinner that scrolls with the page
- Converted all the help sections into markdown - Converted all the help sections into markdown
- LDAP user filters - LDAP user filters
- Streamline the content of notification emails (Pierre de La Morinerie) - Streamline the content of notification emails (Pierre de La Morinerie)
...@@ -24,6 +36,12 @@ v 6.7.0 ...@@ -24,6 +36,12 @@ v 6.7.0
- Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5) - Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
- Create and Update MR calls now support the description parameter (Greg Messner) - Create and Update MR calls now support the description parameter (Greg Messner)
- Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository - Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
- Added Slack service integration (Federico Ravasio)
- Better API responses for access_levels (sponsored by O'Reilly Media)
- Requires at least 2 unicorn workers
- Requires gitlab-shell v1.9+
- Replaced gemoji(due to closed licencing problem) with Phantom Open Emoji library(combined SIL Open Font License, MIT License and the CC 3.0 License)
- Fix `/:username.keys` response content type (Dmitry Medvinsky)
v 6.6.5 v 6.6.5
- Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard) - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
......
...@@ -24,9 +24,12 @@ Issues and merge requests should be in English and contain appropriate language ...@@ -24,9 +24,12 @@ 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 or misbehavior in the latest [stable or development release of GitLab](MAINTENANCE.md). 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. 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 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.
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 [feedback and suggestions 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 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.
...@@ -48,7 +51,7 @@ Please send a merge request with a tested solution or a merge request with a fai ...@@ -48,7 +51,7 @@ Please send a merge request with a tested solution or a merge request with a fai
## Merge requests ## Merge requests
We welcome merge requests with fixes and improvements to GitLab code, tests, and/or documentation. The features we would really like a merge request for are listed with the [status 'accepting merge requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI. We welcome merge requests with fixes and improvements to GitLab code, tests, and/or documentation. The features we would really like a merge request for are listed with the [status 'accepting merge requests' on our feature request forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI.
### Merge request guidelines ### Merge request guidelines
...@@ -64,7 +67,8 @@ If you can, please submit a merge request with the fix or improvements including ...@@ -64,7 +67,8 @@ If you can, please submit a merge request with the fix or improvements including
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. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feedback items](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR 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. 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).
...@@ -74,6 +78,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c ...@@ -74,6 +78,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)
......
...@@ -132,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2" ...@@ -132,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
# Gemnasium integration # Gemnasium integration
gem "gemnasium-gitlab-service", "~> 0.2" gem "gemnasium-gitlab-service", "~> 0.2"
# Slack integration
gem "slack-notifier", "~> 0.2.0"
# d3 # d3
gem "d3_rails", "~> 3.1.4" gem "d3_rails", "~> 3.1.4"
...@@ -162,8 +165,9 @@ gem "modernizr", "2.6.2" ...@@ -162,8 +165,9 @@ gem "modernizr", "2.6.2"
gem "raphael-rails", "~> 2.1.2" gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 3.0' gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 3.2' gem "font-awesome-rails", '~> 3.2'
gem "gemoji", "~> 1.3.0" gem "gitlab_emoji", "~> 0.0.1.1"
gem "gon", '~> 5.0.0' gem "gon", '~> 5.0.0'
gem 'nprogress-rails'
group :development do group :development do
gem "annotate", "~> 2.6.0.beta2" gem "annotate", "~> 2.6.0.beta2"
...@@ -214,7 +218,6 @@ group :development, :test do ...@@ -214,7 +218,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'
......
...@@ -128,6 +128,8 @@ GEM ...@@ -128,6 +128,8 @@ GEM
mail (~> 2.2) mail (~> 2.2)
email_validator (1.4.0) email_validator (1.4.0)
activemodel activemodel
emoji (1.0.1)
json
enumerize (0.7.0) enumerize (0.7.0)
activesupport (>= 3.2) activesupport (>= 3.2)
equalizer (0.0.8) equalizer (0.0.8)
...@@ -165,7 +167,6 @@ GEM ...@@ -165,7 +167,6 @@ GEM
formatador (0.2.4) formatador (0.2.4)
gemnasium-gitlab-service (0.2.1) gemnasium-gitlab-service (0.2.1)
rugged (~> 0.19) rugged (~> 0.19)
gemoji (1.3.1)
gherkin-ruby (0.3.1) gherkin-ruby (0.3.1)
racc racc
github-markdown (0.5.5) github-markdown (0.5.5)
...@@ -190,6 +191,8 @@ GEM ...@@ -190,6 +191,8 @@ GEM
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)
emoji (~> 1.0.1)
gitlab_git (5.7.1) gitlab_git (5.7.1)
activesupport (~> 4.0.0) activesupport (~> 4.0.0)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6.9)
...@@ -297,6 +300,7 @@ GEM ...@@ -297,6 +300,7 @@ GEM
net-ssh (>= 1.99.1) net-ssh (>= 1.99.1)
net-ssh (2.7.0) net-ssh (2.7.0)
nokogiri (1.5.10) nokogiri (1.5.10)
nprogress-rails (0.1.2.3)
oauth (0.4.7) oauth (0.4.7)
oauth2 (0.8.1) oauth2 (0.8.1)
faraday (~> 0.8) faraday (~> 0.8)
...@@ -468,6 +472,7 @@ GEM ...@@ -468,6 +472,7 @@ GEM
rack-protection (~> 1.4) rack-protection (~> 1.4)
tilt (~> 1.3, >= 1.3.4) tilt (~> 1.3, >= 1.3.4)
six (0.2.0) six (0.2.0)
slack-notifier (0.2.0)
slim (2.0.2) slim (2.0.2)
temple (~> 0.6.6) temple (~> 0.6.6)
tilt (>= 1.3.3, < 2.1) tilt (>= 1.3.3, < 2.1)
...@@ -479,7 +484,6 @@ GEM ...@@ -479,7 +484,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)
...@@ -591,12 +595,12 @@ DEPENDENCIES ...@@ -591,12 +595,12 @@ DEPENDENCIES
font-awesome-rails (~> 3.2) font-awesome-rails (~> 3.2)
foreman foreman
gemnasium-gitlab-service (~> 0.2) gemnasium-gitlab-service (~> 0.2)
gemoji (~> 1.3.0)
github-markup (~> 0.7.4)! github-markup (~> 0.7.4)!
gitlab-flowdock-git-hook (~> 0.4.2) gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.1.0) 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_git (~> 5.7.1) gitlab_git (~> 5.7.1)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.4) gitlab_omniauth-ldap (= 1.0.4)
...@@ -620,6 +624,7 @@ DEPENDENCIES ...@@ -620,6 +624,7 @@ DEPENDENCIES
minitest (~> 4.7.0) minitest (~> 4.7.0)
modernizr (= 2.6.2) modernizr (= 2.6.2)
mysql2 mysql2
nprogress-rails
omniauth (~> 1.1.3) omniauth (~> 1.1.3)
omniauth-github omniauth-github
omniauth-google-oauth2 omniauth-google-oauth2
...@@ -652,9 +657,9 @@ DEPENDENCIES ...@@ -652,9 +657,9 @@ DEPENDENCIES
simplecov simplecov
sinatra sinatra
six six
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)
......
...@@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co ...@@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co
- Monitors for new merge requests (at least once a week) - Monitors for new merge requests (at least once a week)
- Manages their work queue by looking at issues and merge requests assigned to them - Manages their work queue by looking at issues and merge requests assigned to them
- Close fixed issues (via commit messages or manually) - Close fixed issues (via commit messages or manually)
- Codes [new features](http://feedback.gitlab.com/forums/176466-general/filters/top)!
- Response guidelines
- 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). - 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
...@@ -73,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue ...@@ -73,7 +71,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 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 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
......
web: bundle exec unicorn_rails -p $PORT -E development web: bundle exec unicorn_rails -p $PORT -E development -c config/unicorn_development.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
...@@ -71,7 +71,7 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl ...@@ -71,7 +71,7 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl
It is recommended to follow a monthly upgrade schedule. Security releases come out when needed. For more information about the release process see the documentation for [monthly](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/monthly.md) and [security](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/security.md) releases. It is recommended to follow a monthly upgrade schedule. Security releases come out when needed. For more information about the release process see the documentation for [monthly](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/monthly.md) and [security](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/release/security.md) releases.
* Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457). * Features that will be in the next releases are listed on the [feature request forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
### Run in production mode ### Run in production mode
...@@ -96,14 +96,9 @@ or start each component separately ...@@ -96,14 +96,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
...@@ -134,22 +129,4 @@ or start each component separately ...@@ -134,22 +129,4 @@ or start each component separately
### 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.
* [Feedback and suggestions 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.pre 6.8.0.pre
// 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 modernizr
//= require select2
//= require raphael
//= require g.raphael-min
//= require g.bar-min
//= require branch-graph
//= require highlightjs.min
//= require ace/ace
//= require_tree .
//= require d3
//= require underscore
# 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 modernizr
#= 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()
...@@ -41,19 +75,11 @@ window.linkify = (str) -> ...@@ -41,19 +75,11 @@ window.linkify = (str) ->
window.simpleFormat = (str) -> window.simpleFormat = (str) ->
linkify(sanitize(str).replace(/\n/g, '<br />')) linkify(sanitize(str).replace(/\n/g, '<br />'))
window.startSpinner = ->
$('.turbolink-spinner').fadeIn()
window.stopSpinner = ->
$('.turbolink-spinner').fadeOut()
window.unbindEvents = -> window.unbindEvents = ->
$(document).unbind('scroll') $(document).unbind('scroll')
$(document).off('scroll') $(document).off('scroll')
document.addEventListener("page:fetch", startSpinner)
document.addEventListener("page:fetch", unbindEvents) document.addEventListener("page:fetch", unbindEvents)
document.addEventListener("page:change", stopSpinner)
$ -> $ ->
# Click a .one_click_select field, select the contents # Click a .one_click_select field, select the contents
......
...@@ -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
......
...@@ -7,6 +7,8 @@ ...@@ -7,6 +7,8 @@
*= require select2 *= require select2
*= require highlightjs.min *= require highlightjs.min
*= require_self *= require_self
*= require nprogress
*= require nprogress-bootstrap
*/ */
@import "main/variables.scss"; @import "main/variables.scss";
......
...@@ -355,3 +355,7 @@ table { ...@@ -355,3 +355,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;
}
...@@ -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;
}
...@@ -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;
......
...@@ -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;
}
}
...@@ -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;
} }
......
class PasswordsController < Devise::PasswordsController
def create
email = resource_params[:email]
resource_found = resource_class.find_by_email(email)
if resource_found && resource_found.ldap_user?
flash[:alert] = "Cannot reset password for LDAP user."
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return
end
self.resource = resource_class.send_reset_password_instructions(resource_params)
if successfully_sent?(resource)
respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
else
respond_with(resource)
end
end
end
...@@ -41,7 +41,7 @@ class Profiles::KeysController < ApplicationController ...@@ -41,7 +41,7 @@ class Profiles::KeysController < ApplicationController
begin begin
user = User.find_by_username(params[:username]) user = User.find_by_username(params[:username])
if user.present? if user.present?
render text: user.all_ssh_keys.join("\n") render text: user.all_ssh_keys.join("\n"), content_type: "text/plain"
else else
render_404 and return render_404 and return
end end
......
...@@ -76,7 +76,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -76,7 +76,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.update_attributes(params[:issue])
@issue.reset_events_cache @issue.reset_events_cache
respond_to do |format| respond_to do |format|
......
...@@ -109,7 +109,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -109,7 +109,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params[:merge_request].delete(:source_project_id) params[:merge_request].delete(:source_project_id)
params[:merge_request].delete(:target_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)) if @merge_request.update_attributes(params[:merge_request])
@merge_request.reset_events_cache @merge_request.reset_events_cache
respond_to do |format| respond_to do |format|
......
...@@ -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
......
...@@ -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.humanize
} }
end end
......
...@@ -40,7 +40,7 @@ module TreeHelper ...@@ -40,7 +40,7 @@ module TreeHelper
# Returns boolean # Returns boolean
def markup?(filename) def markup?(filename)
filename.downcase.end_with?(*%w(.textile .rdoc .org .creole filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
.mediawiki .rst .asciidoc .pod)) .mediawiki .rst .adoc .asciidoc .pod))
end end
def gitlab_markdown?(filename) def gitlab_markdown?(filename)
......
...@@ -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
......
...@@ -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
......
class DiffLine
attr_accessor :type, :content, :num, :code
end
...@@ -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)
......
...@@ -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
......
...@@ -38,7 +38,7 @@ class MergeRequest < ActiveRecord::Base ...@@ -38,7 +38,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
......
...@@ -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
...@@ -199,7 +199,8 @@ class Note < ActiveRecord::Base ...@@ -199,7 +199,8 @@ class Note < ActiveRecord::Base
def downvote? def downvote?
votable? && (note.start_with?('-1') || votable? && (note.start_with?('-1') ||
note.start_with?(':-1:') || note.start_with?(':-1:') ||
note.start_with?(':thumbsdown:') note.start_with?(':thumbsdown:') ||
note.start_with?(':thumbs_down_sign:')
) )
end end
...@@ -249,7 +250,8 @@ class Note < ActiveRecord::Base ...@@ -249,7 +250,8 @@ class Note < ActiveRecord::Base
def upvote? def upvote?
votable? && (note.start_with?('+1') || votable? && (note.start_with?('+1') ||
note.start_with?(':+1:') || note.start_with?(':+1:') ||
note.start_with?(':thumbsup:') note.start_with?(':thumbsup:') ||
note.start_with?(':thumbs_up_sign:')
) )
end end
......
...@@ -56,6 +56,7 @@ class Project < ActiveRecord::Base ...@@ -56,6 +56,7 @@ class Project < ActiveRecord::Base
has_one :flowdock_service, dependent: :destroy has_one :flowdock_service, dependent: :destroy
has_one :assembla_service, dependent: :destroy has_one :assembla_service, dependent: :destroy
has_one :gemnasium_service, dependent: :destroy has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link has_one :forked_from_project, through: :forked_project_link
# Merge Requests for target project should be removed with it # Merge Requests for target project should be removed with it
...@@ -304,7 +305,7 @@ class Project < ActiveRecord::Base ...@@ -304,7 +305,7 @@ class Project < ActiveRecord::Base
end end
def available_services_names def available_services_names
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium) %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack)
end end
def gitlab_ci? def gitlab_ci?
......
require 'slack-notifier'
class SlackMessage
def initialize(params)
@after = params.fetch(:after)
@before = params.fetch(:before)
@commits = params.fetch(:commits, [])
@project_name = params.fetch(:project_name)
@project_url = params.fetch(:project_url)
@ref = params.fetch(:ref).gsub('refs/heads/', '')
@username = params.fetch(:user_name)
end
def compose
format(message)
end
private
attr_reader :after
attr_reader :before
attr_reader :commits
attr_reader :project_name
attr_reader :project_url
attr_reader :ref
attr_reader :username
def message
if new_branch?
new_branch_message
elsif removed_branch?
removed_branch_message
else
push_message << commit_messages
end
end
def format(string)
Slack::Notifier::LinkFormatter.format(string)
end
def new_branch_message
"#{username} pushed new branch #{branch_link} to #{project_link}"
end
def removed_branch_message
"#{username} removed branch #{ref} from #{project_link}"
end
def push_message
"#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
end
def commit_messages
commits.each_with_object('') do |commit, str|
str << compose_commit_message(commit)
end
end
def compose_commit_message(commit)
id = commit.fetch(:id)[0..5]
message = commit.fetch(:message)
url = commit.fetch(:url)
"\n - #{message} ([#{id}](#{url}))"
end
def new_branch?
before =~ /000000/
end
def removed_branch?
after =~ /000000/
end
def branch_url
"#{project_url}/commits/#{ref}"
end
def compare_url
"#{project_url}/compare/#{before}...#{after}"
end
def branch_link
"[#{ref}](#{branch_url})"
end
def project_link
"[#{project_name}](#{project_url})"
end
def compare_link
"[Compare changes](#{compare_url})"
end
end
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# token :string(255)
# project_id :integer not null
# created_at :datetime not null
# updated_at :datetime not null
# active :boolean default(FALSE), not null
# project_url :string(255)
# subdomain :string(255)
# room :string(255)
# api_key :string(255)
#
class SlackService < Service
attr_accessible :room
attr_accessible :subdomain
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
def title
'Slack'
end
def description
'A team communication tool for the 21st century'
end
def to_param
'slack'
end
def fields
[
{ type: 'text', name: 'subdomain', placeholder: '' },
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: 'Ex. #general' },
]
end
def execute(push_data)
message = SlackMessage.new(push_data.merge(
project_url: project_url,
project_name: project_name
))
notifier = Slack::Notifier.new(subdomain, token)
notifier.channel = room
notifier.username = 'GitLab'
notifier.ping(message.compose)
end
private
def project_name
project.name_with_namespace.gsub(/\s/, '')
end
def project_url
project.web_url
end
end
...@@ -204,7 +204,7 @@ class User < ActiveRecord::Base ...@@ -204,7 +204,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)
...@@ -249,7 +249,7 @@ class User < ActiveRecord::Base ...@@ -249,7 +249,7 @@ class User < ActiveRecord::Base
def namespace_uniq def namespace_uniq
namespace_name = self.username namespace_name = self.username
if Namespace.find_by(path: namespace_name) if Namespace.find_by(path: namespace_name)
self.errors.add :username, "already exist" self.errors.add :username, "already exists"
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 IssueObserver < BaseObserver class IssueObserver < BaseObserver
def after_create(issue) def after_create(issue)
notification.new_issue(issue, current_user) notification.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
issue.create_cross_references!(issue.project, current_user) issue.create_cross_references!(issue.project, current_user)
execute_hooks(issue) execute_hooks(issue)
end end
def after_close(issue, transition) def after_close(issue, transition)
notification.close_issue(issue, current_user) notification.close_issue(issue, current_user)
event_service.close_issue(issue, current_user)
create_note(issue) create_note(issue)
execute_hooks(issue) execute_hooks(issue)
end end
def after_reopen(issue, transition) def after_reopen(issue, transition)
event_service.reopen_issue(issue, current_user)
create_note(issue) create_note(issue)
execute_hooks(issue) execute_hooks(issue)
end end
......
class MergeRequestObserver < ActivityObserver class MergeRequestObserver < BaseObserver
observe :merge_request
def after_create(merge_request) def after_create(merge_request)
if merge_request.author_id event_service.open_mr(merge_request, current_user)
create_event(merge_request, Event.determine_action(merge_request))
end
notification.new_merge_request(merge_request, current_user) notification.new_merge_request(merge_request, current_user)
merge_request.create_cross_references!(merge_request.project, current_user) merge_request.create_cross_references!(merge_request.project, current_user)
execute_hooks(merge_request) execute_hooks(merge_request)
end end
def after_close(merge_request, transition) def after_close(merge_request, transition)
create_event(merge_request, Event::CLOSED) event_service.close_mr(merge_request, current_user)
notification.close_mr(merge_request, current_user) notification.close_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
execute_hooks(merge_request) execute_hooks(merge_request)
end end
def after_reopen(merge_request, transition) def after_reopen(merge_request, transition)
create_event(merge_request, Event::REOPENED) event_service.reopen_mr(merge_request, current_user)
create_note(merge_request) create_note(merge_request)
execute_hooks(merge_request) execute_hooks(merge_request)
merge_request.reload_code merge_request.reload_code
...@@ -33,16 +28,6 @@ class MergeRequestObserver < ActivityObserver ...@@ -33,16 +28,6 @@ class MergeRequestObserver < ActivityObserver
execute_hooks(merge_request) execute_hooks(merge_request)
end 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 private
# Create merge request note with service comment like 'Status changed to closed' # Create merge request note with service comment like 'Status changed to closed'
......
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.
......
# EventCreateService class
#
# Used for creating events feed on dashboard after certain user action
#
# Ex.
# EventCreateService.new.new_issue(issue, current_user)
#
class EventCreateService
def open_issue(issue, current_user)
create_event(issue, current_user, Event::CREATED)
end
def close_issue(issue, current_user)
create_event(issue, current_user, Event::CLOSED)
end
def reopen_issue(issue, current_user)
create_event(issue, current_user, Event::REOPENED)
end
def open_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::CREATED)
end
def close_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::CLOSED)
end
def reopen_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::REOPENED)
end
def merge_mr(merge_request, current_user)
create_event(merge_request, current_user, Event::MERGED)
end
def open_milestone(milestone, current_user)
create_event(milestone, current_user, Event::CREATED)
end
def close_milestone(milestone, current_user)
create_event(milestone, current_user, Event::CLOSED)
end
def reopen_milestone(milestone, current_user)
create_event(milestone, current_user, Event::REOPENED)
end
def leave_note(note, current_user)
create_event(note, current_user, Event::COMMENTED)
end
private
def create_event(record, current_user, status)
Event.create(
project: record.project,
target_id: record.id,
target_type: record.class.name,
action: status,
author_id: current_user.id
)
end
end
...@@ -9,11 +9,10 @@ module MergeRequests ...@@ -9,11 +9,10 @@ module MergeRequests
merge_request.lock merge_request.lock
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message) if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
merge_request.author_id_of_changes = current_user.id
merge_request.merge merge_request.merge
notification.merge_mr(merge_request) notification.merge_mr(merge_request, current_user)
create_merge_event(merge_request) create_merge_event(merge_request, current_user)
execute_project_hooks(merge_request) execute_project_hooks(merge_request)
true true
......
...@@ -7,14 +7,8 @@ module MergeRequests ...@@ -7,14 +7,8 @@ module MergeRequests
NotificationService.new NotificationService.new
end end
def create_merge_event(merge_request) def create_merge_event(merge_request, current_user)
Event.create( EventCreateService.new.merge_mr(merge_request, current_user)
project: merge_request.target_project,
target_id: merge_request.id,
target_type: merge_request.class.name,
action: Event::MERGED,
author_id: merge_request.author_id_of_changes
)
end end
def execute_project_hooks(merge_request) def execute_project_hooks(merge_request)
......
...@@ -7,11 +7,10 @@ module MergeRequests ...@@ -7,11 +7,10 @@ module MergeRequests
# to target branch # to target branch
class MergeService < BaseMergeService class MergeService < BaseMergeService
def execute(merge_request, current_user, commit_message) def execute(merge_request, current_user, commit_message)
merge_request.author_id_of_changes = current_user.id
merge_request.merge merge_request.merge
notification.merge_mr(merge_request) notification.merge_mr(merge_request, current_user)
create_merge_event(merge_request) create_merge_event(merge_request, current_user)
execute_project_hooks(merge_request) execute_project_hooks(merge_request)
true true
......
...@@ -86,12 +86,12 @@ class NotificationService ...@@ -86,12 +86,12 @@ class NotificationService
# * merge_request assignee if their notification level is not Disabled # * merge_request assignee if their notification level is not Disabled
# * project team members with notification level higher then Participating # * project team members with notification level higher then Participating
# #
def merge_mr(merge_request) def merge_mr(merge_request, current_user)
recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project) recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
recipients.each do |recipient| recipients.each do |recipient|
mailer.merged_merge_request_email(recipient.id, merge_request.id) mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
end end
end end
...@@ -111,6 +111,7 @@ class NotificationService ...@@ -111,6 +111,7 @@ class NotificationService
# ignore gitlab service messages # ignore gitlab service messages
return true if note.note =~ /\A_Status changed to closed_/ return true if note.note =~ /\A_Status changed to closed_/
return true if note.note =~ /\A_mentioned in / && note.system == true
opts = { noteable_type: note.noteable_type, project_id: note.project_id } opts = { noteable_type: note.noteable_type, project_id: note.project_id }
......
...@@ -2,10 +2,12 @@ ...@@ -2,10 +2,12 @@
- if providers.present? - if providers.present?
%hr %hr
%div{:'data-no-turbolink' => 'data-no-turbolink'} %div{:'data-no-turbolink' => 'data-no-turbolink'}
%span Sign in with: &nbsp; %span Sign in with*: &nbsp;
- providers.each do |provider| - providers.each do |provider|
%span %span
- if default_providers.include?(provider) - if default_providers.include?(provider)
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
- else - else
= link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn" = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
%br
%small * Make sure your email address is public
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
= "#{title} | " if defined?(title) = "#{title} | " if defined?(title)
GitLab GitLab
= favicon_link_tag 'favicon.ico' = favicon_link_tag 'favicon.ico'
= stylesheet_link_tag "application" = stylesheet_link_tag "application", :media => "all"
= stylesheet_link_tag "print", :media => "print"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
= include_gon = include_gon
......
...@@ -14,10 +14,6 @@ ...@@ -14,10 +14,6 @@
.navbar-collapse.collapse .navbar-collapse.collapse
%ul.nav.navbar-nav %ul.nav.navbar-nav
%li.hidden-sm.hidden-xs
%a
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
%li.hidden-sm.hidden-xs %li.hidden-sm.hidden-xs
= render "layouts/search" = render "layouts/search"
%li.visible-sm.visible-xs %li.visible-sm.visible-xs
......
:javascript :javascript
GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}" GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project, type: @noteable.class, type_id: params[:id])}"
GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + '/assets/emoji'}"
GitLab.GfmAutoComplete.setup(); GitLab.GfmAutoComplete.setup();
...@@ -8,11 +8,15 @@ ...@@ -8,11 +8,15 @@
%span.separator %span.separator
%h1.title= title %h1.title= title
.pull-right %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
%span.sr-only Toggle navigation
%i.icon-reorder
.pull-right.hidden-xs
= link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new' = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
.navbar-collapse.collapse
%ul.nav.navbar-nav %ul.nav.navbar-nav
%li %li.visible-xs
%a = link_to "Sign in", new_session_path(:user)
%div.hide.turbolink-spinner
%i.icon-refresh.icon-spin
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%body{class: "#{app_theme} application", :'data-page' => body_data_page} %body{class: "#{app_theme} application", :'data-page' => body_data_page}
= render "layouts/broadcast" = render "layouts/broadcast"
= render "layouts/public_head_panel", title: project_title(@project) = render "layouts/public_head_panel", title: project_title(@project)
%nav.main-nav %nav.main-nav.navbar-collapse.collapse
.container= render 'layouts/nav/project' .container= render 'layouts/nav/project'
.container .container
.content= yield .content= yield
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%li %li
#{commit.short_id} - #{commit.title} #{commit.short_id} - #{commit.title}
%h4 Diff: %h4 Changes:
- @diffs.each do |diff| - @diffs.each do |diff|
%li %li
%strong %strong
...@@ -23,6 +23,6 @@ ...@@ -23,6 +23,6 @@
%br %br
- if @compare.timeout - if @compare.timeout
%h5 Huge diff. To prevent performance issues it was hidden %h5 To prevent performance issues changes are hidden
- elsif @compare.commits_over_limit? - elsif @compare.commits_over_limit?
%h5 Diff for big amount of commits is disabled %h5 Changes are not shown due to large amount of commits
...@@ -6,7 +6,7 @@ Commits: ...@@ -6,7 +6,7 @@ Commits:
#{commit.short_id} - #{truncate(commit.title, length: 40)} #{commit.short_id} - #{truncate(commit.title, length: 40)}
\ \
\ \
Diff: Changes:
- @diffs.each do |diff| - @diffs.each do |diff|
\ \
\===================================== \=====================================
...@@ -22,4 +22,4 @@ Diff: ...@@ -22,4 +22,4 @@ Diff:
- if @compare.timeout - if @compare.timeout
Huge diff. To prevent performance issues it was hidden Huge diff. To prevent performance issues it was hidden
- elsif @compare.commits_over_limit? - elsif @compare.commits_over_limit?
Diff for big amount of commits is disabled Changes are not shown due to large amount of commits
/ Side-by-side diff view / Side-by-side diff view
- old_file = get_old_file(project, @commit, diff) - old_lines, new_lines = parallel_diff_lines(project, @commit, diff, file)
- deleted_lines = {} - num_lines = old_lines.length
- added_lines = {}
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
- 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 }
- max_length = old_file.sloc + added_lines.length if old_file
- max_length ||= file.sloc
- offset1 = 0
- offset2 = 0
%div.text-file-parallel %div.text-file-parallel
%table{ style: "table-layout: fixed;" } %div.diff-side.diff-side-left
- max_length.times do |line_index| %table
- line_index1 = line_index - offset1 - old_lines.each do |line|
- 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
%tr.line_holder.parallel %tr.line_holder.parallel
- if line_index == 0 && diff.new_file - if line.type == :file_created
%td.line_content.parallel= "File was created" %td.line_content.parallel= "File was created"
%td.old_line= "" - elsif line.type == :deleted
- elsif deleted_line %td.line_content{class: "parallel noteable_line old #{line.code}", "line_code" => line.code }= line.content
%td.line_content{class: "parallel noteable_line old #{deleted_line[:line_code]}", "line_code" => deleted_line[:line_code] }= old_line - else line.type == :no_change
%td.old_line.old %td.line_content.parallel= line.content
= line_index1 + 1
- if @comments_allowed %div.diff-middle
=# render "projects/notes/diff_note_link", line_code: deleted_line[:line_code] %table
- elsif old_line - num_lines.times do |index|
%td.line_content.parallel= old_line %tr
%td.old_line= line_index1 + 1 - if old_lines[index].type == :deleted
%td.old_line.old= old_lines[index].num
- else - else
%td.line_content.parallel= "" %td.old_line= old_lines[index].num
%td.old_line= ""
%td.diff_line= "" %td.diff_line=""
- if diff.deleted_file && line_index == 0 - if new_lines[index].type == :added
%td.new_line= "" %td.new_line.new= new_lines[index].num
%td.line_content.parallel= "File was deleted"
- elsif added_line
%td.new_line.new
= line_index2 + 1
- if @comments_allowed
=# render "projects/notes/diff_note_link", line_code: added_line[:line_code]
%td.line_content{class: "parallel noteable_line new #{added_line[:line_code]}", "line_code" => added_line[:line_code] }= new_line
- elsif new_line
%td.new_line= line_index2 + 1
%td.line_content.parallel= new_line
- else - else
%td.new_line= "" %td.new_line= new_lines[index].num
%td.line_content.parallel= ""
%div.diff-side.diff-side-right
%table
- new_lines.each do |line|
%tr.line_holder.parallel
- if line.type == :file_deleted
%td.line_content.parallel= "File was deleted"
- elsif line.type == :added
%td.line_content{class: "parallel noteable_line new #{line.code}", "line_code" => line.code }= line.content
- else line.type == :no_change
%td.line_content.parallel= line.content
:javascript
$('.diff-side-right').on('scroll', function(){
$('.diff-side-left, .diff-middle').scrollTop($(this).scrollTop());
$('.diff-side-left').scrollLeft($(this).scrollLeft());
});
- if @reply_allowed $('.diff-side-left').on('scroll', function(){
- comments1 = [] $('.diff-side-right, .diff-middle').scrollTop($(this).scrollTop()); // might never be relevant
- comments2 = [] $('.diff-side-right').scrollLeft($(this).scrollLeft());
- comments1 = @line_notes.select { |n| n.line_code == deleted_line[:line_code] }.sort_by(&:created_at) if deleted_line });
- comments2 = @line_notes.select { |n| n.line_code == added_line[:line_code] }.sort_by(&:created_at) if added_line
- unless comments1.empty? && comments2.empty?
= render "projects/notes/diff_notes_with_reply_parallel", notes1: comments1, notes2: comments2, line1: deleted_line, line2: added_line
\ No newline at end of file
- too_big = diff.diff.lines.count > 1000 - too_big = diff.diff.lines.count > 1000
- if too_big - if too_big
%a.supp_diff_link Diff suppressed. Click to show %a.supp_diff_link Changes suppressed. Click to show
%table.text-file{class: "#{'hide' if too_big}"} %table.text-file{class: "#{'hide' if too_big}"}
- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line| - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
......
...@@ -18,17 +18,17 @@ ...@@ -18,17 +18,17 @@
- else - else
%ul.well-list= render Commit.decorate(@commits), project: @project %ul.well-list= render Commit.decorate(@commits), project: @project
%h4 Diff %h4 Changes
- if @diffs.present? - if @diffs.present?
= render "projects/commits/diffs", diffs: @diffs, project: @project = render "projects/commits/diffs", diffs: @diffs, project: @project
- elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
.bs-callout.bs-callout-danger .bs-callout.bs-callout-danger
%h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits. %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
%p To preserve performance the line diff is not shown. %p To preserve performance the line changes are not shown.
- elsif @timeout - elsif @timeout
.bs-callout.bs-callout-danger .bs-callout.bs-callout-danger
%h4 Diff for this comparison is extremely large. %h4 Number of changed files for this comparison is extremely large.
%p Use command line to browse diff for this comparison. %p Use command line to browse through changes for this comparison.
- else - else
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
Deploy key: Deploy key:
= @key.title = @key.title
%small %small
created at created on
= @key.created_at.stamp("Aug 21, 2011") = @key.created_at.stamp("Aug 21, 2011")
.back-link .back-link
= link_to project_deploy_keys_path(@project) do = link_to project_deploy_keys_path(@project) do
......
%div.issue-form-holder %div.issue-form-holder
%h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}" %h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
%hr %hr
- if @repository.contribution_guide && !@issue.persisted? - if !@repository.empty? && @repository.contribution_guide && !@issue.persisted?
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name)) - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.alert.alert-info.col-sm-10.col-sm-offset-2 .alert.alert-info.col-sm-10.col-sm-offset-2
="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe ="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
......
- if @repository.contribution_guide && !@merge_request.persisted?
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.alert.alert-info.col-sm-10.col-sm-offset-2
="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
= form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal" } do |f| = form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal" } do |f|
.row
.col-sm-2
.col-sm-10
- if @repository.contribution_guide && !@merge_request.persisted?
- contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
.alert.alert-info
Please review the
%strong #{link_to "guidelines for contribution", contribution_guide_url}
to this repository.
-if @merge_request.errors.any? -if @merge_request.errors.any?
.alert.alert-danger .alert.alert-danger
%ul
- @merge_request.errors.full_messages.each do |msg| - @merge_request.errors.full_messages.each do |msg|
%li= msg %div= msg
.merge-request-branches .merge-request-branches
.form-group .form-group
...@@ -47,24 +52,6 @@ ...@@ -47,24 +52,6 @@
= f.text_area :description, class: "form-control js-gfm-input", rows: 14 = f.text_area :description, class: "form-control js-gfm-input", rows: 14
%p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}. %p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
%hr
.form-group
.merge-request-assignee
= f.label :assignee_id, class: 'control-label' do
%i.icon-user
Assign to
.col-sm-10
= project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
.form-group
.merge-request-milestone
= f.label :milestone_id, class: 'control-label' do
%i.icon-time
Milestone
.col-sm-10= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
.form-actions .form-actions
- if @merge_request.new_record? - if @merge_request.new_record?
= f.submit 'Submit merge request', class: "btn btn-create" = f.submit 'Submit merge request', class: "btn btn-create"
...@@ -96,7 +83,3 @@ ...@@ -96,7 +83,3 @@
target_branch.on("change", function() { target_branch.on("change", function() {
$.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() }); $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
}); });
$('.assign-to-me-link').on('click', function(e){
$('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault();
});
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
%li.diffs-tab{data: {action: 'diffs'}} %li.diffs-tab{data: {action: 'diffs'}}
= link_to diffs_project_merge_request_path(@project, @merge_request) do = link_to diffs_project_merge_request_path(@project, @merge_request) do
%i.icon-list-alt %i.icon-list-alt
Diff Changes
- content_for :note_actions do - content_for :note_actions do
- if can?(current_user, :modify_merge_request, @merge_request) - if can?(current_user, :modify_merge_request, @merge_request)
......
...@@ -3,5 +3,5 @@ ...@@ -3,5 +3,5 @@
var mrTitle = $('#merge_request_title'); var mrTitle = $('#merge_request_title');
if(mrTitle.val().length == 0) { if(mrTitle.val().length == 0) {
mrTitle.val("#{params[:ref].titleize}"); mrTitle.val("#{params[:ref].humanize}");
} }
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
- else - else
.bs-callout.bs-callout-warning .bs-callout.bs-callout-warning
%h4 %h4
Diff for this comparison is extremely large. Changes view for this comparison is extremely large.
%p %p
You can You can
= link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink" = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink"
......
- unless @allowed_to_merge - unless @allowed_to_merge
- if @project.archived?
.bs-callout.bs-callout-warning
%strong Archived projects cannot be committed to!
- else
.bs-callout .bs-callout
%strong You don't have permission to merge this MR .automerge_widget.cannot_be_merged.hide
%strong This can't be merged automatically, even if it could be merged you don't have the permission to do so.
.automerge_widget.can_be_merged.hide
%strong This can be merged automatically but you don't have the permission to do so.
- if @show_merge_controls - if @show_merge_controls
......
...@@ -29,13 +29,13 @@ ...@@ -29,13 +29,13 @@
%span %span
%i.icon-remove %i.icon-remove
Closed by #{link_to_member(@project, @merge_request.closed_event.author)} Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
#{time_ago_with_tooltip(@merge_request.closed_event.created_at)}. #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
- if @merge_request.merged? - if @merge_request.merged?
.alert.alert-info .alert.alert-info
%span %span
%i.icon-ok %i.icon-ok
Merged by #{link_to_member(@project, @merge_request.merge_event.author)} Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}. #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
- if !@closes_issues.empty? && @merge_request.open? - if !@closes_issues.empty? && @merge_request.open?
.alert.alert-info.alert-info .alert.alert-info.alert-info
%span %span
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
%i.icon-thumbs-up %i.icon-thumbs-up
\+1 \+1
- if note.downvote? - if note.downvote?
%span.vote.downvote.label.label-error %span.vote.downvote.label.label-danger
%i.icon-thumbs-down %i.icon-thumbs-down
\-1 \-1
......
...@@ -9,8 +9,8 @@ ...@@ -9,8 +9,8 @@
.col-md-3.project-side.hidden-sm .col-md-3.project-side.hidden-sm
.clearfix .clearfix
- if @project.archived? - if @project.archived?
.alert .alert.alert-warning
%h5 %h4
%i.icon-warning-sign %i.icon-warning-sign
Archived project! Archived project!
%p Repository is read-only %p Repository is read-only
......
...@@ -19,7 +19,7 @@ module Gitlab ...@@ -19,7 +19,7 @@ module Gitlab
# config.plugins = [ :exception_notification, :ssl_requirement, :all ] # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
# Activate observers that should always be running. # Activate observers that should always be running.
config.active_record.observers = :activity_observer, config.active_record.observers = :milestone_observer,
:project_activity_cache_observer, :project_activity_cache_observer,
:issue_observer, :issue_observer,
:key_observer, :key_observer,
......
...@@ -33,6 +33,12 @@ Gitlab::Application.configure do ...@@ -33,6 +33,12 @@ Gitlab::Application.configure do
# See everything in the log (default is :info) # See everything in the log (default is :info)
# config.log_level = :debug # config.log_level = :debug
# Suppress 'Rendered template ...' messages in the log
# source: http://stackoverflow.com/a/16369363
%w{render_template render_partial render_collection}.each do |event|
ActiveSupport::Notifications.unsubscribe "#{event}.action_view"
end
# Prepend all log lines with the following tags # Prepend all log lines with the following tags
# config.log_tags = [ :subdomain, :uuid ] # config.log_tags = [ :subdomain, :uuid ]
......
# Workaround for https://github.com/github/gemoji/pull/18
require 'gemoji'
Gitlab::Application.config.assets.paths << Emoji.images_path
...@@ -167,7 +167,7 @@ Gitlab::Application.routes.draw do ...@@ -167,7 +167,7 @@ Gitlab::Application.routes.draw do
resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create] resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations } devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords}
# #
# Project Area # Project Area
......
worker_processes 2
timeout 30
...@@ -2,7 +2,7 @@ Gitlab::Seeder.quiet do ...@@ -2,7 +2,7 @@ Gitlab::Seeder.quiet do
User.first(30).each_with_index do |user, i| User.first(30).each_with_index do |user, i|
Key.seed(:id, [ Key.seed(:id, [
{ {
id: i, id: i + 1,
title: "Sample key #{i}", title: "Sample key #{i}",
key: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt#{i + 100}6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=", key: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt#{i + 100}6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
user_id: user.id, user_id: user.id,
......
## The GitLab Documentation covers the following subjects
+ [API](api/README.md)
+ [Development](development/README.md)
+ [Install](install/README.md)
+ [Integration](external-issue-tracker/README.md)
+ [Legal](legal/README.md)
+ [Markdown](markdown/markdown.md)
+ [Permissions](permissions/permissions.md)
+ [Public access](public_access/public_access.md)
+ [Raketasks](raketasks/README.md)
+ [Release](release/README.md)
+ [Security](security/README.md)
+ [System hooks](system_hooks/system_hooks.md)
+ [Update](update/README.md)
+ [Web hooks](web_hooks/web_hooks.md)
+ [Workflow](workflow/workflow.md)
# GitLab API # GitLab API
## End-points
+ [Users](users.md)
+ [Session](session.md)
+ [Projects](projects.md)
+ [Project Snippets](project_snippets.md)
+ [Repositories](repositories.md)
+ [Repository Files](repository_files.md)
+ [Commits](commits.md)
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
+ [Notes](notes.md)
+ [Deploy Keys](deploy_keys.md)
+ [System Hooks](system_hooks.md)
+ [Groups](groups.md)
## Clients
+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
## Introduction
All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile. All API requests require authentication. You need to pass a `private_token` parameter by url or header. If passed as header, the header name must be "PRIVATE-TOKEN" (capital and with dash instead of underscore). You can find or reset your private token in your profile.
If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401: If no, or an invalid, `private_token` is provided then an error message will be returned with status code 401:
...@@ -117,30 +143,3 @@ Issue ...@@ -117,30 +143,3 @@ Issue
So if you want to get issue with api you use `http://host/api/v3/.../issues/:id.json` So if you want to get issue with api you use `http://host/api/v3/.../issues/:id.json`
But when you want to create a link to web page - use `http:://host/project/issues/:iid.json` But when you want to create a link to web page - use `http:://host/project/issues/:iid.json`
## Contents
+ [Users](users.md)
+ [Session](session.md)
+ [Projects](projects.md)
+ [Project Snippets](project_snippets.md)
+ [Repositories](repositories.md)
+ [Repository Files](repository_files.md)
+ [Commits](commits.md)
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
+ [Notes](notes.md)
+ [Deploy Keys](deploy_keys.md)
+ [System Hooks](system_hooks.md)
+ [Groups](groups.md)
## Clients
+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
...@@ -150,6 +150,7 @@ Parameters: ...@@ -150,6 +150,7 @@ Parameters:
+ `target_branch` - The target branch + `target_branch` - The target branch
+ `assignee_id` - Assignee user ID + `assignee_id` - Assignee user ID
+ `title` - Title of MR + `title` - Title of MR
+ `state_event` - New state (close|reopen|merge)
```json ```json
...@@ -210,3 +211,44 @@ Parameters: ...@@ -210,3 +211,44 @@ Parameters:
"note":"text1" "note":"text1"
} }
``` ```
## Get the comments on a MR
Gets all the comments associated with a merge request.
```
GET /projects/:id/merge_request/:merge_request_id/comments
```
Parameters:
+ `id` (required) - The ID of a project
+ `merge_request_id` (required) - ID of merge request
```json
[
{
"note":"this is the 1st comment on the 2merge merge request",
"author":{
"id":11,
"username":"admin",
"email":"admin@local.host",
"name":"Administrator",
"state":"active",
"created_at":"2014-03-06T08:17:35.000Z"
}
},
{
"note":"_Status changed to closed_",
"author":{
"id":11,
"username":"admin",
"email":"admin@local.host",
"name":"Administrator",
"state":"active",
"created_at":"2014-03-06T08:17:35.000Z"
}
}
]
```
...@@ -621,3 +621,29 @@ Parameters: ...@@ -621,3 +621,29 @@ Parameters:
+ query (required) - A string contained in the project name + query (required) - A string contained in the project name
+ per_page (optional) - number of projects to return per page + per_page (optional) - number of projects to return per page
+ page (optional) - the page to retrieve + page (optional) - the page to retrieve
## Labels
### List project labels
Get a list of project labels.
```
GET /projects/:id/labels
```
Parameters:
+ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
```json
[
{
"name":"featute"
},
{
"name": "bug"
}
]
```
+ [Architecture](architecture.md)
+ [Shell commands](shell_commands.md)
...@@ -18,7 +18,7 @@ New releases are generally around the same time as GitLab CE releases with excep ...@@ -18,7 +18,7 @@ New releases are generally around the same time as GitLab CE releases with excep
# System Layout # System Layout
When referring to ~git in the picures it means the home directory of the git user which is typically /home/git. When referring to ~git in the pictures it means the home directory of the git user which is typically /home/git.
GitLab is primarily installed within the `/home/git` user home directory as `git` user. GitLab is primarily installed within the `/home/git` user home directory as `git` user.
Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable). Within the home directory is where the gitlabhq server software resides as well as the repositories (though the repository location is configurable).
...@@ -28,7 +28,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell ...@@ -28,7 +28,7 @@ To serve repositories over SSH there's an add-on application called gitlab-shell
## Components ## Components
![GitLab Diagram Overview](resources/gitlab_diagram_overview.png "GitLab Diagram Overview") ![GitLab Diagram Overview](resources/gitlab_diagram_overview.png)
A typical install of GitLab will be on Ubuntu Linux or RHEL/CentOS. A typical install of GitLab will be on Ubuntu Linux or RHEL/CentOS.
It uses Nginx or Apache as a web front end to proxypass the Unicorn web server. It uses Nginx or Apache as a web front end to proxypass the Unicorn web server.
......
# Guidelines for shell commands in the GitLab codebase # Guidelines for shell commands in the GitLab codebase
## References
- [Google Ruby Security Reviewer's Guide](https://code.google.com/p/ruby-security/wiki/Guide)
- [OWASP Command Injection](https://www.owasp.org/index.php/Command_Injection)
- [Ruby on Rails Security Guide Command Line Injection](http://guides.rubyonrails.org/security.html#command-line-injection)
## Use File and FileUtils instead of shell commands ## Use File and FileUtils instead of shell commands
Sometimes we invoke basic Unix commands via the shell when there is also a Ruby API for doing it. Sometimes we invoke basic Unix commands via the shell when there is also a Ruby API for doing it.
......
+ [Installation](installation.md)
+ [Requirements](requirements.md)
+ [Structure](structure.md)
+ [Database MySQL](database_mysql.md)
...@@ -7,6 +7,9 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se ...@@ -7,6 +7,9 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# Install the database packages # Install the database packages
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
# Ensure you have MySQL version 5.5.14 or later
mysql --version
# Pick a database root password (can be anything), type it and press enter # Pick a database root password (can be anything), type it and press enter
# Retype the database root password and press enter # Retype the database root password and press enter
...@@ -23,6 +26,10 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se ...@@ -23,6 +26,10 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
# change $password in the command below to a real password you pick # change $password in the command below to a real password you pick
mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password'; mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
# Ensure you can use the InnoDB engine which is necessary to support long indexes.
# If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off"
mysql> SET storage_engine=INNODB;
# Create the GitLab production database # Create the GitLab production database
mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`; mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
......
...@@ -128,7 +128,7 @@ GitLab Shell is an ssh access and repository management software developed speci ...@@ -128,7 +128,7 @@ GitLab Shell is an ssh access and repository management software developed speci
cd /home/git cd /home/git
# Clone gitlab shell # Clone gitlab shell
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-shell.git -b v1.8.0 sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-shell.git -b v1.9.1
cd gitlab-shell cd gitlab-shell
...@@ -173,7 +173,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da ...@@ -173,7 +173,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
## Clone the Source ## Clone the Source
# Clone GitLab repository # Clone GitLab repository
sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 6-6-stable gitlab sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 6-7-stable gitlab
# Go to gitlab dir # Go to gitlab dir
cd /home/git/gitlab cd /home/git/gitlab
......
...@@ -5,3 +5,5 @@ GitLab has a great issue tracker but you can also use an external issue tracker ...@@ -5,3 +5,5 @@ GitLab has a great issue tracker but you can also use an external issue tracker
- textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue. - textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue.
![jira screenshot](jira-intergration-points.png) ![jira screenshot](jira-intergration-points.png)
You can configure the integration in the gitlab.yml configuration file.
+ [Corporate contributor license agreement](corporate_contributor_license_agreement.md)
+ [Individual contributor license agreement](individual_contributor_license_agreement.md)
...@@ -38,7 +38,7 @@ If a user is a GitLab administrator they receive all permissions. ...@@ -38,7 +38,7 @@ If a user is a GitLab administrator they receive all permissions.
|------|-----|--------|---------|------|-----| |------|-----|--------|---------|------|-----|
|Browse group|✓|✓|✓|✓|✓| |Browse group|✓|✓|✓|✓|✓|
|Edit group|||||✓| |Edit group|||||✓|
|create project in group|||||✓| |Create project in group|||||✓|
|Manage group members|||||✓| |Manage group members|||||✓|
|Remove group|||||✓| |Remove group|||||✓|
......
+ [Backup restore](backup_restore.md)
+ [Cleanup](cleanup.md)
+ [Features](features.md)
+ [Maintenance](maintenance.md)
+ [User management](user_management.md)
+ [Web hooks](web_hooks.md)
+ [Monthly](monthly.md)
+ [Security](security.md)
...@@ -58,16 +58,14 @@ Check if changed since last release (~22nd of last month depending on when last ...@@ -58,16 +58,14 @@ Check if changed since last release (~22nd of last month depending on when last
After making the release branch new commits are cherry-picked from master. When the release gets closer we get more selective what is cherry-picked. The days of the month are approximately as follows: After making the release branch new commits are cherry-picked from master. When the release gets closer we get more selective what is cherry-picked. The days of the month are approximately as follows:
* 17th: feature freeze (stop merging new features in master) * 1-7th: official merge window (see contributing guide)
* 18th: UI freeze (stop merging changes to the user interface) * 8-14th: work on bugfixes, sponsored features and GitLab EE
* 19th: code freeze (stop merging non-essential code improvements) * 15th: code freeze (stop merging into master except essential bugfixes)
* 20th: release candidate 1 (VERSION x.x.0.rc1, tag and tweet about x.x.0.rc1) * 18th: release candidate 1 (VERSION x.x.0.rc1, tag and tweet about x.x.0.rc1, release on GitLab Cloud)
* 21st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems) * 20st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems)
* 22nd: release (VERSION x.x.0, create x-x-stable branch, tag, blog and tweet) * 22nd: release (VERSION x.x.0, create x-x-stable branch, tag, blog and tweet)
* 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems) * 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems)
* 24-end of month: release Enterprise Edition and upgrade GitLab Cloud * 24-end of month: release GitLab EE and GitLab CI
* 1-7th: official merge window (see contributing guide)
* 8-16th: bugfixes and sponsored features
# Write a blog post # Write a blog post
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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