Commit b2e74741555f9cb9d58c3c44810803d0db39b9f3

Authored by dosire
2 parents 775f686e 7f67e066

Merge branch 'master' into define-feature-request

Conflicts:
	PROCESS.md
Showing 363 changed files with 6827 additions and 5406 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 363 files displayed.

1 ---color --drb 1 +--color
@@ -9,7 +9,40 @@ v 6.7.0 @@ -9,7 +9,40 @@ v 6.7.0
9 - Show contribution guide link for new issue form (Jeroen van Baarsen) 9 - Show contribution guide link for new issue form (Jeroen van Baarsen)
10 - Fix CI status for merge requests from fork 10 - Fix CI status for merge requests from fork
11 - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard) 11 - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
  12 + - New page load indicator that includes a spinner that scrolls with the page
12 - Converted all the help sections into markdown 13 - Converted all the help sections into markdown
  14 + - LDAP user filters
  15 + - Streamline the content of notification emails (Pierre de La Morinerie)
  16 + - Fixes a bug with group member administration (Matt DeTullio)
  17 + - Sort tag names using VersionSorter (Robert Speicher)
  18 + - Add GFM autocompletion for MergeRequests (Robert Speicher)
  19 + - Add webhook when a new tag is pushed (Jeroen van Baarsen)
  20 + - Add button for toggling inline comments in diff view
  21 + - Add retry feature for repository import
  22 + - Reuse the GitLab LDAP connection within each request
  23 + - Changed markdown new line behaviour to conform to markdown standards
  24 + - Fix global search
  25 + - Faster authorized_keys rebuilding in `rake gitlab:shell:setup` (requires gitlab-shell 1.8.5)
  26 + - Create and Update MR calls now support the description parameter (Greg Messner)
  27 + - Markdown relative links in the wiki link to wiki pages, markdown relative links in repositories link to files in the repository
  28 + - Added Slack service integration (Federico Ravasio)
  29 + - Better API responses for access_levels (sponsored by O'Reilly Media)
  30 + - Requires at least 2 unicorn workers
  31 + - Requires gitlab-shell v1.9+
  32 + - 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)
  33 + - Fix `/:username.keys` response content type (Dmitry Medvinsky)
  34 +
  35 +v 6.6.5
  36 + - Added option to remove issue assignee on project issue page and issue edit page (Jason Blanchard)
  37 + - Hide mr close button for comment form if merge request was closed or inline comment
  38 + - Adds ability to reopen closed merge request
  39 +
  40 +v 6.6.4
  41 + - Add missing html escape for highlighted code blocks in comments, issues
  42 +
  43 +v 6.6.3
  44 + - Fix 500 error when edit yourself from admin area
  45 + - Hide private groups for public profiles
13 46
14 v 6.6.2 47 v 6.6.2
15 - Fix 500 error on branch/tag create or remove via UI 48 - Fix 500 error on branch/tag create or remove via UI
CONTRIBUTING.md
@@ -22,11 +22,14 @@ Issues and merge requests should be in English and contain appropriate language @@ -22,11 +22,14 @@ Issues and merge requests should be in English and contain appropriate language
22 22
23 ## Issue tracker 23 ## Issue tracker
24 24
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). 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/). 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 bugs in the latest [stable or development release of GitLab](MAINTENANCE.md).
  28 +If something is missing but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request.
  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 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. 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,7 +51,7 @@ Please send a merge request with a tested solution or a merge request with a fai
