Commit 61cfa2a7a6e1d4557b69e17c537656e8a0201ac8

Authored by Sebastian Ziebell
2 parents d269d107 6beae84e

Merge branch 'master' into fixes/api

Conflicts:
	lib/api/projects.rb
Showing 147 changed files with 1924 additions and 1221 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 147 files displayed.

CONTRIBUTING.md
1   -# Contact & support
  1 +# Contribute to GitLab
2 2  
3   -If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq).
4   -Otherwise you can follow our [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) for a more systematic and thorough guide to solving your issues.
  3 +If you have a question or want to contribute to GitLab this guide show you the appropriate channel to use.
5 4  
  5 +## Ruling out common errors
6 6  
  7 +Some errors are common and it may so happen, that you are not the only one who stumbled over a particular issue. We have [collected several of those and documented quick solutions](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) for them.
7 8  
8   -# Contribute to GitLab
  9 +## Support forum
  10 +
  11 +Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) for any kind of question regarding the usage or adiministration/configuration of GitLab.
  12 +
  13 +### Use the support forum if ...
9 14  
10   -## Recipes
  15 +* You get permission denied errors
  16 +* You can't see your repos
  17 +* You have issues cloning, pulling or pushing
  18 +* You have issues with web_hooks not firing
11 19  
12   -We collect user submitted installation scripts and config file templates for platforms we don't support officially.
13   -We believe there is merit in allowing a certain amount of diversity.
14   -You can get and submit your solution to running/configuring GitLab with your favorite OS/distro, database, web server, cloud hoster, configuration management tool, etc.
  20 +**Search** for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved.
15 21  
16   -Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/)
  22 +## Paid support
