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.

.rspec
1   ---color --drb
  1 +--color
... ...
CHANGELOG
... ... @@ -9,7 +9,40 @@ v 6.7.0
9 9 - Show contribution guide link for new issue form (Jeroen van Baarsen)
10 10 - Fix CI status for merge requests from fork
11 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 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 47 v 6.6.2
15 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 22  
23 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 34 Please send a merge request with a tested solution or a merge request with a failing test instead of opening an issue if you can. If you're unsure where to post, post to the [mailing list](https://groups.google.com/forum/#!forum/gitlabhq) or [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) first. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there.
32 35  
... ... @@ -48,7 +51,7 @@ Please send a merge request with a tested solution or a merge request with a fai
48 51  
49 52 ## Merge requests
50 53  
51   -We welcome merge requests with fixes and improvements to GitLab code, tests, and/or documentation. The features we would really like a merge request for are listed with the [status 'accepting merge requests' on our feedback forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI.
  54 +We welcome merge requests with fixes and improvements to GitLab code, tests, and/or documentation. The features we would really like a merge request for are listed with the [status 'accepting merge requests' on our feature request forum](http://feedback.gitlab.com/forums/176466-general/status/796455) but other improvements are also welcome. If you want to add a new feature that is not marked it is best to first create a feedback issue (if there isn't one already) and leave a comment asking for it to be marked accepting merge requests. Please include screenshots or wireframes if the feature will also change the UI.
52 55  
53 56 ### Merge request guidelines
54 57  
... ... @@ -64,7 +67,7 @@ If you can, please submit a merge request with the fix or improvements including
64 67 1. The MR title should describes the change you want to make
65 68 1. The MR description should give a motive for your change and the method you used to achieve it
66 69 1. If the MR changes the UI it should include before and after screenshots
67   -1. Link relevant [issues](https://gitlab.com/gitlab-org/gitlab-ce/issues) and/or [feedback items](http://feedback.gitlab.com/) from the merge request description and leave a comment on them with a link back to the MR
  70 +1. 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 71 1. Be prepared to answer questions and incorporate feedback even if requests for this arrive weeks or months after your MR submittion
69 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 77  
75 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 88 ## Contribution acceptance criteria
78 89  
79 90 1. The change is as small as possible (see the above paragraph for details)
... ...
Gemfile
... ... @@ -48,7 +48,8 @@ gem "gitlab-linguist", "~> 3.0.0", require: "linguist"
48 48  
49 49 # API
50 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 53 gem 'rack-cors', require: 'rack/cors'
53 54  
54 55 # Email validation
... ... @@ -131,6 +132,9 @@ gem "gitlab-flowdock-git-hook", "~> 0.4.2"
131 132 # Gemnasium integration
132 133 gem "gemnasium-gitlab-service", "~> 0.2"
133 134  
  135 +# Slack integration
  136 +gem "slack-notifier", "~> 0.2.0"
  137 +
134 138 # d3
135 139 gem "d3_rails", "~> 3.1.4"
136 140  
... ... @@ -161,8 +165,9 @@ gem "modernizr", "2.6.2"
161 165 gem "raphael-rails", "~> 2.1.2"
162 166 gem 'bootstrap-sass', '~> 3.0'
163 167 gem "font-awesome-rails", '~> 3.2'
164   -gem "gemoji", "~> 1.3.0"
  168 +gem "gitlab_emoji", "~> 0.0.1.1"
165 169 gem "gon", '~> 5.0.0'
  170 +gem 'nprogress-rails'
166 171  
167 172 group :development do
168 173 gem "annotate", "~> 2.6.0.beta2"
... ... @@ -213,7 +218,6 @@ group :development, :test do
213 218 # PhantomJS driver for Capybara
214 219 gem 'poltergeist', '~> 1.4.1'
215 220  
216   - gem 'spork', '~> 1.0rc'
217 221 gem 'jasmine', '2.0.0.rc5'
218 222  
219 223 gem "spring", '1.1.1'
... ...
Gemfile.lock
... ... @@ -5,6 +5,15 @@ GIT
5 5 specs:
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 17 GEM
9 18 remote: https://rubygems.org/
10 19 specs:
... ... @@ -119,6 +128,8 @@ GEM
119 128 mail (~> 2.2)
120 129 email_validator (1.4.0)
121 130 activemodel
  131 + emoji (1.0.1)
  132 + json
122 133 enumerize (0.7.0)
123 134 activesupport (>= 3.2)
124 135 equalizer (0.0.8)
... ... @@ -156,7 +167,6 @@ GEM
156 167 formatador (0.2.4)
157 168 gemnasium-gitlab-service (0.2.1)
158 169 rugged (~> 0.19)
159   - gemoji (1.3.1)
160 170 gherkin-ruby (0.3.1)
161 171 racc
162 172 github-markdown (0.5.5)
... ... @@ -181,6 +191,8 @@ GEM
181 191 charlock_holmes (~> 0.6.6)
182 192 escape_utils (~> 0.2.4)
183 193 mime-types (~> 1.19)
  194 + gitlab_emoji (0.0.1.1)
  195 + emoji (~> 1.0.1)
184 196 gitlab_git (5.7.1)
185 197 activesupport (~> 4.0.0)
186 198 charlock_holmes (~> 0.6.9)
... ... @@ -206,9 +218,6 @@ GEM
206 218 rack-accept
207 219 rack-mount
208 220 virtus (>= 1.0.0)
209   - grape-entity (0.3.0)
210   - activesupport
211   - multi_json (>= 1.3.2)
212 221 growl (1.0.3)
213 222 guard (2.2.4)
214 223 formatador (>= 0.2.4)
... ... @@ -235,7 +244,7 @@ GEM
235 244 httparty
236 245 httparty
237 246 http_parser.rb (0.5.3)
238   - httparty (0.12.0)
  247 + httparty (0.13.0)
239 248 json (~> 1.8)
240 249 multi_xml (>= 0.5.2)
241 250 httpauth (0.2.0)
... ... @@ -291,6 +300,7 @@ GEM
291 300 net-ssh (>= 1.99.1)
292 301 net-ssh (2.7.0)
293 302 nokogiri (1.5.10)
  303 + nprogress-rails (0.1.2.3)
294 304 oauth (0.4.7)
295 305 oauth2 (0.8.1)
296 306 faraday (~> 0.8)
... ... @@ -462,6 +472,7 @@ GEM
462 472 rack-protection (~> 1.4)
463 473 tilt (~> 1.3, >= 1.3.4)
464 474 six (0.2.0)
  475 + slack-notifier (0.2.0)
465 476 slim (2.0.2)
466 477 temple (~> 0.6.6)
467 478 tilt (>= 1.3.3, < 2.1)
... ... @@ -473,7 +484,6 @@ GEM
473 484 capybara (>= 2.0.0)
474 485 railties (>= 3)
475 486 spinach (>= 0.4)
476   - spork (1.0.0rc4)
477 487 spring (1.1.1)
478 488 spring-commands-rspec (1.0.1)
479 489 spring (>= 0.9.1)
... ... @@ -585,18 +595,18 @@ DEPENDENCIES
585 595 font-awesome-rails (~> 3.2)
586 596 foreman
587 597 gemnasium-gitlab-service (~> 0.2)
588   - gemoji (~> 1.3.0)
589 598 github-markup (~> 0.7.4)!
590 599 gitlab-flowdock-git-hook (~> 0.4.2)
591 600 gitlab-gollum-lib (~> 1.1.0)
592 601 gitlab-grack (~> 2.0.0.pre)
593 602 gitlab-linguist (~> 3.0.0)
  603 + gitlab_emoji (~> 0.0.1.1)
594 604 gitlab_git (~> 5.7.1)
595 605 gitlab_meta (= 6.0)
596 606 gitlab_omniauth-ldap (= 1.0.4)
597 607 gon (~> 5.0.0)
598 608 grape (~> 0.6.1)
599   - grape-entity (~> 0.3.0)
  609 + grape-entity (~> 0.4.1)!
600 610 growl
601 611 guard-rspec
602 612 guard-spinach
... ... @@ -614,6 +624,7 @@ DEPENDENCIES
614 624 minitest (~> 4.7.0)
615 625 modernizr (= 2.6.2)
616 626 mysql2
  627 + nprogress-rails
617 628 omniauth (~> 1.1.3)
618 629 omniauth-github
619 630 omniauth-google-oauth2
... ... @@ -646,9 +657,9 @@ DEPENDENCIES
646 657 simplecov
647 658 sinatra
648 659 six
  660 + slack-notifier (~> 0.2.0)
649 661 slim
650 662 spinach-rails
651   - spork (~> 1.0rc)
652 663 spring (= 1.1.1)
653 664 spring-commands-rspec (= 1.0.1)
654 665 spring-commands-spinach (= 1.0.0)
... ...
PROCESS.md
... ... @@ -12,7 +12,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
12 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 13 - Assigns appropriate [labels](#how-we-handle-issues)
14 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 16 - Monitors all issues/merge requests for feedback (but especially ones commented on since automatically watching them):
17 17 - Closes issues with no feedback from the reporter for two weeks
18 18 - Closes stale merge requests
... ... @@ -24,8 +24,6 @@ Below we describe the contributing process to GitLab for two reasons. So that co
24 24 - Monitors for new merge requests (at least once a week)
25 25 - Manages their work queue by looking at issues and merge requests assigned to them
26 26 - Close fixed issues (via commit messages or manually)
27   -- Codes [new features](http://feedback.gitlab.com/forums/176466-general/filters/top)!
28   -- Response guidelines
29 27 - Be kind to people trying to contribute. Be aware that people can be a non-native or a native English speaker, they might not understand thing or they might be very sensitive to how your word things. Use emoji to express your feelings (heart, star, smile, etc.). Some good tips about giving feedback to merge requests is in the [Thoughtbot code review guide](https://github.com/thoughtbot/guides/tree/master/code-review).
30 28  
31 29 ## Priorities of the issue team
... ... @@ -37,7 +35,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
37 35  
38 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 40 ## Workflow labels
43 41  
... ... @@ -73,7 +71,7 @@ Thanks for the issue report. Please reformat your issue to conform to the issue
73 71  
74 72 ### Feature requests
75 73  
76   -Thanks for your interest in GitLab. We don't use the issue tracker for feature requests. 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 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 87  
90 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 92 ### Improperly formatted merge request
95 93  
... ...
Procfile
1   -web: bundle exec unicorn_rails -p $PORT -E development
  1 +web: bundle exec unicorn_rails -p $PORT -E development -c config/unicorn_development.rb
2 2 worker: bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,common,default,gitlab_shell
... ...
README.md
... ... @@ -23,13 +23,11 @@
23 23  
24 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 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 71  
74 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 76 ### Run in production mode
79 77  
... ... @@ -98,14 +96,9 @@ or start each component separately
98 96  
99 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 99 * Run all tests
107 100  
108   - bundle exec rake gitlab:test RAILS_ENV=test
  101 + bundle exec rake test
109 102  
110 103 * [RSpec](http://rspec.info/) unit and functional tests
111 104  
... ... @@ -142,7 +135,7 @@ or start each component separately
142 135  
143 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 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 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 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/)
... ...
VERSION
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   -// This is a manifest file that'll be compiled into including all the files listed below.
2   -// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
3   -// be included in the compiled file accessible from http://example.com/assets/application.js
4   -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
5   -// the compiled file.
6   -//
7   -//= require jquery
8   -//= require jquery.ui.all
9   -//= require jquery_ujs
10   -//= require jquery.cookie
11   -//= require jquery.endless-scroll
12   -//= require jquery.highlight
13   -//= require jquery.history
14   -//= require jquery.waitforimages
15   -//= require jquery.atwho
16   -//= require jquery.scrollto
17   -//= require jquery.blockUI
18   -//= require turbolinks
19   -//= require jquery.turbolinks
20   -//= require bootstrap
21   -//= require modernizr
22   -//= require select2
23   -//= require raphael
24   -//= require g.raphael-min
25   -//= require g.bar-min
26   -//= require branch-graph
27   -//= require highlightjs.min
28   -//= require ace/ace
29   -//= require_tree .
30   -//= require d3
31   -//= require underscore
app/assets/javascripts/application.js.coffee 0 → 100644
... ... @@ -0,0 +1,154 @@
  1 +# This is a manifest file that'll be compiled into including all the files listed below.
  2 +# Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
  3 +# be included in the compiled file accessible from http://example.com/assets/application.js
  4 +# It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
  5 +# the compiled file.
  6 +#
  7 +#= require jquery
  8 +#= require jquery.ui.all
  9 +#= require jquery_ujs
  10 +#= require jquery.cookie
  11 +#= require jquery.endless-scroll
  12 +#= require jquery.highlight
  13 +#= require jquery.history
  14 +#= require jquery.waitforimages
  15 +#= require jquery.atwho
  16 +#= require jquery.scrollto
  17 +#= require jquery.blockUI
  18 +#= require turbolinks
  19 +#= require jquery.turbolinks
  20 +#= require bootstrap
  21 +#= require modernizr
  22 +#= require select2
  23 +#= require raphael
  24 +#= require g.raphael-min
  25 +#= require g.bar-min
  26 +#= require branch-graph
  27 +#= require highlightjs.min
  28 +#= require ace/ace
  29 +#= require d3
  30 +#= require underscore
  31 +#= require nprogress
  32 +#= require nprogress-turbolinks
  33 +#= require_tree .
  34 +
  35 +window.slugify = (text) ->
  36 + text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
  37 +
  38 +window.ajaxGet = (url) ->
  39 + $.ajax({type: "GET", url: url, dataType: "script"})
  40 +
  41 +window.showAndHide = (selector) ->
  42 +
  43 +window.errorMessage = (message) ->
  44 + ehtml = $("<p>")
  45 + ehtml.addClass("error_message")
  46 + ehtml.html(message)
  47 + ehtml
  48 +
  49 +window.split = (val) ->
  50 + return val.split( /,\s*/ )
  51 +
  52 +window.extractLast = (term) ->
  53 + return split( term ).pop()
  54 +
  55 +# Disable button if text field is empty
  56 +window.disableButtonIfEmptyField = (field_selector, button_selector) ->
  57 + field = $(field_selector)
  58 + closest_submit = field.closest("form").find(button_selector)
  59 +
  60 + closest_submit.disable() if field.val() is ""
  61 +
  62 + field.on "input", ->
  63 + if $(@).val() is ""
  64 + closest_submit.disable()
  65 + else
  66 + closest_submit.enable()
  67 +
  68 +window.sanitize = (str) ->
  69 + return str.replace(/<(?:.|\n)*?>/gm, '')
  70 +
  71 +window.linkify = (str) ->
  72 + exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig
  73 + return str.replace(exp,"<a href='$1'>$1</a>")
  74 +
  75 +window.simpleFormat = (str) ->
  76 + linkify(sanitize(str).replace(/\n/g, '<br />'))
  77 +
  78 +window.unbindEvents = ->
  79 + $(document).unbind('scroll')
  80 + $(document).off('scroll')
  81 +
  82 +document.addEventListener("page:fetch", unbindEvents)
  83 +
  84 +$ ->
  85 + # Click a .one_click_select field, select the contents
  86 + $(".one_click_select").on 'click', -> $(@).select()
  87 +
  88 + $('.remove-row').bind 'ajax:success', ->
  89 + $(this).closest('li').fadeOut()
  90 +
  91 + # Initialize select2 selects
  92 + $('select.select2').select2(width: 'resolve', dropdownAutoWidth: true)
  93 +
  94 + # Initialize tooltips
  95 + $('.has_tooltip').tooltip()
  96 +
  97 + # Bottom tooltip
  98 + $('.has_bottom_tooltip').tooltip(placement: 'bottom')
  99 +
  100 + # Form submitter
  101 + $('.trigger-submit').on 'change', ->
  102 + $(@).parents('form').submit()
  103 +
  104 + $("abbr.timeago").timeago()
  105 + $('.js-timeago').timeago()
  106 +
  107 + # Flash
  108 + if (flash = $(".flash-container")).length > 0
  109 + flash.click -> $(@).fadeOut()
  110 + flash.show()
  111 + setTimeout (-> flash.fadeOut()), 5000
  112 +
  113 + # Disable form buttons while a form is submitting
  114 + $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
  115 + buttons = $('[type="submit"]', @)
  116 +
  117 + switch e.type
  118 + when 'ajax:beforeSend', 'submit'
  119 + buttons.disable()
  120 + else
  121 + buttons.enable()
  122 +
  123 + # Show/Hide the profile menu when hovering the account box
  124 + $('.account-box').hover -> $(@).toggleClass('hover')
  125 +
  126 + # Focus search field by pressing 's' key
  127 + $(document).keypress (e) ->
  128 + # Don't do anything if typing in an input
  129 + return if $(e.target).is(":input")
  130 +
  131 + switch e.which
  132 + when 115
  133 + $("#search").focus()
  134 + e.preventDefault()
  135 + when 63
  136 + new Shortcuts()
  137 + e.preventDefault()
  138 +
  139 +
  140 + # Commit show suppressed diff
  141 + $(".diff-content").on "click", ".supp_diff_link", ->
  142 + $(@).next('table').show()
  143 + $(@).remove()
  144 +
  145 +(($) ->
  146 + # Disable an element and add the 'disabled' Bootstrap class
  147 + $.fn.extend disable: ->
  148 + $(@).attr('disabled', 'disabled').addClass('disabled')
  149 +
  150 + # Enable an element and remove the 'disabled' Bootstrap class
  151 + $.fn.extend enable: ->
  152 + $(@).removeAttr('disabled').removeClass('disabled')
  153 +
  154 +)(jQuery)
... ...
app/assets/javascripts/behaviors/details_behavior.coffee
1 1 $ ->
2 2 $("body").on "click", ".js-details-target", ->
3 3 container = $(@).closest(".js-details-container")
4   -
5 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 2 $("body").on "click", ".js-toggler-target", ->
3 3 container = $(@).closest(".js-toggler-container")
4   -
5 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 14 $(@).find('i').
9 15 toggleClass('icon-chevron-down').
10 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 17 $(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
17 18 e.preventDefault()
... ...
app/assets/javascripts/gfm_auto_complete.js.coffee
... ... @@ -6,7 +6,6 @@ GitLab.GfmAutoComplete =
6 6 dataSource: ''
7 7 # Emoji
8 8 Emoji:
9   - assetBase: ''
10 9 template: '<li data-value="${insert}">${name} <img alt="${name}" height="20" src="${image}" width="20" /></li>'
11 10  
12 11 # Team Members
... ... @@ -27,7 +26,7 @@ GitLab.GfmAutoComplete =
27 26 tpl: @Emoji.template
28 27 callbacks:
29 28 before_save: (emojis) =>
30   - $.map emojis, (em) => name: em, insert: em+ ':', image: "#{@Emoji.assetBase}/#{em}.png"
  29 + $.map emojis, (em) => name: em.name, insert: em.name+ ':', image: em.path
31 30  
32 31 # Team Members
33 32 input.atwho
... ...
app/assets/javascripts/main.js.coffee
... ... @@ -1,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 7 *= require select2
8 8 *= require highlightjs.min
9 9 *= require_self
  10 + *= require nprogress
  11 + *= require nprogress-bootstrap
10 12 */
11 13  
12 14 @import "main/variables.scss";
... ...
app/assets/stylesheets/generic/common.scss
... ... @@ -298,10 +298,6 @@ img.emoji {
298 298 width: 20px;
299 299 }
300 300  
301   -.appear-data {
302   - display: none;
303   -}
304   -
305 301 .chart {
306 302 overflow: hidden;
307 303 height: 220px;
... ... @@ -359,3 +355,7 @@ table {
359 355 @media (max-width: $screen-xs-max) {
360 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 @@
  1 +/* Generic print styles */
  2 +header, nav, nav.main-nav, nav.navbar-collapse, nav.navbar-collapse.collapse {display: none!important;}
  3 +.profiler-results {display: none;}
  4 +
  5 +/* Styles targeted specifically at printing files */
  6 +.tree-ref-holder, .tree-holder .breadcrumb, .blob-commit-info {display: none;}
  7 +.file-title {display: none;}
  8 +.file-holder {border: none;}
  9 +
  10 +.wiki h1, .wiki h2, .wiki h3, .wiki h4, .wiki h5, .wiki h6 {margin-top: 17px; }
  11 +.wiki h1 {font-size: 30px;}
  12 +.wiki h2 {font-size: 22px;}
  13 +.wiki h3 {font-size: 18px; font-weight: bold; }
... ...
app/assets/stylesheets/sections/dashboard.scss
... ... @@ -61,7 +61,7 @@
61 61 }
62 62  
63 63 .project-row, .group-row {
64   - padding: 10px 12px !important;
  64 + padding: 8px 12px !important;
65 65 font-size: 14px;
66 66 line-height: 24px;
67 67  
... ...
app/assets/stylesheets/sections/events.scss
... ... @@ -42,7 +42,7 @@
42 42 }
43 43 }
44 44  
45   - padding: 14px 0px;
  45 + padding: 12px 0px;
46 46 border-bottom: 1px solid #eee;
47 47 .event-title {
48 48 color: #333;
... ...
app/assets/stylesheets/sections/header.scss
... ... @@ -273,3 +273,9 @@ header {
273 273 }
274 274 }
275 275 }
  276 +
  277 +@media (max-width: $screen-xs-max) {
  278 + #nprogress .spinner {
  279 + right: 35px !important;
  280 + }
  281 +}
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -189,7 +189,6 @@ ul.notes {
189 189 }
190 190  
191 191  
192   -
193 192 /**
194 193 * Line note button on the side of diffs
195 194 */
... ...
app/controllers/admin/background_jobs_controller.rb
1 1 class Admin::BackgroundJobsController < Admin::ApplicationController
2 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 4 @sidekiq_processes = ps_output.split("\n").grep(/sidekiq/)
5 5 end
6 6 end
... ...
app/controllers/application_controller.rb
... ... @@ -6,6 +6,7 @@ class ApplicationController &lt; ActionController::Base
6 6 before_filter :check_password_expiration
7 7 around_filter :set_current_user_for_thread
8 8 before_filter :add_abilities
  9 + before_filter :ldap_security_check
9 10 before_filter :dev_tools if Rails.env == 'development'
10 11 before_filter :default_headers
11 12 before_filter :add_gon_variables
... ... @@ -179,11 +180,30 @@ class ApplicationController &lt; ActionController::Base
179 180 end
180 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 198 def event_filter
183 199 filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
184 200 @event_filter ||= EventFilter.new(filters)
185 201 end
186 202  
  203 + def gitlab_ldap_access(&block)
  204 + Gitlab::LDAP::Access.open { |access| block.call(access) }
  205 + end
  206 +
187 207 # JSON for infinite scroll via Pager object
188 208 def pager_json(partial, count)
189 209 html = render_to_string(
... ...
app/controllers/dashboard_controller.rb
... ... @@ -22,6 +22,8 @@ class DashboardController &lt; ApplicationController
22 22  
23 23 @last_push = current_user.recent_push
24 24  
  25 + @publicish_project_count = Project.publicish(current_user).count
  26 +
25 27 respond_to do |format|
26 28 format.html
27 29 format.json { pager_json("events/_events", @events.count) }
... ...
app/controllers/passwords_controller.rb 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +class PasswordsController < Devise::PasswordsController
  2 +
  3 + def create
  4 + email = resource_params[:email]
  5 + resource_found = resource_class.find_by_email(email)
  6 + if resource_found && resource_found.ldap_user?
  7 + flash[:alert] = "Cannot reset password for LDAP user."
  8 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name)) and return
  9 + end
  10 +
  11 + self.resource = resource_class.send_reset_password_instructions(resource_params)
  12 + if successfully_sent?(resource)
  13 + respond_with({}, :location => after_sending_reset_password_instructions_path_for(resource_name))
  14 + else
  15 + respond_with(resource)
  16 + end
  17 + end
  18 +end
... ...
app/controllers/profiles/keys_controller.rb
... ... @@ -41,7 +41,7 @@ class Profiles::KeysController &lt; ApplicationController
41 41 begin
42 42 user = User.find_by_username(params[:username])
43 43 if user.present?
44   - render text: user.all_ssh_keys.join("\n")
  44 + render text: user.all_ssh_keys.join("\n"), content_type: "text/plain"
45 45 else
46 46 render_404 and return
47 47 end
... ...
app/controllers/projects_controller.rb
... ... @@ -5,7 +5,7 @@ class ProjectsController &lt; ApplicationController
5 5  
6 6 # Authorize
7 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 9 before_filter :require_non_empty_project, only: [:blob, :tree, :graph]
10 10  
11 11 layout 'navless', only: [:new, :create, :fork]
... ... @@ -21,16 +21,9 @@ class ProjectsController &lt; ApplicationController
21 21  
22 22 def create
23 23 @project = ::Projects::CreateService.new(current_user, params[:project]).execute
  24 + flash[:notice] = 'Project was successfully created.' if @project.saved?
24 25  
25 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 27 format.js
35 28 end
36 29 end
... ... @@ -55,6 +48,11 @@ class ProjectsController &lt; ApplicationController
55 48 end
56 49  
57 50 def show
  51 + if @project.import_in_progress?
  52 + redirect_to import_project_path(@project)
  53 + return
  54 + end
  55 +
58 56 return authenticate_user! unless @project.public? || current_user
59 57  
60 58 limit = (params[:limit] || 20).to_i
... ... @@ -67,9 +65,7 @@ class ProjectsController &lt; ApplicationController
67 65 if @project.empty_repo?
68 66 render "projects/empty", layout: user_layout
69 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 69 render :show, layout: user_layout
74 70 end
75 71 end
... ... @@ -77,6 +73,28 @@ class ProjectsController &lt; ApplicationController
77 73 end
78 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 98 def destroy
81 99 return access_denied! unless can?(current_user, :remove_project, project)
82 100  
... ... @@ -106,7 +124,7 @@ class ProjectsController &lt; ApplicationController
106 124  
107 125 def autocomplete_sources
108 126 @suggestions = {
109   - emojis: Emoji.names,
  127 + emojis: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } },
110 128 issues: @project.issues.select([:iid, :title, :description]),
111 129 mergerequests: @project.merge_requests.select([:iid, :title, :description]),
112 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 7  
8 8 if @project
9 9 return access_denied! unless can?(current_user, :download_code, @project)
  10 +
10 11 @search_results = Search::ProjectService.new(@project, current_user, params).execute
11 12 else
12 13 @search_results = Search::GlobalService.new(current_user, params).execute
... ...
app/controllers/snippets_controller.rb
... ... @@ -19,6 +19,9 @@ class SnippetsController &lt; ApplicationController
19 19  
20 20 def user_index
21 21 @user = User.find_by(username: params[:username])
  22 +
  23 + render_404 and return unless @user
  24 +
22 25 @snippets = @user.snippets.fresh.non_expired
23 26  
24 27 if @user == current_user
... ...
app/finders/base_finder.rb
... ... @@ -47,9 +47,9 @@ class BaseFinder
47 47 []
48 48 end
49 49 elsif current_user && params[:authorized_only].presence
50   - klass.of_projects(current_user.authorized_projects)
  50 + klass.of_projects(current_user.authorized_projects).references(:project)
51 51 else
52   - klass.of_projects(Project.accessible_to(current_user))
  52 + klass.of_projects(Project.accessible_to(current_user)).references(:project)
53 53 end
54 54 end
55 55  
... ...
app/helpers/application_helper.rb
... ... @@ -146,8 +146,7 @@ module ApplicationHelper
146 146  
147 147 def authbutton(provider, size = 64)
148 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 150 end
152 151  
153 152 def simple_sanitize(str)
... ...
app/helpers/gitlab_markdown_helper.rb
... ... @@ -35,7 +35,6 @@ module GitlabMarkdownHelper
35 35 # see https://github.com/vmg/redcarpet#darling-i-packed-you-a-couple-renderers-for-lunch-
36 36 filter_html: true,
37 37 with_toc_data: true,
38   - hard_wrap: true,
39 38 safe_links_only: true
40 39 }.merge(options))
41 40 @markdown = Redcarpet::Markdown.new(gitlab_renderer,
... ... @@ -45,7 +44,7 @@ module GitlabMarkdownHelper
45 44 fenced_code_blocks: true,
46 45 autolink: true,
47 46 strikethrough: true,
48   - lax_html_blocks: true,
  47 + lax_spacing: true,
49 48 space_after_headers: true,
50 49 superscript: true)
51 50 end
... ... @@ -64,8 +63,7 @@ module GitlabMarkdownHelper
64 63 # project_path_with_namespace - namespace/projectname, eg. gitlabhq/gitlabhq
65 64 # ref - name of the branch or reference, eg. stable
66 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 67 @path_to_satellite = project.satellite.path
70 68 project_path_with_namespace = project.path_with_namespace
71 69 paths = extract_paths(text)
... ... @@ -135,12 +133,12 @@ module GitlabMarkdownHelper
135 133 end
136 134  
137 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 137 def path_with_ref(path, ref)
140 138 if file_exists?(path)
141 139 "#{local_path(path)}/#{correct_ref(ref)}"
142 140 else
143   - "wikis"
  141 + "blob/#{correct_ref(ref)}"
144 142 end
145 143 end
146 144  
... ...
app/helpers/merge_requests_helper.rb
... ... @@ -20,7 +20,7 @@ module MergeRequestsHelper
20 20 target_project_id: target_project.id,
21 21 source_branch: event.branch_name,
22 22 target_branch: target_project.repository.root_ref,
23   - title: event.branch_name.titleize
  23 + title: event.branch_name.humanize
24 24 }
25 25 end
26 26  
... ...
app/helpers/profile_helper.rb
... ... @@ -10,7 +10,7 @@ module ProfileHelper
10 10 end
11 11  
12 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 14 end
15 15  
16 16 def show_profile_remove_tab?
... ...
app/helpers/tree_helper.rb
... ... @@ -40,7 +40,7 @@ module TreeHelper
40 40 # Returns boolean
41 41 def markup?(filename)
42 42 filename.downcase.end_with?(*%w(.textile .rdoc .org .creole
43   - .mediawiki .rst .asciidoc .pod))
  43 + .mediawiki .rst .adoc .asciidoc .pod))