48 51
49 ## Merge requests 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 ### Merge request guidelines 56 ### Merge request guidelines
54 57
@@ -64,7 +67,7 @@ If you can, please submit a merge request with the fix or improvements including @@ -64,7 +67,7 @@ If you can, please submit a merge request with the fix or improvements including
64 1. The MR title should describes the change you want to make 67 1. The MR title should describes the change you want to make
65 1. The MR description should give a motive for your change and the method you used to achieve it 68 1. The MR description should give a motive for your change and the method you used to achieve it
66 1. If the MR changes the UI it should include before and after screenshots 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. 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 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion 71 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
69 1. If your MR touches code that executes shell commands, make sure it adheres to the [shell command guidelines]( doc/development/shell_commands.md). 72 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 73
@@ -74,6 +77,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c @@ -74,6 +77,14 @@ Please keep the change in a single MR **as small as possible**. If you want to c
74 77
75 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. 78 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 79
  80 +**Please format your merge request description as follows:**
  81 +
  82 +1. What does this MR do?
  83 +2. Are there points in the code the reviewer needs to double check?
  84 +3. Why was this MR needed?
  85 +4. What are the relevant issue numbers / [Feature requests](http://feedback.gitlab.com/)?
  86 +5. Screenshots (If appropiate)
  87 +
77 ## Contribution acceptance criteria 88 ## Contribution acceptance criteria
78 89
79 1. The change is as small as possible (see the above paragraph for details) 90 1. The change is as small as possible (see the above paragraph for details)
@@ -48,7 +48,8 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist" @@ -48,7 +48,8 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
48 48
49 # API 49 # API
50 gem "grape", "~> 0.6.1" 50 gem "grape", "~> 0.6.1"
51 -gem "grape-entity", "~> 0.3.0" 51 +# Replace with rubygems when nesteted entities get released
  52 +gem "grape-entity", "~> 0.4.1", ref: 'd904381c951e86250c3f44213b349a3dd8e83fb1', git: 'https://github.com/intridea/grape-entity.git'
52 gem 'rack-cors', require: 'rack/cors' 53 gem 'rack-cors', require: 'rack/cors'
53 54
54 # Email validation 55 # Email validation
@@ -131,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2" @@ -131,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
131 # Gemnasium integration 132 # Gemnasium integration
132 gem "gemnasium-gitlab-service", "~> 0.2" 133 gem "gemnasium-gitlab-service", "~> 0.2"
133 134
  135 +# Slack integration
  136 +gem "slack-notifier", "~> 0.2.0"
  137 +
134 # d3 138 # d3
135 gem "d3_rails", "~> 3.1.4" 139 gem "d3_rails", "~> 3.1.4"
136 140
@@ -161,8 +165,9 @@ gem "modernizr", "2.6.2" @@ -161,8 +165,9 @@ gem "modernizr", "2.6.2"
161 gem "raphael-rails", "~> 2.1.2" 165 gem "raphael-rails", "~> 2.1.2"
162 gem 'bootstrap-sass', '~> 3.0' 166 gem 'bootstrap-sass', '~> 3.0'
163 gem "font-awesome-rails", '~> 3.2' 167 gem "font-awesome-rails", '~> 3.2'
164 -gem "gemoji", "~> 1.3.0" 168 +gem "gitlab_emoji", "~> 0.0.1.1"
165 gem "gon", '~> 5.0.0' 169 gem "gon", '~> 5.0.0'
  170 +gem 'nprogress-rails'
166 171
167 group :development do 172 group :development do
168 gem "annotate", "~> 2.6.0.beta2" 173 gem "annotate", "~> 2.6.0.beta2"
@@ -213,7 +218,6 @@ group :development, :test do @@ -213,7 +218,6 @@ group :development, :test do
213 # PhantomJS driver for Capybara 218 # PhantomJS driver for Capybara
214 gem 'poltergeist', '~> 1.4.1' 219 gem 'poltergeist', '~> 1.4.1'
215 220
216 - gem 'spork', '~> 1.0rc'  
217 gem 'jasmine', '2.0.0.rc5' 221 gem 'jasmine', '2.0.0.rc5'
218 222
219 gem "spring", '1.1.1' 223 gem "spring", '1.1.1'
@@ -5,6 +5,15 @@ GIT @@ -5,6 +5,15 @@ GIT
5 specs: 5 specs:
6 github-markup (0.7.6) 6 github-markup (0.7.6)
7 7
  8 +GIT
  9 + remote: https://github.com/intridea/grape-entity.git
  10 + revision: d904381c951e86250c3f44213b349a3dd8e83fb1
  11 + ref: d904381c951e86250c3f44213b349a3dd8e83fb1
  12 + specs:
  13 + grape-entity (0.4.1)
  14 + activesupport
  15 + multi_json (>= 1.3.2)
  16 +
8 GEM 17 GEM
9 remote: https://rubygems.org/ 18 remote: https://rubygems.org/
10 specs: 19 specs:
@@ -119,6 +128,8 @@ GEM @@ -119,6 +128,8 @@ GEM
119 mail (~> 2.2) 128 mail (~> 2.2)
120 email_validator (1.4.0) 129 email_validator (1.4.0)
121 activemodel 130 activemodel
  131 + emoji (1.0.1)
  132 + json
122 enumerize (0.7.0) 133 enumerize (0.7.0)
123 activesupport (>= 3.2) 134 activesupport (>= 3.2)
124 equalizer (0.0.8) 135 equalizer (0.0.8)
@@ -156,7 +167,6 @@ GEM @@ -156,7 +167,6 @@ GEM
156 formatador (0.2.4) 167 formatador (0.2.4)
157 gemnasium-gitlab-service (0.2.1) 168 gemnasium-gitlab-service (0.2.1)
158 rugged (~> 0.19) 169 rugged (~> 0.19)
159 - gemoji (1.3.1)  
160 gherkin-ruby (0.3.1) 170 gherkin-ruby (0.3.1)
161 racc 171 racc
162 github-markdown (0.5.5) 172 github-markdown (0.5.5)
@@ -181,6 +191,8 @@ GEM @@ -181,6 +191,8 @@ GEM
181 charlock_holmes (~> 0.6.6) 191 charlock_holmes (~> 0.6.6)
182 escape_utils (~> 0.2.4) 192 escape_utils (~> 0.2.4)
183 mime-types (~> 1.19) 193 mime-types (~> 1.19)
  194 + gitlab_emoji (0.0.1.1)
  195 + emoji (~> 1.0.1)
184 gitlab_git (5.7.1) 196 gitlab_git (5.7.1)
185 activesupport (~> 4.0.0) 197 activesupport (~> 4.0.0)
186 charlock_holmes (~> 0.6.9) 198 charlock_holmes (~> 0.6.9)
@@ -206,9 +218,6 @@ GEM @@ -206,9 +218,6 @@ GEM
206 rack-accept 218 rack-accept
207 rack-mount 219 rack-mount
208 virtus (>= 1.0.0) 220 virtus (>= 1.0.0)
209 - grape-entity (0.3.0)  
210 - activesupport  
211 - multi_json (>= 1.3.2)  
212 growl (1.0.3) 221 growl (1.0.3)
213 guard (2.2.4) 222 guard (2.2.4)
214 formatador (>= 0.2.4) 223 formatador (>= 0.2.4)
@@ -235,7 +244,7 @@ GEM @@ -235,7 +244,7 @@ GEM
235 httparty 244 httparty
236 httparty 245 httparty
237 http_parser.rb (0.5.3) 246 http_parser.rb (0.5.3)
238 - httparty (0.12.0) 247 + httparty (0.13.0)
239 json (~> 1.8) 248 json (~> 1.8)
240 multi_xml (>= 0.5.2) 249 multi_xml (>= 0.5.2)
241 httpauth (0.2.0) 250 httpauth (0.2.0)
@@ -291,6 +300,7 @@ GEM @@ -291,6 +300,7 @@ GEM
291 net-ssh (>= 1.99.1) 300 net-ssh (>= 1.99.1)
292 net-ssh (2.7.0) 301 net-ssh (2.7.0)
293 nokogiri (1.5.10) 302 nokogiri (1.5.10)
  303 + nprogress-rails (0.1.2.3)
294 oauth (0.4.7) 304 oauth (0.4.7)
295 oauth2 (0.8.1) 305 oauth2 (0.8.1)
296 faraday (~> 0.8) 306 faraday (~> 0.8)
@@ -462,6 +472,7 @@ GEM @@ -462,6 +472,7 @@ GEM
462 rack-protection (~> 1.4) 472 rack-protection (~> 1.4)
463 tilt (~> 1.3, >= 1.3.4) 473 tilt (~> 1.3, >= 1.3.4)
464 six (0.2.0) 474 six (0.2.0)
  475 + slack-notifier (0.2.0)
465 slim (2.0.2) 476 slim (2.0.2)
466 temple (~> 0.6.6) 477 temple (~> 0.6.6)
467 tilt (>= 1.3.3, < 2.1) 478 tilt (>= 1.3.3, < 2.1)
@@ -473,7 +484,6 @@ GEM @@ -473,7 +484,6 @@ GEM
473 capybara (>= 2.0.0) 484 capybara (>= 2.0.0)
474 railties (>= 3) 485 railties (>= 3)
475 spinach (>= 0.4) 486 spinach (>= 0.4)
476 - spork (1.0.0rc4)  
477 spring (1.1.1) 487 spring (1.1.1)
478 spring-commands-rspec (1.0.1) 488 spring-commands-rspec (1.0.1)
479 spring (>= 0.9.1) 489 spring (>= 0.9.1)
@@ -585,18 +595,18 @@ DEPENDENCIES @@ -585,18 +595,18 @@ DEPENDENCIES
585 font-awesome-rails (~> 3.2) 595 font-awesome-rails (~> 3.2)
586 foreman 596 foreman
587 gemnasium-gitlab-service (~> 0.2) 597 gemnasium-gitlab-service (~> 0.2)
588 - gemoji (~> 1.3.0)  
589 github-markup (~> 0.7.4)! 598 github-markup (~> 0.7.4)!
590 gitlab-flowdock-git-hook (~> 0.4.2) 599 gitlab-flowdock-git-hook (~> 0.4.2)
591 gitlab-gollum-lib (~> 1.1.0) 600 gitlab-gollum-lib (~> 1.1.0)
592 gitlab-grack (~> 2.0.0.pre) 601 gitlab-grack (~> 2.0.0.pre)
593 gitlab-linguist (~> 3.0.0) 602 gitlab-linguist (~> 3.0.0)
  603 + gitlab_emoji (~> 0.0.1.1)
594 gitlab_git (~> 5.7.1) 604 gitlab_git (~> 5.7.1)
595 gitlab_meta (= 6.0) 605 gitlab_meta (= 6.0)
596 gitlab_omniauth-ldap (= 1.0.4) 606 gitlab_omniauth-ldap (= 1.0.4)
597 gon (~> 5.0.0) 607 gon (~> 5.0.0)
598 grape (~> 0.6.1) 608 grape (~> 0.6.1)
599 - grape-entity (~> 0.3.0) 609 + grape-entity (~> 0.4.1)!
600 growl 610 growl
601 guard-rspec 611 guard-rspec
602 guard-spinach 612 guard-spinach
@@ -614,6 +624,7 @@ DEPENDENCIES @@ -614,6 +624,7 @@ DEPENDENCIES
614 minitest (~> 4.7.0) 624 minitest (~> 4.7.0)
615 modernizr (= 2.6.2) 625 modernizr (= 2.6.2)
616 mysql2 626 mysql2
  627 + nprogress-rails
617 omniauth (~> 1.1.3) 628 omniauth (~> 1.1.3)
618 omniauth-github 629 omniauth-github
619 omniauth-google-oauth2 630 omniauth-google-oauth2
@@ -646,9 +657,9 @@ DEPENDENCIES @@ -646,9 +657,9 @@ DEPENDENCIES
646 simplecov 657 simplecov
647 sinatra 658 sinatra
648 six 659 six
  660 + slack-notifier (~> 0.2.0)
649 slim 661 slim
650 spinach-rails 662 spinach-rails
651 - spork (~> 1.0rc)  
652 spring (= 1.1.1) 663 spring (= 1.1.1)
653 spring-commands-rspec (= 1.0.1) 664 spring-commands-rspec (= 1.0.1)
654 spring-commands-spinach (= 1.0.0) 665 spring-commands-spinach (= 1.0.0)
@@ -12,7 +12,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co @@ -12,7 +12,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
12 - Closes invalid issues and merge requests with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.) 12 - Closes invalid issues and merge requests with a comment (duplicates, [feature requests](#feature-requests), [fixed in newer version](#issue-fixed-in-newer-version), [issue report for old version](#issue-report-for-old-version), not a problem in GitLab, etc.)
13 - Assigns appropriate [labels](#how-we-handle-issues) 13 - Assigns appropriate [labels](#how-we-handle-issues)
14 - Asks for feedback from issue reporter/merge request initiator ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.) 14 - Asks for feedback from issue reporter/merge request initiator ([invalid issue reports](#improperly-formatted-issue), [format code](#code-format), etc.)
15 -- Asks for feedback from the relevant developer(s) based on the [list of members and their specialities](http://gitlab.org/team/) 15 +- Asks for feedback from the relevant developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
16 - Monitors all issues/merge requests for feedback (but especially ones commented on since automatically watching them): 16 - Monitors all issues/merge requests for feedback (but especially ones commented on since automatically watching them):
17 - Closes issues with no feedback from the reporter for two weeks 17 - Closes issues with no feedback from the reporter for two weeks
18 - Closes stale merge requests 18 - Closes stale merge requests
@@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co @@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co
24 - Monitors for new merge requests (at least once a week) 24 - Monitors for new merge requests (at least once a week)
25 - Manages their work queue by looking at issues and merge requests assigned to them 25 - Manages their work queue by looking at issues and merge requests assigned to them
26 - Close fixed issues (via commit messages or manually) 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 - 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). 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 ## Priorities of the issue team 29 ## Priorities of the issue team
@@ -37,7 +35,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co @@ -37,7 +35,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
37 35
38 ## Mentioning people 36 ## Mentioning people
39 37
40 -The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](http://gitlab.org/team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person. 38 +The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](https://www.gitlab.com/core-team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
41 39
42 ## Workflow labels 40 ## Workflow labels
43 41
@@ -73,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue @@ -73,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue
73 71
74 ### Feature requests 72 ### Feature requests
75 73
76 -Thanks for your interest in GitLab. We don't use the issue tracker for feature requests. Things that are wrong but are not a regression compared to older versions of GitLab are considered feature requests and not issues. Please use 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 ### Issue report for old version 76 ### Issue report for old version
79 77
@@ -89,7 +87,7 @@ Please use ``` to format console output, logs, and code as it&#39;s very hard to rea @@ -89,7 +87,7 @@ Please use ``` to format console output, logs, and code as it&#39;s very hard to rea
89 87
90 ### Issue fixed in newer version 88 ### Issue fixed in newer version
91 89
92 -Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(http://blog.gitlab.org/). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines). 90 +Thanks for the issue report. This issue has already been fixed in newer versions of GitLab. Due to the size of this project and our limited resources we are only able to support the latest stable release as outlined in our \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker). In order to get this bug fix and enjoy many new features please \[upgrade\]\(https://github.com/gitlabhq/gitlabhq/tree/master/doc/update). If you still experience issues at that time please open a new issue following our issue tracker guidelines found in the \[contributing guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#issue-tracker-guidelines).
93 91
94 ### Improperly formatted merge request 92 ### Improperly formatted merge request
95 93
1 -web: bundle exec unicorn_rails -p $PORT -E development 1 +web: bundle exec unicorn_rails -p $PORT -E development -c config/unicorn_development.rb
2 worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell 2 worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
@@ -23,13 +23,11 @@ @@ -23,13 +23,11 @@
23 23
24 ### Resources 24 ### Resources
25 25
26 -* GitLab.org community site: [Homepage](http://gitlab.org) | [Screenshots](http://gitlab.org/screenshots/) | [Blog](http://blog.gitlab.org/) | [Demo](http://demo.gitlabhq.com/users/sign_in) 26 +* [GitLab.com](https://www.gitlab.com/) includes information about [subscriptions](https://www.gitlab.com/subscription/), [consultancy](https://www.gitlab.com/consultancy/), the [community](https://www.gitlab.com/community/) and the [hosted GitLab Cloud](https://www.gitlab.com/cloud/).
27 27
28 -* GitLab.com commercial services: [Homepage](http://www.gitlab.com/) | [Subscription](http://www.gitlab.com/subscription/) | [Consultancy](http://www.gitlab.com/consultancy/) | [GitLab Cloud](http://www.gitlab.com/cloud/) | [Blog](http://blog.gitlab.com/) 28 +* [GitLab Enterprise Edition](https://www.gitlab.com/gitlab-ce/) offers additional features that are useful for larger organizations (100+ users).
29 29
30 -* [GitLab Enterprise Edition](https://www.gitlab.com/features/) offers additional features that are useful for larger organizations (100+ users).  
31 -  
32 -* [GitLab CI](https://gitlab.com/gitlab-org/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab. 30 +* [GitLab CI](https://www.gitlab.com/gitlab-ci/) is a continuous integration (CI) server that is easy to integrate with GitLab.
33 31
34 * Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab 32 * Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab
35 33
@@ -73,7 +71,7 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl @@ -73,7 +71,7 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl
73 71
74 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. 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.
75 73
76 -* 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).
77 75
78 ### Run in production mode 76 ### Run in production mode
79 77
@@ -98,14 +96,9 @@ or start each component separately @@ -98,14 +96,9 @@ or start each component separately
98 96
99 ### Run the tests 97 ### Run the tests
100 98
101 -* Seed the database  
102 -  
103 - bundle exec rake db:setup RAILS_ENV=test  
104 - bundle exec rake db:seed_fu RAILS_ENV=test  
105 -  
106 * Run all tests 99 * Run all tests
107 100
108 - bundle exec rake gitlab:test RAILS_ENV=test 101 + bundle exec rake test
109 102
110 * [RSpec](http://rspec.info/) unit and functional tests 103 * [RSpec](http://rspec.info/) unit and functional tests
111 104
@@ -142,7 +135,7 @@ or start each component separately @@ -142,7 +135,7 @@ or start each component separately
142 135
143 * [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. 136 * [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.
144 137
145 -* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab. 138 +* [Feature request forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
146 139
147 * [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. 140 * [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.
148 141
@@ -155,12 +148,3 @@ or start each component separately @@ -155,12 +148,3 @@ or start each component separately
155 * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview. 148 * [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
156 149
157 * [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help. 150 * [Gitter chat room](https://gitter.im/gitlabhq/gitlabhq#) here you can ask questions when you need help.
158 -  
159 -  
160 -### Getting in touch  
161 -  
162 -* [Core team](http://gitlab.org/team/)  
163 -  
164 -* [Contributors](http://contributors.gitlab.org/)  
165 -  
166 -* [Community](http://gitlab.org/community/)  
1 -6.7.0.pre 1 +6.7.0
app/assets/images/authbuttons/github_32.png 0 → 100644

1.86 KB

app/assets/images/authbuttons/github_64.png 0 → 100644

4.34 KB

app/assets/images/authbuttons/google_32.png 0 → 100644

1.57 KB

app/assets/images/authbuttons/google_64.png 0 → 100644

3.36 KB

app/assets/images/authbuttons/twitter_32.png 0 → 100644

1.38 KB

app/assets/images/authbuttons/twitter_64.png 0 → 100644

3.25 KB

app/assets/images/bg_fallback.png 0 → 100644

2.91 KB

app/assets/images/icon_sprite.png 0 → 100644

2.72 KB

app/assets/images/progress_bar.gif 0 → 100644

494 Bytes

app/assets/images/slider_handles.png 0 → 100644

4.03 KB

app/assets/images/ui-icons_222222_256x240.png 0 → 100644

4.09 KB

app/assets/images/ui-icons_454545_256x240.png 0 → 100644

4.09 KB

app/assets/javascripts/application.js
@@ -1,31 +0,0 @@ @@ -1,31 +0,0 @@
1 -// This is a manifest file that'll be compiled into including all the files listed below.  
2 -// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically  
3 -// be included in the compiled file accessible from http://example.com/assets/application.js  
4 -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the  
5 -// the compiled file.  
6 -//  
7 -//= require jquery  
8 -//= require jquery.ui.all  
9 -//= require jquery_ujs  
10 -//= require jquery.cookie  
11 -//= require jquery.endless-scroll  
12 -//= require jquery.highlight  
13 -//= require jquery.history  
14 -//= require jquery.waitforimages  
15 -//= require jquery.atwho  
16 -//= require jquery.scrollto  
17 -//= require jquery.blockUI  
18 -//= require turbolinks  
19 -//= require jquery.turbolinks  
20 -//= require bootstrap  
21 -//= require modernizr  
22 -//= require select2  
23 -//= require raphael  
24 -//= require g.raphael-min  
25 -//= require g.bar-min  
26 -//= require branch-graph  
27 -//= require highlightjs.min  
28 -//= require ace/ace  
29 -//= require_tree .  
30 -//= require d3  
31 -//= require underscore  
app/assets/javascripts/application.js.coffee 0 → 100644
@@ -0,0 +1,154 @@ @@ -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/behaviors/details_behavior.coffee
1 $ -> 1 $ ->
2 $("body").on "click", ".js-details-target", -> 2 $("body").on "click", ".js-details-target", ->
3 container = $(@).closest(".js-details-container") 3 container = $(@).closest(".js-details-container")
4 -  
5 container.toggleClass("open") 4 container.toggleClass("open")
  5 +
  6 + # Show details content. Hides link after click.
  7 + #
  8 + # %div
  9 + # %a.js-details-expand
  10 + # %div.js-details-content
  11 + #
  12 + $("body").on "click", ".js-details-expand", (e) ->
  13 + $(@).next('.js-details-content').removeClass("hide")
  14 + $(@).hide()
  15 + e.preventDefault()
app/assets/javascripts/behaviors/toggler_behavior.coffee
1 $ -> 1 $ ->
2 $("body").on "click", ".js-toggler-target", -> 2 $("body").on "click", ".js-toggler-target", ->
3 container = $(@).closest(".js-toggler-container") 3 container = $(@).closest(".js-toggler-container")
4 -  
5 container.toggleClass("on") 4 container.toggleClass("on")
6 5
7 - $("body").on "click", ".js-toggle-visibility-link", (e) -> 6 + # Toggle button. Show/hide content inside parent container.
  7 + # Button does not change visibility. If button has icon - it changes chevron style.
  8 + #
  9 + # %div.js-toggle-container
  10 + # %a.js-toggle-button
  11 + # %div.js-toggle-content
  12 + #
  13 + $("body").on "click", ".js-toggle-button", (e) ->
8 $(@).find('i'). 14 $(@).find('i').
9 toggleClass('icon-chevron-down'). 15 toggleClass('icon-chevron-down').
10 toggleClass('icon-chevron-up') 16 toggleClass('icon-chevron-up')
11 - container = $(".js-toggle-visibility-container")  
12 - container.toggleClass("hide")  
13 - e.preventDefault()  
14 -  
15 - $("body").on "click", ".js-toggle-button", (e) ->  
16 $(@).closest(".js-toggle-container").find(".js-toggle-content").toggle() 17 $(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
17 e.preventDefault() 18 e.preventDefault()
app/assets/javascripts/gfm_auto_complete.js.coffee
@@ -6,7 +6,6 @@ GitLab.GfmAutoComplete = @@ -6,7 +6,6 @@ GitLab.GfmAutoComplete =
6 dataSource: '' 6 dataSource: ''
7 # Emoji 7 # Emoji
8 Emoji: 8 Emoji:
9 - assetBase: ''  
10 template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>' 9 template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
11 10
12 # Team Members 11 # Team Members
@@ -27,7 +26,7 @@ GitLab.GfmAutoComplete = @@ -27,7 +26,7 @@ GitLab.GfmAutoComplete =
27 tpl: @Emoji.template 26 tpl: @Emoji.template
28 callbacks: 27 callbacks:
29 before_save: (emojis) => 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 # Team Members 31 # Team Members
33 input.atwho 32 input.atwho
app/assets/javascripts/main.js.coffee
@@ -1,137 +0,0 @@ @@ -1,137 +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 - # Click a .appear-link, appear-data fadeout  
66 - $(".appear-link").on 'click', (e) ->  
67 - $('.appear-data').fadeIn()  
68 - e.preventDefault()  
69 -  
70 - # Initialize select2 selects  
71 - $('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)  
72 -  
73 - # Initialize tooltips  
74 - $('.has_tooltip').tooltip()  
75 -  
76 - # Bottom tooltip  
77 - $('.has_bottom_tooltip').tooltip(placement: 'bottom')  
78 -  
79 - # Form submitter  
80 - $('.trigger-submit').on 'change', ->  
81 - $(@).parents('form').submit()  
82 -  
83 - $("abbr.timeago").timeago()  
84 - $('.js-timeago').timeago()  
85 -  
86 - # Flash  
87 - if (flash = $(".flash-container")).length > 0  
88 - flash.click -> $(@).fadeOut()  
89 - flash.show()  
90 - setTimeout (-> flash.fadeOut()), 5000  
91 -  
92 - # Disable form buttons while a form is submitting  
93 - $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->  
94 - buttons = $('[type="submit"]', @)  
95 -  
96 - switch e.type  
97 - when 'ajax:beforeSend', 'submit'  
98 - buttons.disable()  
99 - else  
100 - buttons.enable()  
101 -  
102 - # Show/Hide the profile menu when hovering the account box  
103 - $('.account-box').hover -> $(@).toggleClass('hover')  
104 -  
105 - # Focus search field by pressing 's' key  
106 - $(document).keypress (e) ->  
107 - # Don't do anything if typing in an input  
108 - return if $(e.target).is(":input")  
109 -  
110 - switch e.which  
111 - when 115  
112 - $("#search").focus()  
113 - e.preventDefault()  
114 - when 63  
115 - new Shortcuts()  
116 - e.preventDefault()  
117 -  
118 -  
119 - # Commit show suppressed diff  
120 - $(".diff-content").on "click", ".supp_diff_link", ->  
121 - $(@).next('table').show()  
122 - $(@).remove()  
123 -  
124 - $(".diff-content").on "click", ".js-details-expand", ->  
125 - $(@).next('.js-details-contain').removeClass("hide")  
126 - $(@).remove()  
127 -  
128 -(($) ->  
129 - # Disable an element and add the 'disabled' Bootstrap class  
130 - $.fn.extend disable: ->  
131 - $(@).attr('disabled', 'disabled').addClass('disabled')  
132 -  
133 - # Enable an element and remove the 'disabled' Bootstrap class  
134 - $.fn.extend enable: ->  
135 - $(@).removeAttr('disabled').removeClass('disabled')  
136 -  
137 -)(jQuery)  
app/assets/stylesheets/application.scss
@@ -7,6 +7,8 @@ @@ -7,6 +7,8 @@
7 *= require select2 7 *= require select2
8 *= require highlightjs.min 8 *= require highlightjs.min
9 *= require_self 9 *= require_self
  10 + *= require nprogress
  11 + *= require nprogress-bootstrap
10 */ 12 */
11 13
12 @import "main/variables.scss"; 14 @import "main/variables.scss";
app/assets/stylesheets/generic/common.scss
@@ -298,10 +298,6 @@ img.emoji { @@ -298,10 +298,6 @@ img.emoji {
298 width: 20px; 298 width: 20px;
299 } 299 }
300 300
301 -.appear-data {  
302 - display: none;  
303 -}  
304 -  
305 .chart { 301 .chart {
306 overflow: hidden; 302 overflow: hidden;
307 height: 220px; 303 height: 220px;
@@ -359,3 +355,7 @@ table { @@ -359,3 +355,7 @@ table {
359 @media (max-width: $screen-xs-max) { 355 @media (max-width: $screen-xs-max) {
360 .container .content { margin-top: 20px; } 356 .container .content { margin-top: 20px; }
361 } 357 }
  358 +
  359 +.wiki .highlight, .note-body .highlight {
  360 + margin-bottom: 9px;
  361 +}
app/assets/stylesheets/print.scss 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +/* Generic print styles */
  2 +header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;}
  3 +.profiler-results {display: none;}
  4 +
  5 +/* Styles targeted specifically at printing files */
  6 +.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;}
  7 +.file-title {display: none;}
  8 +.file-holder {border: none;}
  9 +
  10 +.wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; }
  11 +.wiki h1 {font-size: 30px;}
  12 +.wiki h2 {font-size: 22px;}
  13 +.wiki h3 {font-size: 18px; font-weight: bold; }
app/assets/stylesheets/sections/dashboard.scss
@@ -61,7 +61,7 @@ @@ -61,7 +61,7 @@
61 } 61 }
62 62
63 .project-row, .group-row { 63 .project-row, .group-row {
64 - padding: 10px 12px !important; 64 + padding: 8px 12px !important;
65 font-size: 14px; 65 font-size: 14px;
66 line-height: 24px; 66 line-height: 24px;
67 67
app/assets/stylesheets/sections/events.scss
@@ -42,7 +42,7 @@ @@ -42,7 +42,7 @@
42 } 42 }
43 } 43 }
44 44
45 - padding: 14px 0px; 45 + padding: 12px 0px;
46 border-bottom: 1px solid #eee; 46 border-bottom: 1px solid #eee;
47 .event-title { 47 .event-title {
48 color: #333; 48 color: #333;
app/assets/stylesheets/sections/header.scss
@@ -273,3 +273,9 @@ header { @@ -273,3 +273,9 @@ header {
273 } 273 }
274 } 274 }
275 } 275 }
  276 +
  277 +@media (max-width: $screen-xs-max) {
  278 + #nprogress .spinner {
  279 + right: 35px !important;
  280 + }
  281 +}
app/assets/stylesheets/sections/notes.scss
@@ -189,7 +189,6 @@ ul.notes { @@ -189,7 +189,6 @@ ul.notes {
189 } 189 }
190 190
191 191
192 -  
193 /** 192 /**
194 * Line note button on the side of diffs 193 * Line note button on the side of diffs
195 */ 194 */
app/controllers/admin/background_jobs_controller.rb
1 class Admin::BackgroundJobsController < Admin::ApplicationController 1 class Admin::BackgroundJobsController < Admin::ApplicationController
2 def show 2 def show
3 - ps_output, _ = Gitlab::Popen.popen(%W(ps -U #{Settings.gitlab.user} -o euser,pid,pcpu,pmem,stat,start,command)) 3 + ps_output, _ = Gitlab::Popen.popen(%W(ps -U #{Settings.gitlab.user} -o pid,pcpu,pmem,stat,start,command))
4 @sidekiq_processes = ps_output.split("\n").grep(/sidekiq/) 4 @sidekiq_processes = ps_output.split("\n").grep(/sidekiq/)
5 end 5 end
6 end 6 end
app/controllers/application_controller.rb
@@ -6,6 +6,7 @@ class ApplicationController &lt; ActionController::Base @@ -6,6 +6,7 @@ class ApplicationController &lt; ActionController::Base
6 before_filter :check_password_expiration 6 before_filter :check_password_expiration
7 around_filter :set_current_user_for_thread 7 around_filter :set_current_user_for_thread
8 before_filter :add_abilities 8 before_filter :add_abilities
  9 + before_filter :ldap_security_check
9 before_filter :dev_tools if Rails.env == 'development' 10 before_filter :dev_tools if Rails.env == 'development'
10 before_filter :default_headers 11 before_filter :default_headers
11 before_filter :add_gon_variables 12 before_filter :add_gon_variables
@@ -179,11 +180,30 @@ class ApplicationController &lt; ActionController::Base @@ -179,11 +180,30 @@ class ApplicationController &lt; ActionController::Base
179 end 180 end
180 end 181 end
181 182
  183 + def ldap_security_check
  184 + if current_user && current_user.requires_ldap_check?
  185 + gitlab_ldap_access do |access|
  186 + if access.allowed?(current_user)
  187 + current_user.last_credential_check_at = Time.now
  188 + current_user.save
  189 + else
  190 + sign_out current_user
  191 + flash[:alert] = "Access denied for your LDAP account."
  192 + redirect_to new_user_session_path
  193 + end
  194 + end
  195 + end
  196 + end
  197 +
182 def event_filter 198 def event_filter
183 filters = cookies['event_filter'].split(',') if cookies['event_filter'].present? 199 filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
184 @event_filter ||= EventFilter.new(filters) 200 @event_filter ||= EventFilter.new(filters)
185 end 201 end
186 202
  203 + def gitlab_ldap_access(&block)
  204 + Gitlab::LDAP::Access.open { |access| block.call(access) }
  205 + end
  206 +
187 # JSON for infinite scroll via Pager object 207 # JSON for infinite scroll via Pager object
188 def pager_json(partial, count) 208 def pager_json(partial, count)
189 html = render_to_string( 209 html = render_to_string(
app/controllers/dashboard_controller.rb
@@ -22,6 +22,8 @@ class DashboardController &lt; ApplicationController @@ -22,6 +22,8 @@ class DashboardController &lt; ApplicationController
22 22
23 @last_push = current_user.recent_push 23 @last_push = current_user.recent_push
24 24
  25 + @publicish_project_count = Project.publicish(current_user).count
  26 +
25 respond_to do |format| 27 respond_to do |format|
26 format.html 28 format.html
27 format.json { pager_json("events/_events", @events.count) } 29 format.json { pager_json("events/_events", @events.count) }
app/controllers/passwords_controller.rb 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +class PasswordsController < Devise::PasswordsController
  2 +
  3 + def create
  4 + email = resource_params[:email]
  5 + resource_found = resource_class.find_by_email(email)
  6 + if resource_found && resource_found.ldap_user?
  7 + flash[:alert] = "Cannot reset password for LDAP user."
  8 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return
  9 + end
  10 +
  11 + self.resource = resource_class.send_reset_password_instructions(resource_params)
  12 + if successfully_sent?(resource)
  13 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
  14 + else
  15 + respond_with(resource)
  16 + end
  17 + end
  18 +end
app/controllers/profiles/keys_controller.rb
@@ -41,7 +41,7 @@ class Profiles::KeysController &lt; ApplicationController @@ -41,7 +41,7 @@ class Profiles::KeysController &lt; ApplicationController
41 begin 41 begin
42 user = User.find_by_username(params[:username]) 42 user = User.find_by_username(params[:username])
43 if user.present? 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 else 45 else
46 render_404 and return 46 render_404 and return
47 end 47 end
app/controllers/projects_controller.rb
@@ -5,7 +5,7 @@ class ProjectsController &lt; ApplicationController @@ -5,7 +5,7 @@ class ProjectsController &lt; ApplicationController
5 5
6 # Authorize 6 # Authorize
7 before_filter :authorize_read_project!, except: [:index, :new, :create] 7 before_filter :authorize_read_project!, except: [:index, :new, :create]
8 - before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive] 8 + before_filter :authorize_admin_project!, only: [:edit, :update, :destroy, :transfer, :archive, :unarchive, :retry_import]
9 before_filter :require_non_empty_project, only: [:blob, :tree, :graph] 9 before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
10 10
11 layout 'navless', only: [:new, :create, :fork] 11 layout 'navless', only: [:new, :create, :fork]
@@ -21,16 +21,9 @@ class ProjectsController &lt; ApplicationController @@ -21,16 +21,9 @@ class ProjectsController &lt; ApplicationController
21 21
22 def create 22 def create
23 @project = ::Projects::CreateService.new(current_user, params[:project]).execute 23 @project = ::Projects::CreateService.new(current_user, params[:project]).execute
  24 + flash[:notice] = 'Project was successfully created.' if @project.saved?
24 25
25 respond_to do |format| 26 respond_to do |format|
26 - flash[:notice] = 'Project was successfully created.' if @project.saved?  
27 - format.html do  
28 - if @project.saved?  
29 - redirect_to @project  
30 - else  
31 - render "new"  
32 - end  
33 - end  
34 format.js 27 format.js
35 end 28 end
36 end 29 end
@@ -55,6 +48,11 @@ class ProjectsController &lt; ApplicationController @@ -55,6 +48,11 @@ class ProjectsController &lt; ApplicationController
55 end 48 end
56 49
57 def show 50 def show
  51 + if @project.import_in_progress?
  52 + redirect_to import_project_path(@project)
  53 + return
  54 + end
  55 +
58 return authenticate_user! unless @project.public? || current_user 56 return authenticate_user! unless @project.public? || current_user
59 57
60 limit = (params[:limit] || 20).to_i 58 limit = (params[:limit] || 20).to_i
@@ -67,9 +65,7 @@ class ProjectsController &lt; ApplicationController @@ -67,9 +65,7 @@ class ProjectsController &lt; ApplicationController
67 if @project.empty_repo? 65 if @project.empty_repo?
68 render "projects/empty", layout: user_layout 66 render "projects/empty", layout: user_layout
69 else 67 else
70 - if current_user  
71 - @last_push = current_user.recent_push(@project.id)  
72 - end 68 + @last_push = current_user.recent_push(@project.id) if current_user
73 render :show, layout: user_layout 69 render :show, layout: user_layout
74 end 70 end
75 end 71 end
@@ -77,6 +73,28 @@ class ProjectsController &lt; ApplicationController @@ -77,6 +73,28 @@ class ProjectsController &lt; ApplicationController
77 end 73 end
78 end 74 end
79 75
  76 + def import
  77 + if project.import_finished?
  78 + redirect_to @project
  79 + return
  80 + end
  81 + end
  82 +
  83 + def retry_import
  84 + unless @project.import_failed?
  85 + redirect_to import_project_path(@project)
  86 + end
  87 +
  88 + @project.import_url = params[:project][:import_url]
  89 +
  90 + if @project.save
  91 + @project.reload
  92 + @project.import_retry
  93 + end
  94 +
  95 + redirect_to import_project_path(@project)
  96 + end
  97 +
80 def destroy 98 def destroy
81 return access_denied! unless can?(current_user, :remove_project, project) 99 return access_denied! unless can?(current_user, :remove_project, project)
82 100
@@ -106,7 +124,7 @@ class ProjectsController &lt; ApplicationController @@ -106,7 +124,7 @@ class ProjectsController &lt; ApplicationController
106 124
107 def autocomplete_sources 125 def autocomplete_sources
108 @suggestions = { 126 @suggestions = {
109 - emojis: Emoji.names, 127 + emojis: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } },
110 issues: @project.issues.select([:iid, :title, :description]), 128 issues: @project.issues.select([:iid, :title, :description]),
111 mergerequests: @project.merge_requests.select([:iid, :title, :description]), 129 mergerequests: @project.merge_requests.select([:iid, :title, :description]),
112 members: @project.team.members.sort_by(&:username).map { |user| { username: user.username, name: user.name } } 130 members: @project.team.members.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
app/controllers/search_controller.rb
@@ -7,6 +7,7 @@ class SearchController &lt; ApplicationController @@ -7,6 +7,7 @@ class SearchController &lt; ApplicationController
7 7
8 if @project 8 if @project
9 return access_denied! unless can?(current_user, :download_code, @project) 9 return access_denied! unless can?(current_user, :download_code, @project)
  10 +
10 @search_results = Search::ProjectService.new(@project, current_user, params).execute 11 @search_results = Search::ProjectService.new(@project, current_user, params).execute
11 else 12 else
12 @search_results = Search::GlobalService.new(current_user, params).execute 13 @search_results = Search::GlobalService.new(current_user, params).execute
app/controllers/snippets_controller.rb
@@ -19,6 +19,9 @@ class SnippetsController &lt; ApplicationController @@ -19,6 +19,9 @@ class SnippetsController &lt; ApplicationController
19 19
20 def user_index 20 def user_index
21 @user = User.find_by(username: params[:username]) 21 @user = User.find_by(username: params[:username])
  22 +
  23 + render_404 and return unless @user
  24 +
22 @snippets = @user.snippets.fresh.non_expired 25 @snippets = @user.snippets.fresh.non_expired
23 26
24 if @user == current_user 27 if @user == current_user
app/finders/base_finder.rb
@@ -47,9 +47,9 @@ class BaseFinder @@ -47,9 +47,9 @@ class BaseFinder
47 [] 47 []
48 end 48 end
49 elsif current_user && params[:authorized_only].presence 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 else 51 else
52 - klass.of_projects(Project.accessible_to(current_user)) 52 + klass.of_projects(Project.accessible_to(current_user)).references(:project)
53 end 53 end
54 end 54 end
55 55
app/helpers/application_helper.rb
@@ -146,8 +146,7 @@ module ApplicationHelper @@ -146,8 +146,7 @@ module ApplicationHelper
146 146
147 def authbutton(provider, size = 64) 147 def authbutton(provider, size = 64)
148 file_name = "#{provider.to_s.split('_').first}_#{size}.png" 148 file_name = "#{provider.to_s.split('_').first}_#{size}.png"
149 - image_tag("authbuttons/#{file_name}",  
150 - alt: "Sign in with #{provider.to_s.titleize}") 149 + image_tag(image_path("authbuttons/#{file_name}"), alt: "Sign in with #{provider.to_s.titleize}")
151 end 150 end
152 151
153 def simple_sanitize(str) 152 def simple_sanitize(str)
app/helpers/gitlab_markdown_helper.rb
@@ -35,7 +35,6 @@ module GitlabMarkdownHelper @@ -35,7 +35,6 @@ module GitlabMarkdownHelper
35 # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch- 35 # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
36 filter_html: true, 36 filter_html: true,
37 with_toc_data: true, 37 with_toc_data: true,
38 - hard_wrap: true,  
39 safe_links_only: true 38 safe_links_only: true
40 }.merge(options)) 39 }.merge(options))
41 @markdown = Redcarpet::Markdown.new(gitlab_renderer, 40 @markdown = Redcarpet::Markdown.new(gitlab_renderer,
@@ -45,7 +44,7 @@ module GitlabMarkdownHelper @@ -45,7 +44,7 @@ module GitlabMarkdownHelper
45 fenced_code_blocks: true, 44 fenced_code_blocks: true,
46 autolink: true, 45 autolink: true,
47 strikethrough: true, 46 strikethrough: true,
48 - lax_html_blocks: true, 47 + lax_spacing: true,
49 space_after_headers: true, 48 space_after_headers: true,
50 superscript: true) 49 superscript: true)
51 end 50 end
@@ -64,8 +63,7 @@ module GitlabMarkdownHelper @@ -64,8 +63,7 @@ module GitlabMarkdownHelper
64 # project_path_with_namespace - namespace/projectname, eg. gitlabhq/gitlabhq 63 # project_path_with_namespace - namespace/projectname, eg. gitlabhq/gitlabhq
65 # ref - name of the branch or reference, eg. stable 64 # ref - name of the branch or reference, eg. stable
66 # requested_path - path of request, eg. doc/api/README.md, used in special case when path is pointing to the .md file were the original request is coming from 65 # requested_path - path of request, eg. doc/api/README.md, used in special case when path is pointing to the .md file were the original request is coming from
67 - # wiki - whether the markdown is from wiki or not  
68 - def create_relative_links(text, project, ref, requested_path, wiki = false) 66 + def create_relative_links(text, project, ref, requested_path)
69 @path_to_satellite = project.satellite.path 67 @path_to_satellite = project.satellite.path
70 project_path_with_namespace = project.path_with_namespace 68 project_path_with_namespace = project.path_with_namespace
71 paths = extract_paths(text) 69 paths = extract_paths(text)
@@ -135,12 +133,12 @@ module GitlabMarkdownHelper @@ -135,12 +133,12 @@ module GitlabMarkdownHelper
135 end 133 end
136 134
137 # Checks if the path exists in the repo 135 # Checks if the path exists in the repo
138 - # eg. checks if doc/README.md exists, if it doesn't then it is a wiki link 136 + # eg. checks if doc/README.md exists, if not then link to blob
139 def path_with_ref(path, ref) 137 def path_with_ref(path, ref)
140 if file_exists?(path) 138 if file_exists?(path)
141 "#{local_path(path)}/#{correct_ref(ref)}" 139 "#{local_path(path)}/#{correct_ref(ref)}"
142 else 140 else
143 - "wikis" 141 + "blob/#{correct_ref(ref)}"
144 end 142 end
145 end 143 end
146 144
app/helpers/merge_requests_helper.rb
@@ -20,7 +20,7 @@ module MergeRequestsHelper @@ -20,7 +20,7 @@ module MergeRequestsHelper
20 target_project_id: target_project.id, 20 target_project_id: target_project.id,
21 source_branch: event.branch_name, 21 source_branch: event.branch_name,
22 target_branch: target_project.repository.root_ref, 22 target_branch: target_project.repository.root_ref,
23 - title: event.branch_name.titleize 23 + title: event.branch_name.humanize
24 } 24 }
25 end 25 end
26 26
app/helpers/profile_helper.rb
@@ -10,7 +10,7 @@ module ProfileHelper @@ -10,7 +10,7 @@ module ProfileHelper
10 end 10 end
11 11
12 def show_profile_social_tab? 12 def show_profile_social_tab?
13 - Gitlab.config.omniauth.enabled && !current_user.ldap_user? 13 + enabled_social_providers.any? && !current_user.ldap_user?
14 end 14 end
15 15
16 def show_profile_remove_tab? 16 def show_profile_remove_tab?
app/helpers/tree_helper.rb
@@ -40,7 +40,7 @@ module TreeHelper @@ -40,7 +40,7 @@ module TreeHelper
40 # Returns boolean 40 # Returns boolean
41 def markup?(filename) 41 def markup?(filename)
42 filename.downcase.end_with?(*%w(.textile .rdoc .org .creole 42 filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
43 - .mediawiki .rst .asciidoc .pod)) 43 + .mediawiki .rst .adoc .asciidoc .pod))
44 end 44 end
45 45
46 def gitlab_markdown?(filename) 46 def gitlab_markdown?(filename)
app/mailers/emails/groups.rb
@@ -3,7 +3,7 @@ module Emails @@ -3,7 +3,7 @@ module Emails
3 def group_access_granted_email(user_group_id) 3 def group_access_granted_email(user_group_id)
4 @membership = UsersGroup.find(user_group_id) 4 @membership = UsersGroup.find(user_group_id)
5 @group = @membership.group 5 @group = @membership.group
6 - 6 + @target_url = group_url(@group)
7 mail(to: @membership.user.email, 7 mail(to: @membership.user.email,
8 subject: subject("Access to group was granted")) 8 subject: subject("Access to group was granted"))
9 end 9 end
app/mailers/emails/issues.rb
@@ -3,6 +3,7 @@ module Emails @@ -3,6 +3,7 @@ module Emails
3 def new_issue_email(recipient_id, issue_id) 3 def new_issue_email(recipient_id, issue_id)
4 @issue = Issue.find(issue_id) 4 @issue = Issue.find(issue_id)
5 @project = @issue.project 5 @project = @issue.project
  6 + @target_url = project_issue_url(@project, @issue)
6 mail(from: sender(@issue.author_id), 7 mail(from: sender(@issue.author_id),
7 to: recipient(recipient_id), 8 to: recipient(recipient_id),
8 subject: subject("#{@issue.title} (##{@issue.iid})")) 9 subject: subject("#{@issue.title} (##{@issue.iid})"))
@@ -12,6 +13,7 @@ module Emails @@ -12,6 +13,7 @@ module Emails
12 @issue = Issue.find(issue_id) 13 @issue = Issue.find(issue_id)
13 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id 14 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
14 @project = @issue.project 15 @project = @issue.project
  16 + @target_url = project_issue_url(@project, @issue)
15 mail(from: sender(updated_by_user_id), 17 mail(from: sender(updated_by_user_id),
16 to: recipient(recipient_id), 18 to: recipient(recipient_id),
17 subject: subject("#{@issue.title} (##{@issue.iid})")) 19 subject: subject("#{@issue.title} (##{@issue.iid})"))
@@ -21,6 +23,7 @@ module Emails @@ -21,6 +23,7 @@ module Emails
21 @issue = Issue.find issue_id 23 @issue = Issue.find issue_id
22 @project = @issue.project 24 @project = @issue.project
23 @updated_by = User.find updated_by_user_id 25 @updated_by = User.find updated_by_user_id
  26 + @target_url = project_issue_url(@project, @issue)
24 mail(from: sender(updated_by_user_id), 27 mail(from: sender(updated_by_user_id),
25 to: recipient(recipient_id), 28 to: recipient(recipient_id),
26 subject: subject("#{@issue.title} (##{@issue.iid})")) 29 subject: subject("#{@issue.title} (##{@issue.iid})"))
@@ -31,6 +34,7 @@ module Emails @@ -31,6 +34,7 @@ module Emails
31 @issue_status = status 34 @issue_status = status
32 @project = @issue.project 35 @project = @issue.project
33 @updated_by = User.find updated_by_user_id 36 @updated_by = User.find updated_by_user_id
  37 + @target_url = project_issue_url(@project, @issue)
34 mail(from: sender(updated_by_user_id), 38 mail(from: sender(updated_by_user_id),
35 to: recipient(recipient_id), 39 to: recipient(recipient_id),
36 subject: subject("#{@issue.title} (##{@issue.iid})")) 40 subject: subject("#{@issue.title} (##{@issue.iid})"))
app/mailers/emails/merge_requests.rb
@@ -3,6 +3,7 @@ module Emails @@ -3,6 +3,7 @@ module Emails
3 def new_merge_request_email(recipient_id, merge_request_id) 3 def new_merge_request_email(recipient_id, merge_request_id)
4 @merge_request = MergeRequest.find(merge_request_id) 4 @merge_request = MergeRequest.find(merge_request_id)
5 @project = @merge_request.project 5 @project = @merge_request.project
  6 + @target_url = project_merge_request_url(@project, @merge_request)
6 mail(from: sender(@merge_request.author_id), 7 mail(from: sender(@merge_request.author_id),
7 to: recipient(recipient_id), 8 to: recipient(recipient_id),
8 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) 9 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
@@ -12,6 +13,7 @@ module Emails @@ -12,6 +13,7 @@ module Emails
12 @merge_request = MergeRequest.find(merge_request_id) 13 @merge_request = MergeRequest.find(merge_request_id)
13 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id 14 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
14 @project = @merge_request.project 15 @project = @merge_request.project
  16 + @target_url = project_merge_request_url(@project, @merge_request)
15 mail(from: sender(updated_by_user_id), 17 mail(from: sender(updated_by_user_id),
16 to: recipient(recipient_id), 18 to: recipient(recipient_id),
17 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) 19 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
@@ -21,15 +23,17 @@ module Emails @@ -21,15 +23,17 @@ module Emails
21 @merge_request = MergeRequest.find(merge_request_id) 23 @merge_request = MergeRequest.find(merge_request_id)
22 @updated_by = User.find updated_by_user_id 24 @updated_by = User.find updated_by_user_id
23 @project = @merge_request.project 25 @project = @merge_request.project
  26 + @target_url = project_merge_request_url(@project, @merge_request)
24 mail(from: sender(updated_by_user_id), 27 mail(from: sender(updated_by_user_id),
25 to: recipient(recipient_id), 28 to: recipient(recipient_id),
26 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) 29 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
27 end 30 end
28 31
29 - 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)
30 @merge_request = MergeRequest.find(merge_request_id) 33 @merge_request = MergeRequest.find(merge_request_id)
31 @project = @merge_request.project 34 @project = @merge_request.project
32 - mail(from: sender(@merge_request.author_id_of_changes), 35 + @target_url = project_merge_request_url(@project, @merge_request)
  36 + mail(from: sender(updated_by_user_id),
33 to: recipient(recipient_id), 37 to: recipient(recipient_id),
34 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) 38 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
35 end 39 end
app/mailers/emails/notes.rb
@@ -4,6 +4,7 @@ module Emails @@ -4,6 +4,7 @@ module Emails
4 @note = Note.find(note_id) 4 @note = Note.find(note_id)
5 @commit = @note.noteable 5 @commit = @note.noteable
6 @project = @note.project 6 @project = @note.project
  7 + @target_url = project_commit_url(@project, @commit, anchor: "note_#{@note.id}")
7 mail(from: sender(@note.author_id), 8 mail(from: sender(@note.author_id),
8 to: recipient(recipient_id), 9 to: recipient(recipient_id),
9 subject: subject("#{@commit.title} (#{@commit.short_id})")) 10 subject: subject("#{@commit.title} (#{@commit.short_id})"))
@@ -13,6 +14,7 @@ module Emails @@ -13,6 +14,7 @@ module Emails
13 @note = Note.find(note_id) 14 @note = Note.find(note_id)
14 @issue = @note.noteable 15 @issue = @note.noteable
15 @project = @note.project 16 @project = @note.project
  17 + @target_url = project_issue_url(@project, @issue, anchor: "note_#{@note.id}")
16 mail(from: sender(@note.author_id), 18 mail(from: sender(@note.author_id),
17 to: recipient(recipient_id), 19 to: recipient(recipient_id),
18 subject: subject("#{@issue.title} (##{@issue.iid})")) 20 subject: subject("#{@issue.title} (##{@issue.iid})"))
@@ -22,6 +24,7 @@ module Emails @@ -22,6 +24,7 @@ module Emails
22 @note = Note.find(note_id) 24 @note = Note.find(note_id)
23 @merge_request = @note.noteable 25 @merge_request = @note.noteable
24 @project = @note.project 26 @project = @note.project
  27 + @target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
25 mail(from: sender(@note.author_id), 28 mail(from: sender(@note.author_id),
26 to: recipient(recipient_id), 29 to: recipient(recipient_id),
27 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})")) 30 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
@@ -30,6 +33,7 @@ module Emails @@ -30,6 +33,7 @@ module Emails
30 def note_wall_email(recipient_id, note_id) 33 def note_wall_email(recipient_id, note_id)
31 @note = Note.find(note_id) 34 @note = Note.find(note_id)
32 @project = @note.project 35 @project = @note.project
  36 + @target_url = project_wall_url(@note.project, anchor: "note_#{@note.id}")
33 mail(from: sender(@note.author_id), 37 mail(from: sender(@note.author_id),
34 to: recipient(recipient_id), 38 to: recipient(recipient_id),
35 subject: subject("Note on wall")) 39 subject: subject("Note on wall"))
app/mailers/emails/profile.rb
@@ -3,6 +3,7 @@ module Emails @@ -3,6 +3,7 @@ module Emails
3 def new_user_email(user_id, password) 3 def new_user_email(user_id, password)
4 @user = User.find(user_id) 4 @user = User.find(user_id)
5 @password = password 5 @password = password
  6 + @target_url = user_url(@user)
6 mail(to: @user.email, subject: subject("Account was created for you")) 7 mail(to: @user.email, subject: subject("Account was created for you"))
7 end 8 end
8 9
@@ -15,6 +16,7 @@ module Emails @@ -15,6 +16,7 @@ module Emails
15 def new_ssh_key_email(key_id) 16 def new_ssh_key_email(key_id)
16 @key = Key.find(key_id) 17 @key = Key.find(key_id)
17 @user = @key.user 18 @user = @key.user
  19 + @target_url = user_url(@user)
18 mail(to: @user.email, subject: subject("SSH key was added to your account")) 20 mail(to: @user.email, subject: subject("SSH key was added to your account"))
19 end 21 end
20 end 22 end
app/mailers/emails/projects.rb
@@ -3,6 +3,7 @@ module Emails @@ -3,6 +3,7 @@ module Emails
3 def project_access_granted_email(user_project_id) 3 def project_access_granted_email(user_project_id)
4 @users_project = UsersProject.find user_project_id 4 @users_project = UsersProject.find user_project_id
5 @project = @users_project.project 5 @project = @users_project.project
  6 + @target_url = project_url(@project)
6 mail(to: @users_project.user.email, 7 mail(to: @users_project.user.email,
7 subject: subject("Access to project was granted")) 8 subject: subject("Access to project was granted"))
8 end 9 end
@@ -10,6 +11,7 @@ module Emails @@ -10,6 +11,7 @@ module Emails
10 def project_was_moved_email(project_id, user_id) 11 def project_was_moved_email(project_id, user_id)
11 @user = User.find user_id 12 @user = User.find user_id
12 @project = Project.find project_id 13 @project = Project.find project_id
  14 + @target_url = project_url(@project)
13 mail(to: @user.email, 15 mail(to: @user.email,
14 subject: subject("Project was moved")) 16 subject: subject("Project was moved"))
15 end 17 end
@@ -21,6 +23,11 @@ module Emails @@ -21,6 +23,11 @@ module Emails
21 @commits = Commit.decorate(compare.commits) 23 @commits = Commit.decorate(compare.commits)
22 @diffs = compare.diffs 24 @diffs = compare.diffs
23 @branch = branch 25 @branch = branch
  26 + if @commits.length > 1
  27 + @target_url = project_compare_url(@project, from: @commits.first, to: @commits.last)
  28 + else
  29 + @target_url = project_commit_url(@project, @compare.commit)
  30 + end
24 31
25 mail(from: sender(author_id), 32 mail(from: sender(author_id),
26 to: recipient, 33 to: recipient,
app/models/ability.rb
@@ -240,6 +240,7 @@ class Ability @@ -240,6 +240,7 @@ class Ability
240 can_manage = group_abilities(user, group).include?(:manage_group) 240 can_manage = group_abilities(user, group).include?(:manage_group)
241 if can_manage && (user != target_user) 241 if can_manage && (user != target_user)
242 rules << :modify 242 rules << :modify
  243 + rules << :destroy
243 end 244 end
244 if !group.last_owner?(user) && (can_manage || (user == target_user)) 245 if !group.last_owner?(user) && (can_manage || (user == target_user))
245 rules << :destroy 246 rules << :destroy
app/models/merge_request.rb
@@ -133,7 +133,7 @@ class MergeRequest &lt; ActiveRecord::Base @@ -133,7 +133,7 @@ class MergeRequest &lt; ActiveRecord::Base
133 end 133 end
134 134
135 def reload_code 135 def reload_code
136 - if merge_request_diff && opened? 136 + if merge_request_diff && open?
137 merge_request_diff.reload_content 137 merge_request_diff.reload_content
138 end 138 end
139 end 139 end
app/models/note.rb
@@ -199,7 +199,8 @@ class Note &lt; ActiveRecord::Base @@ -199,7 +199,8 @@ class Note &lt; ActiveRecord::Base
199 def downvote? 199 def downvote?
200 votable? && (note.start_with?('-1') || 200 votable? && (note.start_with?('-1') ||
201 note.start_with?(':-1:') || 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 end 205 end
205 206
@@ -249,7 +250,8 @@ class Note &lt; ActiveRecord::Base @@ -249,7 +250,8 @@ class Note &lt; ActiveRecord::Base
249 def upvote? 250 def upvote?
250 votable? && (note.start_with?('+1') || 251 votable? && (note.start_with?('+1') ||
251 note.start_with?(':+1:') || 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 end 256 end
255 257
app/models/project.rb
@@ -28,7 +28,6 @@ class Project &lt; ActiveRecord::Base @@ -28,7 +28,6 @@ class Project &lt; ActiveRecord::Base
28 include Gitlab::VisibilityLevel 28 include Gitlab::VisibilityLevel
29 extend Enumerize 29 extend Enumerize
30 30
31 - default_value_for :imported, false  
32 default_value_for :archived, false 31 default_value_for :archived, false
33 32
34 ActsAsTaggableOn.strict_case_match = true 33 ActsAsTaggableOn.strict_case_match = true
@@ -57,15 +56,13 @@ class Project &lt; ActiveRecord::Base @@ -57,15 +56,13 @@ class Project &lt; ActiveRecord::Base
57 has_one :flowdock_service, dependent: :destroy 56 has_one :flowdock_service, dependent: :destroy
58 has_one :assembla_service, dependent: :destroy 57 has_one :assembla_service, dependent: :destroy
59 has_one :gemnasium_service, dependent: :destroy 58 has_one :gemnasium_service, dependent: :destroy
  59 + has_one :slack_service, dependent: :destroy
60 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id" 60 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
61 has_one :forked_from_project, through: :forked_project_link 61 has_one :forked_from_project, through: :forked_project_link
62 -  
63 # Merge Requests for target project should be removed with it 62 # Merge Requests for target project should be removed with it
64 has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id" 63 has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id"
65 -  
66 # Merge requests from source project should be kept when source project was removed 64 # Merge requests from source project should be kept when source project was removed
67 has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest 65 has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest
68 -  
69 has_many :issues, -> { order "state DESC, created_at DESC" }, dependent: :destroy 66 has_many :issues, -> { order "state DESC, created_at DESC" }, dependent: :destroy
70 has_many :services, dependent: :destroy 67 has_many :services, dependent: :destroy
71 has_many :events, dependent: :destroy 68 has_many :events, dependent: :destroy
@@ -74,10 +71,8 @@ class Project &lt; ActiveRecord::Base @@ -74,10 +71,8 @@ class Project &lt; ActiveRecord::Base
74 has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet" 71 has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet"
75 has_many :hooks, dependent: :destroy, class_name: "ProjectHook" 72 has_many :hooks, dependent: :destroy, class_name: "ProjectHook"
76 has_many :protected_branches, dependent: :destroy 73 has_many :protected_branches, dependent: :destroy
77 -  
78 has_many :users_projects, dependent: :destroy 74 has_many :users_projects, dependent: :destroy
79 has_many :users, through: :users_projects 75 has_many :users, through: :users_projects
80 -  
81 has_many :deploy_keys_projects, dependent: :destroy 76 has_many :deploy_keys_projects, dependent: :destroy
82 has_many :deploy_keys, through: :deploy_keys_projects 77 has_many :deploy_keys, through: :deploy_keys_projects
83 78
@@ -97,15 +92,12 @@ class Project &lt; ActiveRecord::Base @@ -97,15 +92,12 @@ class Project &lt; ActiveRecord::Base
97 validates :issues_enabled, :wall_enabled, :merge_requests_enabled, 92 validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
98 :wiki_enabled, inclusion: { in: [true, false] } 93 :wiki_enabled, inclusion: { in: [true, false] }
99 validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true 94 validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
100 -  
101 validates :namespace, presence: true 95 validates :namespace, presence: true
102 validates_uniqueness_of :name, scope: :namespace_id 96 validates_uniqueness_of :name, scope: :namespace_id
103 validates_uniqueness_of :path, scope: :namespace_id 97 validates_uniqueness_of :path, scope: :namespace_id
104 -  
105 validates :import_url, 98 validates :import_url,
106 format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" }, 99 format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" },
107 if: :import? 100 if: :import?
108 -  
109 validate :check_limit, on: :create 101 validate :check_limit, on: :create
110 102
111 # Scopes 103 # Scopes
@@ -118,14 +110,36 @@ class Project &lt; ActiveRecord::Base @@ -118,14 +110,36 @@ class Project &lt; ActiveRecord::Base
118 scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") } 110 scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
119 scope :personal, ->(user) { where(namespace_id: user.namespace_id) } 111 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
120 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } 112 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
121 -  
122 scope :public_only, -> { where(visibility_level: Project::PUBLIC) } 113 scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
123 scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) } 114 scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
124 -  
125 scope :non_archived, -> { where(archived: false) } 115 scope :non_archived, -> { where(archived: false) }
126 116
127 enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab 117 enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
128 118
  119 + state_machine :import_status, initial: :none do
  120 + event :import_start do
  121 + transition :none => :started
  122 + end
  123 +
  124 + event :import_finish do
  125 + transition :started => :finished
  126 + end
  127 +
  128 + event :import_fail do
  129 + transition :started => :failed
  130 + end
  131 +
  132 + event :import_retry do
  133 + transition :failed => :started
  134 + end
  135 +
  136 + state :started
  137 + state :finished
  138 + state :failed
  139 +
  140 + after_transition any => :started, :do => :add_import_job
  141 + end
  142 +
129 class << self 143 class << self
130 def public_and_internal_levels 144 def public_and_internal_levels
131 [Project::PUBLIC, Project::INTERNAL] 145 [Project::PUBLIC, Project::INTERNAL]
@@ -164,15 +178,13 @@ class Project &lt; ActiveRecord::Base @@ -164,15 +178,13 @@ class Project &lt; ActiveRecord::Base
164 end 178 end
165 179
166 def find_with_namespace(id) 180 def find_with_namespace(id)
167 - if id.include?("/")  
168 - id = id.split("/")  
169 - namespace = Namespace.find_by(path: id.first)  
170 - return nil unless namespace  
171 -  
172 - where(namespace_id: namespace.id).find_by(path: id.second)  
173 - else  
174 - where(path: id, namespace_id: nil).last  
175 - end 181 + return nil unless id.include?("/")
  182 +
  183 + id = id.split("/")
  184 + namespace = Namespace.find_by(path: id.first)
  185 + return nil unless namespace
  186 +
  187 + where(namespace_id: namespace.id).find_by(path: id.second)
176 end 188 end
177 189
178 def visibility_levels 190 def visibility_levels
@@ -202,12 +214,28 @@ class Project &lt; ActiveRecord::Base @@ -202,12 +214,28 @@ class Project &lt; ActiveRecord::Base
202 id && persisted? 214 id && persisted?
203 end 215 end
204 216
  217 + def add_import_job
  218 + RepositoryImportWorker.perform_in(2.seconds, id)
  219 + end
  220 +
205 def import? 221 def import?
206 import_url.present? 222 import_url.present?
207 end 223 end
208 224
209 def imported? 225 def imported?
210 - imported 226 + import_finished?
  227 + end
  228 +
  229 + def import_in_progress?
  230 + import? && import_status == 'started'
  231 + end
  232 +
  233 + def import_failed?
  234 + import_status == 'failed'
  235 + end
  236 +
  237 + def import_finished?
  238 + import_status == 'finished'
211 end 239 end
212 240
213 def check_limit 241 def check_limit
@@ -277,7 +305,7 @@ class Project &lt; ActiveRecord::Base @@ -277,7 +305,7 @@ class Project &lt; ActiveRecord::Base
277 end 305 end
278 306
279 def available_services_names 307 def available_services_names
280 - %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)
281 end 309 end
282 310
283 def gitlab_ci? 311 def gitlab_ci?
@@ -361,18 +389,17 @@ class Project &lt; ActiveRecord::Base @@ -361,18 +389,17 @@ class Project &lt; ActiveRecord::Base
361 branch_name = ref.gsub("refs/heads/", "") 389 branch_name = ref.gsub("refs/heads/", "")
362 c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) 390 c_ids = self.repository.commits_between(oldrev, newrev).map(&:id)
363 391
  392 + # Close merge requests
  393 + mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a
  394 + mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }
  395 + mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }
  396 +
364 # Update code for merge requests into project between project branches 397 # Update code for merge requests into project between project branches
365 mrs = self.merge_requests.opened.by_branch(branch_name).to_a 398 mrs = self.merge_requests.opened.by_branch(branch_name).to_a
366 # Update code for merge requests between project and project fork 399 # Update code for merge requests between project and project fork
367 mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a 400 mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
368 -  
369 mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } 401 mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked }
370 402
371 - # Close merge requests  
372 - mrs = self.merge_requests.opened.where(target_branch: branch_name).to_a  
373 - mrs = mrs.select(&:last_commit).select { |mr| c_ids.include?(mr.last_commit.id) }  
374 - mrs.each { |merge_request| MergeRequests::MergeService.new.execute(merge_request, user, nil) }  
375 -  
376 true 403 true
377 end 404 end
378 405
app/models/project_hook.rb
@@ -17,9 +17,10 @@ @@ -17,9 +17,10 @@
17 class ProjectHook < WebHook 17 class ProjectHook < WebHook
18 belongs_to :project 18 belongs_to :project
19 19
20 - attr_accessible :push_events, :issues_events, :merge_requests_events 20 + attr_accessible :push_events, :issues_events, :merge_requests_events, :tag_push_events
21 21
22 scope :push_hooks, -> { where(push_events: true) } 22 scope :push_hooks, -> { where(push_events: true) }
  23 + scope :tag_push_hooks, -> { where(tag_push_events: true) }
23 scope :issue_hooks, -> { where(issues_events: true) } 24 scope :issue_hooks, -> { where(issues_events: true) }
24 scope :merge_request_hooks, -> { where(merge_requests_events: true) } 25 scope :merge_request_hooks, -> { where(merge_requests_events: true) }
25 end 26 end
app/models/project_services/slack_message.rb 0 → 100644
@@ -0,0 +1,95 @@ @@ -0,0 +1,95 @@
  1 +require 'slack-notifier'
  2 +
  3 +class SlackMessage
  4 + def initialize(params)
  5 + @after = params.fetch(:after)
  6 + @before = params.fetch(:before)
  7 + @commits = params.fetch(:commits, [])
  8 + @project_name = params.fetch(:project_name)
  9 + @project_url = params.fetch(:project_url)
  10 + @ref = params.fetch(:ref).gsub('refs/heads/', '')
  11 + @username = params.fetch(:user_name)
  12 + end
  13 +
  14 + def compose
  15 + format(message)
  16 + end
  17 +
  18 + private
  19 +
  20 + attr_reader :after
  21 + attr_reader :before
  22 + attr_reader :commits
  23 + attr_reader :project_name
  24 + attr_reader :project_url
  25 + attr_reader :ref
  26 + attr_reader :username
  27 +
  28 + def message
  29 + if new_branch?
  30 + new_branch_message
  31 + elsif removed_branch?
  32 + removed_branch_message
  33 + else
  34 + push_message << commit_messages
  35 + end
  36 + end
  37 +
  38 + def format(string)
  39 + Slack::Notifier::LinkFormatter.format(string)
  40 + end
  41 +
  42 + def new_branch_message
  43 + "#{username} pushed new branch #{branch_link} to #{project_link}"
  44 + end
  45 +
  46 + def removed_branch_message
  47 + "#{username} removed branch #{ref} from #{project_link}"
  48 + end
  49 +
  50 + def push_message
  51 + "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
  52 + end
  53 +
  54 + def commit_messages
  55 + commits.each_with_object('') do |commit, str|
  56 + str << compose_commit_message(commit)
  57 + end
  58 + end
  59 +
  60 + def compose_commit_message(commit)
  61 + id = commit.fetch(:id)[0..5]
  62 + message = commit.fetch(:message)
  63 + url = commit.fetch(:url)
  64 +
  65 + "\n - #{message} ([#{id}](#{url}))"
  66 + end
  67 +
  68 + def new_branch?
  69 + before =~ /000000/
  70 + end
  71 +
  72 + def removed_branch?
  73 + after =~ /000000/
  74 + end
  75 +
  76 + def branch_url
  77 + "#{project_url}/commits/#{ref}"
  78 + end
  79 +
  80 + def compare_url
  81 + "#{project_url}/compare/#{before}...#{after}"
  82 + end
  83 +
  84 + def branch_link
  85 + "[#{ref}](#{branch_url})"
  86 + end
  87 +
  88 + def project_link
  89 + "[#{project_name}](#{project_url})"
  90 + end
  91 +
  92 + def compare_link
  93 + "[Compare changes](#{compare_url})"
  94 + end
  95 +end
app/models/project_services/slack_service.rb 0 → 100644
@@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
  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.ping(message.compose)
  56 + end
  57 +
  58 + private
  59 +
  60 + def project_name
  61 + project.name_with_namespace.gsub(/\s/, '')
  62 + end
  63 +
  64 + def project_url
  65 + project.web_url
  66 + end
  67 +end
app/models/snippet.rb
@@ -20,6 +20,8 @@ class Snippet &lt; ActiveRecord::Base @@ -20,6 +20,8 @@ class Snippet &lt; ActiveRecord::Base
20 20
21 attr_accessible :title, :content, :file_name, :expires_at, :private 21 attr_accessible :title, :content, :file_name, :expires_at, :private
22 22
  23 + default_value_for :private, true
  24 +
23 belongs_to :author, class_name: "User" 25 belongs_to :author, class_name: "User"
24 26
25 has_many :notes, as: :noteable, dependent: :destroy 27 has_many :notes, as: :noteable, dependent: :destroy
app/models/user.rb
@@ -185,7 +185,7 @@ class User &lt; ActiveRecord::Base @@ -185,7 +185,7 @@ class User &lt; ActiveRecord::Base
185 where(conditions).first 185 where(conditions).first
186 end 186 end
187 end 187 end
188 - 188 +
189 def find_for_commit(email, name) 189 def find_for_commit(email, name)
190 # Prefer email match over name match 190 # Prefer email match over name match
191 User.where(email: email).first || 191 User.where(email: email).first ||
@@ -249,7 +249,7 @@ class User &lt; ActiveRecord::Base @@ -249,7 +249,7 @@ class User &lt; ActiveRecord::Base
249 def namespace_uniq 249 def namespace_uniq
250 namespace_name = self.username 250 namespace_name = self.username
251 if Namespace.find_by(path: namespace_name) 251 if Namespace.find_by(path: namespace_name)
252 - self.errors.add :username, "already exist" 252 + self.errors.add :username, "already exists"
253 end 253 end
254 end 254 end
255 255
@@ -275,7 +275,9 @@ class User &lt; ActiveRecord::Base @@ -275,7 +275,9 @@ class User &lt; ActiveRecord::Base
275 # Projects user has access to 275 # Projects user has access to
276 def authorized_projects 276 def authorized_projects
277 @authorized_projects ||= begin 277 @authorized_projects ||= begin
278 - project_ids = (personal_projects.pluck(:id) + groups_projects.pluck(:id) + projects.pluck(:id)).uniq 278 + project_ids = personal_projects.pluck(:id)
  279 + project_ids += groups_projects.pluck(:id)
  280 + project_ids += projects.pluck(:id).uniq
279 Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC') 281 Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC')
280 end 282 end
281 end 283 end
@@ -406,6 +408,14 @@ class User &lt; ActiveRecord::Base @@ -406,6 +408,14 @@ class User &lt; ActiveRecord::Base
406 end 408 end
407 end 409 end
408 410
  411 + def requires_ldap_check?
  412 + if ldap_user?
  413 + !last_credential_check_at || (last_credential_check_at + 1.hour) < Time.now
  414 + else
  415 + false
  416 + end
  417 + end
  418 +
409 def solo_owned_groups 419 def solo_owned_groups
410 @solo_owned_groups ||= owned_groups.select do |group| 420 @solo_owned_groups ||= owned_groups.select do |group|
411 group.owners == [self] 421 group.owners == [self]
app/observers/project_observer.rb
1 class ProjectObserver < BaseObserver 1 class ProjectObserver < BaseObserver
2 def after_create(project) 2 def after_create(project)
3 - project.update_column(:last_activity_at, project.created_at)  
4 -  
5 - return true if project.forked?  
6 -  
7 - if project.import?  
8 - RepositoryImportWorker.perform_in(5.seconds, project.id)  
9 - else  
10 - GitlabShellWorker.perform_async(  
11 - :add_repository,  
12 - project.path_with_namespace  
13 - )  
14 -  
15 - log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")  
16 - end  
17 -  
18 - if project.wiki_enabled?  
19 - begin  
20 - # force the creation of a wiki,  
21 - GollumWiki.new(project, project.owner).wiki  
22 - rescue GollumWiki::CouldNotCreateWikiError => ex  
23 - # Prevent project observer crash  
24 - # if failed to create wiki  
25 - nil  
26 - end  
27 - end 3 + log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
28 end 4 end
29 5
30 def after_update(project) 6 def after_update(project)
app/services/git_tag_push_service.rb 0 → 100644
@@ -0,0 +1,40 @@ @@ -0,0 +1,40 @@
  1 +class GitTagPushService
  2 + attr_accessor :project, :user, :push_data
  3 +
  4 + def execute(project, user, oldrev, newrev, ref)
  5 + @project, @user = project, user
  6 + @push_data = create_push_data(oldrev, newrev, ref)
  7 +
  8 + create_push_event
  9 + project.repository.expire_cache
  10 + project.execute_hooks(@push_data.dup, :tag_push_hooks)
  11 + end
  12 +
  13 + private
  14 +
  15 + def create_push_data(oldrev, newrev, ref)
  16 + data = {
  17 + ref: ref,
  18 + before: oldrev,
  19 + after: newrev,
  20 + user_id: user.id,
  21 + user_name: user.name,
  22 + project_id: project.id,
  23 + repository: {
  24 + name: project.name,
  25 + url: project.url_to_repo,
  26 + description: project.description,
  27 + homepage: project.web_url
  28 + }
  29 + }
  30 + end
  31 +
  32 + def create_push_event
  33 + Event.create!(
  34 + project: project,
  35 + action: Event::PUSHED,
  36 + data: push_data,
  37 + author_id: push_data[:user_id]
  38 + )
  39 + end
  40 +end
app/services/merge_requests/auto_merge_service.rb
@@ -12,7 +12,7 @@ module MergeRequests @@ -12,7 +12,7 @@ module MergeRequests
12 merge_request.author_id_of_changes = current_user.id 12 merge_request.author_id_of_changes = current_user.id
13 merge_request.merge 13 merge_request.merge
14 14
15 - notification.merge_mr(merge_request) 15 + notification.merge_mr(merge_request, current_user)
16 create_merge_event(merge_request) 16 create_merge_event(merge_request)
17 execute_project_hooks(merge_request) 17 execute_project_hooks(merge_request)
18 18
app/services/merge_requests/merge_service.rb
@@ -10,7 +10,7 @@ module MergeRequests @@ -10,7 +10,7 @@ module MergeRequests
10 merge_request.author_id_of_changes = current_user.id 10 merge_request.author_id_of_changes = current_user.id
11 merge_request.merge 11 merge_request.merge
12 12
13 - notification.merge_mr(merge_request) 13 + notification.merge_mr(merge_request, current_user)
14 create_merge_event(merge_request) 14 create_merge_event(merge_request)
15 execute_project_hooks(merge_request) 15 execute_project_hooks(merge_request)
16 16
app/services/notification_service.rb
@@ -86,12 +86,12 @@ class NotificationService @@ -86,12 +86,12 @@ class NotificationService
86 # * merge_request assignee if their notification level is not Disabled 86 # * merge_request assignee if their notification level is not Disabled
87 # * project team members with notification level higher then Participating 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 recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project) 90 recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
91 recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq 91 recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
92 92
93 recipients.each do |recipient| 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 end 95 end
96 end 96 end
97 97
@@ -111,6 +111,7 @@ class NotificationService @@ -111,6 +111,7 @@ class NotificationService
111 111
112 # ignore gitlab service messages 112 # ignore gitlab service messages
113 return true if note.note =~ /\A_Status changed to closed_/ 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 opts = { noteable_type: note.noteable_type, project_id: note.project_id } 116 opts = { noteable_type: note.noteable_type, project_id: note.project_id }
116 117
app/services/projects/create_service.rb
@@ -58,6 +58,29 @@ module Projects @@ -58,6 +58,29 @@ module Projects
58 user: current_user 58 user: current_user
59 ) 59 )
60 end 60 end
  61 +
  62 + @project.update_column(:last_activity_at, @project.created_at)
  63 +
  64 + if @project.import?
  65 + @project.import_start
  66 + else
  67 + GitlabShellWorker.perform_async(
  68 + :add_repository,
  69 + @project.path_with_namespace
  70 + )
  71 +
  72 + end
  73 +
  74 + if @project.wiki_enabled?
  75 + begin
  76 + # force the creation of a wiki,
  77 + GollumWiki.new(@project, @project.owner).wiki
  78 + rescue GollumWiki::CouldNotCreateWikiError => ex
  79 + # Prevent project observer crash
  80 + # if failed to create wiki
  81 + nil
  82 + end
  83 + end
61 end 84 end
62 85
63 @project 86 @project
app/services/search/global_service.rb
@@ -14,10 +14,9 @@ module Search @@ -14,10 +14,9 @@ module Search
14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present? 14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
15 projects = Project.accessible_to(current_user) 15 projects = Project.accessible_to(current_user)
16 projects = projects.where(namespace_id: group.id) if group 16 projects = projects.where(namespace_id: group.id) if group
17 - projects = projects.search(query)  
18 project_ids = projects.pluck(:id) 17 project_ids = projects.pluck(:id)
19 18
20 - result[:projects] = projects.limit(20) 19 + result[:projects] = projects.search(query).limit(20)
21 result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20) 20 result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20)
22 result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20) 21 result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20)
23 result[:total_results] = %w(projects issues merge_requests).sum { |items| result[items.to_sym].size } 22 result[:total_results] = %w(projects issues merge_requests).sum { |items| result[items.to_sym].size }
app/views/admin/background_jobs/show.html.haml
@@ -14,27 +14,21 @@ @@ -14,27 +14,21 @@
14 %table.table 14 %table.table
15 %thead 15 %thead
16 %th USER 16 %th USER
17 - %th  
18 %th PID 17 %th PID
19 - %th  
20 %th CPU 18 %th CPU
21 - %th  
22 %th MEM 19 %th MEM
23 - %th  
24 %th STATE 20 %th STATE
25 - %th  
26 %th START 21 %th START
27 - %th  
28 %th COMMAND 22 %th COMMAND
29 - %th  
30 - - @sidekiq_processes.split("\n").each do |process| 23 + %tbody
  24 + - @sidekiq_processes.each do |process|
31 - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/) 25 - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
32 - - data = process.gsub!(/\s+/m, '|').strip.split('|') 26 + - data = process.strip.split(' ')
33 %tr 27 %tr
34 - - 6.times do 28 + %td= Settings.gitlab.user
  29 + - 5.times do
35 %td= data.shift 30 %td= data.shift
36 - %td  
37 - %td= data.join(" ") 31 + %td= data.join(' ')
38 32
39 .clearfix 33 .clearfix
40 %p 34 %p
app/views/dashboard/_zero_authorized_projects.html.haml
@@ -34,3 +34,18 @@ @@ -34,3 +34,18 @@
34 = link_to new_group_path, class: "btn btn-new" do 34 = link_to new_group_path, class: "btn btn-new" do
35 New group » 35 New group »
36 36
  37 +-if @publicish_project_count > 0
  38 + %hr
  39 + %div
  40 + .dashboard-intro-icon
  41 + %i.icon-globe
  42 + %div
  43 + %p.slead
  44 + There are
  45 + %strong= @publicish_project_count
  46 + public projects on this server.
  47 + %br
  48 + Public projects are an easy way to allow everyone to have read-only access.
  49 + .link_holder
  50 + = link_to public_projects_path, class: "btn btn-new" do
  51 + Browse public projects »
app/views/devise/sessions/_oauth_providers.html.haml
@@ -2,10 +2,12 @@ @@ -2,10 +2,12 @@
2 - if providers.present? 2 - if providers.present?
3 %hr 3 %hr
4 %div{:'data-no-turbolink' => 'data-no-turbolink'} 4 %div{:'data-no-turbolink' => 'data-no-turbolink'}
5 - %span Sign in with: &nbsp; 5 + %span Sign in with*: &nbsp;
6 - providers.each do |provider| 6 - providers.each do |provider|
7 %span 7 %span
8 - if default_providers.include?(provider) 8 - if default_providers.include?(provider)
9 = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider) 9 = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
10 - else 10 - else
11 = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn" 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/groups/members.html.haml
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 9
10 %hr 10 %hr
11 11
12 -.clearfix 12 +.clearfix.js-toggle-container
13 = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do 13 = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
14 .form-group 14 .form-group
15 = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' } 15 = search_field_tag :search, params[:search], { placeholder: 'Find member by name', class: 'form-control search-text-input input-mn-300' }
@@ -17,11 +17,11 @@ @@ -17,11 +17,11 @@
17 17
18 - if current_user && current_user.can?(:manage_group, @group) 18 - if current_user && current_user.can?(:manage_group, @group)
19 .pull-right 19 .pull-right
20 - = link_to '#', class: 'btn btn-new js-toggle-visibility-link' do 20 + = link_to '#', class: 'btn btn-new js-toggle-button' do
21 Add members 21 Add members
22 %i.icon-chevron-down 22 %i.icon-chevron-down
23 23
24 - .js-toggle-visibility-container.hide.new-group-member-holder 24 + .js-toggle-content.hide.new-group-member-holder
25 = render "new_group_member" 25 = render "new_group_member"
26 26
27 .ui-box.prepend-top-20 27 .ui-box.prepend-top-20
app/views/layouts/_head.html.haml
@@ -4,7 +4,8 @@ @@ -4,7 +4,8 @@
4 = "#{title} | " if defined?(title) 4 = "#{title} | " if defined?(title)
5 GitLab 5 GitLab
6 = favicon_link_tag 'favicon.ico' 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 = javascript_include_tag "application" 9 = javascript_include_tag "application"
9 = csrf_meta_tags 10 = csrf_meta_tags
10 = include_gon 11 = include_gon
app/views/layouts/_head_panel.html.haml
@@ -15,10 +15,6 @@ @@ -15,10 +15,6 @@
15 .navbar-collapse.collapse 15 .navbar-collapse.collapse
16 %ul.nav.navbar-nav 16 %ul.nav.navbar-nav
17 %li.hidden-sm.hidden-xs 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 = render "layouts/search" 18 = render "layouts/search"
23 %li.visible-sm.visible-xs 19 %li.visible-sm.visible-xs
24 = link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do 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 :javascript 1 :javascript
2 GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}" 2 GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}"
3 - GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + '/assets/emoji'}"  
4 GitLab.GfmAutoComplete.setup(); 3 GitLab.GfmAutoComplete.setup();
app/views/layouts/_public_head_panel.html.haml
@@ -8,11 +8,15 @@ @@ -8,11 +8,15 @@
8 %span.separator 8 %span.separator
9 %h1.title= title 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 = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new' 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/notify.html.haml
@@ -3,20 +3,24 @@ @@ -3,20 +3,24 @@
3 %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"} 3 %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
4 %title 4 %title
5 GitLab 5 GitLab
  6 + :css
  7 + p.details {
  8 + font-style:italic;
  9 + color:#777
  10 + }
  11 + .footer p {
  12 + font-size:small;
  13 + color:#777
  14 + }
