Commit cfc4a2dbe3652180c1d08d5d9e154e28cbb340fb

Authored by Franz-Robert van Vugt
2 parents f03820eb fc5ac145

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

Showing 170 changed files with 2246 additions and 1429 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 170 files displayed.

.rspec
1   ---color --drb
  1 +--color
... ...
.travis.yml
... ... @@ -19,10 +19,10 @@ rvm:
19 19 services:
20 20 - redis-server
21 21 before_script:
22   - - "bundle exec rake db:setup"
23   - - "bundle exec rake db:seed_fu"
24 22 - "cp config/database.yml.$DB config/database.yml"
25 23 - "cp config/gitlab.yml.example config/gitlab.yml"
  24 + - "bundle exec rake db:setup"
  25 + - "bundle exec rake db:seed_fu"
26 26 script: "bundle exec rake $TASK --trace"
27 27 notifications:
28 28 email: false
... ...
CHANGELOG
  1 +v 6.8.0
  2 + - Ability to at mention users that are participating in issue and merge req. discussion
  3 + - 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)
  4 + - Make user search case-insensitive (Christopher Arnold)
  5 +
  6 +v 6.7.2
  7 + - Fix upgrader script
  8 +
  9 +v 6.7.1
  10 + - Fix GitLab CI integration
  11 +
1 12 v 6.7.0
2 13 - Increased the example Nginx client_max_body_size from 5MB to 20MB, consider updating it manually on existing installations
3 14 - Add support for Gemnasium as a Project Service (Olivier Gonzalez)
... ... @@ -9,6 +20,7 @@ v 6.7.0
9 20 - Show contribution guide link for new issue form (Jeroen van Baarsen)
10 21 - Fix CI status for merge requests from fork
11 22 - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
  23 + - New page load indicator that includes a spinner that scrolls with the page
12 24 - Converted all the help sections into markdown
13 25 - LDAP user filters
14 26 - Streamline the content of notification emails (Pierre de La Morinerie)
... ... @@ -24,6 +36,12 @@ v 6.7.0
24 36 - Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
25 37 - Create and Update MR calls now support the description parameter (Greg Messner)
26 38 - Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
  39 + - Added Slack service integration (Federico Ravasio)
  40 + - Better API responses for access_levels (sponsored by O'Reilly Media)
  41 + - Requires at least 2 unicorn workers
  42 + - Requires gitlab-shell v1.9+
  43 + - 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)
  44 + - Fix `/:username.keys` response content type (Dmitry Medvinsky)
27 45  
28 46 v 6.6.5
29 47 - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
... ...
CONTRIBUTING.md
... ... @@ -24,9 +24,12 @@ Issues and merge requests should be in English and contain appropriate language
24 24  
25 25 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/).
26 26  
27   -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.
  27 +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).
  28 +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.
  29 +When submitting an issue please conform to the issue submission guidelines listed below.
  30 +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.
28 31  
29   -Do not use the issue tracker for feature requests. We have a specific [feedback and suggestions forum](http://feedback.gitlab.com) for this purpose.
  32 +Do not use the issue tracker for feature requests. We have a specific [feature request forum](http://feedback.gitlab.com) for this purpose.
30 33  
31 34 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.
32 35  
... ... @@ -48,7 +51,7 @@ Please send a merge request with a tested solution or a merge request with a fai
48 51  
49 52 ## Merge requests
50 53  
51   -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.
  54 +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.
52 55  
53 56 ### Merge request guidelines
54 57  
... ... @@ -64,7 +67,8 @@ If you can, please submit a merge request with the fix or improvements including
64 67 1. The MR title should describes the change you want to make
65 68 1. The MR description should give a motive for your change and the method you used to achieve it
66 69 1. If the MR changes the UI it should include before and after screenshots
67   -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
  70 +1. If the MR changes CSS classes please include the list of affected pages `grep css-class ./app -R`
  71 +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
68 72 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
69 73 1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md).
70 74  
... ... @@ -74,6 +78,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c
74 78  
75 79 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.
76 80  
  81 +**Please format your merge request description as follows:**
  82 +
  83 +1. What does this MR do?
  84 +2. Are there points in the code the reviewer needs to double check?
  85 +3. Why was this MR needed?
  86 +4. What are the relevant issue numbers / [Feature requests](http://feedback.gitlab.com/)?
  87 +5. Screenshots (If appropiate)
  88 +
77 89 ## Contribution acceptance criteria
78 90  
79 91 1. The change is as small as possible (see the above paragraph for details)
... ...
Gemfile
... ... @@ -132,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
132 132 # Gemnasium integration
133 133 gem "gemnasium-gitlab-service", "~> 0.2"
134 134  
  135 +# Slack integration
  136 +gem "slack-notifier", "~> 0.2.0"
  137 +
135 138 # d3
136 139 gem "d3_rails", "~> 3.1.4"
137 140  
... ... @@ -162,8 +165,9 @@ gem "modernizr", "2.6.2"
162 165 gem "raphael-rails", "~> 2.1.2"
163 166 gem 'bootstrap-sass', '~> 3.0'
164 167 gem "font-awesome-rails", '~> 3.2'
165   -gem "gemoji", "~> 1.3.0"
  168 +gem "gitlab_emoji", "~> 0.0.1.1"
166 169 gem "gon", '~> 5.0.0'
  170 +gem 'nprogress-rails'
167 171  
168 172 group :development do
169 173 gem "annotate", "~> 2.6.0.beta2"
... ... @@ -214,7 +218,6 @@ group :development, :test do
214 218 # PhantomJS driver for Capybara
215 219 gem 'poltergeist', '~> 1.4.1'
216 220  
217   - gem 'spork', '~> 1.0rc'
218 221 gem 'jasmine', '2.0.0.rc5'
219 222  
220 223 gem "spring", '1.1.1'
... ...
Gemfile.lock
... ... @@ -128,6 +128,8 @@ GEM
128 128 mail (~> 2.2)
129 129 email_validator (1.4.0)
130 130 activemodel
  131 + emoji (1.0.1)
  132 + json
131 133 enumerize (0.7.0)
132 134 activesupport (>= 3.2)
133 135 equalizer (0.0.8)
... ... @@ -165,7 +167,6 @@ GEM
165 167 formatador (0.2.4)
166 168 gemnasium-gitlab-service (0.2.1)
167 169 rugged (~> 0.19)
168   - gemoji (1.3.1)
169 170 gherkin-ruby (0.3.1)
170 171 racc
171 172 github-markdown (0.5.5)
... ... @@ -190,6 +191,8 @@ GEM
190 191 charlock_holmes (~> 0.6.6)
191 192 escape_utils (~> 0.2.4)
192 193 mime-types (~> 1.19)
  194 + gitlab_emoji (0.0.1.1)
  195 + emoji (~> 1.0.1)
193 196 gitlab_git (5.7.1)
194 197 activesupport (~> 4.0.0)
195 198 charlock_holmes (~> 0.6.9)
... ... @@ -297,6 +300,7 @@ GEM
297 300 net-ssh (>= 1.99.1)
298 301 net-ssh (2.7.0)
299 302 nokogiri (1.5.10)
  303 + nprogress-rails (0.1.2.3)
300 304 oauth (0.4.7)
301 305 oauth2 (0.8.1)
302 306 faraday (~> 0.8)
... ... @@ -468,6 +472,7 @@ GEM
468 472 rack-protection (~> 1.4)
469 473 tilt (~> 1.3, >= 1.3.4)
470 474 six (0.2.0)
  475 + slack-notifier (0.2.0)
471 476 slim (2.0.2)
472 477 temple (~> 0.6.6)
473 478 tilt (>= 1.3.3, < 2.1)
... ... @@ -479,7 +484,6 @@ GEM
479 484 capybara (>= 2.0.0)
480 485 railties (>= 3)
481 486 spinach (>= 0.4)
482   - spork (1.0.0rc4)
483 487 spring (1.1.1)
484 488 spring-commands-rspec (1.0.1)
485 489 spring (>= 0.9.1)
... ... @@ -591,12 +595,12 @@ DEPENDENCIES
591 595 font-awesome-rails (~> 3.2)
592 596 foreman
593 597 gemnasium-gitlab-service (~> 0.2)
594   - gemoji (~> 1.3.0)
595 598 github-markup (~> 0.7.4)!
596 599 gitlab-flowdock-git-hook (~> 0.4.2)
597 600 gitlab-gollum-lib (~> 1.1.0)
598 601 gitlab-grack (~> 2.0.0.pre)
599 602 gitlab-linguist (~> 3.0.0)
  603 + gitlab_emoji (~> 0.0.1.1)
600 604 gitlab_git (~> 5.7.1)
601 605 gitlab_meta (= 6.0)
602 606 gitlab_omniauth-ldap (= 1.0.4)
... ... @@ -620,6 +624,7 @@ DEPENDENCIES
620 624 minitest (~> 4.7.0)
621 625 modernizr (= 2.6.2)
622 626 mysql2
  627 + nprogress-rails
623 628 omniauth (~> 1.1.3)
624 629 omniauth-github
625 630 omniauth-google-oauth2
... ... @@ -652,9 +657,9 @@ DEPENDENCIES
652 657 simplecov
653 658 sinatra
654 659 six
  660 + slack-notifier (~> 0.2.0)
655 661 slim
656 662 spinach-rails
657   - spork (~> 1.0rc)
658 663 spring (= 1.1.1)
659 664 spring-commands-rspec (= 1.0.1)
660 665 spring-commands-spinach (= 1.0.0)
... ...
PROCESS.md
... ... @@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co
24 24 - Monitors for new merge requests (at least once a week)
25 25 - Manages their work queue by looking at issues and merge requests assigned to them
26 26 - Close fixed issues (via commit messages or manually)
27   -- Codes [new features](http://feedback.gitlab.com/forums/176466-general/filters/top)!
28   -- Response guidelines
29 27 - 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).
30 28  
31 29 ## Priorities of the issue team
... ... @@ -73,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue
73 71  
74 72 ### Feature requests
75 73  
76   -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.
  74 +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.
77 75  
78 76 ### Issue report for old version
79 77  
... ...
Procfile
1   -web: bundle exec unicorn_rails -p $PORT -E development
  1 +web: bundle exec unicorn_rails -p $PORT -E development -c config/unicorn_development.rb
2 2 worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
... ...
README.md
... ... @@ -71,7 +71,7 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl
71 71  
72 72 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.
73 73  
74   -* 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).
  74 +* 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).
75 75  
76 76 ### Run in production mode
77 77  
... ... @@ -96,14 +96,9 @@ or start each component separately
96 96  
97 97 ### Run the tests
98 98  
99   -* Seed the database
100   -
101   - bundle exec rake db:setup RAILS_ENV=test
102   - bundle exec rake db:seed_fu RAILS_ENV=test
103   -
104 99 * Run all tests
105 100  
106   - bundle exec rake gitlab:test RAILS_ENV=test
  101 + bundle exec rake test