44 44 end
45 45  
46 46 def gitlab_markdown?(filename)
... ...
app/mailers/emails/groups.rb
... ... @@ -3,7 +3,7 @@ module Emails
3 3 def group_access_granted_email(user_group_id)
4 4 @membership = UsersGroup.find(user_group_id)
5 5 @group = @membership.group
6   -
  6 + @target_url = group_url(@group)
7 7 mail(to: @membership.user.email,
8 8 subject: subject("Access to group was granted"))
9 9 end
... ...
app/mailers/emails/issues.rb
... ... @@ -3,6 +3,7 @@ module Emails
3 3 def new_issue_email(recipient_id, issue_id)
4 4 @issue = Issue.find(issue_id)
5 5 @project = @issue.project
  6 + @target_url = project_issue_url(@project, @issue)
6 7 mail(from: sender(@issue.author_id),
7 8 to: recipient(recipient_id),
8 9 subject: subject("#{@issue.title} (##{@issue.iid})"))
... ... @@ -12,6 +13,7 @@ module Emails
12 13 @issue = Issue.find(issue_id)
13 14 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
14 15 @project = @issue.project
  16 + @target_url = project_issue_url(@project, @issue)
15 17 mail(from: sender(updated_by_user_id),
16 18 to: recipient(recipient_id),
17 19 subject: subject("#{@issue.title} (##{@issue.iid})"))
... ... @@ -21,6 +23,7 @@ module Emails
21 23 @issue = Issue.find issue_id
22 24 @project = @issue.project
23 25 @updated_by = User.find updated_by_user_id
  26 + @target_url = project_issue_url(@project, @issue)