6 15
7 %body 16 %body
8 - %h1{style: "background: #EEE; border-bottom: 1px solid #DDD; color: #474D57; font: normal 20px Helvetica, Arial, sans-serif; margin: 0; padding: 5px 10px; line-height: 32px; font-size: 16px;"}  
9 - GitLab  
10 - - if @project  
11 - \|  
12 - = link_to @project.name_with_namespace, project_url(@project), style: 'color: #29B; text-decoration: none'  
13 - %table{align: "left", border: "0", cellpadding: "0", cellspacing: "0", style: "padding: 10px 0;", width: "100%"}  
14 - %tr  
15 - %td{align: "left", style: "margin: 0; padding: 10px;"}  
16 - = yield  
17 - %br  
18 - %tr  
19 - %td{align: "left", style: "margin: 0; padding: 10px;"}  
20 - %p{style: "font-size:small;color:#777"}  
21 - - if @project  
22 - You're receiving this notification because you are a member of the #{@project.name_with_namespace} project team. 17 + %div.content
  18 + = yield
  19 + %div.footer{style: "margin-top: 10px;"}
  20 + %p
  21 + \—
  22 + %br
  23 + - if @project
  24 + You're receiving this notification because you are a member of the #{link_to @project.name_with_namespace, project_url(@project)} project team.
  25 + - if @target_url
  26 + #{link_to "View in GitLab", @target_url}