107 102  
108 103 * [RSpec](http://rspec.info/) unit and functional tests
109 104  
... ... @@ -134,22 +129,4 @@ or start each component separately
134 129  
135 130 ### Getting help
136 131  
137   -* [Maintenance policy](MAINTENANCE.md) specifies what versions are supported.
138   -
139   -* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) contains solutions to common problems.
140   -
141   -* [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.
142   -
143   -* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
144   -
145   -* [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.
146   -
147   -* [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
148   -
149   -* [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
150   -
151   -* [#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).
152   -
153   -* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
154   -
155   -* [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
  132 +Please see [Getting help for GitLab](https://www.gitlab.com/getting-help/) on our website for the many options to get help.
... ...
VERSION
1   -6.7.0.pre
  1 +6.8.0.pre
... ...
app/assets/javascripts/application.js
... ... @@ -1,31 +0,0 @@
1   -// This is a manifest file that'll be compiled into including all the files listed below.
2   -// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3   -// be included in the compiled file accessible from http://example.com/assets/application.js
4   -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5   -// the compiled file.
6   -//
7   -//= require jquery
8   -//= require jquery.ui.all
9   -//= require jquery_ujs
10   -//= require jquery.cookie
11   -//= require jquery.endless-scroll
12   -//= require jquery.highlight
13   -//= require jquery.history
14   -//= require jquery.waitforimages
15   -//= require jquery.atwho
16   -//= require jquery.scrollto
17   -//= require jquery.blockUI
18   -//= require turbolinks
19   -//= require jquery.turbolinks
20   -//= require bootstrap
21   -//= require modernizr
22   -//= require select2
23   -//= require raphael
24   -//= require g.raphael-min
25   -//= require g.bar-min
26   -//= require branch-graph
27   -//= require highlightjs.min
28   -//= require ace/ace
29   -//= require_tree .
30   -//= require d3
31   -//= require underscore
app/assets/javascripts/application.js.coffee 0 → 100644
... ... @@ -0,0 +1,154 @@
  1 +# This is a manifest file that'll be compiled into including all the files listed below.
  2 +# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
  3 +# be included in the compiled file accessible from http://example.com/assets/application.js
  4 +# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
  5 +# the compiled file.
  6 +#
  7 +#= require jquery
  8 +#= require jquery.ui.all
  9 +#= require jquery_ujs
  10 +#= require jquery.cookie
  11 +#= require jquery.endless-scroll
  12 +#= require jquery.highlight
  13 +#= require jquery.history
  14 +#= require jquery.waitforimages
  15 +#= require jquery.atwho
  16 +#= require jquery.scrollto
  17 +#= require jquery.blockUI
  18 +#= require turbolinks
  19 +#= require jquery.turbolinks
  20 +#= require bootstrap
  21 +#= require modernizr
  22 +#= require select2
  23 +#= require raphael
  24 +#= require g.raphael-min
  25 +#= require g.bar-min
  26 +#= require branch-graph
  27 +#= require highlightjs.min
  28 +#= require ace/ace
  29 +#= require d3
  30 +#= require underscore
  31 +#= require nprogress
  32 +#= require nprogress-turbolinks
  33 +#= require_tree .
  34 +
  35 +window.slugify = (text) ->
  36 + text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
  37 +
  38 +window.ajaxGet = (url) ->
  39 + $.ajax({type: "GET", url: url, dataType: "script"})
  40 +
  41 +window.showAndHide = (selector) ->
  42 +
  43 +window.errorMessage = (message) ->
  44 + ehtml = $("<p>")
  45 + ehtml.addClass("error_message")
  46 + ehtml.html(message)
  47 + ehtml
  48 +
  49 +window.split = (val) ->
  50 + return val.split( /,\s*/ )
  51 +
  52 +window.extractLast = (term) ->
  53 + return split( term ).pop()
  54 +
  55 +# Disable button if text field is empty
  56 +window.disableButtonIfEmptyField = (field_selector, button_selector) ->
  57 + field = $(field_selector)
  58 + closest_submit = field.closest("form").find(button_selector)
  59 +
  60 + closest_submit.disable() if field.val() is ""
  61 +
  62 + field.on "input", ->
  63 + if $(@).val() is ""
  64 + closest_submit.disable()
  65 + else
  66 + closest_submit.enable()
  67 +
  68 +window.sanitize = (str) ->
  69 + return str.replace(/<(?:.|\n)*?>/gm, '')
  70 +
  71 +window.linkify = (str) ->
  72 + exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
  73 + return str.replace(exp,"<a href='$1'>$1</a>")
  74 +
  75 +window.simpleFormat = (str) ->
  76 + linkify(sanitize(str).replace(/\n/g, '<br />'))
  77 +
  78 +window.unbindEvents = ->
  79 + $(document).unbind('scroll')
  80 + $(document).off('scroll')
  81 +
  82 +document.addEventListener("page:fetch", unbindEvents)
  83 +
  84 +$ ->
  85 + # Click a .one_click_select field, select the contents
  86 + $(".one_click_select").on 'click', -> $(@).select()
  87 +
  88 + $('.remove-row').bind 'ajax:success', ->
  89 + $(this).closest('li').fadeOut()
  90 +
  91 + # Initialize select2 selects
  92 + $('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
  93 +
  94 + # Initialize tooltips
  95 + $('.has_tooltip').tooltip()
  96 +
  97 + # Bottom tooltip
  98 + $('.has_bottom_tooltip').tooltip(placement: 'bottom')
  99 +
  100 + # Form submitter
  101 + $('.trigger-submit').on 'change', ->
  102 + $(@).parents('form').submit()
  103 +
  104 + $("abbr.timeago").timeago()
  105 + $('.js-timeago').timeago()
  106 +
  107 + # Flash
  108 + if (flash = $(".flash-container")).length > 0
  109 + flash.click -> $(@).fadeOut()
  110 + flash.show()
  111 + setTimeout (-> flash.fadeOut()), 5000
  112 +
  113 + # Disable form buttons while a form is submitting
  114 + $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
  115 + buttons = $('[type="submit"]', @)
  116 +
  117 + switch e.type
  118 + when 'ajax:beforeSend', 'submit'
  119 + buttons.disable()
  120 + else
  121 + buttons.enable()
  122 +
  123 + # Show/Hide the profile menu when hovering the account box
  124 + $('.account-box').hover -> $(@).toggleClass('hover')
  125 +
  126 + # Focus search field by pressing 's' key
  127 + $(document).keypress (e) ->
  128 + # Don't do anything if typing in an input
  129 + return if $(e.target).is(":input")
  130 +
  131 + switch e.which
  132 + when 115
  133 + $("#search").focus()
  134 + e.preventDefault()
  135 + when 63
  136 + new Shortcuts()
  137 + e.preventDefault()
  138 +
  139 +
  140 + # Commit show suppressed diff
  141 + $(".diff-content").on "click", ".supp_diff_link", ->
  142 + $(@).next('table').show()
  143 + $(@).remove()
  144 +
  145 +(($) ->
  146 + # Disable an element and add the 'disabled' Bootstrap class
  147 + $.fn.extend disable: ->
  148 + $(@).attr('disabled', 'disabled').addClass('disabled')
  149 +
  150 + # Enable an element and remove the 'disabled' Bootstrap class
  151 + $.fn.extend enable: ->
  152 + $(@).removeAttr('disabled').removeClass('disabled')
  153 +
  154 +)(jQuery)
... ...
app/assets/javascripts/gfm_auto_complete.js.coffee
... ... @@ -6,7 +6,6 @@ GitLab.GfmAutoComplete =
6 6 dataSource: ''
7 7 # Emoji
8 8 Emoji:
9   - assetBase: ''
10 9 template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
11 10  
12 11 # Team Members
... ... @@ -27,7 +26,7 @@ GitLab.GfmAutoComplete =
27 26 tpl: @Emoji.template
28 27 callbacks:
29 28 before_save: (emojis) =>
30   - $.map emojis, (em) => name: em, insert: em+ ':', image: "#{@Emoji.assetBase}/#{em}.png"
  29 + $.map emojis, (em) => name: em.name, insert: em.name+ ':', image: em.path
31 30  
32 31 # Team Members
33 32 input.atwho
... ...
app/assets/javascripts/main.js.coffee
... ... @@ -1,128 +0,0 @@
1   -window.slugify = (text) ->
2   - text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
3   -
4   -window.ajaxGet = (url) ->
5   - $.ajax({type: "GET", url: url, dataType: "script"})
6   -
7   -window.showAndHide = (selector) ->
8   -
9   -window.errorMessage = (message) ->
10   - ehtml = $("<p>")
11   - ehtml.addClass("error_message")
12   - ehtml.html(message)
13   - ehtml
14   -
15   -window.split = (val) ->
16   - return val.split( /,\s*/ )
17   -
18   -window.extractLast = (term) ->
19   - return split( term ).pop()
20   -
21   -# Disable button if text field is empty
22   -window.disableButtonIfEmptyField = (field_selector, button_selector) ->
23   - field = $(field_selector)
24   - closest_submit = field.closest("form").find(button_selector)
25   -
26   - closest_submit.disable() if field.val() is ""
27   -
28   - field.on "input", ->
29   - if $(@).val() is ""
30   - closest_submit.disable()
31   - else
32   - closest_submit.enable()
33   -
34   -window.sanitize = (str) ->
35   - return str.replace(/<(?:.|\n)*?>/gm, '')
36   -
37   -window.linkify = (str) ->
38   - exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
39   - return str.replace(exp,"<a href='$1'>$1</a>")
40   -
41   -window.simpleFormat = (str) ->
42   - linkify(sanitize(str).replace(/\n/g, '<br />'))
43   -
44   -window.startSpinner = ->
45   - $('.turbolink-spinner').fadeIn()
46   -
47   -window.stopSpinner = ->
48   - $('.turbolink-spinner').fadeOut()
49   -
50   -window.unbindEvents = ->
51   - $(document).unbind('scroll')
52   - $(document).off('scroll')
53   -
54   -document.addEventListener("page:fetch", startSpinner)
55   -document.addEventListener("page:fetch", unbindEvents)
56   -document.addEventListener("page:change", stopSpinner)
57   -
58   -$ ->
59   - # Click a .one_click_select field, select the contents
60   - $(".one_click_select").on 'click', -> $(@).select()
61   -
62   - $('.remove-row').bind 'ajax:success', ->
63   - $(this).closest('li').fadeOut()
64   -
65   - # Initialize select2 selects
66   - $('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
67   -
68   - # Initialize tooltips
69   - $('.has_tooltip').tooltip()
70   -
71   - # Bottom tooltip
72   - $('.has_bottom_tooltip').tooltip(placement: 'bottom')
73   -
74   - # Form submitter
75   - $('.trigger-submit').on 'change', ->
76   - $(@).parents('form').submit()
77   -
78   - $("abbr.timeago").timeago()
79   - $('.js-timeago').timeago()
80   -
81   - # Flash
82   - if (flash = $(".flash-container")).length > 0
83   - flash.click -> $(@).fadeOut()
84   - flash.show()
85   - setTimeout (-> flash.fadeOut()), 5000
86   -
87   - # Disable form buttons while a form is submitting
88   - $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
89   - buttons = $('[type="submit"]', @)
90   -
91   - switch e.type
92   - when 'ajax:beforeSend', 'submit'
93   - buttons.disable()
94   - else
95   - buttons.enable()
96   -
97   - # Show/Hide the profile menu when hovering the account box
98   - $('.account-box').hover -> $(@).toggleClass('hover')
99   -
100   - # Focus search field by pressing 's' key
101   - $(document).keypress (e) ->
102   - # Don't do anything if typing in an input
103   - return if $(e.target).is(":input")
104   -
105   - switch e.which
106   - when 115
107   - $("#search").focus()
108   - e.preventDefault()
109   - when 63
110   - new Shortcuts()
111   - e.preventDefault()
112   -
113   -
114   - # Commit show suppressed diff
115   - $(".diff-content").on "click", ".supp_diff_link", ->
116   - $(@).next('table').show()
117   - $(@).remove()
118   -
119   -(($) ->
120   - # Disable an element and add the 'disabled' Bootstrap class
121   - $.fn.extend disable: ->
122   - $(@).attr('disabled', 'disabled').addClass('disabled')
123   -
124   - # Enable an element and remove the 'disabled' Bootstrap class
125   - $.fn.extend enable: ->
126   - $(@).removeAttr('disabled').removeClass('disabled')
127   -
128   -)(jQuery)
app/assets/stylesheets/application.scss
... ... @@ -7,6 +7,8 @@
7 7 *= require select2
8 8 *= require highlightjs.min
9 9 *= require_self
  10 + *= require nprogress
  11 + *= require nprogress-bootstrap
10 12 */
11 13  
12 14 @import "main/variables.scss";
... ...
app/assets/stylesheets/generic/common.scss
... ... @@ -355,3 +355,7 @@ table {
355 355 @media (max-width: $screen-xs-max) {
356 356 .container .content { margin-top: 20px; }
357 357 }
  358 +
  359 +.wiki .highlight, .note-body .highlight {
  360 + margin-bottom: 9px;
  361 +}
... ...
app/assets/stylesheets/generic/typography.scss
... ... @@ -88,9 +88,6 @@ a:focus {
88 88 .wiki {
89 89 @include md-typography;
90 90  
91   - font-size: 14px;
92   - line-height: 1.6;
93   -
94 91 /* Link to current header. */
95 92 h1, h2, h3, h4, h5, h6 {
96 93 position: relative;
... ... @@ -120,3 +117,11 @@ a:focus {
120 117 .md {
121 118 @include md-typography;
122 119 }
  120 +
  121 +/**
  122 + * Textareas intended for GFM
  123 + *
  124 + */
  125 +textarea.js-gfm-input {
  126 + font-family: $monospace_font;
  127 +}
... ...
app/assets/stylesheets/main/mixins.scss
... ... @@ -84,6 +84,9 @@
84 84 }
85 85  
86 86 @mixin md-typography {
  87 + font-size: 14px;
  88 + line-height: 1.6;
  89 +
87 90 img {
88 91 max-width: 100%;
89 92 }
... ...
app/assets/stylesheets/print.scss 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +/* Generic print styles */
  2 +header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;}
  3 +.profiler-results {display: none;}
  4 +
  5 +/* Styles targeted specifically at printing files */
  6 +.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;}
  7 +.file-title {display: none;}
  8 +.file-holder {border: none;}
  9 +
  10 +.wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; }
  11 +.wiki h1 {font-size: 30px;}
  12 +.wiki h2 {font-size: 22px;}
  13 +.wiki h3 {font-size: 18px; font-weight: bold; }
... ...
app/assets/stylesheets/sections/dashboard.scss
... ... @@ -61,7 +61,7 @@
61 61 }
62 62  
63 63 .project-row, .group-row {
64   - padding: 10px 12px !important;
  64 + padding: 8px 12px !important;
65 65 font-size: 14px;
66 66 line-height: 24px;
67 67  
... ...
app/assets/stylesheets/sections/diff.scss
... ... @@ -62,6 +62,29 @@
62 62 font-size: 12px;
63 63 }
64 64 }
  65 +
  66 + .text-file-parallel div {
  67 + display: inline-block;
  68 + padding-bottom: 16px;
  69 + }
  70 + .diff-side {
  71 + overflow-x: scroll;
  72 + width: 508px;
  73 + height: 700px;
  74 + }
  75 + .diff-side.diff-side-left{
  76 + overflow-y:hidden;
  77 + }
  78 + .diff-side table, td.diff-middle table {
  79 + height: 700px;
  80 + }
  81 + .diff-middle {
  82 + width: 114px;
  83 + vertical-align: top;
  84 + height: 700px;
  85 + overflow: hidden
  86 + }
  87 +
65 88 .old_line, .new_line, .diff_line {
66 89 margin: 0px;
67 90 padding: 0px;
... ... @@ -125,8 +148,6 @@
125 148 }
126 149 &.parallel {
127 150 display: table-cell;
128   - overflow: hidden;
129   - width: 50%;
130 151 }
131 152 }
132 153 }
... ...
app/assets/stylesheets/sections/events.scss
... ... @@ -42,7 +42,7 @@
42 42 }
43 43 }
44 44  
45   - padding: 14px 0px;
  45 + padding: 12px 0px;
46 46 border-bottom: 1px solid #eee;
47 47 .event-title {
48 48 color: #333;
... ... @@ -63,6 +63,10 @@
63 63 color: #666;
64 64 margin-top: 5px;
65 65  
  66 + .md {
  67 + font-size: 13px;
  68 + }
  69 +
66 70 pre {
67 71 border: none;
68 72 background: #f9f9f9;
... ...
app/assets/stylesheets/sections/header.scss
... ... @@ -273,3 +273,9 @@ header {
273 273 }
274 274 }
275 275 }
  276 +
  277 +@media (max-width: $screen-xs-max) {
  278 + #nprogress .spinner {
  279 + right: 35px !important;
  280 + }
  281 +}
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -27,11 +27,15 @@ ul.notes {
27 27  
28 28 .discussion-last-update,
29 29 .note-last-update {
30   - font-style: italic;
  30 + &:before {
  31 + content: "\00b7";
  32 + }
  33 + font-size: 13px;
31 34 }
32 35 .author {
33   - color: $style_color;
  36 + color: #555;
34 37 font-weight: bold;
  38 + font-size: 14px;
35 39 &:hover {
36 40 color: $primary_color;
37 41 }
... ...
app/controllers/passwords_controller.rb 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +class PasswordsController < Devise::PasswordsController
  2 +
  3 + def create
  4 + email = resource_params[:email]
  5 + resource_found = resource_class.find_by_email(email)
  6 + if resource_found && resource_found.ldap_user?
  7 + flash[:alert] = "Cannot reset password for LDAP user."
  8 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return
  9 + end
  10 +
  11 + self.resource = resource_class.send_reset_password_instructions(resource_params)
  12 + if successfully_sent?(resource)
  13 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
  14 + else
  15 + respond_with(resource)
  16 + end
  17 + end
  18 +end
... ...
app/controllers/profiles/keys_controller.rb
... ... @@ -41,7 +41,7 @@ class Profiles::KeysController &lt; ApplicationController
41 41 begin
42 42 user = User.find_by_username(params[:username])
43 43 if user.present?
44   - render text: user.all_ssh_keys.join("\n")
  44 + render text: user.all_ssh_keys.join("\n"), content_type: "text/plain"
45 45 else
46 46 render_404 and return
47 47 end
... ...
app/controllers/projects/issues_controller.rb
... ... @@ -76,7 +76,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController
76 76 end
77 77  
78 78 def update
79   - @issue.update_attributes(params[:issue].merge(author_id_of_changes: current_user.id))
  79 + @issue.update_attributes(params[:issue])
80 80 @issue.reset_events_cache
81 81  
82 82 respond_to do |format|
... ...
app/controllers/projects/merge_requests_controller.rb
... ... @@ -109,7 +109,7 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
109 109 params[:merge_request].delete(:source_project_id)
110 110 params[:merge_request].delete(:target_project_id)
111 111  
112   - if @merge_request.update_attributes(params[:merge_request].merge(author_id_of_changes: current_user.id))
  112 + if @merge_request.update_attributes(params[:merge_request])
113 113 @merge_request.reset_events_cache
114 114  
115 115 respond_to do |format|
... ...
app/controllers/projects/milestones_controller.rb
... ... @@ -38,7 +38,6 @@ class Projects::MilestonesController &lt; Projects::ApplicationController
38 38  
39 39 def create
40 40 @milestone = @project.milestones.new(params[:milestone])
41   - @milestone.author_id_of_changes = current_user.id
42 41  
43 42 if @milestone.save
44 43 redirect_to project_milestone_path(@project, @milestone)
... ... @@ -48,7 +47,7 @@ class Projects::MilestonesController &lt; Projects::ApplicationController
48 47 end
49 48  
50 49 def update
51   - @milestone.update_attributes(params[:milestone].merge(author_id_of_changes: current_user.id))
  50 + @milestone.update_attributes(params[:milestone])
52 51  
53 52 respond_to do |format|
54 53 format.js
... ...
app/controllers/projects_controller.rb
... ... @@ -123,11 +123,20 @@ class ProjectsController &lt; ApplicationController
123 123 end
124 124  
125 125 def autocomplete_sources
  126 + note_type = params['type']
  127 + note_id = params['type_id']
  128 + participating = if note_type && note_id
  129 + participants_in(note_type, note_id)
  130 + else
  131 + []
  132 + end
  133 + team_members = sorted(@project.team.members)
  134 + participants = team_members + participating
126 135 @suggestions = {
127   - emojis: Emoji.names,
  136 + emojis: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } },
128 137 issues: @project.issues.select([:iid, :title, :description]),
129 138 mergerequests: @project.merge_requests.select([:iid, :title, :description]),
130   - members: @project.team.members.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
  139 + members: participants.uniq
131 140 }
132 141  
133 142 respond_to do |format|
... ... @@ -162,4 +171,25 @@ class ProjectsController &lt; ApplicationController
162 171 def user_layout
163 172 current_user ? "projects" : "public_projects"
164 173 end
  174 +
  175 + def participants_in(type, id)
  176 + users = case type
  177 + when "Issue"
  178 + issue = @project.issues.find_by_iid(id)
  179 + issue ? issue.participants : []
  180 + when "MergeRequest"
  181 + merge_request = @project.merge_requests.find_by_iid(id)
  182 + merge_request ? merge_request.participants : []
  183 + when "Commit"
  184 + author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
  185 + User.where(id: author_ids)
  186 + else
  187 + []
  188 + end
  189 + sorted(users)
  190 + end
  191 +
  192 + def sorted(users)
  193 + users.uniq.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
  194 + end
165 195 end
... ...
app/finders/base_finder.rb
... ... @@ -47,9 +47,9 @@ class BaseFinder
47 47 []
48 48 end
49 49 elsif current_user && params[:authorized_only].presence
50   - klass.of_projects(current_user.authorized_projects)
  50 + klass.of_projects(current_user.authorized_projects).references(:project)
51 51 else
52   - klass.of_projects(Project.accessible_to(current_user))
  52 + klass.of_projects(Project.accessible_to(current_user)).references(:project)
53 53 end
54 54 end
55 55  
... ...
app/helpers/commits_helper.rb
... ... @@ -105,8 +105,80 @@ module CommitsHelper
105 105 branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
106 106 end
107 107  
108   - def get_old_file(project, commit, diff)
109   - project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
  108 + def parallel_diff_lines(project, commit, diff, file)
  109 + old_file = project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
  110 + deleted_lines = {}
  111 + added_lines = {}
  112 + each_diff_line(diff, 0) do |line, type, line_code, line_new, line_old|
  113 + if type == "old"
  114 + deleted_lines[line_old] = { line_code: line_code, type: type, line: line }
  115 + elsif type == "new"
  116 + added_lines[line_new] = { line_code: line_code, type: type, line: line }
  117 + end
  118 + end
  119 + max_length = old_file ? old_file.sloc + added_lines.length : file.sloc
  120 +
  121 + offset1 = 0
  122 + offset2 = 0
  123 + old_lines = []
  124 + new_lines = []
  125 +
  126 + max_length.times do |line_index|
  127 + line_index1 = line_index - offset1
  128 + line_index2 = line_index - offset2
  129 + deleted_line = deleted_lines[line_index1 + 1]
  130 + added_line = added_lines[line_index2 + 1]
  131 + old_line = old_file.lines[line_index1] if old_file
  132 + new_line = file.lines[line_index2]
  133 +
  134 + if deleted_line && added_line
  135 + elsif deleted_line
  136 + new_line = nil
  137 + offset2 += 1
  138 + elsif added_line
  139 + old_line = nil
  140 + offset1 += 1
  141 + end
  142 +
  143 + old_lines[line_index] = DiffLine.new
  144 + new_lines[line_index] = DiffLine.new
  145 +
  146 + # old
  147 + if line_index == 0 && diff.new_file
  148 + old_lines[line_index].type = :file_created
  149 + old_lines[line_index].content = 'File was created'
  150 + elsif deleted_line
  151 + old_lines[line_index].type = :deleted
  152 + old_lines[line_index].content = old_line
  153 + old_lines[line_index].num = line_index1 + 1
  154 + old_lines[line_index].code = deleted_line[:line_code]
  155 + elsif old_line
  156 + old_lines[line_index].type = :no_change
  157 + old_lines[line_index].content = old_line
  158 + old_lines[line_index].num = line_index1 + 1
  159 + else
  160 + old_lines[line_index].type = :added
  161 + end
  162 +
  163 + # new
  164 + if line_index == 0 && diff.deleted_file
  165 + new_lines[line_index].type = :file_deleted
  166 + new_lines[line_index].content = "File was deleted"
  167 + elsif added_line
  168 + new_lines[line_index].type = :added
  169 + new_lines[line_index].num = line_index2 + 1
  170 + new_lines[line_index].content = new_line
  171 + new_lines[line_index].code = added_line[:line_code]
  172 + elsif new_line
  173 + new_lines[line_index].type = :no_change
  174 + new_lines[line_index].num = line_index2 + 1
  175 + new_lines[line_index].content = new_line
  176 + else
  177 + new_lines[line_index].type = :deleted
  178 + end
  179 + end
  180 +
  181 + return old_lines, new_lines
110 182 end
111 183  
112 184 protected
... ...
app/helpers/merge_requests_helper.rb
... ... @@ -20,7 +20,7 @@ module MergeRequestsHelper
20 20 target_project_id: target_project.id,
21 21 source_branch: event.branch_name,
22 22 target_branch: target_project.repository.root_ref,
23   - title: event.branch_name.titleize
  23 + title: event.branch_name.humanize
24 24 }
25 25 end
26 26  
... ...
app/helpers/tree_helper.rb
... ... @@ -40,7 +40,7 @@ module TreeHelper
40 40 # Returns boolean
41 41 def markup?(filename)
42 42 filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
43   - .mediawiki .rst .asciidoc .pod))
  43 + .mediawiki .rst .adoc .asciidoc .pod))