17 23  
  24 +Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. Paid support is available from [GitLab.com](http://blog.gitlab.com/services/)
18 25  
19 26 ## Feature suggestions
20 27  
21   -Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own.
  28 +Feature suggestions don't belong in issues but can go to [Feedback forum](http://gitlab.uservoice.com/forums/176466-general) where they can be voted on.
  29 +
  30 +## Pull requests
  31 +
  32 +Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows:
  33 +
  34 +1. Fork the project on GitHub
  35 +1. Create a feature branch
  36 +1. Write tests and code
  37 +1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
  38 +1. Push the commit to your fork
  39 +1. Submit a pull request
  40 +
  41 +We will accept pull requests if:
  42 +
  43 +* The code has proper tests and all tests pass
  44 +* It can be merged without problems (if not please use: git rebase master)
  45 +* It doesn't break any existing functionality
  46 +* It's quality code that conforms to the [Rails style guide](https://github.com/bbatsov/rails-style-guide) and best practices
  47 +* The description includes a motive for your change and the method you used to achieve it
  48 +* It keeps the GitLab code base clean and well structured
  49 +* We think other users will need the same functionality
  50 +* If it makes changes to the UI the pull request should include screenshots
  51 +
  52 +For examples of feedback on pull requests please look at already [closed pull requests](https://github.com/gitlabhq/gitlabhq/pulls?direction=desc&page=1&sort=created&state=closed).
  53 +
  54 +## Submitting via GitHub's issue tracker
  55 +
  56 +* For obvious bugs or misbehavior in GitLab in the master branch. Please include the revision id and a reproducible test case.
  57 +* For problematic or insufficient documentation. Please give a suggestion on how to improve it.
  58 +
  59 +If you're unsure where to post, post it to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first.
  60 +There are a lot of helpful GitLab users there who may be able to help you quickly.
  61 +If your particular issue turns out to be a bug, it will find its way from there to the [issue tracker on GitHub](https://github.com/gitlabhq/gitlabhq/issues).
  62 +
  63 +### When submitting an issue
  64 +
  65 +**Search** for similar entries before submitting your own, there's a good chance somebody else had the same issue or idea. Show your support with `:+1:` and/or join the discussion.
  66 +
  67 +Please consider the following points when submitting an **issue**:
22 68  
  69 +* Summarize your issue in one sentence (what happened wrong, when you did/expected something else)
  70 +* Describe your issue in detail (including steps to reproduce)
  71 +* Add logs or screen shots when possible
  72 +* Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`)
23 73  
24   -## Code
  74 +## Thank you!
25 75  
26   -Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab.
  76 +By taking the time to use the right channel, you help the development team to organize and prioritize issues and suggestions in order to make GitLab a better product for us all.
... ...
Gemfile
... ... @@ -15,16 +15,18 @@ gem "mysql2", group: :mysql
15 15 gem "pg", group: :postgres
16 16  
17 17 # Auth
18   -gem "devise", "~> 2.1.0"
19   -gem 'omniauth', "~> 1.1.1"
  18 +gem "devise"
  19 +gem 'omniauth', "~> 1.1.3"
20 20 gem 'omniauth-google-oauth2'
21 21 gem 'omniauth-twitter'
22 22 gem 'omniauth-github'
23 23  
24   -# GITLAB patched libs
25   -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b'
26   -gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8'
27   -gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e'
  24 +# Extracting information from a git repository
  25 +gem "gitlab-grit", '~> 1.0.0', require: 'grit'
  26 +gem 'grit_ext', '~> 0.6.2'
  27 +
  28 +# Ruby/Rack Git Smart-HTTP Server Handler
  29 +gem 'gitlab-grack', '~> 1.0.0', require: 'grack'
28 30  
29 31 # LDAP Auth
30 32 gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap"
... ... @@ -33,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap"
33 35 gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db"
34 36  
35 37 # Syntax highlighter
36   -gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master"
  38 +gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
37 39  
38 40 # Language detection
39 41 gem "github-linguist", "~> 2.3.4" , require: "linguist"
... ... @@ -46,14 +48,17 @@ gem "grape-entity", "~> 0.2.0"
46 48 # based on human-friendly examples
47 49 gem "stamp"
48 50  
  51 +# Enumeration fields
  52 +gem 'enumerize'
  53 +
49 54 # Pagination
50 55 gem "kaminari", "~> 0.14.1"
51 56  
52 57 # HAML
53   -gem "haml-rails", "~> 0.3.5"
  58 +gem "haml-rails"
54 59  
55 60 # Files attachments
56   -gem "carrierwave", "~> 0.7.1"
  61 +gem "carrierwave"
57 62  
58 63 # Authorization
59 64 gem "six"
... ... @@ -69,7 +74,7 @@ gem "redcarpet", "~> 2.2.2"
69 74 gem "github-markup", "~> 0.7.4", require: 'github/markup'
70 75  
71 76 # Servers
72   -gem "unicorn", "~> 4.4.0"
  77 +gem "unicorn"
73 78  
74 79 # State machine
75 80 gem "state_machine"
... ... @@ -78,12 +83,12 @@ gem "state_machine"
78 83 gem "acts-as-taggable-on", "2.3.3"
79 84  
80 85 # Decorators
81   -gem "draper", "~> 0.18.0"
  86 +gem "draper"
82 87  
83 88 # Background jobs
84 89 gem 'slim'
85 90 gem 'sinatra', require: nil
86   -gem 'sidekiq', '2.7.3'
  91 +gem 'sidekiq'
87 92  
88 93 # HTTP requests
89 94 gem "httparty"
... ... @@ -113,6 +118,7 @@ group :assets do
113 118 gem 'bootstrap-sass', "2.2.1.1"
114 119 gem "font-awesome-sass-rails", "~> 3.0.0"
115 120 gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
  121 + gem "gon"
116 122 end
117 123  
118 124 group :development do
... ... @@ -140,7 +146,7 @@ group :development, :test do
140 146 gem "capybara", '2.0.2'
141 147 gem "pry"
142 148 gem "awesome_print"
143   - gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git"
  149 + gem "database_cleaner"
144 150 gem "launchy"
145 151 gem 'factory_girl_rails'
146 152  
... ...
Gemfile.lock
1 1 GIT
2   - remote: https://github.com/bmabey/database_cleaner.git
3   - revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
4   - ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
5   - specs:
6   - database_cleaner (0.9.1)
7   -
8   -GIT
9 2 remote: https://github.com/ctran/annotate_models.git
10 3 revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e
11 4 specs:
... ... @@ -14,41 +7,6 @@ GIT
14 7 rake (>= 0.8.7)
15 8  
16 9 GIT
17   - remote: https://github.com/gitlabhq/grack.git
18   - revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
19   - ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
20   - specs:
21   - grack (1.0.0)
22   - rack (~> 1.4.1)
23   -
24   -GIT
25   - remote: https://github.com/gitlabhq/grit.git
26   - revision: 9e98418ce2d654485b967003726aa2706a10060b
27   - ref: 9e98418ce2d654485b967003726aa2706a10060b
28   - specs:
29   - grit (2.5.0)
30   - diff-lcs (~> 1.1)
31   - mime-types (~> 1.15)
32   - posix-spawn (~> 0.3.6)
33   -
34   -GIT
35   - remote: https://github.com/gitlabhq/grit_ext.git
36   - revision: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
37   - ref: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
38   - specs:
39   - grit_ext (0.6.1)
40   - charlock_holmes (~> 0.6.9)
41   -
42   -GIT
43   - remote: https://github.com/gitlabhq/pygments.rb.git
44   - revision: db1da0343adf86b49bdc3add04d02d2e80438d38
45   - branch: master
46   - specs:
47   - pygments.rb (0.3.2)
48   - posix-spawn (~> 0.3.6)
49   - yajl-ruby (~> 1.1.0)
50   -
51   -GIT
52 10 remote: https://github.com/gitlabhq/raphael-rails.git
53 11 revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58
54 12 specs:
... ... @@ -89,12 +47,13 @@ GEM
89 47 addressable (2.3.2)
90 48 arel (3.0.2)
91 49 awesome_print (1.1.0)
92   - backports (2.6.5)
  50 + backports (2.6.7)
93 51 bcrypt-ruby (3.0.1)
94 52 better_errors (0.3.2)
95 53 coderay (>= 1.0.0)
96 54 erubis (>= 2.7.0)
97   - binding_of_caller (0.6.8)
  55 + binding_of_caller (0.7.1)
  56 + debug_inspector (>= 0.0.1)
98 57 bootstrap-sass (2.2.1.1)
99 58 sass (~> 3.2)
100 59 builder (3.0.4)
... ... @@ -105,7 +64,7 @@ GEM
105 64 rack-test (>= 0.5.4)
106 65 selenium-webdriver (~> 2.0)
107 66 xpath (~> 1.0.0)
108   - carrierwave (0.7.1)
  67 + carrierwave (0.8.0)
109 68 activemodel (>= 3.2.0)
110 69 activesupport (>= 3.2.0)
111 70 celluloid (0.12.4)
... ... @@ -132,18 +91,24 @@ GEM
132 91 connection_pool (1.0.0)
133 92 crack (0.3.1)
134 93 daemons (1.1.9)
135   - devise (2.1.2)
  94 + database_cleaner (0.9.1)
  95 + debug_inspector (0.0.2)
  96 + descendants_tracker (0.0.1)
  97 + devise (2.2.3)
136 98 bcrypt-ruby (~> 3.0)
137 99 orm_adapter (~> 0.1)
138 100 railties (~> 3.1)
139 101 warden (~> 1.2.1)
140 102 diff-lcs (1.1.3)
141   - draper (0.18.0)
142   - actionpack (~> 3.2)
143   - activesupport (~> 3.2)
  103 + draper (1.1.0)
  104 + actionpack (>= 3.0)
  105 + activesupport (>= 3.0)
  106 + request_store (~> 1.0.3)
144 107 email_spec (1.4.0)
145 108 launchy (~> 2.1)
146 109 mail (~> 2.2)
  110 + enumerize (0.5.1)
  111 + activesupport (>= 3.2)
147 112 erubis (2.7.0)
148 113 escape_utils (0.2.4)
149 114 eventmachine (1.0.0)
... ... @@ -155,7 +120,7 @@ GEM
155 120 factory_girl_rails (4.1.0)
156 121 factory_girl (~> 4.1.0)
157 122 railties (>= 3.0.0)
158   - faraday (0.8.4)
  123 + faraday (0.8.6)
159 124 multipart-post (~> 1.1)
160 125 faye-websocket (0.4.7)
161 126 eventmachine (>= 0.12.0)
... ... @@ -164,7 +129,7 @@ GEM
164 129 font-awesome-sass-rails (3.0.0.1)
165 130 railties (>= 3.1.1)
166 131 sass-rails (>= 3.1.1)
167   - foreman (0.60.2)
  132 + foreman (0.61.0)
168 133 thor (>= 0.13.6)
169 134 gemoji (1.2.1)
170 135 gherkin-ruby (0.2.1)
... ... @@ -174,7 +139,16 @@ GEM
174 139 escape_utils (~> 0.2.3)
175 140 mime-types (~> 1.19)
176 141 pygments.rb (>= 0.2.13)
177   - github-markup (0.7.4)
  142 + github-markup (0.7.5)
  143 + gitlab-grack (1.0.0)
  144 + rack (~> 1.4.1)
  145 + gitlab-grit (1.0.0)
  146 + diff-lcs (~> 1.1)
  147 + mime-types (~> 1.15)
  148 + posix-spawn (~> 0.3.6)
  149 + gitlab-pygments.rb (0.3.2)
  150 + posix-spawn (~> 0.3.6)
  151 + yajl-ruby (~> 1.1.0)
178 152 gitlab_meta (5.0)
179 153 gitlab_omniauth-ldap (1.0.2)
180 154 net-ldap (~> 0.2.2)
... ... @@ -182,17 +156,22 @@ GEM
182 156 pyu-ruby-sasl (~> 0.0.3.1)
183 157 rubyntlm (~> 0.1.1)
184 158 gitlab_yaml_db (1.0.0)
185   - grape (0.3.1)
  159 + gon (4.0.2)
  160 + grape (0.3.2)
186 161 activesupport
187   - grape-entity (~> 0.2.0)
188   - hashie (~> 1.2)
  162 + builder
  163 + hashie (>= 1.2.0)
189 164 multi_json (>= 1.3.2)
190   - multi_xml
  165 + multi_xml (>= 0.5.2)
191 166 rack
192 167 rack-accept
193 168 rack-mount
194 169 virtus
195 170 grape-entity (0.2.0)
  171 + activesupport
  172 + multi_json (>= 1.3.2)
  173 + grit_ext (0.6.2)
  174 + charlock_holmes (~> 0.6.9)
196 175 growl (1.0.3)
197 176 guard (1.5.4)
198 177 listen (>= 0.4.2)
... ... @@ -205,20 +184,21 @@ GEM
205 184 guard-spinach (0.0.2)
206 185 guard (>= 1.1)
207 186 spinach
208   - haml (3.1.7)
209   - haml-rails (0.3.5)
  187 + haml (4.0.0)
  188 + tilt
  189 + haml-rails (0.4)
210 190 actionpack (>= 3.1, < 4.1)
211 191 activesupport (>= 3.1, < 4.1)
212   - haml (~> 3.1)
  192 + haml (>= 3.1, < 4.1)
213 193 railties (>= 3.1, < 4.1)
214 194 hashie (1.2.0)
215 195 hike (1.2.1)
216 196 http_parser.rb (0.5.3)
217   - httparty (0.9.0)
  197 + httparty (0.10.2)
218 198 multi_json (~> 1.0)
219   - multi_xml
  199 + multi_xml (>= 0.5.2)
220 200 httpauth (0.2.0)
221   - i18n (0.6.1)
  201 + i18n (0.6.4)
222 202 journey (1.0.4)
223 203 jquery-atwho-rails (0.1.7)
224 204 jquery-rails (2.1.3)
... ... @@ -233,7 +213,7 @@ GEM
233 213 kaminari (0.14.1)
234 214 actionpack (>= 3.0.0)
235 215 activesupport (>= 3.0.0)
236   - kgio (2.7.4)
  216 + kgio (2.8.0)
237 217 launchy (2.1.2)
238 218 addressable (~> 2.3)
239 219 letter_opener (1.0.0)
... ... @@ -250,22 +230,22 @@ GEM
250 230 modernizr (2.6.2)
251 231 sprockets (~> 2.0)
252 232 multi_json (1.6.1)
253   - multi_xml (0.5.1)
254   - multipart-post (1.1.5)
  233 + multi_xml (0.5.3)
  234 + multipart-post (1.2.0)
255 235 mysql2 (0.3.11)
256 236 net-ldap (0.2.2)
257 237 nokogiri (1.5.6)
258 238 oauth (0.4.7)
259   - oauth2 (0.8.0)
  239 + oauth2 (0.8.1)
260 240 faraday (~> 0.8)
261 241 httpauth (~> 0.1)
262 242 jwt (~> 0.1.4)
263 243 multi_json (~> 1.0)
264 244 rack (~> 1.2)
265   - omniauth (1.1.1)
  245 + omniauth (1.1.3)
266 246 hashie (~> 1.2)
267 247 rack
268   - omniauth-github (1.0.3)
  248 + omniauth-github (1.1.0)
269 249 omniauth (~> 1.0)
270 250 omniauth-oauth2 (~> 1.1)
271 251 omniauth-google-oauth2 (0.1.13)
... ... @@ -293,6 +273,9 @@ GEM
293 273 coderay (~> 1.0.5)
294 274 method_source (~> 0.8)
295 275 slop (~> 3.3.1)
  276 + pygments.rb (0.4.2)
  277 + posix-spawn (~> 0.3.6)
  278 + yajl-ruby (~> 1.1.0)
296 279 pyu-ruby-sasl (0.0.3.3)
297 280 quiet_assets (1.0.1)
298 281 railties (~> 3.1)
... ... @@ -305,7 +288,7 @@ GEM
305 288 rack (>= 1.1.3)
306 289 rack-mount (0.8.3)
307 290 rack (>= 1.0.0)
308   - rack-protection (1.3.2)
  291 + rack-protection (1.4.0)
309 292 rack
310 293 rack-ssl (1.3.3)
311 294 rack
... ... @@ -342,12 +325,13 @@ GEM
342 325 rb-fsevent (0.9.2)
343 326 rb-inotify (0.8.8)
344 327 ffi (>= 0.5.0)
345   - rdoc (3.12.1)
  328 + rdoc (3.12.2)
346 329 json (~> 1.4)
347 330 redcarpet (2.2.2)
348 331 redis (3.0.2)
349 332 redis-namespace (1.2.1)
350 333 redis (~> 3.0.0)
  334 + request_store (1.0.5)
351 335 rspec (2.12.0)
352 336 rspec-core (~> 2.12.0)
353 337 rspec-expectations (~> 2.12.0)
... ... @@ -381,11 +365,11 @@ GEM
381 365 multi_json (~> 1.0)
382 366 rubyzip
383 367 websocket (~> 1.0.4)
384   - settingslogic (2.0.8)
  368 + settingslogic (2.0.9)
385 369 sexp_processor (4.1.3)
386 370 shoulda-matchers (1.3.0)
387 371 activesupport (>= 3.0.0)
388   - sidekiq (2.7.3)
  372 + sidekiq (2.7.5)
389 373 celluloid (~> 0.12.0)
390 374 connection_pool (~> 1.0)
391 375 multi_json (~> 1)
... ... @@ -395,9 +379,9 @@ GEM
395 379 multi_json (~> 1.0)
396 380 simplecov-html (~> 0.7.1)
397 381 simplecov-html (0.7.1)
398   - sinatra (1.3.3)
399   - rack (~> 1.3, >= 1.3.6)
400   - rack-protection (~> 1.2)
  382 + sinatra (1.3.5)
  383 + rack (~> 1.4)
  384 + rack-protection (~> 1.3)
401 385 tilt (~> 1.3, >= 1.3.3)
402 386 six (0.2.0)
403 387 slim (1.3.6)
... ... @@ -416,7 +400,7 @@ GEM
416 400 multi_json (~> 1.0)
417 401 rack (~> 1.0)
418 402 tilt (~> 1.1, != 1.3.0)
419   - stamp (0.3.0)
  403 + stamp (0.5.0)
420 404 state_machine (1.1.2)
421 405 temple (0.5.5)
422 406 test_after_commit (0.0.1)
... ... @@ -427,7 +411,7 @@ GEM
427 411 eventmachine (>= 0.12.6)
428 412 rack (>= 1.0.0)
429 413 thor (0.17.0)
430   - tilt (1.3.3)
  414 + tilt (1.3.4)
431 415 timers (1.1.0)
432 416 treetop (1.4.12)
433 417 polyglot
... ... @@ -436,12 +420,13 @@ GEM
436 420 uglifier (1.3.0)
437 421 execjs (>= 0.3.0)
438 422 multi_json (~> 1.0, >= 1.0.2)
439   - unicorn (4.4.0)
  423 + unicorn (4.6.2)
440 424 kgio (~> 2.6)
441 425 rack
442 426 raindrops (~> 0.7)
443   - virtus (0.5.2)
  427 + virtus (0.5.4)
444 428 backports (~> 2.6.1)
  429 + descendants_tracker (~> 0.0.1)
445 430 warden (1.2.1)
446 431 rack (>= 1.0)
447 432 webmock (1.9.0)
... ... @@ -463,14 +448,15 @@ DEPENDENCIES
463 448 binding_of_caller
464 449 bootstrap-sass (= 2.2.1.1)
465 450 capybara (= 2.0.2)
466   - carrierwave (~> 0.7.1)
  451 + carrierwave
467 452 chosen-rails (= 0.9.8)
468 453 coffee-rails (~> 3.2.2)
469 454 colored
470   - database_cleaner!
471   - devise (~> 2.1.0)
472   - draper (~> 0.18.0)
  455 + database_cleaner
  456 + devise
  457 + draper
473 458 email_spec
  459 + enumerize
474 460 factory_girl_rails
475 461 ffaker
476 462 font-awesome-sass-rails (~> 3.0.0)
... ... @@ -479,18 +465,20 @@ DEPENDENCIES
479 465 git
480 466 github-linguist (~> 2.3.4)
481 467 github-markup (~> 0.7.4)
  468 + gitlab-grack (~> 1.0.0)
  469 + gitlab-grit (~> 1.0.0)
  470 + gitlab-pygments.rb (~> 0.3.2)
482 471 gitlab_meta (= 5.0)
483 472 gitlab_omniauth-ldap (= 1.0.2)
484 473 gitlab_yaml_db (= 1.0.0)
485   - grack!
  474 + gon
486 475 grape (~> 0.3.1)
487 476 grape-entity (~> 0.2.0)
488   - grit!
489   - grit_ext!
  477 + grit_ext (~> 0.6.2)
490 478 growl
491 479 guard-rspec
492 480 guard-spinach
493   - haml-rails (~> 0.3.5)
  481 + haml-rails
494 482 httparty
495 483 jquery-atwho-rails (= 0.1.7)
496 484 jquery-rails (= 2.1.3)
... ... @@ -500,14 +488,13 @@ DEPENDENCIES
500 488 letter_opener
501 489 modernizr (= 2.6.2)
502 490 mysql2
503   - omniauth (~> 1.1.1)
  491 + omniauth (~> 1.1.3)
504 492 omniauth-github
505 493 omniauth-google-oauth2
506 494 omniauth-twitter
507 495 pg
508 496 poltergeist (= 1.1.0)
509 497 pry
510   - pygments.rb!
511 498 quiet_assets (~> 1.0.1)
512 499 rack-mini-profiler
513 500 rails (= 3.2.12)
... ... @@ -523,7 +510,7 @@ DEPENDENCIES
523 510 seed-fu
524 511 settingslogic
525 512 shoulda-matchers (= 1.3.0)
526   - sidekiq (= 2.7.3)
  513 + sidekiq
527 514 simplecov
528 515 sinatra
529 516 six
... ... @@ -535,5 +522,5 @@ DEPENDENCIES
535 522 therubyracer
536 523 thin
537 524 uglifier (~> 1.3.0)
538   - unicorn (~> 4.4.0)
  525 + unicorn
539 526 webmock
... ...
README.md
1   -# Welcome to GitLab! Self hosted Git management software
  1 +## GitLab: self hosted Git management software
2 2  
  3 +![logo](https://raw.github.com/gitlabhq/gitlabhq/master/public/gitlab_logo.png)
3 4  
4   -## Badges:
  5 +### GitLab allows you to
  6 + * keep your code secure on your own server
  7 + * manage repositories, users and access permissions
  8 + * communicate though issues, line-comments and wiki's
  9 + * perform code reviews with merge requests
  10 +
  11 +### GitLab is
  12 +
  13 +* powered by Ruby on Rails
  14 +* completely free and open source (MIT license)
  15 +* used by 10.000 organization to keep their code secure
  16 +
  17 +### Code status
  18 +
  19 +* [![build status](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) ci.gitlab.org (master branch)
  20 +
  21 +* [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) travis-ci.org (master branch)
  22 +
  23 +* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
5 24  
6   -* master: travis-ci.org [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq)a
7   -* master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master)
8   -* [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
9 25 * [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq)
10 26  
11   -GitLab is a free project and repository management application
  27 +### Resources
12 28  
  29 +* 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)
13 30  
14   -## Application details
  31 +* GitLab.com: [Homepage](http://blog.gitlab.com/) [Hosted pricing](http://blog.gitlab.com/pricing/) [Services](http://blog.gitlab.com/services/) [Blog](http://blog.gitlab.com/blog/)
15 32  
16   -* powered by Ruby on Rails
17   -* its completely free and open source
18   -* distributed under the MIT License
  33 +* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server
19 34  
20   -## Requirements
  35 +### Requirements
21 36  
22   -* Ubuntu/Debian
  37 +* Ubuntu/Debian*
23 38 * ruby 1.9.3+
24 39 * MySQL
25 40 * git
26 41 * gitlab-shell
27 42 * redis
28 43  
29   -## Install
  44 +* More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md)
  45 +
  46 +### Installation
  47 +
  48 +You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vargrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing.
  49 +
  50 +* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md)
  51 +
  52 +* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md)
  53 +
  54 +* [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm)
  55 +
  56 +### Starting
  57 +
  58 +1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with:
  59 +
  60 + sudo service gitlab start
  61 +
  62 + or
  63 +
  64 + sudo /etc/init.d/gitlab restart
  65 +
  66 +2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model
  67 +
  68 + bundle exec foreman start -p 3000
  69 +
  70 +3. Start it manually in development mode
  71 +
  72 + bundle exec rails s
  73 + bundle exec rake sidekiq:start
  74 +
  75 +### Running the tests
  76 +
  77 +* Seed the database with
  78 +
  79 + bundle exec rake db:setup RAILS_ENV=test
  80 + bundle exec rake db:seed_fu RAILS_ENV=test
  81 +
  82 +* Run all tests
  83 +
  84 + bundle exec rake gitlab:test
  85 +
  86 +* Rspec unit and functional tests
  87 +
  88 + bundle exec rake spec
  89 +
  90 +* Spinach integration tests
  91 +
  92 + bundle exec rake spinach
  93 +
  94 +### Getting help
  95 +
  96 +* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide)
  97 +
  98 +* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq)
  99 +
  100 +* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general)
  101 +
  102 +* [Paid support](http://blog.gitlab.com/support/)
  103 +
  104 +* [Paid services](http://blog.gitlab.com/services/)
  105 +
  106 +### New versions and the API
  107 +
  108 +Each month on the 22th a new version is released together with an upgrade guide.
  109 +
  110 +* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki)
  111 +
  112 +* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md)
  113 +
  114 +### Other documentation
  115 +
  116 +* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md)
  117 +
  118 +* [Rake tasks](https://github.com/gitlabhq/gitlabhq/tree/master/doc/raketasks)
  119 +
  120 +* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes)
  121 +
  122 +### Getting in touch
30 123  
31   -Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc.
  124 +* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md)
32 125  
33   -## [Community](http://gitlab.org/community/)
  126 +* [Core team](https://github.com/gitlabhq?tab=members)
34 127  
35   -## [Contact](http://gitlab.org/contact/)
  128 +* [Contributors](https://github.com/gitlabhq/gitlabhq/graphs/contributors)
36 129  
37   -## Contribute
  130 +* [Leader](https://github.com/randx)
38 131  
39   -[Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide)
40   -Want to help - send a pull request.
41   -We'll accept good pull requests.
  132 +* [Contact page](http://gitlab.org/contact/)
... ...
ROADMAP.md
... ... @@ -4,9 +4,4 @@
4 4  
5 5 * Replace gitolite with gitlab-shell
6 6 * Usability improvements
7   -* Notification improvements
8   -
9   -### v4.2 February 22
10   -
11   -* Teams
12   -
  7 +* Notification improvements
13 8 \ No newline at end of file
... ...
app/assets/fonts/OFL.txt
... ... @@ -1,92 +0,0 @@
1   -Copyright (c) 2010, Jan Gerner (post@yanone.de)
2   -This Font Software is licensed under the SIL Open Font License, Version 1.1.
3   -This license is copied below, and is also available with a FAQ at:
4   -http://scripts.sil.org/OFL
5   -
6   -
7   ------------------------------------------------------------
8   -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9   ------------------------------------------------------------
10   -
11   -PREAMBLE
12   -The goals of the Open Font License (OFL) are to stimulate worldwide
13   -development of collaborative font projects, to support the font creation
14   -efforts of academic and linguistic communities, and to provide a free and
15   -open framework in which fonts may be shared and improved in partnership
16   -with others.
17   -
18   -The OFL allows the licensed fonts to be used, studied, modified and
19   -redistributed freely as long as they are not sold by themselves. The
20   -fonts, including any derivative works, can be bundled, embedded,
21   -redistributed and/or sold with any software provided that any reserved
22   -names are not used by derivative works. The fonts and derivatives,
23   -however, cannot be released under any other type of license. The
24   -requirement for fonts to remain under this license does not apply
25   -to any document created using the fonts or their derivatives.
26   -
27   -DEFINITIONS
28   -"Font Software" refers to the set of files released by the Copyright
29   -Holder(s) under this license and clearly marked as such. This may
30   -include source files, build scripts and documentation.
31   -
32   -"Reserved Font Name" refers to any names specified as such after the
33   -copyright statement(s).
34   -
35   -"Original Version" refers to the collection of Font Software components as
36   -distributed by the Copyright Holder(s).
37   -
38   -"Modified Version" refers to any derivative made by adding to, deleting,
39   -or substituting -- in part or in whole -- any of the components of the
40   -Original Version, by changing formats or by porting the Font Software to a
41   -new environment.
42   -
43   -"Author" refers to any designer, engineer, programmer, technical
44   -writer or other person who contributed to the Font Software.
45   -
46   -PERMISSION & CONDITIONS
47   -Permission is hereby granted, free of charge, to any person obtaining
48   -a copy of the Font Software, to use, study, copy, merge, embed, modify,
49   -redistribute, and sell modified and unmodified copies of the Font
50   -Software, subject to the following conditions:
51   -
52   -1) Neither the Font Software nor any of its individual components,
53   -in Original or Modified Versions, may be sold by itself.
54   -
55   -2) Original or Modified Versions of the Font Software may be bundled,
56   -redistributed and/or sold with any software, provided that each copy
57   -contains the above copyright notice and this license. These can be
58   -included either as stand-alone text files, human-readable headers or
59   -in the appropriate machine-readable metadata fields within text or
60   -binary files as long as those fields can be easily viewed by the user.
61   -
62   -3) No Modified Version of the Font Software may use the Reserved Font
63   -Name(s) unless explicit written permission is granted by the corresponding
64   -Copyright Holder. This restriction only applies to the primary font name as
65   -presented to the users.
66   -
67   -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68   -Software shall not be used to promote, endorse or advertise any
69   -Modified Version, except to acknowledge the contribution(s) of the
70   -Copyright Holder(s) and the Author(s) or with their explicit written
71   -permission.
72   -
73   -5) The Font Software, modified or unmodified, in part or in whole,
74   -must be distributed entirely under this license, and must not be
75   -distributed under any other license. The requirement for fonts to
76   -remain under this license does not apply to any document created
77   -using the Font Software.
78   -
79   -TERMINATION
80   -This license becomes null and void if any of the above conditions are
81   -not met.
82   -
83   -DISCLAIMER
84   -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85   -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86   -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87   -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88   -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89   -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90   -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91   -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92   -OTHER DEALINGS IN THE FONT SOFTWARE.
app/assets/fonts/YanoneKaffeesatz-Light.ttf
No preview for this file type
app/assets/javascripts/branch-graph.js 0 → 100644
... ... @@ -0,0 +1,400 @@
  1 +!function(){
  2 +
  3 + var BranchGraph = function(element, options){
  4 + this.element = element;
  5 + this.options = options;
  6 +
  7 + this.preparedCommits = {};
  8 + this.mtime = 0;
  9 + this.mspace = 0;
  10 + this.parents = {};
  11 + this.colors = ["#000"];
  12 +
  13 + this.load();
  14 + };
  15 +
  16 + BranchGraph.prototype.load = function(){
  17 + $.ajax({
  18 + url: this.options.url,
  19 + method: 'get',
  20 + dataType: 'json',
  21 + success: $.proxy(function(data){
  22 + $('.loading', this.element).hide();
  23 + this.prepareData(data.days, data.commits);
  24 + this.buildGraph();
  25 + }, this)
  26 + });
  27 + };
  28 +
  29 + BranchGraph.prototype.prepareData = function(days, commits){
  30 + this.days = days;
  31 + this.dayCount = days.length;
  32 + this.commits = commits;
  33 + this.commitCount = commits.length;
  34 +
  35 + this.collectParents();
  36 +
  37 + this.mtime += 4;
  38 + this.mspace += 10;
  39 + for (var i = 0; i < this.commitCount; i++) {
  40 + if (this.commits[i].id in this.parents) {
  41 + this.commits[i].isParent = true;
  42 + }
  43 + this.preparedCommits[this.commits[i].id] = this.commits[i];
  44 + }
  45 + this.collectColors();
  46 + };
  47 +
  48 + BranchGraph.prototype.collectParents = function(){
  49 + for (var i = 0; i < this.commitCount; i++) {
  50 + for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
  51 + this.parents[this.commits[i].parents[j][0]] = true;
  52 + }
  53 + this.mtime = Math.max(this.mtime, this.commits[i].time);
  54 + this.mspace = Math.max(this.mspace, this.commits[i].space);
  55 + }
  56 + };
  57 +
  58 + BranchGraph.prototype.collectColors = function(){
  59 + for (var k = 0; k < this.mspace; k++) {
  60 + this.colors.push(Raphael.getColor(.8));
  61 + // Skipping a few colors in the spectrum to get more contrast between colors
  62 + Raphael.getColor();Raphael.getColor();
  63 + }
  64 + };
  65 +
  66 + BranchGraph.prototype.buildGraph = function(){
  67 + var graphWidth = $(this.element).width()
  68 + , ch = this.mspace * 20 + 100
  69 + , cw = Math.max(graphWidth, this.mtime * 20 + 260)
  70 + , r = Raphael(this.element.get(0), cw, ch)
  71 + , top = r.set()
  72 + , cuday = 0
  73 + , cumonth = ""
  74 + , offsetX = 20
  75 + , offsetY = 60
  76 + , barWidth = Math.max(graphWidth, this.dayCount * 20 + 320)
  77 + , scrollLeft = cw;
  78 +
  79 + this.raphael = r;
  80 +
  81 + r.rect(0, 0, barWidth, 20).attr({fill: "#222"});
  82 + r.rect(0, 20, barWidth, 20).attr({fill: "#444"});
  83 +
  84 + for (mm = 0; mm < this.dayCount; mm++) {
  85 + if(this.days[mm] != null){
  86 + if(cuday != this.days[mm][0]){
  87 + // Dates
  88 + r.text(offsetX + mm * 20, 31, this.days[mm][0]).attr({
  89 + font: "12px Monaco, monospace",
  90 + fill: "#DDD"
  91 + });
  92 + cuday = this.days[mm][0];
  93 + }
  94 + if(cumonth != this.days[mm][1]){
  95 + // Months
  96 + r.text(offsetX + mm * 20, 11, this.days[mm][1]).attr({
  97 + font: "12px Monaco, monospace",
  98 + fill: "#EEE"
  99 + });
  100 + cumonth = this.days[mm][1];
  101 + }
  102 + }
  103 + }
  104 +
  105 + for (i = 0; i < this.commitCount; i++) {
  106 + var x = offsetX + 20 * this.commits[i].time
  107 + , y = offsetY + 10 * this.commits[i].space
  108 + , c
  109 + , ps;
  110 +
  111 + // Draw dot
  112 + r.circle(x, y, 3).attr({
  113 + fill: this.colors[this.commits[i].space],
  114 + stroke: "none"
  115 + });
  116 +
  117 + // Draw lines
  118 + for (var j = 0, jj = this.commits[i].parents.length; j < jj; j++) {
  119 + c = this.preparedCommits[this.commits[i].parents[j][0]];
  120 + ps = this.commits[i].parent_spaces[j];
  121 + if (c) {
  122 + var cx = offsetX + 20 * c.time
  123 + , cy = offsetY + 10 * c.space
  124 + , psy = offsetY + 10 * ps;
  125 + if (c.space == this.commits[i].space && c.space == ps) {
  126 + r.path([
  127 + "M", x, y,
  128 + "L", cx, cy
  129 + ]).attr({
  130 + stroke: this.colors[c.space],
  131 + "stroke-width": 2
  132 + });
  133 +
  134 + } else if (c.space < this.commits[i].space) {
  135 + if (y == psy) {
  136 + r.path([
  137 + "M", x - 5, y,
  138 + "l-5,-2,0,4,5,-2",
  139 + "L", x - 10, y,
  140 + "L", x - 15, psy,
  141 + "L", cx + 5, psy,
  142 + "L", cx, cy])
  143 + .attr({
  144 + stroke: this.colors[this.commits[i].space],
  145 + "stroke-width": 2
  146 + });
  147 + } else {
  148 + r.path([
  149 + "M", x - 3, y - 6,
  150 + "l-4,-3,4,-2,0,5",
  151 + "L", x - 5, y - 10,
  152 + "L", x - 10, psy,
  153 + "L", cx + 5, psy,
  154 + "L", cx, cy])
  155 + .attr({
  156 + stroke: this.colors[this.commits[i].space],
  157 + "stroke-width": 2
  158 + });
  159 + }
  160 + } else {
  161 + r.path([
  162 + "M", x - 3, y + 6,
  163 + "l-4,3,4,2,0,-5",
  164 + "L", x - 5, y + 10,
  165 + "L", x - 10, psy,
  166 + "L", cx + 5, psy,
  167 + "L", cx, cy])
  168 + .attr({
  169 + stroke: this.colors[c.space],
  170 + "stroke-width": 2
  171 + });
  172 + }
  173 + }
  174 + }
  175 +
  176 + if (this.commits[i].refs) {
  177 + this.appendLabel(x, y, this.commits[i].refs);
  178 + }
  179 +
  180 + // mark commit and displayed in the center
  181 + if (this.commits[i].id == this.options.commit_id) {
  182 + r.path([
  183 + 'M', x, y - 5,
  184 + 'L', x + 4, y - 15,
  185 + 'L', x - 4, y - 15,
  186 + 'Z'
  187 + ]).attr({
  188 + "fill": "#000",
  189 + "fill-opacity": .7,
  190 + "stroke": "none"
  191 + });
  192 + scrollLeft = x - graphWidth / 2;
  193 + }
  194 +
  195 + this.appendAnchor(top, this.commits[i], x, y);
  196 + }
  197 + top.toFront();
  198 + this.element.scrollLeft(scrollLeft);
  199 + this.bindEvents();
  200 + };
  201 +
  202 + BranchGraph.prototype.bindEvents = function(){
  203 + var drag = {}
  204 + , element = this.element;
  205 +
  206 + var dragger = function(event){
  207 + element.scrollLeft(drag.sl - (event.clientX - drag.x));
  208 + element.scrollTop(drag.st - (event.clientY - drag.y));
  209 + };
  210 +
  211 + element.on({
  212 + mousedown: function (event) {
  213 + drag = {
  214 + x: event.clientX,
  215 + y: event.clientY,
  216 + st: element.scrollTop(),
  217 + sl: element.scrollLeft()
  218 + };
  219 + $(window).on('mousemove', dragger);
  220 + }
  221 + });
  222 + $(window).on({
  223 + mouseup: function(){
  224 + //bars.animate({opacity: 0}, 300);
  225 + $(window).off('mousemove', dragger);
  226 + },
  227 + keydown: function(event){
  228 + if(event.keyCode == 37){
  229 + // left
  230 + element.scrollLeft( element.scrollLeft() - 50);
  231 + }
  232 + if(event.keyCode == 38){
  233 + // top
  234 + element.scrollTop( element.scrollTop() - 50);
  235 + }
  236 + if(event.keyCode == 39){
  237 + // right
  238 + element.scrollLeft( element.scrollLeft() + 50);
  239 + }
  240 + if(event.keyCode == 40){
  241 + // bottom
  242 + element.scrollTop( element.scrollTop() + 50);
  243 + }
  244 + }
  245 + });
  246 + };
  247 +
  248 + BranchGraph.prototype.appendLabel = function(x, y, refs){
  249 + var r = this.raphael
  250 + , shortrefs = refs
  251 + , text, textbox, rect;
  252 +
  253 + if (shortrefs.length > 17){
  254 + // Truncate if longer than 15 chars
  255 + shortrefs = shortrefs.substr(0,15) + "…";
  256 + }
  257 +
  258 + text = r.text(x+5, y+8 + 10, shortrefs).attr({
  259 + font: "10px Monaco, monospace",
  260 + fill: "#FFF",
  261 + title: refs
  262 + });
  263 +
  264 + textbox = text.getBBox();
  265 + text.transform([
  266 + 't', textbox.height/-4, textbox.width/2 + 5,
  267 + 'r90'
  268 + ]);
  269 +
  270 + // Create rectangle based on the size of the textbox
  271 + rect = r.rect(x, y, textbox.width + 15, textbox.height + 5, 4).attr({
  272 + "fill": "#000",
  273 + "fill-opacity": .7,
  274 + "stroke": "none"
  275 + });
  276 +
  277 + triangle = r.path([
  278 + 'M', x, y + 5,
  279 + 'L', x + 4, y + 15,
  280 + 'L', x - 4, y + 15,
  281 + 'Z'
  282 + ]).attr({
  283 + "fill": "#000",
  284 + "fill-opacity": .7,
  285 + "stroke": "none"
  286 + });
  287 +
  288 + // Rotate and reposition rectangle over text
  289 + rect.transform([
  290 + 'r', 90, x, y,
  291 + 't', 15, -9
  292 + ]);
  293 +
  294 + // Set text to front
  295 + text.toFront();
  296 + };
  297 +
  298 + BranchGraph.prototype.appendAnchor = function(top, commit, x, y) {
  299 + var r = this.raphael
  300 + , options = this.options
  301 + , anchor;
  302 + anchor = r.circle(x, y, 10).attr({
  303 + fill: "#000",
  304 + opacity: 0,
  305 + cursor: "pointer"
  306 + })
  307 + .click(function(){
  308 + window.open(options.commit_url.replace('%s', commit.id), '_blank');
  309 + })
  310 + .hover(function(){
  311 + this.tooltip = r.commitTooltip(x, y + 5, commit);
  312 + top.push(this.tooltip.insertBefore(this));
  313 + }, function(){
  314 + this.tooltip && this.tooltip.remove() && delete this.tooltip;
  315 + });
  316 + top.push(anchor);
  317 + };
  318 +
  319 + this.BranchGraph = BranchGraph;
  320 +
  321 +}(this);
  322 +Raphael.fn.commitTooltip = function(x, y, commit){
  323 + var icon, nameText, idText, messageText
  324 + , boxWidth = 300
  325 + , boxHeight = 200;
  326 +
  327 + icon = this.image(commit.author.icon, x, y, 20, 20);
  328 + nameText = this.text(x + 25, y + 10, commit.author.name);
  329 + idText = this.text(x, y + 35, commit.id);
  330 + messageText = this.text(x, y + 50, commit.message);
  331 +
  332 + textSet = this.set(icon, nameText, idText, messageText).attr({
  333 + "text-anchor": "start",
  334 + "font": "12px Monaco, monospace"
  335 + });
  336 +
  337 + nameText.attr({
  338 + "font": "14px Arial",
  339 + "font-weight": "bold"
  340 + });
  341 +
  342 + idText.attr({
  343 + "fill": "#AAA"
  344 + });
  345 +
  346 + textWrap(messageText, boxWidth - 50);
  347 +
  348 + var rect = this.rect(x - 10, y - 10, boxWidth, 100, 4).attr({
  349 + "fill": "#FFF",
  350 + "stroke": "#000",
  351 + "stroke-linecap": "round",
  352 + "stroke-width": 2
  353 + });
  354 + var tooltip = this.set(rect, textSet);
  355 +
  356 + rect.attr({
  357 + "height" : tooltip.getBBox().height + 10,
  358 + "width" : tooltip.getBBox().width + 10
  359 + });
  360 +
  361 + tooltip.transform([
  362 + 't', 20, 20
  363 + ]);
  364 +
  365 + return tooltip;
  366 +};
  367 +
  368 +function textWrap(t, width) {
  369 + var content = t.attr("text");
  370 + var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  371 + t.attr({
  372 + "text" : abc
  373 + });
  374 + var letterWidth = t.getBBox().width / abc.length;
  375 +
  376 + t.attr({
  377 + "text" : content
  378 + });
  379 +
  380 + var words = content.split(" ");
  381 + var x = 0, s = [];
  382 + for ( var i = 0; i < words.length; i++) {
  383 +
  384 + var l = words[i].length;
  385 + if (x + (l * letterWidth) > width) {
  386 + s.push("\n");
  387 + x = 0;
  388 + }
  389 + x += l * letterWidth;
  390 + s.push(words[i] + " ");
  391 + }
  392 + t.attr({
  393 + "text" : s.join("")
  394 + });
  395 + var b = t.getBBox()
  396 + , h = Math.abs(b.y2) - Math.abs(b.y) + 1;
  397 + t.attr({
  398 + "y": b.y + h
  399 + });
  400 +}
... ...
app/assets/javascripts/main.js.coffee
... ... @@ -54,10 +54,10 @@ $ -&gt;
54 54 $(@).parents('form').submit()
55 55  
56 56 # Flash
57   - if (flash = $("#flash-container")).length > 0
58   - flash.click -> $(@).slideUp("slow")
59   - flash.slideDown "slow"
60   - setTimeout (-> flash.slideUp("slow")), 3000
  57 + if (flash = $(".flash-container")).length > 0
  58 + flash.click -> $(@).fadeOut()
  59 + flash.show()
  60 + setTimeout (-> flash.fadeOut()), 3000
61 61  
62 62 # Disable form buttons while a form is submitting
63 63 $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
... ...
app/assets/javascripts/projects.js.coffee
... ... @@ -18,3 +18,18 @@ $ -&gt;
18 18 # Ref switcher
19 19 $('.project-refs-select').on 'change', ->
20 20 $(@).parents('form').submit()
  21 +
  22 + $('#project_issues_enabled').change ->
  23 + if ($(this).is(':checked') == true)
  24 + $('#project_issues_tracker').removeAttr('disabled')
  25 + else
  26 + $('#project_issues_tracker').attr('disabled', 'disabled')
  27 +
  28 + $('#project_issues_tracker').change()
  29 +
  30 + $('#project_issues_tracker').change ->
  31 + if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
  32 + $('#project_issues_tracker_id').attr('disabled', 'disabled')
  33 + else
  34 + $('#project_issues_tracker_id').removeAttr('disabled')
  35 +
... ...
app/assets/stylesheets/common.scss
... ... @@ -67,27 +67,17 @@ table a code {
67 67 }
68 68  
69 69 /** FLASH message **/
70   -#flash-container {
71   - height: 50px;
72   - position: fixed;
73   - z-index: 10001;
74   - top: 0px;
75   - width: 100%;
76   - margin-bottom: 15px;
77   - overflow: hidden;
78   - background: white;
79   - cursor: pointer;
80   - border-bottom: 1px solid #ccc;
81   - text-align: center;
  70 +.flash-container {
82 71 display: none;
  72 + .alert {
  73 + cursor: pointer;
  74 + margin: 0;
  75 + text-align: center;
  76 + border-radius: 0;
83 77  
84   - h4 {
85   - color: #666;
86   - font-size: 18px;
87   - line-height: 38px;
88   - padding-top: 5px;
89   - margin: 2px;
90   - font-weight: normal;
  78 + span {
  79 + font-size: 14px;
  80 + }
91 81 }
92 82 }
93 83  
... ... @@ -203,10 +193,6 @@ input[type=text] {
203 193 }
204 194 }
205 195  
206   -input.git_clone_url {
207   - width: 325px;
208   -}
209   -
210 196 .merge-request-form-holder {
211 197 select {
212 198 width: 300px;
... ...
app/assets/stylesheets/gitlab_bootstrap/common.scss
... ... @@ -30,6 +30,8 @@
30 30 border-color: #DDD;
31 31 }
32 32  
  33 +.well { padding: 15px; }
  34 +
33 35 /** HELPERS **/
34 36 .nothing_here_message {
35 37 text-align: center;
... ...
app/assets/stylesheets/gitlab_bootstrap/fonts.scss
1   -@font-face{
2   - font-family: Yanone;
3   - src: font-url('YanoneKaffeesatz-Light.ttf');
4   -}
5   -
6 1 /** Typo **/
7 2 $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
... ...
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
... ... @@ -70,8 +70,19 @@
70 70 @mixin header-font {
71 71 color: $style_color;
72 72 text-shadow: 0 1px 1px #FFF;
73   - font-family: 'Yanone', sans-serif;
74   - font-size: 24px;
75   - line-height: 36px;
  73 + font-size: 18px;
  74 + line-height: 42px;
76 75 font-weight: normal;
  76 + letter-spacing: -1px;
  77 +}
  78 +
  79 +@mixin md-typography {
  80 + code { padding: 0 4px; }
  81 + p { font-size: 13px; }
  82 + h1 { font-size: 26px; line-height: 40px; margin: 10px 0;}
  83 + h2 { font-size: 22px; line-height: 40px; margin: 10px 0;}
  84 + h3 { font-size: 18px; line-height: 40px; margin: 10px 0;}
  85 + h4 { font-size: 16px; line-height: 20px; margin: 10px 0;}
  86 + h5 { font-size: 14px; line-height: 20px; margin: 10px 0;}
  87 + h6 { font-size: 12px; line-height: 20px; margin: 10px 0;}
77 88 }
... ...
app/assets/stylesheets/gitlab_bootstrap/typography.scss
... ... @@ -87,16 +87,15 @@ a:focus {
87 87 *
88 88 */
89 89 .wiki {
  90 + @include md-typography;
  91 +
90 92 font-size: 13px;
  93 + line-height: 20px;
91 94  
92   - code { padding: 0 4px; }
93   - p { font-size: 13px; }
94   - h1 { font-size: 32px; line-height: 40px; margin: 10px 0;}
95   - h2 { font-size: 26px; line-height: 40px; margin: 10px 0;}
96   - h3 { font-size: 22px; line-height: 40px; margin: 10px 0;}
97   - h4 { font-size: 18px; line-height: 20px; margin: 10px 0;}
98   - h5 { font-size: 14px; line-height: 20px; margin: 10px 0;}
99   - h6 { font-size: 12px; line-height: 20px; margin: 10px 0;}
100 95 .white .highlight pre { background: #f5f5f5; }
101 96 ul { margin: 0 0 9px 25px !important; }
102 97 }
  98 +
  99 +.md {
  100 + @include md-typography;
  101 +}
... ...
app/assets/stylesheets/highlight/dark.scss
1 1 .black .highlight {
2   - background-color: #333;
3 2 pre {
  3 + background-color: #333;
4 4 color: #eee;
5   - background: inherit;
6 5 }
7 6  
8 7 .hll { display: block; background-color: darken($hover, 65%) }
... ...
app/assets/stylesheets/sections/commits.scss
... ... @@ -100,8 +100,9 @@
100 100 }
101 101 }
102 102 .line_content {
  103 + display: block;
103 104 white-space: pre;
104   - height: 14px;
  105 + height: 18px;
105 106 margin: 0px;
106 107 padding: 0px;
107 108 border: none;
... ...
app/assets/stylesheets/sections/events.scss
... ... @@ -48,15 +48,13 @@
48 48 color: #666;
49 49 }
50 50 .event-note {
51   - padding-top: 5px;
52   - padding-left: 5px;
53   - display: inline-block;
54 51 color: #555;
  52 + margin-top: 5px;
  53 + margin-left: 40px;
55 54  
56 55 .note-file-attach {
57   - margin-left: -25px;
58   - float: left;
59 56 .note-image-attach {
  57 + margin-top: 4px;
60 58 margin-left: 0px;
61 59 max-width: 200px;
62 60 }
... ... @@ -66,8 +64,8 @@
66 64 color: #777;
67 65 float: left;
68 66 font-size: 16px;
69   - line-height: 18px;
70   - margin: 5px;
  67 + line-height: 16px;
  68 + margin-right: 5px;
71 69 }
72 70 }
73 71 .avatar {
... ...
app/assets/stylesheets/sections/header.scss
... ... @@ -67,7 +67,7 @@ header {
67 67 position: relative;
68 68 float: left;
69 69 margin: 0;
70   - margin-left: 15px;
  70 + margin-left: 10px;
71 71 @include header-font;
72 72 }
73 73  
... ...
app/assets/stylesheets/sections/login.scss
1 1 /* Login Page */
2 2 body.login-page{
3   - padding-top: 7%;
4   - background: #666;
  3 + background: #EEE;
  4 + .container .content { padding-top: 5%; }
5 5 }
6 6  
7 7 .login-box{
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -83,6 +83,7 @@ ul.notes {
83 83 margin-top: -20px;
84 84 }
85 85 .note-body {
  86 + @include md-typography;
86 87 margin-left: 45px;
87 88 }
88 89 .note-header {
... ...
app/assets/stylesheets/sections/projects.scss
... ... @@ -80,6 +80,7 @@
80 80 border: 1px solid #BBB;
81 81 box-shadow: none;
82 82 margin-left: -1px;
  83 + background: #FFF;
83 84 }
84 85 }
85 86  
... ...
app/contexts/issues_list_context.rb
... ... @@ -7,12 +7,13 @@ class IssuesListContext &lt; BaseContext
7 7 @issues = case params[:status]
8 8 when issues_filter[:all] then @project.issues
9 9 when issues_filter[:closed] then @project.issues.closed
10   - when issues_filter[:to_me] then @project.issues.opened.assigned(current_user)
  10 + when issues_filter[:to_me] then @project.issues.assigned(current_user)
  11 + when issues_filter[:by_me] then @project.issues.authored(current_user)
11 12 else @project.issues.opened
12 13 end
13 14  
14 15 @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
15   - @issues = @issues.includes(:author, :project).order("updated_at")
  16 + @issues = @issues.includes(:author, :project)
16 17  
17 18 # Filter by specific assignee_id (or lack thereof)?
18 19 if params[:assignee_id].present?
... ...
app/controllers/admin/teams/members_controller.rb
1 1 class Admin::Teams::MembersController < Admin::Teams::ApplicationController
2 2 def new
3 3 @users = User.potential_team_members(user_team)
4   - @users = UserDecorator.decorate @users
  4 + @users = UserDecorator.decorate_collection @users
5 5 end
6 6  
7 7 def create
... ...
app/controllers/admin/users_controller.rb
... ... @@ -45,7 +45,7 @@ class Admin::UsersController &lt; Admin::ApplicationController
45 45 end
46 46  
47 47 def unblock
48   - if admin_user.update_attribute(:blocked, false)
  48 + if admin_user.activate
49 49 redirect_to :back, alert: "Successfully unblocked"
50 50 else
51 51 redirect_to :back, alert: "Error occured. User was not unblocked"
... ...
app/controllers/application_controller.rb
... ... @@ -5,6 +5,7 @@ class ApplicationController &lt; ActionController::Base
5 5 before_filter :add_abilities
6 6 before_filter :dev_tools if Rails.env == 'development'
7 7 before_filter :default_headers
  8 + before_filter :add_gon_variables
8 9  
9 10 protect_from_forgery
10 11  
... ... @@ -29,7 +30,7 @@ class ApplicationController &lt; ActionController::Base
29 30 end
30 31  
31 32 def reject_blocked!
32   - if current_user && current_user.blocked
  33 + if current_user && current_user.blocked?
33 34 sign_out current_user
34 35 flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
35 36 redirect_to new_user_session_path
... ... @@ -37,7 +38,7 @@ class ApplicationController &lt; ActionController::Base
37 38 end
38 39  
39 40 def after_sign_in_path_for resource
40   - if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked
  41 + if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
41 42 sign_out resource
42 43 flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
43 44 new_user_session_path
... ... @@ -148,4 +149,8 @@ class ApplicationController &lt; ActionController::Base
148 149 headers['X-Frame-Options'] = 'DENY'
149 150 headers['X-XSS-Protection'] = '1; mode=block'
150 151 end
  152 +
  153 + def add_gon_variables
  154 + gon.default_issues_tracker = Project.issues_tracker.default_value
  155 + end
151 156 end
... ...
app/controllers/commits_controller.rb
... ... @@ -13,7 +13,7 @@ class CommitsController &lt; ProjectResourceController
13 13 @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
14 14  
15 15 @commits = @repo.commits(@ref, @path, @limit, @offset)
16   - @commits = CommitDecorator.decorate(@commits)
  16 + @commits = CommitDecorator.decorate_collection(@commits)
17 17  
18 18 respond_to do |format|
19 19 format.html # index.html.erb
... ...
app/controllers/compare_controller.rb
... ... @@ -16,7 +16,7 @@ class CompareController &lt; ProjectResourceController
16 16 @refs_are_same = result[:same]
17 17 @line_notes = []
18 18  
19   - @commits = CommitDecorator.decorate(@commits)
  19 + @commits = CommitDecorator.decorate_collection(@commits)
20 20 end
21 21  
22 22 def create
... ...
app/controllers/graph_controller.rb
1 1 class GraphController < ProjectResourceController
2 2 include ExtractsPath
  3 + include ApplicationHelper
3 4  
4 5 # Authorize
5 6 before_filter :authorize_read_project!
... ... @@ -20,7 +21,10 @@ class GraphController &lt; ProjectResourceController
20 21 respond_to do |format|
21 22 format.html
22 23 format.json do
23   - graph = Gitlab::Graph::JsonBuilder.new(project, @ref, @commit)
  24 + graph = Graph::JsonBuilder.new(project, @ref, @commit)
  25 + graph.commits.each do |c|
  26 + c.icon = gravatar_icon(c.author.email)
  27 + end
24 28 render :json => graph.to_json
25 29 end
26 30 end
... ...
app/controllers/merge_requests_controller.rb
... ... @@ -81,7 +81,8 @@ class MergeRequestsController &lt; ProjectResourceController
81 81 end
82 82  
83 83 def automerge
84   - return access_denied! unless can?(current_user, :accept_mr, @project)
  84 + return access_denied! unless allowed_to_merge?
  85 +
85 86 if @merge_request.opened? && @merge_request.can_be_merged?
86 87 @merge_request.should_remove_source_branch = params[:should_remove_source_branch]
87 88 @merge_request.automerge!(current_user)
... ... @@ -142,6 +143,19 @@ class MergeRequestsController &lt; ProjectResourceController
142 143 # Get commits from repository
143 144 # or from cache if already merged
144 145 @commits = @merge_request.commits
145   - @commits = CommitDecorator.decorate(@commits)
  146 + @commits = CommitDecorator.decorate_collection(@commits)
  147 +
  148 + @allowed_to_merge = allowed_to_merge?
  149 + @show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
  150 + end
  151 +
  152 + def allowed_to_merge?
  153 + action = if project.protected_branch?(@merge_request.target_branch)
  154 + :push_code_to_protected_branches
  155 + else
  156 + :push_code
  157 + end
  158 +
  159 + can?(current_user, action, @project)
146 160 end
147 161 end
... ...
app/controllers/milestones_controller.rb
... ... @@ -32,7 +32,7 @@ class MilestonesController &lt; ProjectResourceController
32 32  
33 33 def show
34 34 @issues = @milestone.issues
35   - @users = UserDecorator.decorate(@milestone.participants)
  35 + @users = UserDecorator.decorate_collection(@milestone.participants)
36 36 @merge_requests = @milestone.merge_requests
37 37  
38 38 respond_to do |format|
... ...
app/controllers/projects_controller.rb
1   -require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder')
2   -
3 1 class ProjectsController < ProjectResourceController
4 2 skip_before_filter :project, only: [:new, :create]
5 3 skip_before_filter :repository, only: [:new, :create]
... ...
app/controllers/teams/members_controller.rb
... ... @@ -8,7 +8,7 @@ class Teams::MembersController &lt; Teams::ApplicationController
8 8  
9 9 def new
10 10 @users = User.potential_team_members(user_team)
11   - @users = UserDecorator.decorate @users
  11 + @users = UserDecorator.decorate_collection @users
12 12 end
13 13  
14 14 def create
... ...
app/decorators/application_decorator.rb
1   -class ApplicationDecorator < Draper::Base
  1 +class ApplicationDecorator < Draper::Decorator
  2 + delegate_all
2 3 # Lazy Helpers
3 4 # PRO: Call Rails helpers without the h. proxy
4 5 # ex: number_to_currency(model.price)
5 6 # CON: Add a bazillion methods into your decorator's namespace
6 7 # and probably sacrifice performance/memory
7   - #
  8 + #
8 9 # Enable them by uncommenting this line:
9 10 # lazy_helpers
10 11  
11 12 # Shared Decorations
12 13 # Consider defining shared methods common to all your models.
13   - #
  14 + #
14 15 # Example: standardize the formatting of timestamps
15 16 #
16 17 # def formatted_timestamp(time)
17   - # h.content_tag :span, time.strftime("%a %m/%d/%y"),
18   - # class: 'timestamp'
  18 + # h.content_tag :span, time.strftime("%a %m/%d/%y"),
  19 + # class: 'timestamp'
19 20 # end
20   - #
  21 + #
21 22 # def created_at
22 23 # formatted_timestamp(model.created_at)
23 24 # end
24   - #
  25 + #
25 26 # def updated_at
26 27 # formatted_timestamp(model.updated_at)
27 28 # end
... ...
app/helpers/application_helper.rb
... ... @@ -164,7 +164,8 @@ module ApplicationHelper
164 164 end
165 165  
166 166 def image_url(source)
167   - root_url + path_to_image(source)
  167 + # prevent relative_root_path being added twice (it's part of root_url and path_to_image)
  168 + root_url.sub(/#{root_path}$/, path_to_image(source))
168 169 end
169 170  
170 171 alias_method :url_to_image, :image_url
... ...
app/helpers/issues_helper.rb
... ... @@ -27,6 +27,7 @@ module IssuesHelper
27 27 all: "all",
28 28 closed: "closed",
29 29 to_me: "assigned-to-me",
  30 + by_me: "created-by-me",
30 31 open: "open"
31 32 }
32 33 end
... ... @@ -40,4 +41,39 @@ module IssuesHelper
40 41 def issues_active_milestones
41 42 @project.milestones.active.order("id desc").all
42 43 end
  44 +
  45 + def url_for_project_issues
  46 + return "" if @project.nil?
  47 +
  48 + if @project.used_default_issues_tracker?
  49 + project_issues_filter_path(@project)
  50 + else
  51 + url = Settings[:issues_tracker][@project.issues_tracker]["project_url"]
  52 + url.gsub(':project_id', @project.id.to_s)
  53 + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
  54 + end
  55 + end
  56 +
  57 + def url_for_issue(issue_id)
  58 + return "" if @project.nil?
  59 +
  60 + if @project.used_default_issues_tracker?
  61 + url = project_issue_url project_id: @project, id: issue_id
  62 + else
  63 + url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"]
  64 + url.gsub(':id', issue_id.to_s)
  65 + .gsub(':project_id', @project.id.to_s)
  66 + .gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
  67 + end
  68 + end
  69 +
  70 + def title_for_issue(issue_id)
  71 + return "" if @project.nil?
  72 +
  73 + if @project.used_default_issues_tracker? && issue = @project.issues.where(id: issue_id).first
  74 + issue.title
  75 + else
  76 + ""
  77 + end
  78 + end
43 79 end
... ...
app/helpers/tree_helper.rb
... ... @@ -13,13 +13,15 @@ module TreeHelper
13 13 tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
14 14  
15 15 files.each do |f|
16   - if f.respond_to?(:url)
17   - # Object is a Submodule
18   - tree += render partial: 'tree/submodule_item', object: f
19   - else
20   - # Object is a Blob
21   - tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
22   - end
  16 + html = if f.respond_to?(:url)
  17 + # Object is a Submodule
  18 + render partial: 'tree/submodule_item', object: f
  19 + else
  20 + # Object is a Blob
  21 + render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
  22 + end
  23 +
  24 + tree += html if html.present?
23 25 end
24 26  
25 27 tree.html_safe
... ...
app/models/ability.rb
... ... @@ -91,7 +91,6 @@ class Ability
91 91 :admin_team_member,
92 92 :admin_merge_request,
93 93 :admin_note,
94   - :accept_mr,
95 94 :admin_wiki,
96 95 :admin_project
97 96 ]
... ...
app/models/graph/commit.rb 0 → 100644
... ... @@ -0,0 +1,59 @@
  1 +require "grit"
  2 +
  3 +module Graph
  4 + class Commit
  5 + include ActionView::Helpers::TagHelper
  6 +
  7 + attr_accessor :time, :spaces, :refs, :parent_spaces, :icon
  8 +
  9 + def initialize(commit)
  10 + @_commit = commit
  11 + @time = -1
  12 + @spaces = []
  13 + @parent_spaces = []
  14 + end
  15 +
  16 + def method_missing(m, *args, &block)
  17 + @_commit.send(m, *args, &block)
  18 + end
  19 +
  20 + def to_graph_hash
  21 + h = {}
  22 + h[:parents] = self.parents.collect do |p|
  23 + [p.id,0,0]
  24 + end
  25 + h[:author] = {
  26 + name: author.name,
  27 + email: author.email,
  28 + icon: icon
  29 + }
  30 + h[:time] = time
  31 + h[:space] = spaces.first
  32 + h[:parent_spaces] = parent_spaces
  33 + h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
  34 + h[:id] = sha
  35 + h[:date] = date
  36 + h[:message] = message
  37 + h
  38 + end
  39 +
  40 + def add_refs(ref_cache, repo)
  41 + if ref_cache.empty?
  42 + repo.refs.each do |ref|
  43 + ref_cache[ref.commit.id] ||= []
  44 + ref_cache[ref.commit.id] << ref
  45 + end
  46 + end
  47 + @refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
  48 + @refs ||= []
  49 + end
  50 +
  51 + def space
  52 + if @spaces.size > 0
  53 + @spaces.first
  54 + else
  55 + 0
  56 + end
  57 + end
  58 + end
  59 +end
... ...
app/models/graph/json_builder.rb 0 → 100644
... ... @@ -0,0 +1,291 @@
  1 +require "grit"
  2 +
  3 +module Graph
  4 + class JsonBuilder
  5 + attr_accessor :days, :commits, :ref_cache, :repo
  6 +
  7 + def self.max_count
  8 + @max_count ||= 650
  9 + end
  10 +
  11 + def initialize project, ref, commit
  12 + @project = project
  13 + @ref = ref
  14 + @commit = commit
  15 + @repo = project.repo
  16 + @ref_cache = {}
  17 +
  18 + @commits = collect_commits
  19 + @days = index_commits
  20 + end
  21 +
  22 + def to_json(*args)
  23 + {
  24 + days: @days.compact.map { |d| [d.day, d.strftime("%b")] },
  25 + commits: @commits.map(&:to_graph_hash)
  26 + }.to_json(*args)
  27 + end
  28 +
  29 + protected
  30 +
  31 + # Get commits from repository
  32 + #
  33 + def collect_commits
  34 +
  35 + @commits = Grit::Commit.find_all(repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup
  36 +
  37 + # Decorate with app/models/commit.rb
  38 + @commits.map! { |commit| Commit.new(commit) }
  39 +
  40 + # Decorate with lib/gitlab/graph/commit.rb
  41 + @commits.map! { |commit| Graph::Commit.new(commit) }
  42 +
  43 + # add refs to each commit
  44 + @commits.each { |commit| commit.add_refs(ref_cache, repo) }
  45 +
  46 + @commits
  47 + end
  48 +
  49 + # Method is adding time and space on the
  50 + # list of commits. As well as returns date list
  51 + # corelated with time set on commits.
  52 + #
  53 + # @param [Array<Graph::Commit>] commits to index
  54 + #
  55 + # @return [Array<TimeDate>] list of commit dates corelated with time on commits
  56 + def index_commits
  57 + days, times = [], []
  58 + map = {}
  59 +
  60 + commits.reverse.each_with_index do |c,i|
  61 + c.time = i
  62 + days[i] = c.committed_date
  63 + map[c.id] = c
  64 + times[i] = c
  65 + end
  66 +
  67 + @_reserved = {}
  68 + days.each_index do |i|
  69 + @_reserved[i] = []
  70 + end
  71 +
  72 + commits_sort_by_ref.each do |commit|
  73 + if map.include? commit.id then
  74 + place_chain(map[commit.id], map)
  75 + end
  76 + end
  77 +
  78 + # find parent spaces for not overlap lines
  79 + times.each do |c|
  80 + c.parent_spaces.concat(find_free_parent_spaces(c, map, times))
  81 + end
  82 +
  83 + days
  84 + end
  85 +
  86 + # Skip count that the target commit is displayed in center.
  87 + def to_commit
  88 + commits = Grit::Commit.find_all(repo, nil, {date_order: true})
  89 + commit_index = commits.index do |c|
  90 + c.id == @commit.id
  91 + end
  92 +
  93 + if commit_index && (self.class.max_count / 2 < commit_index) then
  94 + # get max index that commit is displayed in the center.
  95 + commit_index - self.class.max_count / 2
  96 + else
  97 + 0
  98 + end
  99 + end
  100 +
  101 + def commits_sort_by_ref
  102 + commits.sort do |a,b|
  103 + if include_ref?(a)
  104 + -1
  105 + elsif include_ref?(b)
  106 + 1
  107 + else
  108 + b.committed_date <=> a.committed_date
  109 + end
  110 + end
  111 + end
  112 +
  113 + def include_ref?(commit)
  114 + heads = commit.refs.select do |ref|
  115 + ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag)
  116 + end
  117 +
  118 + heads.map! do |head|
  119 + head.name
  120 + end
  121 +
  122 + heads.include?(@ref)
  123 + end
  124 +
  125 + def find_free_parent_spaces(commit, map, times)
  126 + spaces = []
  127 +
  128 + commit.parents.each do |p|
  129 + if map.include?(p.id) then
  130 + parent = map[p.id]
  131 +
  132 + range = if commit.time < parent.time then
  133 + commit.time..parent.time
  134 + else
  135 + parent.time..commit.time
  136 + end
  137 +
  138 + space = if commit.space >= parent.space then
  139 + find_free_parent_space(range, parent.space, -1, commit.space, times)
  140 + else
  141 + find_free_parent_space(range, commit.space, -1, parent.space, times)
  142 + end
  143 +
  144 + mark_reserved(range, space)
  145 + spaces << space
  146 + end
  147 + end
  148 +
  149 + spaces
  150 + end
  151 +
  152 + def find_free_parent_space(range, space_base, space_step, space_default, times)
  153 + if is_overlap?(range, times, space_default) then
  154 + find_free_space(range, space_step, space_base, space_default)
  155 + else
  156 + space_default
  157 + end
  158 + end
  159 +
  160 + def is_overlap?(range, times, overlap_space)
  161 + range.each do |i|
  162 + if i != range.first &&
  163 + i != range.last &&
  164 + times[i].spaces.include?(overlap_space) then
  165 +
  166 + return true;
  167 + end
  168 + end
  169 +
  170 + false
  171 + end
  172 +
  173 + # Add space mark on commit and its parents
  174 + #
  175 + # @param [Graph::Commit] the commit object.
  176 + # @param [Hash<String,Graph::Commit>] map of commits
  177 + def place_chain(commit, map, parent_time = nil)
  178 + leaves = take_left_leaves(commit, map)
  179 + if leaves.empty?
  180 + return
  181 + end
  182 +
  183 + time_range = leaves.last.time..leaves.first.time
  184 + space_base = get_space_base(leaves, map)
  185 + space = find_free_space(time_range, 2, space_base)
  186 + leaves.each do |l|
  187 + l.spaces << space
  188 + # Also add space to parent
  189 + l.parents.each do |p|
  190 + if map.include?(p.id)
  191 + parent = map[p.id]
  192 + if parent.space > 0
  193 + parent.spaces << space
  194 + end
  195 + end
  196 + end
  197 + end
  198 +
  199 + # and mark it as reserved
  200 + min_time = leaves.last.time
  201 + parents = leaves.last.parents.collect
  202 + parents.each do |p|
  203 + if map.include? p.id
  204 + parent = map[p.id]
  205 + if parent.time < min_time
  206 + min_time = parent.time
  207 + end
  208 + end
  209 + end
  210 +
  211 + if parent_time.nil?
  212 + max_time = leaves.first.time
  213 + else
  214 + max_time = parent_time - 1
  215 + end
  216 + mark_reserved(min_time..max_time, space)
  217 +
  218 + # Visit branching chains
  219 + leaves.each do |l|
  220 + parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?}
  221 + for p in parents
  222 + place_chain(map[p.id], map, l.time)
  223 + end
  224 + end
  225 + end
  226 +
  227 + def get_space_base(leaves, map)
  228 + space_base = 1
  229 + if leaves.last.parents.size > 0
  230 + first_parent = leaves.last.parents.first
  231 + if map.include?(first_parent.id)
  232 + first_p = map[first_parent.id]
  233 + if first_p.space > 0
  234 + space_base = first_p.space
  235 + end
  236 + end
  237 + end
  238 + space_base
  239 + end
  240 +
  241 + def mark_reserved(time_range, space)
  242 + for day in time_range
  243 + @_reserved[day].push(space)
  244 + end
  245 + end
  246 +
  247 + def find_free_space(time_range, space_step, space_base = 1, space_default = nil)
  248 + space_default ||= space_base
  249 +
  250 + reserved = []
  251 + for day in time_range
  252 + reserved += @_reserved[day]
  253 + end
  254 + reserved.uniq!
  255 +
  256 + space = space_default
  257 + while reserved.include?(space) do
  258 + space += space_step
  259 + if space < space_base then
  260 + space_step *= -1
  261 + space = space_base + space_step
  262 + end
  263 + end
  264 +
  265 + space
  266 + end
  267 +
  268 + # Takes most left subtree branch of commits
  269 + # which don't have space mark yet.
  270 + #
  271 + # @param [Graph::Commit] the commit object.
  272 + # @param [Hash<String,Graph::Commit>] map of commits
  273 + #
  274 + # @return [Array<Graph::Commit>] list of branch commits
  275 + def take_left_leaves(commit, map)
  276 + leaves = []
  277 + leaves.push(commit) if commit.space.zero?
  278 +
  279 + while true
  280 + return leaves if commit.parents.count.zero?
  281 + return leaves unless map.include? commit.parents.first.id
  282 +
  283 + commit = map[commit.parents.first.id]
  284 +
  285 + return leaves unless commit.space.zero?
  286 +
  287 + leaves.push(commit)
  288 + end
  289 + end
  290 + end
  291 +end
... ...
app/models/group.rb
... ... @@ -2,13 +2,14 @@
2 2 #
3 3 # Table name: namespaces
4 4 #
5   -# id :integer not null, primary key
6   -# name :string(255) not null
7   -# path :string(255) not null
8   -# owner_id :integer not null
9   -# created_at :datetime not null
10   -# updated_at :datetime not null
11   -# type :string(255)
  5 +# id :integer not null, primary key
  6 +# name :string(255) not null
  7 +# description :string(255) not null
  8 +# path :string(255) not null
  9 +# owner_id :integer not null
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +# type :string(255)
12 13 #
13 14  
14 15 class Group < Namespace
... ...
app/models/issue.rb
... ... @@ -30,6 +30,10 @@ class Issue &lt; ActiveRecord::Base
30 30 where('assignee_id = :user', user: user.id)
31 31 end
32 32  
  33 + def authored(user)
  34 + where('author_id = :user', user: user.id)
  35 + end
  36 +
33 37 def open_for(user)
34 38 opened.assigned(user)
35 39 end
... ...
app/models/namespace.rb
... ... @@ -2,17 +2,18 @@
2 2 #
3 3 # Table name: namespaces
4 4 #
5   -# id :integer not null, primary key
6   -# name :string(255) not null
7   -# path :string(255) not null
8   -# owner_id :integer not null
9   -# created_at :datetime not null
10   -# updated_at :datetime not null
11   -# type :string(255)
  5 +# id :integer not null, primary key
  6 +# name :string(255) not null
  7 +# description :string(255) not null
  8 +# path :string(255) not null
  9 +# owner_id :integer not null
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +# type :string(255)
12 13 #
13 14  
14 15 class Namespace < ActiveRecord::Base
15   - attr_accessible :name, :path
  16 + attr_accessible :name, :description, :path
16 17  
17 18 has_many :projects, dependent: :destroy
18 19 belongs_to :owner, class_name: "User"
... ... @@ -22,7 +23,7 @@ class Namespace &lt; ActiveRecord::Base
22 23 length: { within: 0..255 },
23 24 format: { with: Gitlab::Regex.name_regex,
24 25 message: "only letters, digits, spaces & '_' '-' '.' allowed." }
25   -
  26 + validates :description, length: { within: 0..255 }
26 27 validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
27 28 format: { with: Gitlab::Regex.path_regex,
28 29 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
... ...
app/models/project.rb
... ... @@ -11,6 +11,7 @@
11 11 # creator_id :integer
12 12 # default_branch :string(255)
13 13 # issues_enabled :boolean default(TRUE), not null
  14 +# issues_tracker :string not null
14 15 # wall_enabled :boolean default(TRUE), not null
15 16 # merge_requests_enabled :boolean default(TRUE), not null
16 17 # wiki_enabled :boolean default(TRUE), not null
... ... @@ -22,11 +23,12 @@ require &quot;grit&quot;
22 23  
23 24 class Project < ActiveRecord::Base
24 25 include Gitolited
  26 + extend Enumerize
25 27  
26 28 class TransferError < StandardError; end
27 29  
28   - attr_accessible :name, :path, :description, :default_branch,
29   - :issues_enabled, :wall_enabled, :merge_requests_enabled,
  30 + attr_accessible :name, :path, :description, :default_branch, :issues_tracker,
  31 + :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id,
30 32 :wiki_enabled, :public, :import_url, as: [:default, :admin]
31 33  
32 34 attr_accessible :namespace_id, :creator_id, as: :admin
... ... @@ -43,7 +45,7 @@ class Project &lt; ActiveRecord::Base
43 45  
44 46 has_many :events, dependent: :destroy
45 47 has_many :merge_requests, dependent: :destroy
46   - has_many :issues, dependent: :destroy, order: "state, created_at DESC"
  48 + has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
47 49 has_many :milestones, dependent: :destroy
48 50 has_many :users_projects, dependent: :destroy
49 51 has_many :notes, dependent: :destroy
... ... @@ -72,6 +74,7 @@ class Project &lt; ActiveRecord::Base
72 74 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
73 75 validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
74 76 :wiki_enabled, inclusion: { in: [true, false] }
  77 + validates :issues_tracker_id, length: { within: 0..255 }
75 78  
76 79 validates_uniqueness_of :name, scope: :namespace_id
77 80 validates_uniqueness_of :path, scope: :namespace_id
... ... @@ -93,6 +96,8 @@ class Project &lt; ActiveRecord::Base
93 96 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
94 97 scope :public_only, -> { where(public: true) }
95 98  
  99 + enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab
  100 +
96 101 class << self
97 102 def abandoned
98 103 project_ids = Event.select('max(created_at) as latest_date, project_id').
... ... @@ -201,6 +206,22 @@ class Project &lt; ActiveRecord::Base
201 206 issues.tag_counts_on(:labels)
202 207 end
203 208  
  209 + def issue_exists?(issue_id)
  210 + if used_default_issues_tracker?
  211 + self.issues.where(id: issue_id).first.present?
  212 + else
  213 + true
  214 + end
  215 + end
  216 +
  217 + def used_default_issues_tracker?
  218 + self.issues_tracker == Project.issues_tracker.default_value
  219 + end
  220 +
  221 + def can_have_issues_tracker_id?
  222 + self.issues_enabled && !self.used_default_issues_tracker?
  223 + end
  224 +
204 225 def services
205 226 [gitlab_ci_service].compact
206 227 end
... ...
app/models/repository.rb
... ... @@ -137,7 +137,7 @@ class Repository
137 137 file_path = File.join(storage_path, self.path_with_namespace, file_name)
138 138  
139 139 # Put files into a directory before archiving
140   - prefix = self.path_with_namespace + "/"
  140 + prefix = File.basename(self.path_with_namespace) + "/"
141 141  
142 142 # Create file if not exists
143 143 unless File.exists?(file_path)
... ...
app/models/user.rb
... ... @@ -25,7 +25,7 @@
25 25 # dark_scheme :boolean default(FALSE), not null
26 26 # theme_id :integer default(1), not null
27 27 # bio :string(255)
28   -# blocked :boolean default(FALSE), not null
  28 +# state :string(255)
29 29 # failed_attempts :integer default(0)
30 30 # locked_at :datetime
31 31 # extern_uid :string(255)
... ... @@ -46,10 +46,35 @@ class User &lt; ActiveRecord::Base
46 46  
47 47 attr_accessor :force_random_password
48 48  
  49 + #
  50 + # Relations
  51 + #
  52 +
49 53 # Namespace for personal projects
50   - has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL'
  54 + has_one :namespace,
  55 + dependent: :destroy,
  56 + foreign_key: :owner_id,
  57 + class_name: "Namespace",
  58 + conditions: 'type IS NULL'
  59 +
  60 + # Profile
  61 + has_many :keys, dependent: :destroy
  62 +
  63 + # Groups
  64 + has_many :groups, class_name: "Group", foreign_key: :owner_id
  65 +
  66 + # Teams
  67 + has_many :own_teams,
  68 + class_name: "UserTeam",
  69 + foreign_key: :owner_id,
  70 + dependent: :destroy
  71 +
  72 + has_many :user_team_user_relationships, dependent: :destroy
  73 + has_many :user_teams, through: :user_team_user_relationships
  74 + has_many :user_team_project_relationships, through: :user_teams
  75 + has_many :team_projects, through: :user_team_project_relationships
51 76  
52   - has_many :keys, dependent: :destroy
  77 + # Projects
53 78 has_many :users_projects, dependent: :destroy
54 79 has_many :issues, dependent: :destroy, foreign_key: :author_id
55 80 has_many :notes, dependent: :destroy, foreign_key: :author_id
... ... @@ -57,18 +82,16 @@ class User &lt; ActiveRecord::Base
57 82 has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
58 83 has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
59 84 has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
  85 + has_many :projects, through: :users_projects
60 86  
61   - has_many :groups, class_name: "Group", foreign_key: :owner_id
62   - has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
63   -
64   - has_many :projects, through: :users_projects
65   -
66   - has_many :user_team_user_relationships, dependent: :destroy
67   -
68   - has_many :user_teams, through: :user_team_user_relationships
69   - has_many :user_team_project_relationships, through: :user_teams
70   - has_many :team_projects, through: :user_team_project_relationships
  87 + has_many :recent_events,
  88 + class_name: "Event",
  89 + foreign_key: :author_id,
  90 + order: "id DESC"
71 91  
  92 + #
  93 + # Validations
  94 + #
72 95 validates :name, presence: true
73 96 validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }
74 97 validates :bio, length: { within: 0..255 }
... ... @@ -87,10 +110,27 @@ class User &lt; ActiveRecord::Base
87 110  
88 111 delegate :path, to: :namespace, allow_nil: true, prefix: true
89 112  
  113 + state_machine :state, initial: :active do
  114 + after_transition any => :blocked do |user, transition|
  115 + # Remove user from all projects and
  116 + user.users_projects.find_each do |membership|
  117 + return false unless membership.destroy
  118 + end
  119 + end
  120 +
  121 + event :block do
  122 + transition active: :blocked
  123 + end
  124 +
  125 + event :activate do
  126 + transition blocked: :active
  127 + end
  128 + end
  129 +
90 130 # Scopes
91 131 scope :admins, -> { where(admin: true) }
92   - scope :blocked, -> { where(blocked: true) }
93   - scope :active, -> { where(blocked: false) }
  132 + scope :blocked, -> { with_state(:blocked) }
  133 + scope :active, -> { with_state(:active) }
94 134 scope :alphabetically, -> { order('name ASC') }
95 135 scope :in_team, ->(team){ where(id: team.member_ids) }
96 136 scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
... ... @@ -260,17 +300,6 @@ class User &lt; ActiveRecord::Base
260 300 MergeRequest.cared(self)
261 301 end
262 302  
263   - # Remove user from all projects and
264   - # set blocked attribute to true
265   - def block
266   - users_projects.find_each do |membership|
267   - return false unless membership.destroy
268   - end
269   -
270   - self.blocked = true
271   - save
272   - end
273   -
274 303 def projects_limit_percent
275 304 return 100 if projects_limit.zero?
276 305 (personal_projects.count.to_f / projects_limit) * 100
... ...
app/models/user_team.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12  
13 13 class UserTeam < ActiveRecord::Base
14   - attr_accessible :name, :owner_id, :path
  14 + attr_accessible :name, :description, :owner_id, :path
15 15  
16 16 belongs_to :owner, class_name: User
17 17  
... ... @@ -26,6 +26,7 @@ class UserTeam &lt; ActiveRecord::Base
26 26 length: { within: 0..255 },
27 27 format: { with: Gitlab::Regex.name_regex,
28 28 message: "only letters, digits, spaces & '_' '-' '.' allowed." }
  29 + validates :description, length: { within: 0..255 }
29 30 validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
30 31 format: { with: Gitlab::Regex.path_regex,
31 32 message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
... ...
app/observers/issue_observer.rb
... ... @@ -27,7 +27,7 @@ class IssueObserver &lt; ActiveRecord::Observer
27 27  
28 28 def create_note(issue)
29 29 Note.create_status_change_note(issue, current_user, issue.state)
30   - [issue.author, issue.assignee].compact.each do |recipient|
  30 + [issue.author, issue.assignee].compact.uniq.each do |recipient|
31 31 Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id)
32 32 end
33 33 end
... ...
app/observers/user_observer.rb
... ... @@ -2,7 +2,8 @@ class UserObserver &lt; ActiveRecord::Observer
2 2 def after_create(user)
3 3 log_info("User \"#{user.name}\" (#{user.email}) was created")
4 4  
5   - Notify.delay.new_user_email(user.id, user.password)
  5 + # Dont email omniauth created users
  6 + Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid?
6 7 end
7 8  
8 9 def after_destroy user
... ...
app/services/git_push_service.rb
... ... @@ -19,6 +19,8 @@ class GitPushService
19 19 # Collect data for this git push
20 20 @push_data = post_receive_data(oldrev, newrev, ref)
21 21  
  22 + create_push_event
  23 +
22 24 project.ensure_satellite_exists
23 25 project.discover_default_branch
24 26  
... ... @@ -27,8 +29,6 @@ class GitPushService
27 29 project.execute_hooks(@push_data.dup)
28 30 project.execute_services(@push_data.dup)
29 31 end
30   -
31   - create_push_event
32 32 end
33 33  
34 34 # This method provide a sample data
... ...
app/services/project_transfer_service.rb
... ... @@ -25,7 +25,7 @@ class ProjectTransferService
25 25  
26 26 Gitlab::ProjectMover.new(project, old_dir, new_dir).execute
27 27  
28   - save!
  28 + project.save!
29 29 end
30 30 rescue Gitlab::ProjectMover::ProjectMoveError => ex
31 31 raise Project::TransferError.new(ex.message)
... ...
app/views/admin/groups/edit.html.haml
1   -%h3.page_title Rename Group
  1 +%h3.page_title Edit Group
2 2 %hr
3 3 = form_for [:admin, @group] do |f|
4 4 - if @group.errors.any?
... ... @@ -10,7 +10,10 @@
10 10 .input
11 11 = f.text_field :name, placeholder: "Example Group", class: "xxlarge"
12 12  
13   -
  13 + .clearfix.group-description-holder
  14 + = f.label :description, "Details"
  15 + .input
  16 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
14 17  
15 18 .clearfix.group_name_holder
16 19 = f.label :path do
... ... @@ -24,5 +27,5 @@
24 27 %li It will change the git path to repositories under this group.
25 28  
26 29 .form-actions
27   - = f.submit 'Rename group', class: "btn btn-remove"
  30 + = f.submit 'Edit group', class: "btn btn-remove"
28 31 = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
... ...
app/views/admin/groups/index.html.haml
... ... @@ -17,6 +17,7 @@
17 17 Name
18 18 %i.icon-sort-down
19 19 %th Path
  20 + %th Description
20 21 %th Projects
21 22 %th Owner
22 23 %th.cred Danger Zone!
... ... @@ -25,11 +26,12 @@
25 26 %tr
26 27 %td
27 28 %strong= link_to group.name, [:admin, group]
  29 + %td= truncate group.description
28 30 %td= group.path
29 31 %td= group.projects.count
30 32 %td
31 33 = link_to group.owner_name, admin_user_path(group.owner)
32 34 %td.bgred
33   - = link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
  35 + = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
34 36 = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
35 37 = paginate @groups, theme: "admin"
... ...
app/views/admin/groups/new.html.haml
... ... @@ -9,8 +9,14 @@
9 9 Group name is
10 10 .input
11 11 = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
12   - &nbsp;
13   - = f.submit 'Create group', class: "btn btn-primary"
  12 + .clearfix.group-description-holder
  13 + = f.label :description, "Details"
  14 + .input
  15 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  16 +
  17 + .form-actions
  18 + = f.submit 'Create group', class: "btn btn-primary"
  19 +
14 20 %hr
15 21 .padded
16 22 %ul
... ...
app/views/admin/groups/show.html.haml
... ... @@ -16,7 +16,13 @@
16 16 &nbsp;
17 17 = link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do
18 18 %i.icon-edit
19   - Rename
  19 + Edit
  20 + %tr
  21 + %td
  22 + %b
  23 + Description:
  24 + %td
  25 + = @group.description
20 26 %tr
21 27 %td
22 28 %b
... ...
app/views/admin/projects/_form.html.haml
... ... @@ -31,6 +31,15 @@
31 31 = f.label :issues_enabled, "Issues"
32 32 .input= f.check_box :issues_enabled
33 33  
  34 + - if Project.issues_tracker.values.count > 1
  35 + .clearfix
  36 + = f.label :issues_tracker, "Issues tracker", class: 'control-label'
  37 + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
  38 +
  39 + .clearfix
  40 + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
  41 + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
  42 +
34 43 .clearfix
35 44 = f.label :merge_requests_enabled, "Merge Requests"
36 45 .input= f.check_box :merge_requests_enabled
... ...
app/views/admin/teams/edit.html.haml
1   -%h3.page_title Rename Team
  1 +%h3.page_title Edit Team
2 2 %hr
3 3 = form_for @team, url: admin_team_path(@team), method: :put do |f|
4 4 - if @team.errors.any?
... ... @@ -10,6 +10,11 @@
10 10 .input
11 11 = f.text_field :name, placeholder: "Example Team", class: "xxlarge"
12 12  
  13 + .clearfix.team-description-holder
  14 + = f.label :description, "Details"
  15 + .input
  16 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  17 +
13 18 .clearfix.team_name_holder
14 19 = f.label :path do
15 20 %span.cred Team path is
... ... @@ -19,5 +24,5 @@
19 24 %li It will change web url for access team and team projects.
20 25  
21 26 .form-actions
22   - = f.submit 'Rename team', class: "btn btn-remove"
  27 + = f.submit 'Edit team', class: "btn btn-remove"
23 28 = link_to 'Cancel', admin_teams_path, class: "btn btn-cancel"
... ...
app/views/admin/teams/index.html.haml
... ... @@ -16,6 +16,7 @@
16 16 %th
17 17 Name
18 18 %i.icon-sort-down
  19 + %th Description
19 20 %th Path
20 21 %th Projects
21 22 %th Members
... ... @@ -26,13 +27,17 @@
26 27 %tr
27 28 %td
28 29 %strong= link_to team.name, admin_team_path(team)
  30 + %td= truncate team.description
29 31 %td= team.path
30 32 %td= team.projects.count
31 33 %td= team.members.count
32 34 %td
33   - = link_to team.owner.name, admin_user_path(team.owner)
  35 + - if team.owner
  36 + = link_to team.owner.name, admin_user_path(team.owner)
  37 + - else
  38 + (deleted)
34 39 %td.bgred
35   - = link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small"
  40 + = link_to 'Edit', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small"
36 41 = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
37 42  
38 43 = paginate @teams, theme: "admin"
... ...
app/views/admin/teams/new.html.haml
... ... @@ -9,8 +9,15 @@
9 9 Team name is
10 10 .input
11 11 = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
12   - &nbsp;
13   - = f.submit 'Create team', class: "btn btn-primary"
  12 +
  13 + .clearfix.team-description-holder
  14 + = f.label :description, "Details"
  15 + .input
  16 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  17 +
  18 + .form-actions
  19 + = f.submit 'Create team', class: "btn btn-primary"
  20 +
14 21 %hr
15 22 .padded
16 23 %ul
... ...
app/views/admin/teams/show.html.haml
... ... @@ -16,7 +16,13 @@
16 16 &nbsp;
17 17 = link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do
18 18 %i.icon-edit
19   - Rename
  19 + Edit
  20 + %tr
  21 + %td
  22 + %b
  23 + Description:
  24 + %td
  25 + = @team.description
20 26 %tr
21 27 %td
22 28 %b
... ...
app/views/admin/users/_form.html.haml
... ... @@ -61,7 +61,7 @@
61 61 .span4
62 62 - unless @admin_user.new_record?
63 63 .alert.alert-error
64   - - if @admin_user.blocked
  64 + - if @admin_user.blocked?
65 65 %p This user is blocked and is not able to login to GitLab
66 66 = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small"
67 67 - else
... ...
app/views/admin/users/index.html.haml
... ... @@ -53,7 +53,7 @@
53 53 &nbsp;
54 54 = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small"
55 55 - unless user == current_user
56   - - if user.blocked
  56 + - if user.blocked?
57 57 = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success"
58 58 - else
59 59 = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove"
... ...
app/views/admin/users/show.html.haml
... ... @@ -3,7 +3,7 @@
3 3 %h3.page_title
4 4 = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90"
5 5 = @admin_user.name
6   - - if @admin_user.blocked
  6 + - if @admin_user.blocked?
7 7 %span.cred (Blocked)
8 8 - if @admin_user.admin
9 9 %span.cred (Admin)
... ...
app/views/commits/_commits.html.haml
1   -- @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits|
  1 +- @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits|
2 2 %div.ui-box
3 3 %h5.title
4 4 %i.icon-calendar
... ...
app/views/events/event/_note.html.haml
... ... @@ -21,9 +21,10 @@
21 21 = event.project_name
22 22  
23 23 .event-body
24   - %i.icon-comment-alt.event-note-icon
25   - %span.event-note
26   - = markdown truncate(event.target.note, length: 70)
  24 + .event-note
  25 + .md
  26 + %i.icon-comment-alt.event-note-icon
  27 + = sanitize(markdown(truncate(event.target.note, length: 150)), tags: %w(a img b pre p))
27 28 - note = event.target
28 29 - if note.attachment.url
29 30 = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do
... ...
app/views/groups/edit.html.haml
... ... @@ -9,8 +9,15 @@
9 9 Group name is
10 10 .input
11 11 = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
12   - &nbsp;
13   - = f.submit 'Save group', class: "btn btn-save"
  12 +
  13 + .clearfix.group-description-holder
  14 + = f.label :description, "Details"
  15 + .input
  16 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  17 +
  18 + .form-actions
  19 + = f.submit 'Save group', class: "btn btn-save"
  20 +
14 21 %hr
15 22  
16 23  
... ...
app/views/groups/new.html.haml
... ... @@ -9,9 +9,16 @@
9 9 Group name is
10 10 .input
11 11 = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
12   - &nbsp;
13   - = f.submit 'Create group', class: "btn btn-create"
14   - %hr
  12 +
  13 + .clearfix.group-description-holder
  14 + = f.label :description, "Details"
  15 + .input
  16 + = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
  17 +
  18 + .form-actions
  19 + = f.submit 'Create group', class: "btn btn-create"
  20 +
  21 +
15 22 .padded
16 23 %ul
17 24 %li Group is kind of directory for several projects
... ...
app/views/groups/show.html.haml
... ... @@ -12,6 +12,9 @@
12 12 %p.nothing_here_message Project activity will be displayed here
13 13 .loading.hide
14 14 .side.span4
  15 + - if @group.description.present?
  16 + .description.well.light
  17 + = @group.description
15 18 = render "projects", projects: @projects
16 19 %div
17 20 %span.rss-icon
... ...
app/views/issues/_filter.html.haml
... ... @@ -6,7 +6,10 @@
6 6 Open
7 7 %li{class: ("active" if params[:status] == 'assigned-to-me')}
8 8 = link_to project_issues_path(@project, status: 'assigned-to-me') do
9   - Assigned To Me
  9 + Assigned to me
  10 + %li{class: ("active" if params[:status] == 'created-by-me')}
  11 + = link_to project_issues_path(@project, status: 'created-by-me') do
  12 + Created by me
10 13 %li{class: ("active" if params[:status] == 'closed')}
11 14 = link_to project_issues_path(@project, status: 'closed') do
12 15 Closed
... ...
app/views/layouts/_flash.html.haml
1   -- if text = alert || notice
2   - #flash-container
3   - %h4= text
  1 +.flash-container
  2 + - if alert
  3 + .alert
  4 + %span= alert
  5 +
  6 + - elsif notice
  7 + .alert.alert-info
  8 + %span= notice
... ...
app/views/layouts/_head.html.haml
... ... @@ -7,6 +7,7 @@
7 7 = stylesheet_link_tag "application"
8 8 = javascript_include_tag "application"
9 9 = csrf_meta_tags
  10 + = include_gon
10 11  
11 12 -# Atom feed
12 13 - if current_user
... ...
app/views/layouts/_head_panel.html.haml
... ... @@ -8,6 +8,9 @@
8 8 %span.separator
9 9 %h1.project_name= title
10 10 %ul.nav
  11 + %li
  12 + = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
  13 + %i.icon-globe
11 14 - if current_user.is_admin?
12 15 %li
13 16 = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do
... ...
app/views/layouts/admin.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "Admin area"
4 4 %body{class: "#{app_theme} admin"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: "Admin area"
  6 + = render "layouts/flash"
7 7 .container
8 8 %ul.main_menu
9 9 = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
... ...
app/views/layouts/application.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "Dashboard"
4 4 %body{class: "#{app_theme} application"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: "Dashboard"
  6 + = render "layouts/flash"
7 7 .container
8 8 %ul.main_menu
9 9 = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
... ...
app/views/layouts/devise.html.haml
... ... @@ -3,4 +3,6 @@
3 3 = render "layouts/head"
4 4 %body.ui_basic.login-page
5 5 = render "layouts/flash"
6   - .container= yield
  6 + .container
  7 + .content
  8 + = yield
... ...
app/views/layouts/errors.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "Error"
4 4 %body{class: "#{app_theme} application"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: ""
  6 + = render "layouts/flash"
7 7 .container
8 8 .content
9 9 %center.padded.prepend-top-20
... ...
app/views/layouts/group.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "#{@group.name}"
4 4 %body{class: "#{app_theme} application"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: "group: #{@group.name}"
  6 + = render "layouts/flash"
7 7 .container
8 8 %ul.main_menu
9 9 = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
... ...
app/views/layouts/profile.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "Profile"
4 4 %body{class: "#{app_theme} profile"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: "Profile"
  6 + = render "layouts/flash"
7 7 .container
8 8 %ul.main_menu
9 9 = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
... ...
app/views/layouts/project_resource.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: @project.name_with_namespace
4 4 %body{class: "#{app_theme} project"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: project_title(@project)
  6 + = render "layouts/flash"
7 7 - if can?(current_user, :download_code, @project)
8 8 = render 'shared/no_ssh'
9 9  
... ... @@ -22,11 +22,12 @@
22 22 = nav_link(controller: %w(graph)) do
23 23 = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref)
24 24  
25   - - if @project.issues_enabled
  25 + - if @project.issues_enabled
26 26 = nav_link(controller: %w(issues milestones labels)) do
27   - = link_to project_issues_filter_path(@project) do
  27 + = link_to url_for_project_issues do
28 28 Issues
29   - %span.count.issue_counter= @project.issues.opened.count
  29 + - if @project.used_default_issues_tracker?
  30 + %span.count.issue_counter= @project.issues.opened.count
30 31  
31 32 - if @project.repo_exists? && @project.merge_requests_enabled
32 33 = nav_link(controller: :merge_requests) do
... ...
app/views/layouts/user_team.html.haml
... ... @@ -2,8 +2,8 @@
2 2 %html{ lang: "en"}
3 3 = render "layouts/head", title: "#{@team.name}"
4 4 %body{class: "#{app_theme} application"}
5   - = render "layouts/flash"
6 5 = render "layouts/head_panel", title: "team: #{@team.name}"
  6 + = render "layouts/flash"
7 7 .container
8 8 %ul.main_menu
9 9 = nav_link(path: 'teams#show', html_options: {class: 'home'}) do
... ...
app/views/merge_requests/show/_mr_accept.html.haml
1   -- unless can?(current_user, :accept_mr, @project)
  1 +- unless @allowed_to_merge
2 2 .alert
3   - %strong Only masters can accept MR
  3 + %strong You don't have enough permissions to merge this MR
4 4  
5 5  
6   -- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project)
  6 +- if @show_merge_controls
7 7 .automerge_widget.can_be_merged{style: "display:none"}
8 8 .alert.alert-success
9 9 %span
... ...
app/views/notify/issue_status_changed_email.text.erb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +Issue was <%= @issue_status %> by <%= @updated_by.name %>
  2 +
  3 +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
  4 +
... ...
app/views/notify/new_issue_email.text.erb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +New Issue was created and assigned to you.
  2 +
  3 +
  4 +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
... ...
app/views/notify/new_merge_request_email.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +New Merge Request <%= @merge_request.id %>
  2 +
  3 +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %>
  4 +
  5 +
  6 +Branches: <%= @merge_request.source_branch %> to <%= @merge_request.target_branch %>
  7 +Author: <%= @merge_request.author_name %>
  8 +Asignee: <%= @merge_request.assignee_name %>
  9 +
... ...
app/views/notify/new_user_email.text.erb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +Hi <%= @user.name %>!
  2 +
  3 +Administrator created account for you. Now you are a member of company GitLab application.
  4 +
  5 +login.................. <%= @user.email %>
  6 +<% unless Gitlab.config.gitlab.signup_enabled %>
  7 + password............... <%= @password %>
  8 +<% end %>
  9 +
  10 +Click here to login: <%= url_for(root_url) %>
... ...
app/views/notify/note_commit_email.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +New comment for Commit <%= @commit.short_id %>
  2 +
  3 +<%= url_for(project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}")) %>
  4 +
  5 +
  6 +Author: <%= @note.author_name %>
  7 +
  8 +<%= @note.note %>
  9 +
... ...
app/views/notify/note_issue_email.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +New comment for Issue <%= @issue.id %>
  2 +
  3 +<%= url_for(project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")) %>
  4 +
  5 +
  6 +Author: <%= @note.author_name %>
  7 +
  8 +<%= @note.note %>
  9 +
... ...
app/views/notify/note_merge_request_email.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +New comment for Merge Request <%= @merge_request.id %>
  2 +
  3 +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}")) %>
  4 +
  5 +
  6 +<%= @note.author_name %>
  7 +
  8 +<%= @note.note %>
  9 +
... ...
app/views/notify/note_wall_email.text.erb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +New message on the project wall <%= @note.project %>
  2 +
  3 +<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %>
  4 +
  5 +
  6 +<%= @note.author_name %>
  7 +
  8 +<%= @note.note %>
  9 +
... ...
app/views/notify/project_access_granted_email.text.erb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +
  2 +You have been granted <%= @users_project.project_access_human %> access to project <%= @project.name_with_namespace %>
  3 +
  4 +<%= url_for(project_url(@project)) %>
... ...
app/views/notify/project_was_moved_email.text.erb 0 → 100644
... ... @@ -0,0 +1,8 @@
  1 +Project was moved to another location
  2 +
  3 +The project is now located under
  4 +<%= url_for(link_to project_url(@project)) %>
  5 +
  6 +
  7 +To update the remote url in your local repository run:
  8 + git remote set-url origin <%= @project.ssh_url_to_repo %>
... ...
app/views/notify/reassigned_issue_email.text.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +Reassigned Issue <%= @issue.id %>
  2 +
  3 +<%= url_for(project_issue_url(@issue.project, @issue)) %>
  4 +
  5 +
  6 +Assignee changed from <%= @previous_assignee.name %> to <%= @issue.assignee_name %>
  7 +
... ...
app/views/notify/reassigned_merge_request_email.text.erb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +Reassigned Merge Request <%= @merge_request.id %>
  2 +
  3 +<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %>
  4 +
  5 +
  6 +Assignee changed from <%= @previous_assignee.name %> to <%= @merge_request.assignee_name %>
  7 +
... ...
app/views/projects/_form.html.haml
... ... @@ -24,6 +24,15 @@
24 24 = f.check_box :issues_enabled
25 25 %span.descr Lightweight issue tracking system for this project
26 26  
  27 + - if Project.issues_tracker.values.count > 1
  28 + .control-group
  29 + = f.label :issues_tracker, "Issues tracker", class: 'control-label'
  30 + .input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
  31 +
  32 + .clearfix
  33 + = f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
  34 + .input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
  35 +
27 36 .control-group
28 37 = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
29 38 .controls
... ...
app/views/projects/empty.html.haml
... ... @@ -5,14 +5,14 @@
5 5 %fieldset
6 6 %legend Git global setup:
7 7 %pre.dark
8   - = preserve do
  8 + :preserve
9 9 git config --global user.name "#{current_user.name}"
10 10 git config --global user.email "#{current_user.email}"
11 11  
12 12 %fieldset
13 13 %legend Create Repository
14 14 %pre.dark
15   - = preserve do
  15 + :preserve
16 16 mkdir #{@project.path}
17 17 cd #{@project.path}
18 18 git init
... ... @@ -25,7 +25,7 @@
25 25 %fieldset
26 26 %legend Existing Git Repo?
27 27 %pre.dark
28   - = preserve do
  28 + :preserve
29 29 cd existing_git_repo
30 30 git remote add origin #{@project.url_to_repo}
31 31 git push -u origin master
... ...
app/views/public/projects/index.html.haml
... ... @@ -12,5 +12,7 @@
12 12 .pull-right
13 13 %pre.dark.tiny git clone #{project.http_url_to_repo}
14 14  
  15 + - unless @projects.present?
  16 + %h3.nothing_here_message No public projects
15 17  
16 18 = paginate @projects, theme: "admin"
... ...
app/views/shared/_clone_panel.html.haml
1 1 .input-prepend.project_clone_holder
2 2 %button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH
3 3 %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
4   -
5   - = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge"
  4 + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
... ...
app/views/team_members/_team_member.html.haml
... ... @@ -20,7 +20,7 @@
20 20 %span.label This is you!
21 21 - if @project.namespace_owner == user
22 22 %span.label Owner
23   - - elsif user.blocked
  23 + - elsif user.blocked?
24 24 %span.label Blocked
25 25 - elsif allow_admin
26 26 = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do
... ...
app/views/teams/edit.html.haml
... ... @@ -12,13 +12,19 @@
12 12 .input
13 13 = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left"
14 14  
  15 + .clearfix.team-description-holder
  16 + = f.label :description, "Details"
  17 + .input
  18 + = f.text_area :description, maxlength: 250, class: "xlarge js-gfm-input", rows: 4
  19 +
15 20 .clearfix
16 21 = f.label :path do
17 22 Team path is
18 23 .input
19 24 = f.text_field :path, placeholder: "opensource", class: "xlarge left"
  25 +
20 26 .form-actions
21   - = f.submit 'Save team changes', class: "btn btn-save"
  27 + = f.submit 'Save team changes', class: "btn btn-primary"
22 28 .span5
23 29 .ui-box
24 30 %h5.title Remove team
... ... @@ -26,4 +32,3 @@
26 32 %p
27 33 Removed team can not be restored!
28 34 = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small"
29   -
... ...
app/views/teams/members/_show.html.haml
... ... @@ -23,7 +23,7 @@
23 23 %span.btn.disabled This is you!
24 24 - if @team.owner == user
25 25 %span.btn.disabled Owner
26   - - elsif user.blocked
  26 + - elsif user.blocked?
27 27 %span.btn.disabled.blocked Blocked
28 28 - elsif allow_admin
29 29 = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do
... ...