app/views/layouts/public_projects.html.haml
@@ -4,7 +4,7 @@ @@ -4,7 +4,7 @@
4 %body{class: "#{app_theme} application", :'data-page' => body_data_page} 4 %body{class: "#{app_theme} application", :'data-page' => body_data_page}
5 = render "layouts/broadcast" 5 = render "layouts/broadcast"
6 = render "layouts/public_head_panel", title: project_title(@project) 6 = render "layouts/public_head_panel", title: project_title(@project)
7 - %nav.main-nav 7 + %nav.main-nav.navbar-collapse.collapse
8 .container= render 'layouts/nav/project' 8 .container= render 'layouts/nav/project'
9 .container 9 .container
10 .content= yield 10 .content= yield
app/views/notify/_note_message.html.haml
1 -%p  
2 - %strong #{@note.author_name}  
3 - wrote:  
4 -  
5 -%cite{style: 'color: #666'} 1 +%div
6 = markdown(@note.note) 2 = markdown(@note.note)
app/views/notify/closed_issue_email.html.haml
1 %p 1 %p
2 = "Issue was closed by #{@updated_by.name}" 2 = "Issue was closed by #{@updated_by.name}"
3 -%p  
4 - = "Issue ##{@issue.iid}"  
5 - = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title  
app/views/notify/closed_merge_request_email.html.haml
1 %p 1 %p
2 - = "Merge Request #{@merge_request.iid} was closed by #{@updated_by.name}"  
3 -%p  
4 - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request)  
5 -%p  
6 - != merge_path_description(@merge_request, '&rarr;')  
7 -%p  
8 - Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}  
9 - 2 + = "Merge Request !#{@merge_request.iid} was closed by #{@updated_by.name}"
app/views/notify/group_access_granted_email.html.haml
1 %p 1 %p
2 = "You have been granted #{@membership.human_access} access to group" 2 = "You have been granted #{@membership.human_access} access to group"
3 -%p  
4 = link_to group_url(@group) do 3 = link_to group_url(@group) do
5 = @group.name 4 = @group.name
app/views/notify/issue_status_changed_email.html.haml
1 %p 1 %p
2 = "Issue was #{@issue_status} by #{@updated_by.name}" 2 = "Issue was #{@issue_status} by #{@updated_by.name}"
3 -%p  
4 - = "Issue ##{@issue.iid}"  
5 - = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title  
app/views/notify/merged_merge_request_email.html.haml
1 %p 1 %p
2 - = "Merge Request #{@merge_request.iid} was merged"  
3 -%p  
4 - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request)  
5 -%p  
6 - != merge_path_description(@merge_request, '&rarr;')  
7 -%p  
8 - Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}  
9 - 2 + = "Merge Request !#{@merge_request.iid} was merged"
app/views/notify/new_issue_email.html.haml
1 -%p  
2 - New Issue was created.  
3 -%p  
4 - = "Issue ##{@issue.iid}"  
5 - = link_to_gfm truncate(@issue.title, length: 45), project_issue_url(@issue.project, @issue), title: @issue.title  
6 -%p  
7 - Author: #{@issue.author_name}  
8 -%p  
9 - Assignee: #{@issue.assignee_name} 1 +-if @issue.description
  2 + = markdown(@issue.description)
  3 +
  4 +- if @issue.assignee_id.present?
  5 + %p
  6 + Assignee: #{@issue.assignee_name}