44 44 end
45 45  
46 46 def gitlab_markdown?(filename)
... ...
app/mailers/emails/merge_requests.rb
... ... @@ -29,11 +29,11 @@ module Emails
29 29 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
30 30 end
31 31  
32   - def merged_merge_request_email(recipient_id, merge_request_id)
  32 + def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
33 33 @merge_request = MergeRequest.find(merge_request_id)
34 34 @project = @merge_request.project
35 35 @target_url = project_merge_request_url(@project, @merge_request)
36   - mail(from: sender(@merge_request.author_id_of_changes),
  36 + mail(from: sender(updated_by_user_id),
37 37 to: recipient(recipient_id),
38 38 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
39 39 end
... ...
app/models/concerns/issuable.rb
... ... @@ -37,8 +37,6 @@ module Issuable
37 37 allow_nil: true,
38 38 prefix: true
39 39  
40   - attr_accessor :author_id_of_changes
41   -
42 40 attr_mentionable :title, :description
43 41 end
44 42  
... ...
app/models/diff_line.rb 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +class DiffLine
  2 + attr_accessor :type, :content, :num, :code
  3 +end
... ...
app/models/event.rb
... ... @@ -47,14 +47,6 @@ class Event &lt; ActiveRecord::Base
47 47 scope :in_projects, ->(project_ids) { where(project_id: project_ids).recent }
48 48  
49 49 class << self
50   - def determine_action(record)
51   - if [Issue, MergeRequest].include? record.class
52   - Event::CREATED
53   - elsif record.kind_of? Note
54   - Event::COMMENTED
55   - end
56   - end
57   -
58 50 def create_ref_event(project, user, ref, action = 'add', prefix = 'refs/heads')
59 51 commit = project.repository.commit(ref.target)
60 52  
... ...
app/models/issue.rb
... ... @@ -30,8 +30,7 @@ class Issue &lt; ActiveRecord::Base
30 30 scope :of_user_team, ->(team) { where(project_id: team.project_ids, assignee_id: team.member_ids) }
31 31  
32 32 attr_accessible :title, :assignee_id, :position, :description,
33   - :milestone_id, :label_list, :author_id_of_changes,
34   - :state_event
  33 + :milestone_id, :label_list, :state_event
35 34  
36 35 acts_as_taggable_on :labels
37 36  
... ...
app/models/merge_request.rb
... ... @@ -38,7 +38,7 @@ class MergeRequest &lt; ActiveRecord::Base
38 38  
39 39 delegate :commits, :diffs, :last_commit, :last_commit_short_sha, to: :merge_request_diff, prefix: nil
40 40  
41   - attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :author_id_of_changes, :state_event, :description
  41 + attr_accessible :title, :assignee_id, :source_project_id, :source_branch, :target_project_id, :target_branch, :milestone_id, :state_event, :description
42 42  
43 43 attr_accessor :should_remove_source_branch
44 44  
... ...
app/models/milestone.rb
... ... @@ -16,8 +16,7 @@
16 16 class Milestone < ActiveRecord::Base
17 17 include InternalId
18 18  
19   - attr_accessible :title, :description, :due_date, :state_event, :author_id_of_changes
20   - attr_accessor :author_id_of_changes
  19 + attr_accessible :title, :description, :due_date, :state_event
21 20  
22 21 belongs_to :project
23 22 has_many :issues
... ... @@ -89,6 +88,6 @@ class Milestone &lt; ActiveRecord::Base
89 88 end
90 89  
91 90 def author_id
92   - author_id_of_changes
  91 + nil
93 92 end
94 93 end
... ...
app/models/note.rb
... ... @@ -199,7 +199,8 @@ class Note &lt; ActiveRecord::Base
199 199 def downvote?
200 200 votable? && (note.start_with?('-1') ||
201 201 note.start_with?(':-1:') ||
202   - note.start_with?(':thumbsdown:')
  202 + note.start_with?(':thumbsdown:') ||
  203 + note.start_with?(':thumbs_down_sign:')
203 204 )
204 205 end
205 206  
... ... @@ -249,7 +250,8 @@ class Note &lt; ActiveRecord::Base
249 250 def upvote?
250 251 votable? && (note.start_with?('+1') ||
251 252 note.start_with?(':+1:') ||
252   - note.start_with?(':thumbsup:')
  253 + note.start_with?(':thumbsup:') ||
  254 + note.start_with?(':thumbs_up_sign:')
253 255 )
254 256 end
255 257  
... ...
app/models/project.rb
... ... @@ -56,6 +56,7 @@ class Project &lt; ActiveRecord::Base
56 56 has_one :flowdock_service, dependent: :destroy
57 57 has_one :assembla_service, dependent: :destroy
58 58 has_one :gemnasium_service, dependent: :destroy
  59 + has_one :slack_service, dependent: :destroy
59 60 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
60 61 has_one :forked_from_project, through: :forked_project_link
61 62 # Merge Requests for target project should be removed with it
... ... @@ -304,7 +305,7 @@ class Project &lt; ActiveRecord::Base
304 305 end
305 306  
306 307 def available_services_names
307   - %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium)
  308 + %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack)