24 27 mail(from: sender(updated_by_user_id),
25 28 to: recipient(recipient_id),
26 29 subject: subject("#{@issue.title} (##{@issue.iid})"))
... ... @@ -31,6 +34,7 @@ module Emails
31 34 @issue_status = status
32 35 @project = @issue.project
33 36 @updated_by = User.find updated_by_user_id
  37 + @target_url = project_issue_url(@project, @issue)
34 38 mail(from: sender(updated_by_user_id),
35 39 to: recipient(recipient_id),
36 40 subject: subject("#{@issue.title} (##{@issue.iid})"))
... ...
app/mailers/emails/merge_requests.rb
... ... @@ -3,6 +3,7 @@ module Emails
3 3 def new_merge_request_email(recipient_id, merge_request_id)
4 4 @merge_request = MergeRequest.find(merge_request_id)
5 5 @project = @merge_request.project
  6 + @target_url = project_merge_request_url(@project, @merge_request)
6 7 mail(from: sender(@merge_request.author_id),
7 8 to: recipient(recipient_id),
8 9 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
... ... @@ -12,6 +13,7 @@ module Emails
12 13 @merge_request = MergeRequest.find(merge_request_id)
13 14 @previous_assignee = User.find_by(id: previous_assignee_id) if previous_assignee_id
14 15 @project = @merge_request.project
  16 + @target_url = project_merge_request_url(@project, @merge_request)
15 17 mail(from: sender(updated_by_user_id),
16 18 to: recipient(recipient_id),
17 19 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
... ... @@ -21,15 +23,17 @@ module Emails
21 23 @merge_request = MergeRequest.find(merge_request_id)
22 24 @updated_by = User.find updated_by_user_id
23 25 @project = @merge_request.project
  26 + @target_url = project_merge_request_url(@project, @merge_request)
24 27 mail(from: sender(updated_by_user_id),
25 28 to: recipient(recipient_id),
26 29 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
27 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 33 @merge_request = MergeRequest.find(merge_request_id)
31 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 37 to: recipient(recipient_id),
34 38 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
35 39 end
... ...
app/mailers/emails/notes.rb
... ... @@ -4,6 +4,7 @@ module Emails
4 4 @note = Note.find(note_id)
5 5 @commit = @note.noteable
6 6 @project = @note.project
  7 + @target_url = project_commit_url(@project, @commit, anchor: "note_#{@note.id}")
7 8 mail(from: sender(@note.author_id),
8 9 to: recipient(recipient_id),
9 10 subject: subject("#{@commit.title} (#{@commit.short_id})"))
... ... @@ -13,6 +14,7 @@ module Emails
13 14 @note = Note.find(note_id)
14 15 @issue = @note.noteable
15 16 @project = @note.project
  17 + @target_url = project_issue_url(@project, @issue, anchor: "note_#{@note.id}")
16 18 mail(from: sender(@note.author_id),
17 19 to: recipient(recipient_id),
18 20 subject: subject("#{@issue.title} (##{@issue.iid})"))
... ... @@ -22,6 +24,7 @@ module Emails
22 24 @note = Note.find(note_id)
23 25 @merge_request = @note.noteable
24 26 @project = @note.project
  27 + @target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
25 28 mail(from: sender(@note.author_id),
26 29 to: recipient(recipient_id),
27 30 subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
... ... @@ -30,6 +33,7 @@ module Emails
30 33 def note_wall_email(recipient_id, note_id)
31 34 @note = Note.find(note_id)
32 35 @project = @note.project
  36 + @target_url = project_wall_url(@note.project, anchor: "note_#{@note.id}")
33 37 mail(from: sender(@note.author_id),
34 38 to: recipient(recipient_id),
35 39 subject: subject("Note on wall"))
... ...
app/mailers/emails/profile.rb
... ... @@ -3,6 +3,7 @@ module Emails
3 3 def new_user_email(user_id, password)
4 4 @user = User.find(user_id)
5 5 @password = password
  6 + @target_url = user_url(@user)
6 7 mail(to: @user.email, subject: subject("Account was created for you"))
7 8 end
8 9  
... ... @@ -15,6 +16,7 @@ module Emails
15 16 def new_ssh_key_email(key_id)
16 17 @key = Key.find(key_id)
17 18 @user = @key.user
  19 + @target_url = user_url(@user)
18 20 mail(to: @user.email, subject: subject("SSH key was added to your account"))
19 21 end
20 22 end
... ...
app/mailers/emails/projects.rb
... ... @@ -3,6 +3,7 @@ module Emails
3 3 def project_access_granted_email(user_project_id)
4 4 @users_project = UsersProject.find user_project_id
5 5 @project = @users_project.project
  6 + @target_url = project_url(@project)
6 7 mail(to: @users_project.user.email,
7 8 subject: subject("Access to project was granted"))
8 9 end
... ... @@ -10,6 +11,7 @@ module Emails
10 11 def project_was_moved_email(project_id, user_id)
11 12 @user = User.find user_id
12 13 @project = Project.find project_id
  14 + @target_url = project_url(@project)
13 15 mail(to: @user.email,
14 16 subject: subject("Project was moved"))
15 17 end
... ... @@ -21,6 +23,11 @@ module Emails
21 23 @commits = Commit.decorate(compare.commits)
22 24 @diffs = compare.diffs
23 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 32 mail(from: sender(author_id),
26 33 to: recipient,
... ...
app/models/ability.rb
... ... @@ -240,6 +240,7 @@ class Ability
240 240 can_manage = group_abilities(user, group).include?(:manage_group)
241 241 if can_manage && (user != target_user)
242 242 rules << :modify
  243 + rules << :destroy
243 244 end
244 245 if !group.last_owner?(user) && (can_manage || (user == target_user))
245 246 rules << :destroy
... ...
app/models/merge_request.rb
... ... @@ -133,7 +133,7 @@ class MergeRequest &lt; ActiveRecord::Base
133 133 end
134 134  
135 135 def reload_code
136   - if merge_request_diff && opened?
  136 + if merge_request_diff && open?
137 137 merge_request_diff.reload_content
138 138 end
139 139 end
... ...
app/models/note.rb
... ... @@ -199,7 +199,8 @@ class Note &lt; ActiveRecord::Base
199 199 def downvote?
200 200 votable? && (note.start_with?('-1') ||
201 201 note.start_with?(':-1:') ||
202   - note.start_with?(':thumbsdown:')
  202 + note.start_with?(':thumbsdown:') ||
  203 + note.start_with?(':thumbs_down_sign:')
203 204 )
204 205 end
205 206  
... ... @@ -249,7 +250,8 @@ class Note &lt; ActiveRecord::Base
249 250 def upvote?
250 251 votable? && (note.start_with?('+1') ||
251 252 note.start_with?(':+1:') ||
252   - note.start_with?(':thumbsup:')
  253 + note.start_with?(':thumbsup:') ||
  254 + note.start_with?(':thumbs_up_sign:')
253 255 )
254 256 end
255 257  
... ...
app/models/project.rb
... ... @@ -28,7 +28,6 @@ class Project &lt; ActiveRecord::Base
28 28 include Gitlab::VisibilityLevel
29 29 extend Enumerize
30 30  
31   - default_value_for :imported, false
32 31 default_value_for :archived, false
33 32  
34 33 ActsAsTaggableOn.strict_case_match = true
... ... @@ -57,15 +56,13 @@ class Project &lt; ActiveRecord::Base
57 56 has_one :flowdock_service, dependent: :destroy
58 57 has_one :assembla_service, dependent: :destroy
59 58 has_one :gemnasium_service, dependent: :destroy
  59 + has_one :slack_service, dependent: :destroy
60 60 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
61 61 has_one :forked_from_project, through: :forked_project_link
62   -
63 62 # Merge Requests for target project should be removed with it
64 63 has_many :merge_requests, dependent: :destroy, foreign_key: "target_project_id"
65   -
66 64 # Merge requests from source project should be kept when source project was removed
67 65 has_many :fork_merge_requests, foreign_key: "source_project_id", class_name: MergeRequest
68   -
69 66 has_many :issues, -> { order "state DESC, created_at DESC" }, dependent: :destroy
70 67 has_many :services, dependent: :destroy
71 68 has_many :events, dependent: :destroy
... ... @@ -74,10 +71,8 @@ class Project &lt; ActiveRecord::Base
74 71 has_many :snippets, dependent: :destroy, class_name: "ProjectSnippet"
75 72 has_many :hooks, dependent: :destroy, class_name: "ProjectHook"
76 73 has_many :protected_branches, dependent: :destroy
77   -
78 74 has_many :users_projects, dependent: :destroy
79 75 has_many :users, through: :users_projects
80   -
81 76 has_many :deploy_keys_projects, dependent: :destroy
82 77 has_many :deploy_keys, through: :deploy_keys_projects
83 78  
... ... @@ -97,15 +92,12 @@ class Project &lt; ActiveRecord::Base
97 92 validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
98 93 :wiki_enabled, inclusion: { in: [true, false] }
99 94 validates :issues_tracker_id, length: { maximum: 255 }, allow_blank: true
100   -
101 95 validates :namespace, presence: true
102 96 validates_uniqueness_of :name, scope: :namespace_id
103 97 validates_uniqueness_of :path, scope: :namespace_id
104   -
105 98 validates :import_url,
106 99 format: { with: URI::regexp(%w(git http https)), message: "should be a valid url" },
107 100 if: :import?
108   -
109 101 validate :check_limit, on: :create
110 102  
111 103 # Scopes
... ... @@ -118,14 +110,36 @@ class Project &lt; ActiveRecord::Base
118 110 scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
119 111 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
120 112 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
121   -
122 113 scope :public_only, -> { where(visibility_level: Project::PUBLIC) }
123 114 scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
124   -
125 115 scope :non_archived, -> { where(archived: false) }
126 116  
127 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 143 class << self
130 144 def public_and_internal_levels
131 145 [Project::PUBLIC, Project::INTERNAL]
... ... @@ -164,15 +178,13 @@ class Project &lt; ActiveRecord::Base
164 178 end
165 179  
166 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 188 end
177 189  
178 190 def visibility_levels
... ... @@ -202,12 +214,28 @@ class Project &lt; ActiveRecord::Base
202 214 id && persisted?
203 215 end
204 216  
  217 + def add_import_job
  218 + RepositoryImportWorker.perform_in(2.seconds, id)
  219 + end
  220 +
205 221 def import?
206 222 import_url.present?
207 223 end
208 224  
209 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 239 end
212 240  
213 241 def check_limit
... ... @@ -277,7 +305,7 @@ class Project &lt; ActiveRecord::Base
277 305 end
278 306  
279 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 309 end
282 310  
283 311 def gitlab_ci?
... ... @@ -361,18 +389,17 @@ class Project &lt; ActiveRecord::Base
361 389 branch_name = ref.gsub("refs/heads/", "")
362 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 397 # Update code for merge requests into project between project branches
365 398 mrs = self.merge_requests.opened.by_branch(branch_name).to_a
366 399 # Update code for merge requests between project and project fork
367 400 mrs += self.fork_merge_requests.opened.by_branch(branch_name).to_a
368   -
369 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 403 true
377 404 end
378 405  
... ...
app/models/project_hook.rb
... ... @@ -17,9 +17,10 @@
17 17 class ProjectHook < WebHook
18 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 22 scope :push_hooks, -> { where(push_events: true) }
  23 + scope :tag_push_hooks, -> { where(tag_push_events: true) }
23 24 scope :issue_hooks, -> { where(issues_events: true) }
24 25 scope :merge_request_hooks, -> { where(merge_requests_events: true) }
25 26 end
... ...
app/models/project_services/slack_message.rb 0 → 100644
... ... @@ -0,0 +1,95 @@
  1 +require 'slack-notifier'
  2 +
  3 +class SlackMessage
  4 + def initialize(params)
  5 + @after = params.fetch(:after)
  6 + @before = params.fetch(:before)
  7 + @commits = params.fetch(:commits, [])
  8 + @project_name = params.fetch(:project_name)
  9 + @project_url = params.fetch(:project_url)
  10 + @ref = params.fetch(:ref).gsub('refs/heads/', '')
  11 + @username = params.fetch(:user_name)
  12 + end
  13 +
  14 + def compose
  15 + format(message)
  16 + end
  17 +
  18 + private
  19 +
  20 + attr_reader :after
  21 + attr_reader :before
  22 + attr_reader :commits
  23 + attr_reader :project_name
  24 + attr_reader :project_url
  25 + attr_reader :ref
  26 + attr_reader :username
  27 +
  28 + def message
  29 + if new_branch?
  30 + new_branch_message
  31 + elsif removed_branch?
  32 + removed_branch_message
  33 + else
  34 + push_message << commit_messages
  35 + end
  36 + end
  37 +
  38 + def format(string)
  39 + Slack::Notifier::LinkFormatter.format(string)
  40 + end
  41 +
  42 + def new_branch_message
  43 + "#{username} pushed new branch #{branch_link} to #{project_link}"
  44 + end
  45 +
  46 + def removed_branch_message
  47 + "#{username} removed branch #{ref} from #{project_link}"
  48 + end
  49 +
  50 + def push_message
  51 + "#{username} pushed to branch #{branch_link} of #{project_link} (#{compare_link})"
  52 + end
  53 +
  54 + def commit_messages
  55 + commits.each_with_object('') do |commit, str|
  56 + str << compose_commit_message(commit)
  57 + end
  58 + end
  59 +
  60 + def compose_commit_message(commit)
  61 + id = commit.fetch(:id)[0..5]
  62 + message = commit.fetch(:message)
  63 + url = commit.fetch(:url)
  64 +
  65 + "\n - #{message} ([#{id}](#{url}))"
  66 + end
  67 +
  68 + def new_branch?
  69 + before =~ /000000/
  70 + end
  71 +
  72 + def removed_branch?
  73 + after =~ /000000/
  74 + end
  75 +
  76 + def branch_url
  77 + "#{project_url}/commits/#{ref}"
  78 + end
  79 +
  80 + def compare_url
  81 + "#{project_url}/compare/#{before}...#{after}"
  82 + end
  83 +
  84 + def branch_link
  85 + "[#{ref}](#{branch_url})"
  86 + end
  87 +
  88 + def project_link
  89 + "[#{project_name}](#{project_url})"
  90 + end
  91 +
  92 + def compare_link
  93 + "[Compare changes](#{compare_url})"
  94 + end
  95 +end
... ...
app/models/project_services/slack_service.rb 0 → 100644
... ... @@ -0,0 +1,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 20  
21 21 attr_accessible :title, :content, :file_name, :expires_at, :private
22 22  
  23 + default_value_for :private, true
  24 +
23 25 belongs_to :author, class_name: "User"
24 26  
25 27 has_many :notes, as: :noteable, dependent: :destroy
... ...
app/models/user.rb
... ... @@ -185,7 +185,7 @@ class User &lt; ActiveRecord::Base
185 185 where(conditions).first
186 186 end
187 187 end
188   -
  188 +
189 189 def find_for_commit(email, name)
190 190 # Prefer email match over name match
191 191 User.where(email: email).first ||
... ... @@ -249,7 +249,7 @@ class User &lt; ActiveRecord::Base
249 249 def namespace_uniq
250 250 namespace_name = self.username
251 251 if Namespace.find_by(path: namespace_name)
252   - self.errors.add :username, "already exist"
  252 + self.errors.add :username, "already exists"
253 253 end
254 254 end
255 255  
... ... @@ -275,7 +275,9 @@ class User &lt; ActiveRecord::Base
275 275 # Projects user has access to
276 276 def authorized_projects
277 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 281 Project.where(id: project_ids).joins(:namespace).order('namespaces.name ASC')
280 282 end
281 283 end
... ... @@ -406,6 +408,14 @@ class User &lt; ActiveRecord::Base
406 408 end
407 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 419 def solo_owned_groups
410 420 @solo_owned_groups ||= owned_groups.select do |group|
411 421 group.owners == [self]
... ...
app/observers/project_observer.rb
1 1 class ProjectObserver < BaseObserver
2 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 4 end
29 5  
30 6 def after_update(project)
... ...
app/services/git_tag_push_service.rb 0 → 100644
... ... @@ -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 12 merge_request.author_id_of_changes = current_user.id
13 13 merge_request.merge
14 14  
15   - notification.merge_mr(merge_request)
  15 + notification.merge_mr(merge_request, current_user)
16 16 create_merge_event(merge_request)
17 17 execute_project_hooks(merge_request)
18 18  
... ...
app/services/merge_requests/merge_service.rb
... ... @@ -10,7 +10,7 @@ module MergeRequests
10 10 merge_request.author_id_of_changes = current_user.id
11 11 merge_request.merge
12 12  
13   - notification.merge_mr(merge_request)
  13 + notification.merge_mr(merge_request, current_user)
14 14 create_merge_event(merge_request)
15 15 execute_project_hooks(merge_request)
16 16  
... ...
app/services/notification_service.rb
... ... @@ -86,12 +86,12 @@ class NotificationService
86 86 # * merge_request assignee if their notification level is not Disabled
87 87 # * project team members with notification level higher then Participating
88 88 #
89   - def merge_mr(merge_request)
  89 + def merge_mr(merge_request, current_user)
90 90 recipients = reject_muted_users([merge_request.author, merge_request.assignee], merge_request.target_project)
91 91 recipients = recipients.concat(project_watchers(merge_request.target_project)).uniq
92 92  
93 93 recipients.each do |recipient|
94   - mailer.merged_merge_request_email(recipient.id, merge_request.id)
  94 + mailer.merged_merge_request_email(recipient.id, merge_request.id, current_user.id)
95 95 end
96 96 end
97 97  
... ... @@ -111,6 +111,7 @@ class NotificationService
111 111  
112 112 # ignore gitlab service messages
113 113 return true if note.note =~ /\A_Status changed to closed_/
  114 + return true if note.note =~ /\A_mentioned in / && note.system == true
114 115  
115 116 opts = { noteable_type: note.noteable_type, project_id: note.project_id }
116 117  
... ...
app/services/projects/create_service.rb
... ... @@ -58,6 +58,29 @@ module Projects
58 58 user: current_user
59 59 )
60 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 84 end
62 85  
63 86 @project
... ...
app/services/search/global_service.rb
... ... @@ -14,10 +14,9 @@ module Search
14 14 group = Group.find_by(id: params[:group_id]) if params[:group_id].present?
15 15 projects = Project.accessible_to(current_user)
16 16 projects = projects.where(namespace_id: group.id) if group
17   - projects = projects.search(query)
18 17 project_ids = projects.pluck(:id)
19 18  
20   - result[:projects] = projects.limit(20)
  19 + result[:projects] = projects.search(query).limit(20)
21 20 result[:merge_requests] = MergeRequest.in_projects(project_ids).search(query).order('updated_at DESC').limit(20)
22 21 result[:issues] = Issue.where(project_id: project_ids).search(query).order('updated_at DESC').limit(20)
23 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 14 %table.table
15 15 %thead
16 16 %th USER
17   - %th
18 17 %th PID
19   - %th
20 18 %th CPU
21   - %th
22 19 %th MEM
23   - %th
24 20 %th STATE
25   - %th
26 21 %th START
27   - %th
28 22 %th COMMAND
29   - %th
30   - - @sidekiq_processes.split("\n").each do |process|
  23 + %tbody
  24 + - @sidekiq_processes.each do |process|
31 25 - next unless process.match(/(sidekiq \d+\.\d+\.\d+.+$)/)
32   - - data = process.gsub!(/\s+/m, '|').strip.split('|')
  26 + - data = process.strip.split(' ')
33 27 %tr
34   - - 6.times do
  28 + %td= Settings.gitlab.user
  29 + - 5.times do
35 30 %td= data.shift
36   - %td
37   - %td= data.join(" ")
  31 + %td= data.join(' ')
38 32  
39 33 .clearfix
40 34 %p
... ...
app/views/dashboard/_zero_authorized_projects.html.haml
... ... @@ -34,3 +34,18 @@
34 34 = link_to new_group_path, class: "btn btn-new" do
35 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 2 - if providers.present?
3 3 %hr
4 4 %div{:'data-no-turbolink' => 'data-no-turbolink'}
5   - %span Sign in with: &nbsp;
  5 + %span Sign in with*: &nbsp;
6 6 - providers.each do |provider|
7 7 %span
8 8 - if default_providers.include?(provider)
9 9 = link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
10 10 - else
11 11 = link_to provider.to_s.titleize, omniauth_authorize_path(resource_name, provider), class: "btn"
  12 + %br
  13 + %small * Make sure your email address is public
... ...
app/views/groups/members.html.haml
... ... @@ -9,7 +9,7 @@
9 9  
10 10 %hr
11 11  
12   -.clearfix
  12 +.clearfix.js-toggle-container
13 13 = form_tag members_group_path(@group), method: :get, class: 'form-inline member-search-form' do
14 14 .form-group
15 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 17  
18 18 - if current_user && current_user.can?(:manage_group, @group)
19 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 21 Add members
22 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 25 = render "new_group_member"
26 26  
27 27 .ui-box.prepend-top-20
... ...
app/views/layouts/_head.html.haml
... ... @@ -4,7 +4,8 @@
4 4 = "#{title} | " if defined?(title)
5 5 GitLab
6 6 = favicon_link_tag 'favicon.ico'
7   - = stylesheet_link_tag "application"
  7 + = stylesheet_link_tag "application", :media => "all"
  8 + = stylesheet_link_tag "print", :media => "print"
8 9 = javascript_include_tag "application"
9 10 = csrf_meta_tags
10 11 = include_gon
... ...
app/views/layouts/_head_panel.html.haml
... ... @@ -15,10 +15,6 @@
15 15 .navbar-collapse.collapse
16 16 %ul.nav.navbar-nav
17 17 %li.hidden-sm.hidden-xs
18   - %a
19   - %div.hide.turbolink-spinner
20   - %i.icon-refresh.icon-spin
21   - %li.hidden-sm.hidden-xs
22 18 = render "layouts/search"
23 19 %li.visible-sm.visible-xs
24 20 = link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
... ...
app/views/layouts/_init_auto_complete.html.haml
1 1 :javascript
2 2 GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_project_path(@project)}"
3   - GitLab.GfmAutoComplete.Emoji.assetBase = "#{Gitlab.config.gitlab.relative_url_root + '/assets/emoji'}"
4 3 GitLab.GfmAutoComplete.setup();
... ...
app/views/layouts/_public_head_panel.html.haml
... ... @@ -8,11 +8,15 @@
8 8 %span.separator
9 9 %h1.title= title
10 10  
11   - .pull-right
  11 + %button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
  12 + %span.sr-only Toggle navigation
  13 + %i.icon-reorder
  14 +
  15 + .pull-right.hidden-xs
12 16 = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
13 17  
14   - %ul.nav.navbar-nav
15   - %li
16   - %a
17   - %div.hide.turbolink-spinner
18   - %i.icon-refresh.icon-spin
  18 + .navbar-collapse.collapse
  19 + %ul.nav.navbar-nav
  20 + %li.visible-xs
  21 + = link_to "Sign in", new_session_path(:user)
  22 +
... ...
app/views/layouts/notify.html.haml
... ... @@ -3,20 +3,24 @@
3 3 %meta{content: "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
4 4 %title
5 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 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 4 %body{class: "#{app_theme} application", :'data-page' => body_data_page}
5 5 = render "layouts/broadcast"
6 6 = render "layouts/public_head_panel", title: project_title(@project)
7   - %nav.main-nav
  7 + %nav.main-nav.navbar-collapse.collapse
8 8 .container= render 'layouts/nav/project'
9 9 .container
10 10 .content= yield
... ...
app/views/notify/_note_message.html.haml
1   -%p
2   - %strong #{@note.author_name}
3   - wrote:
4   -
5   -%cite{style: 'color: #666'}
  1 +%div
6 2 = markdown(@note.note)
... ...
app/views/notify/closed_issue_email.html.haml
1 1 %p
2 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 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 1 %p
2 2 = "You have been granted #{@membership.human_access} access to group"
3   -%p
4 3 = link_to group_url(@group) do
5 4 = @group.name
... ...
app/views/notify/issue_status_changed_email.html.haml
1 1 %p
2 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 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 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 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 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 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 1 = render 'note_message'
... ...
app/views/notify/reassigned_issue_email.html.haml
1 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 2 Assignee changed
6 3 - if @previous_assignee
7 4 from
... ...
app/views/notify/reassigned_merge_request_email.html.haml
1 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 2 Assignee changed
6 3 - if @previous_assignee
7 4 from
... ...
app/views/projects/commit/_commit_box.html.haml
1 1 .pull-right
2 2 %div
3 3 - if @notes_count > 0
4   - %span.btn.disabled.grouped
  4 + %span.btn.disabled.btn-grouped
5 5 %i.icon-comment
6 6 = @notes_count
7 7 .pull-left.btn-group
... ... @@ -47,7 +47,7 @@
47 47 - if @branches.any?
48 48 and in
49 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 51 = commit_branches_links(@project, @branches)
52 52  
53 53 .commit-box
... ...
app/views/projects/commits/_diffs.html.haml
... ... @@ -44,7 +44,7 @@
44 44 - file = project.repository.blob_at(@commit.id, diff.new_path)
45 45 - file = project.repository.blob_at(@commit.parent_id, diff.old_path) unless file
46 46 - next unless file
47   - .diff-file{id: "diff-#{i}"}
  47 + .diff-file.js-toggle-container{id: "diff-#{i}"}
48 48 .diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"}
49 49 - if diff.deleted_file
50 50 %span= diff.old_path
... ... @@ -60,6 +60,11 @@
60 60 %span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
61 61  
62 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 68 - if @merge_request && @merge_request.source_project
64 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 70 Edit
... ...
app/views/projects/create.js.haml
1 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 8 - else
5 9 :plain
6 10 $(".project-edit-errors").html("#{escape_javascript(render('errors'))}");
... ...
app/views/projects/edit.html.haml
... ... @@ -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 160 .ui-box.ui-box-danger
140   - .title Transfer project
  161 + .title Rename repository
141 162 .errors-holder
142 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 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 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 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 175 %li You will need to update your local repositories to point to the new location.
154 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 192 .save-project-loader.hide
192 193 %center
... ...
app/views/projects/empty.html.haml
1 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 27 %p.light
28 28 This url will be triggered by a push to the repository
29 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 37 = f.check_box :issues_events, class: 'pull-left'
31 38 .prepend-left-20
32 39 = f.label :issues_events, class: 'list-label' do
... ... @@ -56,6 +63,6 @@
56 63 .clearfix
57 64 %span.monospace= hook.url
58 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 67 - if hook.send(trigger)
61 68 %span.label.label-gray= trigger.titleize
... ...