app/views/notify/new_merge_request_email.html.haml
1 -%p  
2 - = "New Merge Request ##{@merge_request.iid}"  
3 -%p  
4 - = link_to_gfm truncate(@merge_request.title, length: 40), project_merge_request_url(@merge_request.target_project, @merge_request)  
5 -%p 1 +%p.details
6 != merge_path_description(@merge_request, '&rarr;') 2 != merge_path_description(@merge_request, '&rarr;')
7 -%p  
8 - Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}  
9 3
  4 +- if @merge_request.assignee_id.present?
  5 + %p
  6 + Assignee: #{@merge_request.author_name} &rarr; #{@merge_request.assignee_name}
  7 +
  8 +-if @merge_request.description
  9 + = markdown(@merge_request.description)
app/views/notify/note_commit_email.html.haml
1 -%p  
2 - = "New comment for Commit #{@commit.short_id}"  
3 - = link_to_gfm truncate(@commit.title, length: 16), project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}")  
4 = render 'note_message' 1 = render 'note_message'
5 2
app/views/notify/note_issue_email.html.haml
1 -%p  
2 - = "New comment for Issue ##{@issue.iid}"  
3 - = link_to_gfm truncate(@issue.title, length: 35), project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")  
4 = render 'note_message' 1 = render 'note_message'
app/views/notify/note_merge_request_email.html.haml
1 -%p  
2 - - if @note.for_diff_line?  
3 - = link_to "New comment on diff", diffs_project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}")  
4 - - else  
5 - = link_to "New comment", project_merge_request_url(@merge_request.target_project, @merge_request, anchor: "note_#{@note.id}")  
6 - for Merge Request ##{@merge_request.iid}  
7 - %cite "#{truncate(@merge_request.title, length: 20)}" 1 +- if @note.diff_file_name
  2 + %p.details
  3 + New comment on diff for
  4 + = link_to @note.diff_file_name, @target_url
  5 + \:
  6 +