308 309 end
309 310  
310 311 def gitlab_ci?
... ...
app/models/project_services/slack_message.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +require 'slack-notifier'
  2 +
  3 +class SlackMessage
  4 + def initialize(params)
  5 + @after = params.fetch(:after)
  6 + @before = params.fetch(:before)
  7 + @commits = params.fetch(:commits, [])
  8 + @project_name = params.fetch(:project_name)
  9 + @project_url = params.fetch(:project_url)
  10 + @ref = params.fetch(:ref).gsub('refs/heads/', '')
  11 + @username = params.fetch(:user_name)
  12 + end
  13 +
  14 + def compose
  15 + format(message)
  16 + end
  17 +
  18 + private
  19 +
  20 + attr_reader :after
  21 + attr_reader :before
  22 + attr_reader :commits
  23 + attr_reader :project_name
  24 + attr_reader :project_url
  25 + attr_reader :ref
  26 + attr_reader :username
  27 +
  28 + def message
  29 + if new_branch?
  30 + new_branch_message
  31 + elsif removed_branch?
  32 + removed_branch_message
  33 + else
  34 + push_message << commit_messages
  35 + end
  36 + end
  37 +
  38 + def format(string)
  39 + Slack::Notifier::LinkFormatter.format(string)
  40 + end
  41 +
  42 + def new_branch_message
  43 + "#{username} pushed new branch #{branch_link} to #{project_link}"
  44 + end
  45 +
  46 + def removed_branch_message
  47 + "#{username} removed branch #{ref} from #{project_link}"
  48 + end
  49 +
  50 + def push_message
  51 + "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
  52 + end
  53 +
  54 + def commit_messages
  55 + commits.each_with_object('') do |commit, str|
  56 + str << compose_commit_message(commit)
  57 + end
  58 + end
  59 +
  60 + def compose_commit_message(commit)
  61 + id = commit.fetch(:id)[0..5]
  62 + message = commit.fetch(:message)
  63 + url = commit.fetch(:url)
  64 +
  65 + "\n - #{message} ([#{id}](#{url}))"
  66 + end
  67 +
  68 + def new_branch?
  69 + before =~ /000000/
  70 + end
  71 +
  72 + def removed_branch?
  73 + after =~ /000000/
  74 + end
  75 +
  76 + def branch_url
  77 + "#{project_url}/commits/#{ref}"
  78 + end
  79 +
  80 + def compare_url
  81 + "#{project_url}/compare/#{before}...#{after}"
  82 + end
  83 +
  84 + def branch_link
  85 + "[#{ref}](#{branch_url})"
  86 + end
  87 +
  88 + def project_link
  89 + "[#{project_name}](#{project_url})"
  90 + end
  91 +
  92 + def compare_link
  93 + "[Compare changes](#{compare_url})"
  94 + end
  95 +end
