Commit cfc4a2dbe3652180c1d08d5d9e154e28cbb340fb
Exists in
spb-stable
and in
3 other branches
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
.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
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
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 |
... | ... | @@ -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
app/assets/stylesheets/generic/common.scss
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
... | ... | @@ -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
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
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 | } | ... | ... |
... | ... | @@ -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 < 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 < 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 < 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 < 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 < 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 < 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 < 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
app/models/event.rb
... | ... | @@ -47,14 +47,6 @@ class Event < 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 < 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 < 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 < 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 < 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 < 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 < 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 < 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? | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 < 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 < 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
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 < 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' | ... | ... |
... | ... | @@ -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 < 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. | ... | ... |
... | ... | @@ -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: | |
5 | + %span Sign in with*: | |
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
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 | - | |
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
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
app/views/projects/show.html.haml
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
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 | ... | ... |
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, | ... | ... |
... | ... | @@ -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/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's an add-on application called gitlab-shell |
28 | 28 | |
29 | 29 | ## Components |
30 | 30 | |
31 | - | |
31 | + | |
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/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 |  |
8 | + | |
9 | +You can configure the integration in the gitlab.yml configuration file. | ... | ... |
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 | ... | ... |