8 = render 'note_message' 7 = render 'note_message'
app/views/notify/note_wall_email.html.haml
1 -%p  
2 - New message on  
3 - = link_to "Project Wall", project_wall_url(@note.project, anchor: "note_#{@note.id}")  
4 -  
5 = render 'note_message' 1 = render 'note_message'
app/views/notify/reassigned_issue_email.html.haml
1 %p 1 %p
2 - = "Reassigned Issue ##{@issue.iid}"  
3 - = link_to_gfm truncate(@issue.title, length: 30), project_issue_url(@issue.project, @issue)  
4 -%p  
5 Assignee changed 2 Assignee changed
6 - if @previous_assignee 3 - if @previous_assignee
7 from 4 from
app/views/notify/reassigned_merge_request_email.html.haml
1 %p 1 %p
2 - = "Reassigned Merge Request ##{@merge_request.iid}"  
3 - = link_to_gfm truncate(@merge_request.title, length: 30), project_merge_request_url(@merge_request.target_project, @merge_request)  
4 -%p  
5 Assignee changed 2 Assignee changed
6 - if @previous_assignee 3 - if @previous_assignee
7 from 4 from
app/views/projects/commit/_commit_box.html.haml
1 .pull-right 1 .pull-right
2 %div 2 %div
3 - if @notes_count > 0 3 - if @notes_count > 0
4 - %span.btn.disabled.grouped 4 + %span.btn.disabled.btn-grouped
5 %i.icon-comment 5 %i.icon-comment
6 = @notes_count 6 = @notes_count
7 .pull-left.btn-group 7 .pull-left.btn-group
@@ -47,7 +47,7 @@ @@ -47,7 +47,7 @@
47 - if @branches.any? 47 - if @branches.any?
48 and in 48 and in
49 = link_to("#{pluralize(@branches.count, "other branch")}", "#", class: "js-details-expand") 49 = link_to("#{pluralize(@branches.count, "other branch")}", "#", class: "js-details-expand")
50 - %span.js-details-contain.hide 50 + %span.js-details-content.hide
51 = commit_branches_links(@project, @branches) 51 = commit_branches_links(@project, @branches)
52 52
53 .commit-box 53 .commit-box
app/views/projects/commits/_diffs.html.haml
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 - file = project.repository.blob_at(@commit.id, diff.new_path) 44 - file = project.repository.blob_at(@commit.id, diff.new_path)
45 - file = project.repository.blob_at(@commit.parent_id, diff.old_path) unless file 45 - file = project.repository.blob_at(@commit.parent_id, diff.old_path) unless file
46 - next unless file 46 - next unless file
47 - .diff-file{id: "diff-#{i}"} 47 + .diff-file.js-toggle-container{id: "diff-#{i}"}
48 .diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"} 48 .diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"}
49 - if diff.deleted_file 49 - if diff.deleted_file
50 %span= diff.old_path 50 %span= diff.old_path
@@ -60,6 +60,11 @@ @@ -60,6 +60,11 @@
60 %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}" 60 %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
61 61
62 .diff-btn-group 62 .diff-btn-group
  63 + = link_to "#", class: "js-toggle-button btn btn-small" do
  64 + %i.icon-chevron-down
  65 + Diff comments
  66 + &nbsp;
  67 +