... ...
app/models/project_services/slack_service.rb 0 → 100644
... ... @@ -0,0 +1,68 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: services
  4 +#
  5 +# id :integer not null, primary key
  6 +# type :string(255)
  7 +# title :string(255)
  8 +# token :string(255)
  9 +# project_id :integer not null
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +# active :boolean default(FALSE), not null
  13 +# project_url :string(255)
  14 +# subdomain :string(255)
  15 +# room :string(255)
  16 +# api_key :string(255)
  17 +#
  18 +
  19 +class SlackService < Service
  20 + attr_accessible :room
  21 + attr_accessible :subdomain
  22 +
  23 + validates :room, presence: true, if: :activated?
  24 + validates :subdomain, presence: true, if: :activated?
  25 + validates :token, presence: true, if: :activated?
  26 +
  27 + def title
  28 + 'Slack'
  29 + end
  30 +
  31 + def description
  32 + 'A team communication tool for the 21st century'
  33 + end
  34 +
  35 + def to_param
  36 + 'slack'
  37 + end
  38 +
  39 + def fields
  40 + [
  41 + { type: 'text', name: 'subdomain', placeholder: '' },
  42 + { type: 'text', name: 'token', placeholder: '' },
  43 + { type: 'text', name: 'room', placeholder: 'Ex. #general' },
  44 + ]
  45 + end
  46 +
  47 + def execute(push_data)
  48 + message = SlackMessage.new(push_data.merge(
  49 + project_url: project_url,
  50 + project_name: project_name
  51 + ))
  52 +
  53 + notifier = Slack::Notifier.new(subdomain, token)
  54 + notifier.channel = room
  55 + notifier.username = 'GitLab'
  56 + notifier.ping(message.compose)
  57 + end
  58 +
  59 + private
  60 +
  61 + def project_name
  62 + project.name_with_namespace.gsub(/\s/, '')
  63 + end
  64 +
  65 + def project_url
  66 + project.web_url
  67 + end
  68 +end
... ...
app/models/user.rb
... ... @@ -204,7 +204,7 @@ class User &lt; ActiveRecord::Base
204 204 end
205 205  
206 206 def search query
207   - where("name LIKE :query OR email LIKE :query OR username LIKE :query", query: "%#{query}%")
  207 + where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
208 208 end
209 209  
210 210 def by_username_or_id(name_or_id)
... ... @@ -249,7 +249,7 @@ class User &lt; ActiveRecord::Base
249 249 def namespace_uniq
250 250 namespace_name = self.username
251 251 if Namespace.find_by(path: namespace_name)
252   - self.errors.add :username, "already exist"
  252 + self.errors.add :username, "already exists"
253 253 end
254 254 end
255 255  
... ...
app/observers/activity_observer.rb
... ... @@ -1,39 +0,0 @@
1   -class ActivityObserver < BaseObserver
2   - observe :issue, :note, :milestone
3   -
4   - def after_create(record)
5   - event_author_id = record.author_id
6   -
7   - if record.kind_of?(Note)
8   - # Skip system notes, like status changes and cross-references.
9   - return true if record.system?
10   -
11   - # Skip wall notes to prevent spamming of dashboard
12   - return true if record.noteable_type.blank?
13   - end
14   -
15   - if event_author_id
16   - create_event(record, Event.determine_action(record))
17   - end
18   - end
19   -
20   - def after_close(record, transition)
21   - create_event(record, Event::CLOSED)
22   - end
23   -
24   - def after_reopen(record, transition)
25   - create_event(record, Event::REOPENED)
26   - end
27   -
28   - protected
29   -
30   - def create_event(record, status)
31   - Event.create(
32   - project: record.project,
33   - target_id: record.id,
34   - target_type: record.class.name,
35   - action: status,
36   - author_id: current_user.id
37   - )
38   - end
39   -end
app/observers/base_observer.rb
... ... @@ -3,6 +3,10 @@ class BaseObserver &lt; ActiveRecord::Observer
3 3 NotificationService.new
4 4 end
5 5  
  6 + def event_service
  7 + EventCreateService.new
  8 + end
  9 +
6 10 def log_info message
7 11 Gitlab::AppLogger.info message
8 12 end
... ...
app/observers/issue_observer.rb
1 1 class IssueObserver < BaseObserver
2 2 def after_create(issue)
3 3 notification.new_issue(issue, current_user)
  4 + event_service.open_issue(issue, current_user)
4 5 issue.create_cross_references!(issue.project, current_user)
5 6 execute_hooks(issue)
6 7 end
7 8  
8 9 def after_close(issue, transition)
9 10 notification.close_issue(issue, current_user)
  11 + event_service.close_issue(issue, current_user)
10 12 create_note(issue)
11 13 execute_hooks(issue)
12 14 end
13 15  
14 16 def after_reopen(issue, transition)
  17 + event_service.reopen_issue(issue, current_user)
15 18 create_note(issue)
16 19 execute_hooks(issue)
17 20 end
... ...
app/observers/merge_request_observer.rb
1   -class MergeRequestObserver < ActivityObserver
2   - observe :merge_request
3   -
  1 +class MergeRequestObserver < BaseObserver
4 2 def after_create(merge_request)
5   - if merge_request.author_id
6   - create_event(merge_request, Event.determine_action(merge_request))
7   - end
8   -
  3 + event_service.open_mr(merge_request, current_user)
9 4 notification.new_merge_request(merge_request, current_user)
10 5 merge_request.create_cross_references!(merge_request.project, current_user)
11 6 execute_hooks(merge_request)
12 7 end
13 8  
14 9 def after_close(merge_request, transition)
15   - create_event(merge_request, Event::CLOSED)
  10 + event_service.close_mr(merge_request, current_user)
16 11 notification.close_mr(merge_request, current_user)
17 12 create_note(merge_request)
18 13 execute_hooks(merge_request)
19 14 end
20 15  
21 16 def after_reopen(merge_request, transition)
22   - create_event(merge_request, Event::REOPENED)
  17 + event_service.reopen_mr(merge_request, current_user)
23 18 create_note(merge_request)
24 19 execute_hooks(merge_request)
25 20 merge_request.reload_code
... ... @@ -33,16 +28,6 @@ class MergeRequestObserver &lt; ActivityObserver
33 28 execute_hooks(merge_request)
34 29 end
35 30  
36   - def create_event(record, status)
37   - Event.create(
38   - project: record.target_project,
39   - target_id: record.id,
40   - target_type: record.class.name,
41   - action: status,
42   - author_id: current_user.id
43   - )
44   - end
45   -
46 31 private
47 32  
48 33 # Create merge request note with service comment like 'Status changed to closed'
... ...
app/observers/milestone_observer.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class MilestoneObserver < BaseObserver
  2 + def after_create(milestone)
  3 + event_service.open_milestone(milestone, current_user)
  4 + end
  5 +
  6 + def after_close(milestone, transition)
  7 + event_service.close_milestone(milestone, current_user)
  8 + end
  9 +
  10 + def after_reopen(milestone, transition)
  11 + event_service.reopen_milestone(milestone, current_user)
  12 + end
  13 +end
... ...
app/observers/note_observer.rb
... ... @@ -2,6 +2,12 @@ class NoteObserver &lt; BaseObserver
2 2 def after_create(note)
3 3 notification.new_note(note)
4 4  
  5 + # Skip system notes, like status changes and cross-references.
  6 + # Skip wall notes to prevent spamming of dashboard
  7 + if note.noteable_type.present? && !note.system
  8 + event_service.leave_note(note, current_user)
  9 + end
  10 +
5 11 unless note.system?
6 12 # Create a cross-reference note if this Note contains GFM that names an
7 13 # issue, merge request, or commit.
... ...
app/services/event_create_service.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +# EventCreateService class
  2 +#
  3 +# Used for creating events feed on dashboard after certain user action
  4 +#
  5 +# Ex.
  6 +# EventCreateService.new.new_issue(issue, current_user)
  7 +#
  8 +class EventCreateService
  9 + def open_issue(issue, current_user)
  10 + create_event(issue, current_user, Event::CREATED)
  11 + end
  12 +
  13 + def close_issue(issue, current_user)
  14 + create_event(issue, current_user, Event::CLOSED)
  15 + end
  16 +
  17 + def reopen_issue(issue, current_user)
  18 + create_event(issue, current_user, Event::REOPENED)
  19 + end
  20 +
  21 + def open_mr(merge_request, current_user)
  22 + create_event(merge_request, current_user, Event::CREATED)
  23 + end
  24 +
  25 + def close_mr(merge_request, current_user)
  26 + create_event(merge_request, current_user, Event::CLOSED)
  27 + end
  28 +
  29 + def reopen_mr(merge_request, current_user)
  30 + create_event(merge_request, current_user, Event::REOPENED)
  31 + end
  32 +
  33 + def merge_mr(merge_request, current_user)
  34 + create_event(merge_request, current_user, Event::MERGED)
  35 + end
  36 +
  37 + def open_milestone(milestone, current_user)
  38 + create_event(milestone, current_user, Event::CREATED)
  39 + end
  40 +
  41 + def close_milestone(milestone, current_user)
  42 + create_event(milestone, current_user, Event::CLOSED)
  43 + end
  44 +
  45 + def reopen_milestone(milestone, current_user)
  46 + create_event(milestone, current_user, Event::REOPENED)
  47 + end
  48 +
  49 + def leave_note(note, current_user)
  50 + create_event(note, current_user, Event::COMMENTED)
  51 + end
  52 +
  53 + private
  54 +
  55 + def create_event(record, current_user, status)
  56 + Event.create(
  57 + project: record.project,
  58 + target_id: record.id,
  59 + target_type: record.class.name,
  60 + action: status,
  61 + author_id: current_user.id
  62 + )
  63 + end
  64 +end
... ...
app/services/merge_requests/auto_merge_service.rb
... ... @@ -9,11 +9,10 @@ module MergeRequests
9 9 merge_request.lock
10 10  
11 11 if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
12   - merge_request.author_id_of_changes = current_user.id
13 12 merge_request.merge
14 13  
15   - notification.merge_mr(merge_request)
16   - create_merge_event(merge_request)
  14 + notification.merge_mr(merge_request, current_user)
  15 + create_merge_event(merge_request, current_user)
17 16 execute_project_hooks(merge_request)
18 17  
19 18 true
... ...
app/services/merge_requests/base_merge_service.rb
... ... @@ -7,14 +7,8 @@ module MergeRequests
7 7 NotificationService.new
8 8 end
9 9  
10   - def create_merge_event(merge_request)
11   - Event.create(
12   - project: merge_request.target_project,
13   - target_id: merge_request.id,
14   - target_type: merge_request.class.name,
15   - action: Event::MERGED,
16   - author_id: merge_request.author_id_of_changes
17   - )
  10 + def create_merge_event(merge_request, current_user)
  11 + EventCreateService.new.merge_mr(merge_request, current_user)
18 12 end
19 13  
20 14 def execute_project_hooks(merge_request)
... ...
app/services/merge_requests/merge_service.rb
... ... @@ -7,11 +7,10 @@ module MergeRequests
7 7 # to target branch
8 8 class MergeService < BaseMergeService
9 9 def execute(merge_request, current_user, commit_message)
10   - merge_request.author_id_of_changes = current_user.id
11 10 merge_request.merge
12 11  
13   - notification.merge_mr(merge_request)
14   - create_merge_event(merge_request)
  12 + notification.merge_mr(merge_request, current_user)
  13 + create_merge_event(merge_request, current_user)
15 14 execute_project_hooks(merge_request)
16 15  
17 16 true
... ...
app/services/notification_service.rb
... ... @@ -86,12 +86,12 @@ class NotificationService
86 86 # * merge_request assignee if their notification level is not Disabled
87 87 # * project team members with notification level higher then Participating
88 88 #
89   - def merge_mr(merge_request)
  89 + def merge_mr(merge_request, current_user)
90 90 recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
91 91 recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
92 92  
93 93 recipients.each do |recipient|
94   - mailer.merged_merge_request_email(recipient.id, merge_request.id)
  94 + mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
95 95 end
96 96 end
97 97  
... ... @@ -111,6 +111,7 @@ class NotificationService
111 111  
112 112 # ignore gitlab service messages
113 113 return true if note.note =~ /\A_Status changed to closed_/
  114 + return true if note.note =~ /\A_mentioned in / && note.system == true