63 - if @merge_request && @merge_request.source_project 68 - if @merge_request && @merge_request.source_project
64 = link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do 69 = link_to project_edit_tree_path(@merge_request.source_project, tree_join(@merge_request.source_branch, diff.new_path), from_merge_request_id: @merge_request.id), { class: 'btn btn-small' } do
65 Edit 70 Edit
app/views/projects/create.js.haml
1 - if @project.saved? 1 - if @project.saved?
2 - :plain  
3 - location.href = "#{project_path(@project)}"; 2 + - if @project.import?
  3 + :plain
  4 + location.href = "#{import_project_path(@project)}";
  5 + - else
  6 + :plain
  7 + location.href = "#{project_path(@project)}";
4 - else 8 - else
5 :plain 9 :plain
6 $(".project-edit-errors").html("#{escape_javascript(render('errors'))}"); 10 $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
app/views/projects/edit.html.haml
@@ -93,100 +93,101 @@ @@ -93,100 +93,101 @@
93 93
94 94
95 95
96 - .centered-light-block  
97 - %h3  
98 - %i.icon-warning-sign  
99 - Dangerous settings  
100 -  
101 - %p Project settings below may result in data loss!  
102 - = link_to '#', class: 'btn js-toggle-visibility-link' do  
103 - Show it to me  
104 - %i.icon-chevron-down  
105 -  
106 - .js-toggle-visibility-container.hide  
107 - - if can? current_user, :archive_project, @project  
108 - .ui-box.ui-box-danger  
109 - .title  
110 - - if @project.archived?  
111 - Unarchive project  
112 - - else  
113 - Archive project  
114 - .body  
115 - - if @project.archived?  
116 - %p  
117 - Unarchiving the project will mark its repository as active.  
118 - %br  
119 - The project can be committed to.  
120 - %br  
121 - %strong Once active this project shows up in the search and on the dashboard.  
122 - = link_to 'Unarchive', unarchive_project_path(@project),  
123 - data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be comitted to again." },  
124 - method: :post, class: "btn btn-remove"  
125 - - else  
126 - %p  
127 - Archiving the project will mark its repository as read-only.  
128 - %br  
129 - It is hidden from the dashboard and doesn't show up in searches.  
130 - %br  
131 - %strong Archived projects cannot be committed to!  
132 - = link_to 'Archive', archive_project_path(@project),  
133 - data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },  
134 - method: :post, class: "btn btn-remove"  
135 - - else  
136 - .nothing-here-block Only the project owner can archive a project  
137 -  
138 - - if can?(current_user, :change_namespace, @project) 96 + .danger-settings.js-toggle-container
  97 + .centered-light-block
  98 + %h3
  99 + %i.icon-warning-sign
  100 + Dangerous settings
  101 +
  102 + %p Project settings below may result in data loss!
  103 + = link_to '#', class: 'btn js-toggle-button' do
  104 + Show it to me
  105 + %i.icon-chevron-down
  106 +
  107 + .js-toggle-content.hide
  108 + - if can? current_user, :archive_project, @project
  109 + .ui-box.ui-box-danger
  110 + .title
  111 + - if @project.archived?
  112 + Unarchive project
  113 + - else
  114 + Archive project
  115 + .body
  116 + - if @project.archived?
  117 + %p
  118 + Unarchiving the project will mark its repository as active.
  119 + %br
  120 + The project can be committed to.
  121 + %br
  122 + %strong Once active this project shows up in the search and on the dashboard.
  123 + = link_to 'Unarchive', unarchive_project_path(@project),
  124 + data: { confirm: "Are you sure that you want to unarchive this project?\nWhen this project is unarchived it is active and can be comitted to again." },
  125 + method: :post, class: "btn btn-remove"
  126 + - else
  127 + %p
  128 + Archiving the project will mark its repository as read-only.
  129 + %br
  130 + It is hidden from the dashboard and doesn't show up in searches.
  131 + %br
  132 + %strong Archived projects cannot be committed to!
  133 + = link_to 'Archive', archive_project_path(@project),
  134 + data: { confirm: "Are you sure that you want to archive this project?\nAn archived project cannot be committed to." },
  135 + method: :post, class: "btn btn-remove"
  136 + - else
  137 + .nothing-here-block Only the project owner can archive a project
  138 +
  139 + - if can?(current_user, :change_namespace, @project)
  140 + .ui-box.ui-box-danger
  141 + .title Transfer project
  142 + .errors-holder
  143 + .form-holder
  144 + = form_for(@project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f|
  145 + .form-group
  146 + = f.label :namespace_id, class: 'control-label' do
  147 + %span Namespace
  148 + .col-sm-10
  149 + .form-group
  150 + = f.select :namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace' }, { class: 'select2' }
  151 + %ul
  152 + %li Be careful. Changing the project's namespace can have unintended side effects.
  153 + %li You can only transfer the project to namespaces you manage.
  154 + %li You will need to update your local repositories to point to the new location.
  155 + .form-actions
  156 + = f.submit 'Transfer', class: "btn btn-remove"
  157 + - else
  158 + .nothing-here-block Only the project owner can transfer a project
  159 +
139 .ui-box.ui-box-danger 160 .ui-box.ui-box-danger
140 - .title Transfer project 161 + .title Rename repository
141 .errors-holder 162 .errors-holder
142 .form-holder 163 .form-holder
143 - = form_for(@project, url: transfer_project_path(@project), method: :put, remote: true, html: { class: 'transfer-project form-horizontal' }) do |f| 164 + = form_for(@project, html: { class: 'form-horizontal' }) do |f|
144 .form-group 165 .form-group
145 - = f.label :namespace_id, class: 'control-label' do  
146 - %span Namespace  
147 - .col-sm-10 166 + = f.label :path, class: 'control-label' do
  167 + %span Path
  168 + .col-sm-9
148 .form-group 169 .form-group
149 - = f.select :namespace_id, namespaces_options(@project.namespace_id), { prompt: 'Choose a project namespace' }, { class: 'select2' } 170 + .input-group
  171 + = f.text_field :path, class: 'form-control'
  172 + %span.input-group-addon .git
150 %ul 173 %ul
151 - %li Be careful. Changing the project's namespace can have unintended side effects.  
152 - %li You can only transfer the project to namespaces you manage. 174 + %li Be careful. Renaming a project's repository can have unintended side effects.
153 %li You will need to update your local repositories to point to the new location. 175 %li You will need to update your local repositories to point to the new location.
154 .form-actions 176 .form-actions
155 - = f.submit 'Transfer', class: "btn btn-remove"  
156 - - else  
157 - .nothing-here-block Only the project owner can transfer a project  
158 -  
159 - .ui-box.ui-box-danger  
160 - .title Rename repository  
161 - .errors-holder  
162 - .form-holder  
163 - = form_for(@project, html: { class: 'form-horizontal' }) do |f|  
164 - .form-group  
165 - = f.label :path, class: 'control-label' do  
166 - %span Path  
167 - .col-sm-9  
168 - .form-group  
169 - .input-group  
170 - = f.text_field :path, class: 'form-control'  
171 - %span.input-group-addon .git  
172 - %ul  
173 - %li Be careful. Renaming a project's repository can have unintended side effects.  
174 - %li You will need to update your local repositories to point to the new location.  
175 - .form-actions  
176 - = f.submit 'Rename', class: "btn btn-remove"  
177 -  
178 - - if can?(current_user, :remove_project, @project)  
179 - .ui-box.ui-box-danger  
180 - .title Remove project  
181 - .body  
182 - %p  
183 - Removing the project will delete its repository and all related resources including issues, merge requests etc.  
184 - %br  
185 - %strong Removed projects cannot be restored!  
186 -  
187 - = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project) }, method: :delete, class: "btn btn-remove"  
188 - - else  
189 - .nothing-here-block Only project owner can remove a project 177 + = f.submit 'Rename', class: "btn btn-remove"
  178 +
  179 + - if can?(current_user, :remove_project, @project)
  180 + .ui-box.ui-box-danger
  181 + .title Remove project
  182 + .body
  183 + %p
  184 + Removing the project will delete its repository and all related resources including issues, merge requests etc.
  185 + %br
  186 + %strong Removed projects cannot be restored!
  187 +
  188 + = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project) }, method: :delete, class: "btn btn-remove"
  189 + - else
  190 + .nothing-here-block Only project owner can remove a project
190 191
191 .save-project-loader.hide 192 .save-project-loader.hide
192 %center 193 %center
app/views/projects/empty.html.haml
1 = render "home_panel" 1 = render "home_panel"
2 2
3 -- if @project.import? && !@project.imported  
4 - .save-project-loader  
5 - %center  
6 - %h2  
7 - %i.icon-spinner.icon-spin  
8 - Importing repository.  
9 - %p.monospace git clone --bare #{@project.import_url}  
10 - %p Please wait while we import the repository for you. Refresh at will.  
11 - :javascript  
12 - new ProjectImport(); 3 +%div.git-empty
  4 + %fieldset
  5 + %legend Git global setup:
  6 + %pre.dark
  7 + :preserve
  8 + git config --global user.name "#{git_user_name}"
  9 + git config --global user.email "#{git_user_email}"
13 10
14 -- else  
15 - %div.git-empty  
16 - %fieldset  
17 - %legend Git global setup:  
18 - %pre.dark  
19 - :preserve  
20 - git config --global user.name "#{git_user_name}"  
21 - git config --global user.email "#{git_user_email}" 11 + %fieldset
  12 + %legend Create Repository
  13 + %pre.dark
  14 + :preserve
  15 + mkdir #{@project.path}
  16 + cd #{@project.path}
  17 + git init
  18 + touch README
  19 + git add README
  20 + git commit -m 'first commit'
  21 + git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
  22 + git push -u origin master
22 23
23 - %fieldset  
24 - %legend Create Repository  
25 - %pre.dark  
26 - :preserve  
27 - mkdir #{@project.path}  
28 - cd #{@project.path}  
29 - git init  
30 - touch README  
31 - git add README  
32 - git commit -m 'first commit'  
33 - git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}  
34 - git push -u origin master 24 + %fieldset
  25 + %legend Existing Git Repo?
  26 + %pre.dark
  27 + :preserve
  28 + cd existing_git_repo
  29 + git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}
  30 + git push -u origin master
35 31
36 - %fieldset  
37 - %legend Existing Git Repo?  
38 - %pre.dark  
39 - :preserve  
40 - cd existing_git_repo  
41 - git remote add origin #{ content_tag(:span, default_url_to_repo, class: 'clone')}  
42 - git push -u origin master  
43 -  
44 - - if can? current_user, :remove_project, @project  
45 - .prepend-top-20  
46 - = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right" 32 +- if can? current_user, :remove_project, @project
  33 + .prepend-top-20
  34 + = link_to 'Remove project', @project, data: { confirm: remove_project_message(@project)}, method: :delete, class: "btn btn-remove pull-right"
app/views/projects/hooks/index.html.haml
@@ -27,6 +27,13 @@ @@ -27,6 +27,13 @@
27 %p.light 27 %p.light
28 This url will be triggered by a push to the repository 28 This url will be triggered by a push to the repository
29 %div 29 %div
  30 + = f.check_box :tag_push_events, class: 'pull-left'
  31 + .prepend-left-20
  32 + = f.label :tag_push_events, class: 'list-label' do
  33 + %strong Tag push events
  34 + %p.light
  35 + This url will be triggered when a new tag is pushed to the repository
  36 + %div
30 = f.check_box :issues_events, class: 'pull-left' 37 = f.check_box :issues_events, class: 'pull-left'
31 .prepend-left-20 38 .prepend-left-20
32 = f.label :issues_events, class: 'list-label' do 39 = f.label :issues_events, class: 'list-label' do
@@ -56,6 +63,6 @@ @@ -56,6 +63,6 @@
56 .clearfix 63 .clearfix
57 %span.monospace= hook.url 64 %span.monospace= hook.url
58 %p 65 %p
59 - - %w(push_events issues_events merge_requests_events).each do |trigger| 66 + - %w(push_events tag_push_events issues_events merge_requests_events).each do |trigger|
60 - if hook.send(trigger) 67 - if hook.send(trigger)
61 %span.label.label-gray= trigger.titleize 68 %span.label.label-gray= trigger.titleize