114 115  
115 116 opts = { noteable_type: note.noteable_type, project_id: note.project_id }
116 117  
... ...
app/views/devise/sessions/_oauth_providers.html.haml
... ... @@ -2,10 +2,12 @@
2 2 - if providers.present?
3 3 %hr
4 4 %div{:'data-no-turbolink' => 'data-no-turbolink'}
5   - %span Sign in with: &nbsp;
  5 + %span Sign in with*: &nbsp;
6 6 - providers.each do |provider|
7 7 %span
8 8 - if default_providers.include?(provider)
9 9 = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
10 10 - else
11 11 = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
  12 + %br
  13 + %small * Make sure your email address is public
... ...
app/views/layouts/_head.html.haml
... ... @@ -4,7 +4,8 @@
4 4 = "#{title} | " if defined?(title)
5 5 GitLab
6 6 = favicon_link_tag 'favicon.ico'
7   - = stylesheet_link_tag "application"
  7 + = stylesheet_link_tag "application", :media => "all"
  8 + = stylesheet_link_tag "print", :media => "print"
8 9 = javascript_include_tag "application"
9 10 = csrf_meta_tags
10 11 = include_gon
... ...
app/views/layouts/_head_panel.html.haml
... ... @@ -15,10 +15,6 @@
15 15 .navbar-collapse.collapse
16 16 %ul.nav.navbar-nav
17 17 %li.hidden-sm.hidden-xs
18   - %a
19   - %div.hide.turbolink-spinner
20   - %i.icon-refresh.icon-spin
21   - %li.hidden-sm.hidden-xs
22 18 = render "layouts/search"
23 19 %li.visible-sm.visible-xs
24 20 = link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
... ...
app/views/layouts/_init_auto_complete.html.haml
1 1 :javascript
2   - GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}"
3   - GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + '/assets/emoji'}"
  2 + GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project, type: @noteable.class, type_id: params[:id])}"
4 3 GitLab.GfmAutoComplete.setup();
... ...
app/views/layouts/_public_head_panel.html.haml
... ... @@ -8,11 +8,15 @@
8 8 %span.separator
9 9 %h1.title= title
10 10  
11   - .pull-right
  11 + %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
  12 + %span.sr-only Toggle navigation
  13 + %i.icon-reorder
  14 +
  15 + .pull-right.hidden-xs
12 16 = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
13 17  
14   - %ul.nav.navbar-nav
15   - %li
16   - %a
17   - %div.hide.turbolink-spinner
18   - %i.icon-refresh.icon-spin
  18 + .navbar-collapse.collapse
  19 + %ul.nav.navbar-nav
  20 + %li.visible-xs
  21 + = link_to "Sign in", new_session_path(:user)
  22 +
... ...
app/views/layouts/public_projects.html.haml
... ... @@ -4,7 +4,7 @@
4 4 %body{class: "#{app_theme} application", :'data-page' => body_data_page}
5 5 = render "layouts/broadcast"
6 6 = render "layouts/public_head_panel", title: project_title(@project)
7   - %nav.main-nav
  7 + %nav.main-nav.navbar-collapse.collapse
8 8 .container= render 'layouts/nav/project'
9 9 .container
10 10 .content= yield
... ...
app/views/notify/repository_push_email.html.haml
... ... @@ -7,7 +7,7 @@
7 7 %li
8 8 #{commit.short_id} - #{commit.title}
9 9  
10   -%h4 Diff:
  10 +%h4 Changes:
11 11 - @diffs.each do |diff|
12 12 %li
13 13 %strong
... ... @@ -23,6 +23,6 @@
23 23 %br
24 24  
25 25 - if @compare.timeout
26   - %h5 Huge diff. To prevent performance issues it was hidden
  26 + %h5 To prevent performance issues changes are hidden
27 27 - elsif @compare.commits_over_limit?
28   - %h5 Diff for big amount of commits is disabled
  28 + %h5 Changes are not shown due to large amount of commits
... ...
app/views/notify/repository_push_email.text.haml
... ... @@ -6,7 +6,7 @@ Commits:
6 6 #{commit.short_id} - #{truncate(commit.title, length: 40)}
7 7 \
8 8 \
9   -Diff:
  9 +Changes:
10 10 - @diffs.each do |diff|
11 11 \
12 12 \=====================================
... ... @@ -22,4 +22,4 @@ Diff:
22 22 - if @compare.timeout
23 23 Huge diff. To prevent performance issues it was hidden
24 24 - elsif @compare.commits_over_limit?
25   - Diff for big amount of commits is disabled
  25 + Changes are not shown due to large amount of commits
... ...
app/views/projects/commits/_parallel_view.html.haml
1 1 / Side-by-side diff view
2   -- old_file = get_old_file(project, @commit, diff)
3   -- deleted_lines = {}
4   -- added_lines = {}
5   -- each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
6   - - if type == "old"
7   - - deleted_lines[line_old] = { line_code: line_code, type: type, line: line }
8   - - elsif type == "new"
9   - - added_lines[line_new] = { line_code: line_code, type: type, line: line }
10   -
11   -- max_length = old_file.sloc + added_lines.length if old_file
12   -- max_length ||= file.sloc
13   -- offset1 = 0
14   -- offset2 = 0
  2 +- old_lines, new_lines = parallel_diff_lines(project, @commit, diff, file)
  3 +- num_lines = old_lines.length
15 4  
16 5 %div.text-file-parallel
17   - %table{ style: "table-layout: fixed;" }
18   - - max_length.times do |line_index|
19   - - line_index1 = line_index - offset1
20   - - line_index2 = line_index - offset2
21   - - deleted_line = deleted_lines[line_index1 + 1]
22   - - added_line = added_lines[line_index2 + 1]
23   - - old_line = old_file.lines[line_index1] if old_file
24   - - new_line = file.lines[line_index2]
  6 + %div.diff-side.diff-side-left
  7 + %table
  8 + - old_lines.each do |line|
  9 +
  10 + %tr.line_holder.parallel
  11 + - if line.type == :file_created
  12 + %td.line_content.parallel= "File was created"
  13 + - elsif line.type == :deleted
  14 + %td.line_content{class: "parallel noteable_line old #{line.code}", "line_code" => line.code }= line.content
  15 + - else line.type == :no_change
  16 + %td.line_content.parallel= line.content
  17 +
  18 + %div.diff-middle
  19 + %table
  20 + - num_lines.times do |index|
  21 + %tr
  22 + - if old_lines[index].type == :deleted
  23 + %td.old_line.old= old_lines[index].num
  24 + - else
  25 + %td.old_line= old_lines[index].num
  26 +
  27 + %td.diff_line=""
25 28  
26   - - if deleted_line && added_line
27   - - elsif deleted_line
28   - - new_line = nil
29   - - offset2 += 1
30   - - elsif added_line
31   - - old_line = nil
32   - - offset1 += 1
  29 + - if new_lines[index].type == :added
  30 + %td.new_line.new= new_lines[index].num
  31 + - else
  32 + %td.new_line= new_lines[index].num
33 33  
34   - %tr.line_holder.parallel
35   - - if line_index == 0 && diff.new_file
36   - %td.line_content.parallel= "File was created"
37   - %td.old_line= ""
38   - - elsif deleted_line
39   - %td.line_content{class: "parallel noteable_line old #{deleted_line[:line_code]}", "line_code" => deleted_line[:line_code] }= old_line
40   - %td.old_line.old
41   - = line_index1 + 1
42   - - if @comments_allowed
43   - =# render "projects/notes/diff_note_link", line_code: deleted_line[:line_code]
44   - - elsif old_line
45   - %td.line_content.parallel= old_line
46   - %td.old_line= line_index1 + 1
47   - - else
48   - %td.line_content.parallel= ""
49   - %td.old_line= ""
  34 + %div.diff-side.diff-side-right
  35 + %table
  36 + - new_lines.each do |line|
50 37  
51   - %td.diff_line= ""
  38 + %tr.line_holder.parallel
  39 + - if line.type == :file_deleted
  40 + %td.line_content.parallel= "File was deleted"
  41 + - elsif line.type == :added
  42 + %td.line_content{class: "parallel noteable_line new #{line.code}", "line_code" => line.code }= line.content
  43 + - else line.type == :no_change
  44 + %td.line_content.parallel= line.content
52 45  
53   - - if diff.deleted_file && line_index == 0
54   - %td.new_line= ""
55   - %td.line_content.parallel= "File was deleted"
56   - - elsif added_line
57   - %td.new_line.new
58   - = line_index2 + 1
59   - - if @comments_allowed
60   - =# render "projects/notes/diff_note_link", line_code: added_line[:line_code]
61   - %td.line_content{class: "parallel noteable_line new #{added_line[:line_code]}", "line_code" => added_line[:line_code] }= new_line
62   - - elsif new_line
63   - %td.new_line= line_index2 + 1
64   - %td.line_content.parallel= new_line
65   - - else
66   - %td.new_line= ""
67   - %td.line_content.parallel= ""
  46 +:javascript
  47 + $('.diff-side-right').on('scroll', function(){
  48 + $('.diff-side-left, .diff-middle').scrollTop($(this).scrollTop());
  49 + $('.diff-side-left').scrollLeft($(this).scrollLeft());
  50 + });
68 51  
69   - - if @reply_allowed
70   - - comments1 = []
71   - - comments2 = []
72   - - comments1 = @line_notes.select { |n| n.line_code == deleted_line[:line_code] }.sort_by(&:created_at) if deleted_line
73   - - comments2 = @line_notes.select { |n| n.line_code == added_line[:line_code] }.sort_by(&:created_at) if added_line
74   - - unless comments1.empty? && comments2.empty?
75   - = render "projects/notes/diff_notes_with_reply_parallel", notes1: comments1, notes2: comments2, line1: deleted_line, line2: added_line
76 52 \ No newline at end of file
  53 + $('.diff-side-left').on('scroll', function(){
  54 + $('.diff-side-right, .diff-middle').scrollTop($(this).scrollTop()); // might never be relevant
  55 + $('.diff-side-right').scrollLeft($(this).scrollLeft());
  56 + });
... ...
app/views/projects/commits/_text_file.html.haml
1 1 - too_big = diff.diff.lines.count > 1000
2 2 - if too_big
3   - %a.supp_diff_link Diff suppressed. Click to show
  3 + %a.supp_diff_link Changes suppressed. Click to show
4 4  
5 5 %table.text-file{class: "#{'hide' if too_big}"}
6 6 - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old, raw_line|
... ...
app/views/projects/compare/show.html.haml
... ... @@ -18,17 +18,17 @@
18 18 - else
19 19 %ul.well-list= render Commit.decorate(@commits), project: @project
20 20  
21   - %h4 Diff
  21 + %h4 Changes
22 22 - if @diffs.present?
23 23 = render "projects/commits/diffs", diffs: @diffs, project: @project
24 24 - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
25 25 .bs-callout.bs-callout-danger
26 26 %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
27   - %p To preserve performance the line diff is not shown.
  27 + %p To preserve performance the line changes are not shown.
28 28 - elsif @timeout
29 29 .bs-callout.bs-callout-danger
30   - %h4 Diff for this comparison is extremely large.
31   - %p Use command line to browse diff for this comparison.
  30 + %h4 Number of changed files for this comparison is extremely large.
  31 + %p Use command line to browse through changes for this comparison.
32 32  
33 33  
34 34 - else
... ...
app/views/projects/deploy_keys/show.html.haml
... ... @@ -2,7 +2,7 @@
2 2 Deploy key:
3 3 = @key.title
4 4 %small
5   - created at
  5 + created on
6 6 = @key.created_at.stamp("Aug 21, 2011")
7 7 .back-link
8 8 = link_to project_deploy_keys_path(@project) do
... ...
app/views/projects/issues/_form.html.haml
1 1 %div.issue-form-holder
2 2 %h3.page-title= @issue.new_record? ? "New Issue" : "Edit Issue ##{@issue.iid}"
3 3 %hr
4   - - if @repository.contribution_guide && !@issue.persisted?
  4 + - if !@repository.empty? && @repository.contribution_guide && !@issue.persisted?
5 5 - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
6 6 .alert.alert-info.col-sm-10.col-sm-offset-2
7 7 ="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
... ...
app/views/projects/merge_requests/_form.html.haml
1   -- if @repository.contribution_guide && !@merge_request.persisted?
2   - - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
3   - .alert.alert-info.col-sm-10.col-sm-offset-2
4   - ="Please review the <strong>#{link_to "guidelines for contribution", contribution_guide_url}</strong> to this repository.".html_safe
5 1 = form_for [@project, @merge_request], html: { class: "merge-request-form form-horizontal" } do |f|
6   - -if @merge_request.errors.any?
7   - .alert.alert-danger
8   - %ul
9   - - @merge_request.errors.full_messages.each do |msg|
10   - %li= msg
  2 + .row
  3 + .col-sm-2
  4 + .col-sm-10
  5 + - if @repository.contribution_guide && !@merge_request.persisted?
  6 + - contribution_guide_url = project_blob_path(@project, tree_join(@repository.root_ref, @repository.contribution_guide.name))
  7 + .alert.alert-info
  8 + Please review the
  9 + %strong #{link_to "guidelines for contribution", contribution_guide_url}
  10 + to this repository.
  11 +
  12 + -if @merge_request.errors.any?
  13 + .alert.alert-danger
  14 + - @merge_request.errors.full_messages.each do |msg|
  15 + %div= msg
11 16  
12 17 .merge-request-branches
13 18 .form-group
... ... @@ -47,24 +52,6 @@
47 52 = f.text_area :description, class: "form-control js-gfm-input", rows: 14
48 53 %p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
49 54  
50   - %hr
51   - .form-group
52   - .merge-request-assignee
53   - = f.label :assignee_id, class: 'control-label' do
54   - %i.icon-user
55   - Assign to
56   - .col-sm-10
57   - = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
58   - &nbsp;
59   - = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
60   - .form-group
61   - .merge-request-milestone
62   - = f.label :milestone_id, class: 'control-label' do
63   - %i.icon-time
64   - Milestone
65   - .col-sm-10= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
66   -
67   -
68 55 .form-actions
69 56 - if @merge_request.new_record?
70 57 = f.submit 'Submit merge request', class: "btn btn-create"
... ... @@ -96,7 +83,3 @@
96 83 target_branch.on("change", function() {
97 84 $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
98 85 });
99   - $('.assign-to-me-link').on('click', function(e){
100   - $('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
101   - e.preventDefault();
102   - });
... ...
app/views/projects/merge_requests/_show.html.haml
... ... @@ -20,7 +20,7 @@
20 20 %li.diffs-tab{data: {action: 'diffs'}}
21 21 = link_to diffs_project_merge_request_path(@project, @merge_request) do
22 22 %i.icon-list-alt
23   - Diff
  23 + Changes
24 24  
25 25 - content_for :note_actions do
26 26 - if can?(current_user, :modify_merge_request, @merge_request)
... ...
app/views/projects/merge_requests/branch_from.js.haml
... ... @@ -3,5 +3,5 @@
3 3 var mrTitle = $('#merge_request_title');
4 4  
5 5 if(mrTitle.val().length == 0) {
6   - mrTitle.val("#{params[:ref].titleize}");
  6 + mrTitle.val("#{params[:ref].humanize}");
7 7 }
... ...
app/views/projects/merge_requests/show/_diffs.html.haml
... ... @@ -5,7 +5,7 @@
5 5 - else
6 6 .bs-callout.bs-callout-warning
7 7 %h4
8   - Diff for this comparison is extremely large.
  8 + Changes view for this comparison is extremely large.
9 9 %p
10 10 You can
11 11 = link_to "download it", project_merge_request_path(@merge_request.source_project, @merge_request, format: :diff), class: "vlink"
... ...
app/views/projects/merge_requests/show/_mr_accept.html.haml
1 1 - unless @allowed_to_merge
2   - .bs-callout
3   - %strong You don't have permission to merge this MR
  2 + - if @project.archived?
  3 + .bs-callout.bs-callout-warning
  4 + %strong Archived projects cannot be committed to!
  5 + - else
  6 + .bs-callout
  7 + .automerge_widget.cannot_be_merged.hide
  8 + %strong This can't be merged automatically, even if it could be merged you don't have the permission to do so.
  9 + .automerge_widget.can_be_merged.hide
  10 + %strong This can be merged automatically but you don't have the permission to do so.
4 11  
5 12  
6 13 - if @show_merge_controls
... ...
app/views/projects/merge_requests/show/_mr_box.html.haml
... ... @@ -29,13 +29,13 @@
29 29 %span
30 30 %i.icon-remove
31 31 Closed by #{link_to_member(@project, @merge_request.closed_event.author)}
32   - #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}.
  32 + #{time_ago_with_tooltip(@merge_request.closed_event.created_at)}
33 33 - if @merge_request.merged?
34 34 .alert.alert-info
35 35 %span
36 36 %i.icon-ok
37 37 Merged by #{link_to_member(@project, @merge_request.merge_event.author)}
38   - #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}.
  38 + #{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
39 39 - if !@closes_issues.empty? && @merge_request.open?
40 40 .alert.alert-info.alert-info
41 41 %span
... ...
app/views/projects/notes/_note.html.haml
... ... @@ -23,7 +23,7 @@
23 23 %i.icon-thumbs-up
24 24 \+1
25 25 - if note.downvote?
26   - %span.vote.downvote.label.label-error
  26 + %span.vote.downvote.label.label-danger
27 27 %i.icon-thumbs-down
28 28 \-1
29 29  
... ...
app/views/projects/show.html.haml
... ... @@ -9,8 +9,8 @@
9 9 .col-md-3.project-side.hidden-sm
10 10 .clearfix
11 11 - if @project.archived?
12   - .alert
13   - %h5
  12 + .alert.alert-warning
  13 + %h4
14 14 %i.icon-warning-sign
15 15 Archived project!
16 16 %p Repository is read-only
... ...
config/application.rb
... ... @@ -19,7 +19,7 @@ module Gitlab
19 19 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
20 20  
21 21 # Activate observers that should always be running.
22   - config.active_record.observers = :activity_observer,
  22 + config.active_record.observers = :milestone_observer,
23 23 :project_activity_cache_observer,
24 24 :issue_observer,
25 25 :key_observer,
... ...
config/environments/production.rb
... ... @@ -33,6 +33,12 @@ Gitlab::Application.configure do
33 33 # See everything in the log (default is :info)
34 34 # config.log_level = :debug
35 35  
  36 + # Suppress 'Rendered template ...' messages in the log
  37 + # source: http://stackoverflow.com/a/16369363
  38 + %w{render_template render_partial render_collection}.each do |event|
  39 + ActiveSupport::Notifications.unsubscribe "#{event}.action_view"
  40 + end
  41 +
36 42 # Prepend all log lines with the following tags
37 43 # config.log_tags = [ :subdomain, :uuid ]
38 44  
... ...
config/initializers/gemoji.rb
... ... @@ -1,3 +0,0 @@
1   -# Workaround for https://github.com/github/gemoji/pull/18
2   -require 'gemoji'
3   -Gitlab::Application.config.assets.paths << Emoji.images_path
config/routes.rb
... ... @@ -167,7 +167,7 @@ Gitlab::Application.routes.draw do
167 167  
168 168 resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
169 169  
170   - devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations }
  170 + devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords}
171 171  
172 172 #
173 173 # Project Area
... ...
config/unicorn_development.rb 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +worker_processes 2
  2 +timeout 30
... ...
db/fixtures/development/11_keys.rb
... ... @@ -2,7 +2,7 @@ Gitlab::Seeder.quiet do
2 2 User.first(30).each_with_index do |user, i|
3 3 Key.seed(:id, [
4 4 {
5   - id: i,
  5 + id: i + 1,
6 6 title: "Sample key #{i}",
7 7 key: "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt#{i + 100}6k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
8 8 user_id: user.id,
... ...
doc/README.md 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +## The GitLab Documentation covers the following subjects
  2 +
  3 ++ [API](api/README.md)
  4 ++ [Development](development/README.md)
  5 ++ [Install](install/README.md)
  6 ++ [Integration](external-issue-tracker/README.md)
  7 ++ [Legal](legal/README.md)
  8 ++ [Markdown](markdown/markdown.md)
  9 ++ [Permissions](permissions/permissions.md)
  10 ++ [Public access](public_access/public_access.md)
  11 ++ [Raketasks](raketasks/README.md)
  12 ++ [Release](release/README.md)
  13 ++ [Security](security/README.md)
  14 ++ [System hooks](system_hooks/system_hooks.md)
  15 ++ [Update](update/README.md)
  16 ++ [Web hooks](web_hooks/web_hooks.md)
  17 ++ [Workflow](workflow/workflow.md)
... ...
doc/api/README.md
1 1 # GitLab API
2 2  
  3 +## End-points
  4 +
  5 ++ [Users](users.md)
  6 ++ [Session](session.md)
  7 ++ [Projects](projects.md)
  8 ++ [Project Snippets](project_snippets.md)
  9 ++ [Repositories](repositories.md)
  10 ++ [Repository Files](repository_files.md)
  11 ++ [Commits](commits.md)
  12 ++ [Merge Requests](merge_requests.md)
  13 ++ [Issues](issues.md)
  14 ++ [Milestones](milestones.md)
  15 ++ [Notes](notes.md)
  16 ++ [Deploy Keys](deploy_keys.md)
  17 ++ [System Hooks](system_hooks.md)
  18 ++ [Groups](groups.md)
  19 +
  20 +## Clients
  21 +
  22 ++ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
  23 ++ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
  24 ++ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
  25 ++ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
  26 +
  27 +## Introduction
  28 +
3 29 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.
4 30  
5 31 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 143  
118 144 So if you want to get issue with api you use `http://host/api/v3/.../issues/:id.json`
119 145 But when you want to create a link to web page - use `http:://host/project/issues/:iid.json`
120   -
121   -
122   -
123   -## Contents
124   -
125   -+ [Users](users.md)
126   -+ [Session](session.md)
127   -+ [Projects](projects.md)
128   -+ [Project Snippets](project_snippets.md)
129   -+ [Repositories](repositories.md)
130   -+ [Repository Files](repository_files.md)
131   -+ [Commits](commits.md)
132   -+ [Merge Requests](merge_requests.md)
133   -+ [Issues](issues.md)
134   -+ [Milestones](milestones.md)
135   -+ [Notes](notes.md)
136   -+ [Deploy Keys](deploy_keys.md)
137   -+ [System Hooks](system_hooks.md)
138   -+ [Groups](groups.md)
139   -
140   -
141   -## Clients
142   -
143   -+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
144   -+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
145   -+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
146   -+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
... ...
doc/api/merge_requests.md
... ... @@ -150,6 +150,7 @@ Parameters:
150 150 + `target_branch` - The target branch
151 151 + `assignee_id` - Assignee user ID
152 152 + `title` - Title of MR
  153 ++ `state_event` - New state (close|reopen|merge)
153 154  
154 155 ```json
155 156  
... ... @@ -210,3 +211,44 @@ Parameters:
210 211 "note":"text1"
211 212 }
212 213 ```
  214 +
  215 +
  216 +## Get the comments on a MR
  217 +
  218 +Gets all the comments associated with a merge request.
  219 +
  220 +```
  221 +GET /projects/:id/merge_request/:merge_request_id/comments
  222 +```
  223 +
  224 +Parameters:
  225 +
  226 ++ `id` (required) - The ID of a project
  227 ++ `merge_request_id` (required) - ID of merge request
  228 +
  229 +```json
  230 +[
  231 + {
  232 + "note":"this is the 1st comment on the 2merge merge request",
  233 + "author":{
  234 + "id":11,
  235 + "username":"admin",
  236 + "email":"admin@local.host",
  237 + "name":"Administrator",
  238 + "state":"active",
  239 + "created_at":"2014-03-06T08:17:35.000Z"
  240 + }
  241 + },
  242 + {
  243 + "note":"_Status changed to closed_",
  244 + "author":{
  245 + "id":11,
  246 + "username":"admin",
  247 + "email":"admin@local.host",
  248 + "name":"Administrator",
  249 + "state":"active",
  250 + "created_at":"2014-03-06T08:17:35.000Z"
  251 + }
  252 + }
  253 +]
  254 +```
... ...
doc/api/projects.md
... ... @@ -621,3 +621,29 @@ Parameters:
621 621 + query (required) - A string contained in the project name
622 622 + per_page (optional) - number of projects to return per page
623 623 + page (optional) - the page to retrieve
  624 +
  625 +
  626 +## Labels
  627 +
  628 +### List project labels
  629 +
  630 +Get a list of project labels.
  631 +
  632 +```
  633 +GET /projects/:id/labels
  634 +```
  635 +
  636 +Parameters:
  637 +
  638 ++ `id` (required) - The ID or NAMESPACE/PROJECT_NAME of a project
  639 +
  640 +```json
  641 +[
  642 + {
  643 + "name":"featute"
  644 + },
  645 + {
  646 + "name": "bug"
  647 + }
  648 +]
  649 +```
... ...
doc/api/system_hooks.md
1   -All methods require admin authorization.
2   -
3   -The url endpoint of the system hooks can be configured in [the admin area under hooks](/admin/hooks).
4   -
5   -## List system hooks
6   -
7   -Get list of system hooks
8   -
9   -```
10   -GET /hooks
11   -```
12   -
13   -Parameters:
14   -
15   -+ **none**
16   -
17   -```json
18   -[
19   - {
20   - "id":3,
21   - "url":"http://example.com/hook",
22   - "created_at":"2013-10-02T10:15:31Z"
23   - }
24   -]
25   -```
26   -
27   -## Add new system hook hook
28   -
29   -```
30   -POST /hooks
31   -```
32   -
33   -Parameters:
34   -
35   -+ `url` (required) - The hook URL
36   -
37   -
38   -## Test system hook
39   -
40   -```
41   -GET /hooks/:id
42   -```
43   -
44   -Parameters:
45   -
46   -+ `id` (required) - The ID of hook
47   -
48   -```json
49   -{
50   - "event_name":"project_create",
51   - "name":"Ruby",
52   - "path":"ruby",
53   - "project_id":1,
54   - "owner_name":"Someone",
55   - "owner_email":"example@gitlabhq.com"
56   -}
57   -```
58   -
59   -## Delete system hook
60   -
61   -Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook
62   -is not available. If the hook is deleted it is also returned as JSON.
63   -
64   -```
65   -DELETE /hooks/:id
66   -```
67   -
68   -Parameters:
69   -
70   -+ `id` (required) - The ID of hook
  1 +All methods require admin authorization.
  2 +
  3 +The url endpoint of the system hooks can be configured in [the admin area under hooks](/admin/hooks).
  4 +
  5 +## List system hooks
  6 +
  7 +Get list of system hooks
  8 +
  9 +```
  10 +GET /hooks
  11 +```
  12 +
  13 +Parameters:
  14 +
  15 ++ **none**
  16 +
  17 +```json
  18 +[
  19 + {
  20 + "id":3,
  21 + "url":"http://example.com/hook",
  22 + "created_at":"2013-10-02T10:15:31Z"
  23 + }
  24 +]
  25 +```
  26 +
  27 +## Add new system hook hook
  28 +
  29 +```
  30 +POST /hooks
  31 +```
  32 +
  33 +Parameters:
  34 +
  35 ++ `url` (required) - The hook URL
  36 +
  37 +
  38 +## Test system hook
  39 +
  40 +```
  41 +GET /hooks/:id
  42 +```
  43 +
  44 +Parameters:
  45 +
  46 ++ `id` (required) - The ID of hook
  47 +
  48 +```json
  49 +{
  50 + "event_name":"project_create",
  51 + "name":"Ruby",
  52 + "path":"ruby",
  53 + "project_id":1,
  54 + "owner_name":"Someone",
  55 + "owner_email":"example@gitlabhq.com"
  56 +}
  57 +```
  58 +
  59 +## Delete system hook
  60 +
  61 +Deletes a system hook. This is an idempotent API function and returns `200 Ok` even if the hook
  62 +is not available. If the hook is deleted it is also returned as JSON.
  63 +
  64 +```
  65 +DELETE /hooks/:id
  66 +```
  67 +
  68 +Parameters:
  69 +
  70 ++ `id` (required) - The ID of hook
... ...
doc/development/README.md 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 ++ [Architecture](architecture.md)
  2 ++ [Shell commands](shell_commands.md)
... ...
doc/development/architecture.md
... ... @@ -18,7 +18,7 @@ New releases are generally around the same time as GitLab CE releases with excep
18 18  
19 19 # System Layout
20 20  
21   -When referring to ~git in the picures it means the home directory of the git user which is typically /home/git.
  21 +When referring to ~git in the pictures it means the home directory of the git user which is typically /home/git.
22 22  
23 23 GitLab is primarily installed within the `/home/git` user home directory as `git` user.
24 24 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&#39;s an add-on application called gitlab-shell
28 28  
29 29 ## Components
30 30  
31   -![GitLab Diagram Overview](resources/gitlab_diagram_overview.png "GitLab Diagram Overview")
  31 +![GitLab Diagram Overview](resources/gitlab_diagram_overview.png)
32 32  
33 33 A typical install of GitLab will be on Ubuntu Linux or RHEL/CentOS.
34 34 It uses Nginx or Apache as a web front end to proxypass the Unicorn web server.
... ... @@ -180,4 +180,4 @@ bundle exec rake gitlab:check RAILS_ENV=production
180 180 ```
181 181  
182 182 Note: It is recommended to log into the `git` user using `sudo -i -u git` or `sudo su - git`.
183 183 -While the sudo commands provided by gitlabhq work in Ubuntu they do not always work in RHEL.
  184 +While the sudo commands provided by gitlabhq work in Ubuntu they do not always work in RHEL.
184 185 \ No newline at end of file
... ...
doc/development/shell_commands.md
1 1 # Guidelines for shell commands in the GitLab codebase
2 2  
  3 +## References
  4 +
  5 +- [Google Ruby Security Reviewer's Guide](https://code.google.com/p/ruby-security/wiki/Guide)
  6 +- [OWASP Command Injection](https://www.owasp.org/index.php/Command_Injection)
  7 +- [Ruby on Rails Security Guide Command Line Injection](http://guides.rubyonrails.org/security.html#command-line-injection)
  8 +
3 9 ## Use File and FileUtils instead of shell commands
4 10  
5 11 Sometimes we invoke basic Unix commands via the shell when there is also a Ruby API for doing it.
... ...
doc/install/README.md 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 ++ [Installation](installation.md)
  2 ++ [Requirements](requirements.md)
  3 ++ [Structure](structure.md)
  4 ++ [Database MySQL](database_mysql.md)
... ...
doc/install/database_mysql.md
... ... @@ -6,6 +6,9 @@ We do not recommend using MySQL due to various issues. For example, case [(in)se
6 6  
7 7 # Install the database packages
8 8 sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
  9 +
  10 + # Ensure you have MySQL version 5.5.14 or later
  11 + mysql --version
9 12  
10 13 # Pick a database root password (can be anything), type it and press enter
11 14 # 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 26 # change $password in the command below to a real password you pick
24 27 mysql> CREATE USER 'git'@'localhost' IDENTIFIED BY '$password';
25 28  
  29 + # Ensure you can use the InnoDB engine which is necessary to support long indexes.
  30 + # If this fails, check your MySQL config files (e.g. `/etc/mysql/*.cnf`, `/etc/mysql/conf.d/*`) for the setting "innodb = off"
  31 + mysql> SET storage_engine=INNODB;
  32 +
26 33 # Create the GitLab production database
27 34 mysql> CREATE DATABASE IF NOT EXISTS `gitlabhq_production` DEFAULT CHARACTER SET `utf8` COLLATE `utf8_unicode_ci`;
28 35  
... ...
doc/install/installation.md
... ... @@ -128,7 +128,7 @@ GitLab Shell is an ssh access and repository management software developed speci
128 128 cd /home/git
129 129  
130 130 # Clone gitlab shell
131   - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-shell.git -b v1.8.0
  131 + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-shell.git -b v1.9.1
132 132  
133 133 cd gitlab-shell
134 134  
... ... @@ -173,7 +173,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
173 173 ## Clone the Source
174 174  
175 175 # Clone GitLab repository
176   - sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 6-6-stable gitlab
  176 + sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-ce.git -b 6-7-stable gitlab
177 177  
178 178 # Go to gitlab dir
179 179 cd /home/git/gitlab
... ...
doc/integration/external-issue-tracker.md
... ... @@ -5,3 +5,5 @@ GitLab has a great issue tracker but you can also use an external issue tracker
5 5 - textual references to PROJECT-1234 in comments, commit messages get turned into HTML links to the corresponding JIRA issue.
6 6  
7 7 ![jira screenshot](jira-intergration-points.png)
  8 +
  9 +You can configure the integration in the gitlab.yml configuration file.
... ...
doc/legal/README.md 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 ++ [Corporate contributor license agreement](corporate_contributor_license_agreement.md)
  2 ++ [Individual contributor license agreement](individual_contributor_license_agreement.md)
... ...
doc/permissions/permissions.md
... ... @@ -38,7 +38,7 @@ If a user is a GitLab administrator they receive all permissions.
38 38 |------|-----|--------|---------|------|-----|
39 39 |Browse group|✓|✓|✓|✓|✓|
40 40 |Edit group|||||✓|
41   -|create project in group|||||✓|
  41 +|Create project in group|||||✓|
42 42 |Manage group members|||||✓|
43 43 |Remove group|||||✓|
44 44  
... ...
doc/raketasks/README.md 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 ++ [Backup restore](backup_restore.md)
  2 ++ [Cleanup](cleanup.md)
  3 ++ [Features](features.md)
  4 ++ [Maintenance](maintenance.md)
  5 ++ [User management](user_management.md)
  6 ++ [Web hooks](web_hooks.md)
... ...
doc/release/README.md 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 ++ [Monthly](monthly.md)
  2 ++ [Security](security.md)
... ...