Commit 906c65b6243e1f55f96d58cc1d4d60dd64c5cc65

Authored by Crom (Thibaut CHARLES)
2 parents 87fc3507 dbf8ae73

Merge branch 'master' of https://github.com/gitlabhq/gitlabhq

Conflicts:
	config/application.rb
	config/gitlab.yml.example
	config/unicorn.rb.example
Showing 303 changed files with 4882 additions and 1336 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 303 files displayed.

.travis.yml
... ... @@ -9,7 +9,6 @@ env:
9 9 - TASK=jasmine:ci
10 10 before_install:
11 11 - sudo apt-get install libicu-dev -y
12   - - gem install charlock_holmes -v="0.6.9"
13 12 branches:
14 13 only:
15 14 - 'master'
... ... @@ -17,9 +16,12 @@ rvm:
17 16 - 2.0.0
18 17 services:
19 18 - mysql
  19 + - redis-server
20 20 before_script:
21 21 - "cp config/database.yml.$DB config/database.yml"
22 22 - "cp config/gitlab.yml.example config/gitlab.yml"
23 23 - "bundle exec rake db:setup"
24 24 - "bundle exec rake db:seed_fu"
25 25 script: "bundle exec rake $TASK --trace"
  26 +notifications:
  27 + email: false
... ...
CHANGELOG
  1 +v 6.4.0
  2 + - Added sorting to project issues page (Jason Blanchard)
  3 + - Assembla integration (Carlos Paramio)
  4 + - Fixed another 500 error with submodules
  5 + - UI: More compact issues page
  6 + - Minimal password length increased to 8 symbols
  7 + - Side-by-side diff view (Steven Thonus)
  8 + - Internal projects (Jason Hollingsworth)
  9 + - Allow removal of avatar (Drew Blessing)
  10 + - Project web hooks now support issues and merge request events
  11 + - Visiting project page while not logged in will redirect to sign-in instead of 404 (Jason Hollingsworth)
  12 +
1 13 v 6.3.0
2 14 - API for adding gitlab-ci service
3 15 - Init script now waits for pids to appear after (re)starting before reporting status (Rovanion Luckey)
... ... @@ -9,6 +21,34 @@ v 6.3.0
9 21 - Fixed issue with 500 error when group did not exist
10 22 - Ability to leave project
11 23 - You can create file in repo using UI
  24 + - You can remove file from repo using UI
  25 + - API: dropped default_branch attribute from project during creation
  26 + - Project default_branch is not stored in db any more. It takes from repo now.
  27 + - Admin broadcast messages
  28 + - UI improvements
  29 + - Dont show last push widget if user removed this branch
  30 + - Fix 500 error for repos with newline in file name
  31 + - Extended html titles
  32 + - API: create/update/delete repo files
  33 + - Admin can transfer project to any namespace
  34 + - API: projects/all for admin users
  35 + - Fix recent branches order
  36 +
  37 +v 6.2.4
  38 + - Security: Cast API private_token to string (CVE-2013-4580)
  39 + - Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
  40 + - Fix for Git SSH access for LDAP users
  41 +
  42 +v 6.2.3
  43 + - Security: More protection against CVE-2013-4489
  44 + - Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
  45 + - Fix sidekiq rake tasks
  46 +
  47 +v 6.2.2
  48 + - Security: Update gitlab_git (CVE-2013-4489)
  49 +
  50 +v 6.2.1
  51 + - Security: Fix issue with generated passwords for new users
12 52  
13 53 v 6.2.0
14 54 - Public project pages are now visible to everyone (files, issues, wik, etc.)
... ... @@ -30,7 +70,7 @@ v 6.2.0
30 70 - Avatar upload on profile page with a maximum of 100KB (Steven Thonus)
31 71 - Store the sessions in Redis instead of the cookie store
32 72 - Fixed relative links in markdown
33   - - User must confirm his email if signup enabled
  73 + - User must confirm their email if signup enabled
34 74 - User must confirm changed email
35 75  
36 76 v 6.1.0
... ... @@ -52,7 +92,7 @@ v 6.1.0
52 92 - Add links to create branch/tag from project home page
53 93 - Add public-project? checkbox to new-project view
54 94 - Improved compare page. Added link to proceed into Merge Request
55   - - Send email to user when he was added to group
  95 + - Send an email to a user when they are added to group
56 96 - New landing page when you have 0 projects
57 97  
58 98 v 6.0.0
... ... @@ -95,6 +135,14 @@ v 6.0.0
95 135 - Improved MR comments logic
96 136 - Render readme file for projects in public area
97 137  
  138 +v 5.4.2
  139 + - Security: Cast API private_token to string (CVE-2013-4580)
  140 + - Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
  141 +
  142 +v 5.4.1
  143 + - Security: Fixes for CVE-2013-4489
  144 + - Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
  145 +
98 146 v 5.4.0
99 147 - Ability to edit own comments
100 148 - Documentation improvements
... ...
CONTRIBUTING.md
... ... @@ -9,6 +9,14 @@ This guide details how to use issues and pull requests to improve GitLab.
9 9  
10 10 If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md).
11 11  
  12 +## Contributor license agreement
  13 +
  14 +By submitting code as an individual you agree to the [individual contributor license agreement](doc/legal/individual_contributor_license_agreement.md). By submitting code as an entity you agree to the [corporate contributor license agreement](doc/legal/corporate_contributor_license_agreement.md).
  15 +
  16 +## Security vulnerability disclosure
  17 +
  18 +Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://www.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
  19 +
12 20 ## Closing policy for issues and pull requests
13 21  
14 22 GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. Out of respect for our volunteers, issues and pull requests not in line with the guidelines listed in this document may be closed without notice.
... ... @@ -74,6 +82,3 @@ We will accept pull requests if:
74 82 * It is a single commit (please use `git rebase -i` to squash commits)
75 83  
76 84 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).
77   -
78   -## Security vulnerabilities
79   -Please report security vulnerabilities in private to support@gitlab.com; also see http://www.gitlab.com/disclosure/. Do NOT create GitHub issues for security vulnerabilities.
... ...
Gemfile
... ... @@ -8,7 +8,7 @@ def linux_only(require_as)
8 8 RUBY_PLATFORM.include?('linux') && require_as
9 9 end
10 10  
11   -gem "rails", "3.2.15"
  11 +gem "rails", "3.2.16"
12 12  
13 13 # Supported DBs
14 14 gem "mysql2", group: :mysql
... ... @@ -24,26 +24,27 @@ gem 'omniauth-github'
24 24  
25 25 # Extracting information from a git repository
26 26 # Provide access to Gitlab::Git library
27   -gem "gitlab_git", "~> 3.0.0.rc2"
  27 +gem "gitlab_git", "~> 3.1.0"
28 28  
29 29 # Ruby/Rack Git Smart-HTTP Server Handler
30   -gem 'gitlab-grack', '~> 1.0.1', require: 'grack'
  30 +gem 'gitlab-grack', '~> 1.1.0', require: 'grack'
31 31  
32 32 # LDAP Auth
33 33 gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
34 34  
35 35 # Syntax highlighter
36   -gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
  36 +gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
37 37  
38 38 # Git Wiki
39   -gem "gitlab-gollum-lib", "~> 1.0.1", require: 'gollum-lib'
  39 +gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib'
40 40  
41 41 # Language detection
42   -gem "github-linguist", require: "linguist"
  42 +gem "gitlab-linguist", "~> 2.9.6", require: "linguist"
43 43  
44 44 # API
45 45 gem "grape", "~> 0.4.1"
46 46 gem "grape-entity", "~> 0.3.0"
  47 +gem 'rack-cors', require: 'rack/cors'
47 48  
48 49 # Format dates and times
49 50 # based on human-friendly examples
... ... @@ -135,7 +136,7 @@ group :assets do
135 136 gem 'turbolinks'
136 137 gem 'jquery-turbolinks'
137 138  
138   - gem 'chosen-rails', "1.0.0"
  139 + gem 'chosen-rails', "1.0.1"
139 140 gem 'select2-rails'
140 141 gem 'jquery-atwho-rails', "0.3.0"
141 142 gem "jquery-rails", "2.1.3"
... ...
Gemfile.lock
1 1 GEM
2 2 remote: https://rubygems.org/
3 3 specs:
4   - actionmailer (3.2.15)
5   - actionpack (= 3.2.15)
  4 + actionmailer (3.2.16)
  5 + actionpack (= 3.2.16)
6 6 mail (~> 2.5.4)
7   - actionpack (3.2.15)
8   - activemodel (= 3.2.15)
9   - activesupport (= 3.2.15)
  7 + actionpack (3.2.16)
  8 + activemodel (= 3.2.16)
  9 + activesupport (= 3.2.16)
10 10 builder (~> 3.0.0)
11 11 erubis (~> 2.7.0)
12 12 journey (~> 1.0.4)
... ... @@ -14,18 +14,18 @@ GEM
14 14 rack-cache (~> 1.2)
15 15 rack-test (~> 0.6.1)
16 16 sprockets (~> 2.2.1)
17   - activemodel (3.2.15)
18   - activesupport (= 3.2.15)
  17 + activemodel (3.2.16)
  18 + activesupport (= 3.2.16)
19 19 builder (~> 3.0.0)
20   - activerecord (3.2.15)
21   - activemodel (= 3.2.15)
22   - activesupport (= 3.2.15)
  20 + activerecord (3.2.16)
  21 + activemodel (= 3.2.16)
  22 + activesupport (= 3.2.16)
23 23 arel (~> 3.0.2)
24 24 tzinfo (~> 0.3.29)
25   - activeresource (3.2.15)
26   - activemodel (= 3.2.15)
27   - activesupport (= 3.2.15)
28   - activesupport (3.2.15)
  25 + activeresource (3.2.16)
  26 + activemodel (= 3.2.16)
  27 + activesupport (= 3.2.16)
  28 + activesupport (3.2.16)
29 29 i18n (~> 0.6, >= 0.6.4)
30 30 multi_json (~> 1.0)
31 31 acts-as-taggable-on (2.4.1)
... ... @@ -34,11 +34,11 @@ GEM
34 34 annotate (2.6.0.beta2)
35 35 activerecord (>= 2.3.0)
36 36 rake (>= 0.8.7)
37   - arel (3.0.2)
  37 + arel (3.0.3)
38 38 asciidoctor (0.1.3)
39 39 awesome_print (1.2.0)
40 40 backports (3.3.2)
41   - bcrypt-ruby (3.1.1)
  41 + bcrypt-ruby (3.1.2)
42 42 better_errors (1.0.1)
43 43 coderay (>= 1.0.0)
44 44 erubis (>= 2.6.6)
... ... @@ -61,12 +61,12 @@ GEM
61 61 charlock_holmes (0.6.9.4)
62 62 childprocess (0.3.9)
63 63 ffi (~> 1.0, >= 1.0.11)
64   - chosen-rails (1.0.0)
  64 + chosen-rails (1.0.1)
65 65 coffee-rails (>= 3.2)
66 66 compass-rails (>= 1.0)
67 67 railties (>= 3.0)
68 68 sass-rails (>= 3.2)
69   - chunky_png (1.2.8)
  69 + chunky_png (1.2.9)
70 70 cliver (0.2.1)
71 71 code_analyzer (0.4.3)
72 72 sexp_processor
... ... @@ -77,7 +77,7 @@ GEM
77 77 coffee-script (2.2.0)
78 78 coffee-script-source
79 79 execjs
80   - coffee-script-source (1.6.2)
  80 + coffee-script-source (1.6.3)
81 81 colored (1.2)
82 82 colorize (0.5.8)
83 83 compass (0.12.2)
... ... @@ -101,14 +101,14 @@ GEM
101 101 database_cleaner (1.1.1)
102 102 debug_inspector (0.0.2)
103 103 descendants_tracker (0.0.1)
104   - devise (2.2.5)
  104 + devise (2.2.8)
105 105 bcrypt-ruby (~> 3.0)
106 106 orm_adapter (~> 0.1)
107 107 railties (~> 3.1)
108 108 warden (~> 1.2.1)
109 109 devise-async (0.8.0)
110 110 devise (>= 2.2, < 3.2)
111   - diff-lcs (1.2.4)
  111 + diff-lcs (1.2.5)
112 112 dotenv (0.8.0)
113 113 email_spec (1.4.0)
114 114 launchy (~> 2.1)
... ... @@ -119,8 +119,7 @@ GEM
119 119 escape_utils (0.2.4)
120 120 eventmachine (1.0.3)
121 121 excon (0.13.4)
122   - execjs (1.4.0)
123   - multi_json (~> 1.0)
  122 + execjs (2.0.2)
124 123 factory_girl (4.2.0)
125 124 activesupport (>= 3.0.0)
126 125 factory_girl_rails (4.2.1)
... ... @@ -151,38 +150,39 @@ GEM
151 150 fssm (0.2.10)
152 151 gemoji (1.2.1)
153 152 gherkin-ruby (0.3.0)
154   - github-linguist (2.3.4)
155   - charlock_holmes (~> 0.6.6)
156   - escape_utils (~> 0.2.3)
157   - mime-types (~> 1.19)
158   - pygments.rb (>= 0.2.13)
159   - github-markdown (0.5.3)
  153 + github-markdown (0.5.5)
160 154 github-markup (0.7.5)
161 155 gitlab-flowdock-git-hook (0.4.2.2)
162 156 gitlab-grit (>= 2.4.1)
163 157 multi_json
164   - gitlab-gollum-lib (1.0.1)
  158 + gitlab-gollum-lib (1.0.2)
165 159 github-markdown (~> 0.5.3)
166 160 github-markup (>= 0.7.5, < 1.0.0)
167   - gitlab-grit (>= 2.5.1)
  161 + gitlab-grit (~> 2.6.1)
  162 + gitlab-pygments.rb (~> 0.5.4)
168 163 nokogiri (~> 1.5.9)
169   - pygments.rb (~> 0.4.2)
170 164 sanitize (~> 2.0.3)
171 165 stringex (~> 1.5.1)
172   - gitlab-grack (1.0.1)
  166 + gitlab-grack (1.1.0)
173 167 rack (~> 1.4.1)
174   - gitlab-grit (2.6.1)
  168 + gitlab-grit (2.6.3)
175 169 charlock_holmes (~> 0.6.9)
176 170 diff-lcs (~> 1.1)
177 171 mime-types (~> 1.15)
178 172 posix-spawn (~> 0.3.6)
179   - gitlab-pygments.rb (0.3.2)
  173 + gitlab-linguist (2.9.6)
  174 + charlock_holmes (~> 0.6.6)
  175 + escape_utils (~> 0.2.4)
  176 + gitlab-pygments.rb (~> 0.5.4)
  177 + mime-types (~> 1.19)
  178 + gitlab-pygments.rb (0.5.4)
180 179 posix-spawn (~> 0.3.6)
181 180 yajl-ruby (~> 1.1.0)
182   - gitlab_git (3.0.0.rc2)
  181 + gitlab_git (3.1.0)
183 182 activesupport (~> 3.2.13)
184   - github-linguist (~> 2.3.4)
185 183 gitlab-grit (~> 2.6.1)
  184 + gitlab-linguist (~> 2.9.5)
  185 + gitlab-pygments.rb (~> 0.5.4)
186 186 gitlab_meta (6.0)
187 187 gitlab_omniauth-ldap (1.0.3)
188 188 net-ldap (~> 0.3.1)
... ... @@ -235,7 +235,7 @@ GEM
235 235 multi_json (~> 1.0)
236 236 multi_xml (>= 0.5.2)
237 237 httpauth (0.2.0)
238   - i18n (0.6.5)
  238 + i18n (0.6.9)
239 239 jasmine (1.3.2)
240 240 jasmine-core (~> 1.3.1)
241 241 rack (~> 1.0)
... ... @@ -274,7 +274,7 @@ GEM
274 274 mime-types (~> 1.16)
275 275 treetop (~> 1.4.8)
276 276 method_source (0.8.1)
277   - mime-types (1.25)
  277 + mime-types (1.25.1)
278 278 minitest (4.7.4)
279 279 modernizr (2.6.2)
280 280 sprockets (~> 2.0)
... ... @@ -312,7 +312,7 @@ GEM
312 312 omniauth-twitter (0.0.17)
313 313 multi_json (~> 1.3)
314 314 omniauth-oauth (~> 1.0)
315   - orm_adapter (0.4.0)
  315 + orm_adapter (0.5.0)
316 316 pg (0.15.1)
317 317 poltergeist (1.4.1)
318 318 capybara (~> 2.1.0)
... ... @@ -325,9 +325,6 @@ GEM
325 325 coderay (~> 1.0.5)
326 326 method_source (~> 0.8)
327 327 slop (~> 3.4)
328   - pygments.rb (0.4.2)
329   - posix-spawn (~> 0.3.6)
330   - yajl-ruby (~> 1.1.0)
331 328 pyu-ruby-sasl (0.0.3.3)
332 329 quiet_assets (1.0.2)
333 330 railties (>= 3.1, < 5.0)
... ... @@ -338,6 +335,7 @@ GEM
338 335 rack
339 336 rack-cache (1.2)
340 337 rack (>= 0.4)
  338 + rack-cors (0.2.9)
341 339 rack-mini-profiler (0.1.31)
342 340 rack (>= 1.1.3)
343 341 rack-mount (0.8.3)
... ... @@ -348,14 +346,14 @@ GEM
348 346 rack
349 347 rack-test (0.6.2)
350 348 rack (>= 1.0)
351   - rails (3.2.15)
352   - actionmailer (= 3.2.15)
353   - actionpack (= 3.2.15)
354   - activerecord (= 3.2.15)
355   - activeresource (= 3.2.15)
356   - activesupport (= 3.2.15)
  349 + rails (3.2.16)
  350 + actionmailer (= 3.2.16)
  351 + actionpack (= 3.2.16)
  352 + activerecord (= 3.2.16)
  353 + activeresource (= 3.2.16)
  354 + activesupport (= 3.2.16)
357 355 bundler (~> 1.0)
358   - railties (= 3.2.15)
  356 + railties (= 3.2.16)
359 357 rails-dev-tweaks (0.6.1)
360 358 actionpack (~> 3.1)
361 359 railties (~> 3.1)
... ... @@ -368,9 +366,9 @@ GEM
368 366 i18n
369 367 require_all
370 368 ruby-progressbar
371   - railties (3.2.15)
372   - actionpack (= 3.2.15)
373   - activesupport (= 3.2.15)
  369 + railties (3.2.16)
  370 + actionpack (= 3.2.16)
  371 + activesupport (= 3.2.16)
374 372 rack-ssl (~> 1.3.2)
375 373 rake (>= 0.8.7)
376 374 rdoc (~> 3.4)
... ... @@ -431,7 +429,7 @@ GEM
431 429 safe_yaml (0.9.3)
432 430 sanitize (2.0.3)
433 431 nokogiri (>= 1.4.4, < 1.6)
434   - sass (3.2.11)
  432 + sass (3.2.12)
435 433 sass-rails (3.2.6)
436 434 railties (~> 3.2.0)
437 435 sass (>= 3.1.10)
... ... @@ -559,7 +557,7 @@ DEPENDENCIES
559 557 bootstrap-sass
560 558 capybara
561 559 carrierwave
562   - chosen-rails (= 1.0.0)
  560 + chosen-rails (= 1.0.1)
563 561 coffee-rails
564 562 colored
565 563 coveralls
... ... @@ -575,13 +573,13 @@ DEPENDENCIES
575 573 font-awesome-rails
576 574 foreman
577 575 gemoji (~> 1.2.1)
578   - github-linguist
579 576 github-markup (~> 0.7.4)
580 577 gitlab-flowdock-git-hook (~> 0.4.2)
581   - gitlab-gollum-lib (~> 1.0.1)
582   - gitlab-grack (~> 1.0.1)
583   - gitlab-pygments.rb (~> 0.3.2)
584   - gitlab_git (~> 3.0.0.rc2)
  578 + gitlab-gollum-lib (~> 1.0.2)
  579 + gitlab-grack (~> 1.1.0)
  580 + gitlab-linguist (~> 2.9.6)
  581 + gitlab-pygments.rb (~> 0.5.4)
  582 + gitlab_git (~> 3.1.0)
585 583 gitlab_meta (= 6.0)
586 584 gitlab_omniauth-ldap (= 1.0.3)
587 585 gon
... ... @@ -613,8 +611,9 @@ DEPENDENCIES
613 611 pry
614 612 quiet_assets (~> 1.0.1)
615 613 rack-attack
  614 + rack-cors
616 615 rack-mini-profiler
617   - rails (= 3.2.15)
  616 + rails (= 3.2.16)
618 617 rails-dev-tweaks
619 618 rails_best_practices
620 619 raphael-rails (~> 2.1.2)
... ...
README.md
... ... @@ -32,7 +32,9 @@
32 32  
33 33 * GitLab.com commercial services: [Homepage](http://www.gitlab.com/) | [Subscription](http://www.gitlab.com/subscription/) | [Consultancy](http://www.gitlab.com/consultancy/) | [GitLab Cloud](http://www.gitlab.com/cloud/) | [Blog](http://blog.gitlab.com/)
34 34  
35   -* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server
  35 +* [GitLab Enterprise Edition](https://www.gitlab.com/features/) offers additional features that are useful for larger organizations (100+ users).
  36 +
  37 +* [GitLab CI](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) is a continuous integration (CI) server that is easy to integrate with GitLab.
36 38  
37 39 ### Requirements
38 40  
... ... @@ -44,31 +46,24 @@
44 46  
45 47 ** More details are in the [requirements doc](doc/install/requirements.md)
46 48  
47   -### Installation
48   -
49   -#### Official production installation
50   -
51   -* [Installation guide for a production server](doc/install/installation.md)
  49 +### Official installation methods
52 50  
  51 +* [Manual installation guide for a production server](doc/install/installation.md)
53 52  
54   -#### Official development installation
  53 +* [GitLab Chef Cookbook](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/README.md) This cookbook can be used both for development installations and production installations. If you want to [contribute](CONTRIBUTE.md) to GitLab we suggest you follow the [development installation on a virtual machine with Vagrant](https://gitlab.com/gitlab-org/cookbook-gitlab/blob/master/doc/development.md) instructions to install all testing dependencies.
55 54  
56   -If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working with all dependencies.
  55 +### Third party one-click installers
57 56  
58   -* [Vagrant virtual machine for development](https://github.com/gitlabhq/gitlab-vagrant-vm)
  57 +* [Digital Ocean 1-Click Application Install](https://www.digitalocean.com/blog_posts/host-your-git-repositories-in-55-seconds-with-gitlab) Have a new server up in 55 seconds. Digital Ocean uses SSD disks which is great for an IO intensive app such as GitLab.
59 58  
  59 +* [BitNami one-click installers](http://bitnami.com/stack/gitlab) This package contains both GitLab and GitLab CI. It is available as installer, virtual machine or for cloud hosting providers (Amazon Web Services/Azure/etc.).
60 60  
61   -#### Unofficial production installations
  61 +#### Unofficial installation methods
62 62  
63 63 * [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) repository with unofficial guides for using GitLab with different software (operating systems, webservers, etc.) than the official version.
64 64  
65 65 * [Installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) public wiki with unofficial guides to install GitLab on different operating systems.
66 66  
67   -* [BitNami one-click installers](http://bitnami.com/stack/gitlab)
68   -
69   -* [TurnKey Linux virtual appliance](http://www.turnkeylinux.org/gitlab)
70   -
71   -
72 67 ### New versions and upgrading
73 68  
74 69 Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide.
... ... @@ -79,7 +74,6 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl
79 74  
80 75 * Features that will be in the next releases are listed on [the feedback and suggestions forum](http://feedback.gitlab.com/forums/176466-general) with the status [started](http://feedback.gitlab.com/forums/176466-general/status/796456) and [completed](http://feedback.gitlab.com/forums/176466-general/status/796457).
81 76  
82   -
83 77 ### Run in production mode
84 78  
85 79 The Installation guide contains instructions on how to download an init script and run it automatically on boot. You can also start the init script manually:
... ... @@ -110,7 +104,7 @@ or start each component separately
110 104  
111 105 * Run all tests
112 106  
113   - bundle exec rake gitlab:test
  107 + bundle exec rake gitlab:test RAILS_ENV=test
114 108  
115 109 * [RSpec](http://rspec.info/) unit and functional tests
116 110  
... ... @@ -147,15 +141,17 @@ or start each component separately
147 141  
148 142 * [Mailing list](https://groups.google.com/forum/#!forum/gitlabhq) and [Stack Overflow](http://stackoverflow.com/questions/tagged/gitlab) are the best places to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and has resolved it. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix.
149 143  
150   -* [Unofficial #gitlab IRC on Freenode](http://www.freenode.net/) is another way to get in touch with other GitLab users who may be able to help you.
151   -
152 144 * [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
153 145  
154 146 * [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed.
155 147  
156 148 * [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
157 149  
158   -* [Consultancy](http://www.gitlab.com/consultancy/) allows you hire GitLab experts for installations, upgrades and customizations.
  150 +* [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
  151 +
  152 +* [#gitlab IRC channel](http://www.freenode.net/) on Freenode is unofficial but offers a way to get in touch with other GitLab users who may be able to help you.
  153 +
  154 +* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
159 155  
160 156  
161 157 ### Getting in touch
... ...
VERSION
1   -6.3.0.pre
  1 +6.4.0.pre
... ...
app/assets/images/favicon.ico
No preview for this file type
app/assets/images/logo-black.png

3.01 KB | W: | H:

2.95 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
app/assets/images/logo-white.png

5.59 KB | W: | H:

8.14 KB | W: | H:

  • 2-up
  • Swipe
  • Onion skin
app/assets/javascripts/api.js.coffee
... ... @@ -2,6 +2,7 @@
2 2 users_path: "/api/:version/users.json"
3 3 user_path: "/api/:version/users/:id.json"
4 4 notes_path: "/api/:version/projects/:id/notes.json"
  5 + namespaces_path: "/api/:version/namespaces.json"
5 6  
6 7 # Get 20 (depends on api) recent notes
7 8 # and sort the ascending from oldest to newest
... ... @@ -49,6 +50,20 @@
49 50 ).done (users) ->
50 51 callback(users)
51 52  
  53 + # Return namespaces list. Filtered by query
  54 + namespaces: (query, callback) ->
  55 + url = Api.buildUrl(Api.namespaces_path)
  56 +
  57 + $.ajax(
  58 + url: url
  59 + data:
  60 + private_token: gon.api_token
  61 + search: query
  62 + per_page: 20
  63 + dataType: "json"
  64 + ).done (namespaces) ->
  65 + callback(namespaces)
  66 +
52 67 buildUrl: (url) ->
53 68 url = gon.relative_url_root + url if gon.relative_url_root?
54 69 return url.replace(':version', gon.api_version)
... ...
app/assets/javascripts/blob.js.coffee
1 1 class BlobView
2 2 constructor: ->
  3 + # handle multi-line select
  4 + handleMultiSelect = (e) ->
  5 + [ first_line, last_line ] = parseSelectedLines()
  6 + [ line_number ] = parseSelectedLines($(this).attr("id"))
  7 + hash = "L#{line_number}"
  8 +
  9 + if e.shiftKey and not isNaN(first_line) and not isNaN(line_number)
  10 + if line_number < first_line
  11 + last_line = first_line
  12 + first_line = line_number
  13 + else
  14 + last_line = line_number
  15 +
  16 + hash = if first_line == last_line then "L#{first_line}" else "L#{first_line}-#{last_line}"
  17 +
  18 + setHash(hash)
  19 + e.preventDefault()
  20 +
3 21 # See if there are lines selected
4 22 # "#L12" and "#L34-56" supported
5   - highlightBlobLines = ->
6   - if window.location.hash isnt ""
7   - matches = window.location.hash.match(/\#L(\d+)(\-(\d+))?/)
  23 + highlightBlobLines = (e) ->
  24 + [ first_line, last_line ] = parseSelectedLines()
  25 +
  26 + unless isNaN first_line
  27 + $("#tree-content-holder .highlight .line").removeClass("hll")
  28 + $("#LC#{line}").addClass("hll") for line in [first_line..last_line]
  29 + $("#L#{first_line}").ScrollTo() unless e?
  30 +
  31 + # parse selected lines from hash
  32 + # always return first and last line (initialized to NaN)
  33 + parseSelectedLines = (str) ->
  34 + first_line = NaN
  35 + last_line = NaN
  36 + hash = str || window.location.hash
  37 +
  38 + if hash isnt ""
  39 + matches = hash.match(/\#?L(\d+)(\-(\d+))?/)
8 40 first_line = parseInt(matches?[1])
9 41 last_line = parseInt(matches?[3])
  42 + last_line = first_line if isNaN(last_line)
  43 +
  44 + [ first_line, last_line ]
  45 +
  46 + setHash = (hash) ->
  47 + hash = hash.replace(/^\#/, "")
  48 + nodes = $("#" + hash)
  49 + # if any nodes are using this id, they must be temporarily changed
  50 + # also, add a temporary div at the top of the screen to prevent scrolling
  51 + if nodes.length > 0
  52 + scroll_top = $(document).scrollTop()
  53 + nodes.attr("id", "")
  54 + tmp = $("<div></div>")
  55 + .css({ position: "absolute", visibility: "hidden", top: scroll_top + "px" })
  56 + .attr("id", hash)
  57 + .appendTo(document.body)
  58 +
  59 + window.location.hash = hash
  60 +
  61 + # restore the nodes
  62 + if nodes.length > 0
  63 + tmp.remove()
  64 + nodes.attr("id", hash)
10 65  
11   - unless isNaN first_line
12   - last_line = first_line if isNaN(last_line)
13   - $("#tree-content-holder .highlight .line").removeClass("hll")
14   - $("#LC#{line}").addClass("hll") for line in [first_line..last_line]
15   - $("#L#{first_line}").ScrollTo()
  66 + # initialize multi-line select
  67 + $("#tree-content-holder .line_numbers a[id^=L]").on("click", handleMultiSelect)
16 68  
17 69 # Highlight the correct lines on load
18 70 highlightBlobLines()
19 71  
20 72 # Highlight the correct lines when the hash part of the URL changes
21   - $(window).on 'hashchange', highlightBlobLines
  73 + $(window).on("hashchange", highlightBlobLines)
22 74  
23 75  
24 76 @BlobView = BlobView
... ...
app/assets/javascripts/commits.js.coffee
... ... @@ -4,13 +4,13 @@ class CommitsList
4 4 limit: 0
5 5 offset: 0
6 6 @disable = false
7   -
  7 +
8 8 @showProgress: ->
9 9 $('.loading').show()
10   -
  10 +
11 11 @hideProgress: ->
12 12 $('.loading').hide()
13   -
  13 +
14 14 @init: (ref, limit) ->
15 15 $(".day-commits-table li.commit").live 'click', (event) ->
16 16 if event.target.nodeName != "A"
... ... @@ -21,7 +21,7 @@ class CommitsList
21 21 @data.ref = ref
22 22 @data.limit = limit
23 23 @data.offset = limit
24   -
  24 +
25 25 this.initLoadMore()
26 26 this.showProgress()
27 27  
... ... @@ -32,7 +32,9 @@ class CommitsList
32 32 url: location.href
33 33 data: @data
34 34 complete: this.hideProgress
35   - dataType: "script"
  35 + success: (data) ->
  36 + CommitsList.append(data.count, data.html)
  37 + dataType: "json"
36 38  
37 39 @append: (count, html) ->
38 40 $("#commits-list").append(html)
... ... @@ -40,7 +42,7 @@ class CommitsList
40 42 @data.offset += count
41 43 else
42 44 @disable = true
43   -
  45 +
44 46 @initLoadMore: ->
45 47 $(document).unbind('scroll')
46 48 $(document).endlessScroll
... ...
app/assets/javascripts/issues.js.coffee
... ... @@ -22,7 +22,7 @@
22 22 backgroundColor: '#DDD'
23 23 opacity: .4
24 24 )
25   -
  25 +
26 26 reload: ->
27 27 Issues.initSelects()
28 28 Issues.initChecks()
... ... @@ -54,7 +54,16 @@
54 54 unless terms is last_terms
55 55 last_terms = terms
56 56 if terms.length >= 2 or terms.length is 0
57   - form.submit()
  57 + $.ajax
  58 + type: "GET"
  59 + url: location.href
  60 + data: "issue_search=" + terms
  61 + complete: ->
  62 + $(".loading").hide()
  63 + success: (data) ->
  64 + $('.issues-holder').html(data.html)
  65 + Issues.reload()
  66 + dataType: "json"
58 67  
59 68 checkChanged: ->
60 69 checked_issues = $(".selected_issue:checked")
... ...
app/assets/javascripts/main.js.coffee
1   -window.updatePage = (data) ->
2   - $.ajax({type: "GET", url: location.href, data: data, dataType: "script"})
3   -
4 1 window.slugify = (text) ->
5 2 text.replace(/[^-a-zA-Z0-9]+/g, '_').toLowerCase()
6 3  
... ...
app/assets/javascripts/merge_requests.js.coffee
... ... @@ -21,7 +21,7 @@ class MergeRequest
21 21 this.initMergeWidget()
22 22 this.$('.show-all-commits').on 'click', =>
23 23 this.showAllCommits()
24   -
  24 +
25 25 modal = $('#modal_merge_info').modal(show: false)
26 26  
27 27 # Local jQuery finder
... ... @@ -83,12 +83,12 @@ class MergeRequest
83 83 url: this.$('.nav-tabs .diffs-tab a').attr('href')
84 84 beforeSend: =>
85 85 this.$('.status').addClass 'loading'
86   -
87 86 complete: =>
88 87 @diffs_loaded = true
89 88 this.$('.status').removeClass 'loading'
90   -
91   - dataType: 'script'
  89 + success: (data) =>
  90 + this.$(".diffs").html(data.html)
  91 + dataType: 'json'
92 92  
93 93 showAllCommits: ->
94 94 this.$('.first-commits').remove()
... ...
app/assets/javascripts/namespace_select.js.coffee 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +$ ->
  2 + namespaceFormatResult = (namespace) ->
  3 + markup = "<div class='namespace-result'>"
  4 + markup += "<span class='namespace-kind'>" + namespace.kind + "</span>"
  5 + markup += "<span class='namespace-path'>" + namespace.path + "</span>"
  6 + markup += "</div>"
  7 + markup
  8 +
  9 + formatSelection = (namespace) ->
  10 + namespace.kind + ": " + namespace.path
  11 +
  12 + $('.ajax-namespace-select').each (i, select) ->
  13 + $(select).select2
  14 + placeholder: "Search for namespace"
  15 + multiple: $(select).hasClass('multiselect')
  16 + minimumInputLength: 0
  17 + query: (query) ->
  18 + Api.namespaces query.term, (namespaces) ->
  19 + data = { results: namespaces }
  20 + query.callback(data)
  21 +
  22 + dropdownCssClass: "ajax-namespace-dropdown"
  23 + formatResult: namespaceFormatResult
  24 + formatSelection: formatSelection
... ...
app/assets/javascripts/notes.js
... ... @@ -6,7 +6,7 @@ var NoteList = {
6 6 target_type: null,
7 7  
8 8 init: function(tid, tt, path) {
9   - NoteList.notes_path = path + ".js";
  9 + NoteList.notes_path = path + ".json";
10 10 NoteList.target_id = tid;
11 11 NoteList.target_type = tt;
12 12 NoteList.target_params = "target_type=" + NoteList.target_type + "&target_id=" + NoteList.target_id;
... ... @@ -233,10 +233,12 @@ var NoteList = {
233 233 form.show();
234 234  
235 235 var textarea = form.find("textarea");
236   - var p = $("<p></p>").text(textarea.val());
237   - var hidden_div = $('<div class="note-original-content"></div>').append(p);
238   - form.append(hidden_div);
239   - hidden_div.hide();
  236 + if (form.find(".note-original-content").length === 0) {
  237 + var p = $("<p></p>").text(textarea.val());
  238 + var hidden_div = $('<div class="note-original-content"></div>').append(p);
  239 + form.append(hidden_div);
  240 + hidden_div.hide();
  241 + }
240 242 textarea.focus();
241 243 },
242 244  
... ... @@ -409,7 +411,10 @@ var NoteList = {
409 411 data: NoteList.target_params,
410 412 complete: function(){ $('.js-notes-busy').removeClass("loading")},
411 413 beforeSend: function() { $('.js-notes-busy').addClass("loading") },
412   - dataType: "script"
  414 + success: function(data) {
  415 + NoteList.setContent(data.html);
  416 + },
  417 + dataType: "json"
413 418 });
414 419 },
415 420  
... ... @@ -417,7 +422,7 @@ var NoteList = {
417 422 * Called in response to getContent().
418 423 * Replaces the content of #notes-list with the given html.
419 424 */
420   - setContent: function(newNoteIds, html) {
  425 + setContent: function(html) {
421 426 $("#notes-list").html(html);
422 427 },
423 428  
... ... @@ -532,6 +537,8 @@ var NoteList = {
532 537 note_text.html(response.note).show();
533 538  
534 539 var note_form = note_li.find(".note-edit-form");
  540 + var original_content = note_form.find(".note-original-content");
  541 + original_content.remove();
535 542 note_form.hide();
536 543 note_form.find(".btn-save").enableButton();
537 544  
... ...
app/assets/javascripts/pager.js.coffee
... ... @@ -19,8 +19,9 @@
19 19 data: "limit=" + @limit + "&offset=" + @offset
20 20 complete: ->
21 21 $(".loading").hide()
22   -
23   - dataType: "script"
  22 + success: (data) ->
  23 + Pager.append(data.count, data.html)
  24 + dataType: "json"
24 25  
25 26 append: (count, html) ->
26 27 $(".content_list").append html
... ...
app/assets/javascripts/project.js.coffee
... ... @@ -40,3 +40,9 @@ $ -&gt;
40 40 # Ref switcher
41 41 $('.project-refs-select').on 'change', ->
42 42 $(@).parents('form').submit()
  43 +
  44 + $('.hide-no-ssh-message').on 'click', (e) ->
  45 + path = '/'
  46 + $.cookie('hide_no_ssh_message', 'false', { path: path })
  47 + $(@).parents('.no-ssh-key-message').hide()
  48 + e.preventDefault()
... ...
app/assets/stylesheets/common.scss
... ... @@ -220,7 +220,6 @@ li.note {
220 220 .error-message {
221 221 padding: 10px;
222 222 background: #C67;
223   - padding-left: 20px;
224 223 margin: 0;
225 224 color: #FFF;
226 225  
... ... @@ -228,8 +227,18 @@ li.note {
228 227 color: #fff;
229 228 text-decoration: underline;
230 229 }
231   - &.centered {
232   - text-align: center;
  230 +}
  231 +
  232 +.no-ssh-key-message {
  233 + padding: 10px 0;
  234 + background: #C67;
  235 + margin: 0;
  236 + color: #FFF;
  237 + text-align: center;
  238 +
  239 + a {
  240 + color: #fff;
  241 + text-decoration: underline;
233 242 }
234 243 }
235 244  
... ... @@ -341,4 +350,46 @@ table {
341 350 .navbar-gitlab .navbar-inner .nav > li .btn-sign-in {
342 351 @extend .btn-new;
343 352 padding: 5px 15px;
  353 + text-shadow: none;
  354 +}
  355 +
  356 +.broadcast-message {
  357 + padding: 10px;
  358 + text-align: center;
  359 + background: #555;
  360 + color: #BBB;
  361 +}
  362 +
  363 +.ajax-users-select {
  364 + width: 400px;
  365 +
  366 + &.input-large {
  367 + width: 210px;
  368 + }
  369 +
  370 + &.input-clamp {
  371 + max-width: 100%;
  372 + }
  373 +}
  374 +
  375 +.user-result {
  376 + .user-image {
  377 + float: left;
  378 + }
  379 + .user-name {
  380 + }
  381 + .user-username {
  382 + color: #999;
  383 + }
  384 +}
  385 +
  386 +.namespace-result {
  387 + .namespace-kind {
  388 + color: #AAA;
  389 + font-weight: normal;
  390 + }
  391 + .namespace-path {
  392 + margin-left: 10px;
  393 + font-weight: bolder;
  394 + }
344 395 }
... ...
app/assets/stylesheets/gitlab_bootstrap/blocks.scss
... ... @@ -34,9 +34,7 @@
34 34 &.ui-box-show {
35 35 color: #666;
36 36 margin:20px 0;
37   - background: #FFF;
38   - box-shadow: inset 0 1px 0 #fff, 0 1px 5px #f1f1f1;
39   - @include linear-gradient(#fafafa, #f1f1f1);
  37 + background: #FAFAFA;
40 38  
41 39 .control-group {
42 40 margin-bottom: 0;
... ... @@ -44,11 +42,13 @@
44 42 }
45 43  
46 44 &.ui-box-danger {
  45 + background: #f7f7f7;
  46 + border: none;
  47 +
47 48 .title {
48   - @include linear-gradient(#F26E5E, #bd362f);
  49 + background: #D65;
49 50 color: #fff;
50 51 text-shadow: 0 1px 1px #900;
51   - font-weight: bold;
52 52 }
53 53 }
54 54  
... ... @@ -98,9 +98,9 @@
98 98 }
99 99  
100 100 .title {
101   - @include bg-gray-gradient;
102   - border-bottom: 1px solid #CCC;
103   - color: #456;
  101 + background-color: #EEE;
  102 + border-bottom: 1px solid #DDD;
  103 + color: #666;
104 104 font-size: 16px;
105 105 text-shadow: 0 1px 1px #fff;
106 106 padding: 0 10px;
... ...
app/assets/stylesheets/gitlab_bootstrap/buttons.scss
1 1 .btn {
2 2 display: inline-block;
3   - padding: 6px 12px;
4 3 margin-bottom: 0;
5   - font-size: 13px;
6   - line-height: $baseLineHeight;
  4 + font-weight: normal;
7 5 text-align: center;
8 6 vertical-align: middle;
9 7 cursor: pointer;
10   - border: 1px solid #BBB;
11   - color: $style_color;
12   - @include border-radius($baseBorderRadius);
13   - @include box-shadow(inset 0 1px 0 rgba(255,255,255,.2));
14   - @include linear-gradient(#f1f1f1, #e1e1e1);
15   - text-shadow: 0 1px 1px #FFF;
16   - text-decoration: none;
  8 + background-image: none;
  9 + border: 1px solid transparent;
  10 + white-space: nowrap;
  11 + padding: 6px 12px;
  12 + font-size: 13px;
  13 + line-height: 18px;
  14 + border-radius: 4px;
  15 + -webkit-user-select: none;
  16 + -moz-user-select: none;
  17 + -ms-user-select: none;
  18 + -o-user-select: none;
  19 + user-select: none;
  20 + color: #444444;
  21 + background-color: #fff;
  22 + border-color: #ccc;
  23 + text-shadow: none;
17 24  
18 25 &.hover,
19 26 &:hover {
20   - color: $style_color;
21   - background: #f1f1f1;
22   - border-color: #AAA;
  27 + color: #444444;
23 28 text-decoration: none;
24   - @include linear-gradient(#fAfAfA, #f1f1f1);
  29 + background-color: #ebebeb;
  30 + border-color: #adadad;
25 31 }
26 32  
27 33 &.focus,
28 34 &:focus {
  35 + color: #444444;
29 36 text-decoration: none;
30   - @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
  37 + outline: thin dotted #333;
  38 + outline: 5px auto -webkit-focus-ring-color;
  39 + outline-offset: -2px;
31 40 }
32 41  
33 42 &.active,
34 43 &:active {
35   - background-image: none;
36 44 outline: 0;
37   - text-decoration: none;
38   - @include box-shadow(inset 0 2px 4px rgba(0,0,0,.15));
  45 + background-image: none;
  46 + -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
  47 + box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
39 48 }
40 49  
41 50 &.disabled,
42 51 &[disabled] {
43   - cursor: default;
44   - background-image: none;
45   - @include opacity(65);
46   - @include box-shadow(none);
  52 + cursor: not-allowed;
  53 + pointer-events: none;
  54 + opacity: 0.65;
  55 + filter: alpha(opacity=65);
  56 + -webkit-box-shadow: none;
  57 + box-shadow: none;
47 58 }
48 59  
49 60 &.btn-primary {
50   - color: #FFF;
51   - border-color: #189;
52   - text-shadow: 0 1px 1px #189;
53   - @include linear-gradient(#4AC, #289);
  61 + color: #ffffff;
  62 + background-color: #429bca;
  63 + border-color: #358ebd;
54 64  
55 65 &.hover,
56 66 &:hover,
57 67 &.disabled,
58 68 &[disabled] {
59   - color: #FFF;
60   - background: #389;
  69 + color: #ffffff;
  70 + background-color: #3286b1;
  71 + border-color: #286e8e;
61 72 }
62 73 }
63 74  
64 75 &.btn-success {
65   - color: #FFF;
66   - border-color: #1A1;
67   - text-shadow: 0 1px 1px #FFF;
68   - text-shadow: 0 1px 1px #181;
69   - @include linear-gradient(#62C452, #51a351);
  76 + color: #ffffff;
  77 + background-color: #5cb85c;
  78 + border-color: #4cae4c;
70 79  
71 80  
72 81 &.hover,
73 82 &:hover,
74 83 &.disabled,
75 84 &[disabled] {
76   - color: #FFF;
77   - background: #2A2;
  85 + color: #ffffff;
  86 + background-color: #47a447;
  87 + border-color: #398439;
78 88 }
79 89 }
80 90  
81 91 &.btn-danger {
82   - color: #FFF;
83   - text-shadow: 0 1px 1px #811;
84   - border-color: #BD362F;
85   - @include linear-gradient(#EE5F5B, #BD362F);
  92 + color: #ffffff;
  93 + background-color: #d9534f;
  94 + border-color: #d43f3a;
86 95  
87 96  
88 97 &.hover,
89 98 &:hover,
90 99 &.disabled,
91 100 &[disabled] {
92   - color: #FFF;
93   - background: #A22;
  101 + color: #ffffff;
  102 + background-color: #d2322d;
  103 + border-color: #ac2925;
94 104 }
95 105 }
96 106  
... ...
app/assets/stylesheets/gitlab_bootstrap/common.scss
1 1 /** COLORS **/
2 2 .cgray { color: gray }
  3 +.clgray { color: #BBB }
3 4 .cred { color: #D12F19 }
4 5 .cgreen { color: #4a2 }
5 6 .cblue { color: #29A }
6 7 .cblack { color: #111 }
7 8 .cdark { color: #444 }
  9 +.camber { color: #ffc000 }
8 10 .cwhite { color: #fff!important }
9 11 .bgred { background: #F2DEDE!important }
10 12  
... ... @@ -93,6 +95,12 @@ pre.well-pre {
93 95 font-size: 12px;
94 96 font-style: normal;
95 97 font-weight: normal;
  98 +
  99 + &.label-gray {
  100 + background-color: #eee;
  101 + color: #999;
  102 + text-shadow: none;
  103 + }
96 104 }
97 105  
98 106 /** Big Labels **/
... ... @@ -116,3 +124,12 @@ pre.well-pre {
116 124 color: #FFF;
117 125 }
118 126 }
  127 +
  128 +.dropdown-menu > li > a {
  129 + text-shadow: none;
  130 +}
  131 +
  132 +.dropdown-menu > li > a:hover,
  133 +.dropdown-menu > li > a:focus {
  134 + background: #29b;
  135 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/files.scss
... ... @@ -11,8 +11,8 @@
11 11 }
12 12  
13 13 .file-title {
14   - border-bottom: 1px solid #bbb;
15   - @include bg-dark-gray-gradient;
  14 + background: #DDD;
  15 + border-bottom: 1px solid #CCC;
16 16 text-shadow: 0 1px 1px #fff;
17 17 margin: 0;
18 18 font-weight: normal;
... ...
app/assets/stylesheets/gitlab_bootstrap/forms.scss
... ... @@ -3,6 +3,23 @@ form {
3 3  
4 4 label {
5 5 @extend .control-label;
  6 +
  7 + &.radio-label {
  8 + text-align: left;
  9 + width: 100%;
  10 + margin-left: 0;
  11 +
  12 + input[type="radio"] {
  13 + margin-top: 1px !important;
  14 + }
  15 + }
  16 +
  17 + &.list-label {
  18 + float: none;
  19 + padding: 0 !important;
  20 + margin: 0;
  21 + text-align: left;
  22 + }
6 23 }
7 24 }
8 25  
... ... @@ -49,3 +66,9 @@ fieldset legend {
49 66 font-size: 16px;
50 67 margin-bottom: 10px;
51 68 }
  69 +
  70 +.datetime-controls {
  71 + select {
  72 + width: 100px;
  73 + }
  74 +}
... ...
app/assets/stylesheets/gitlab_bootstrap/mixins.scss
... ... @@ -89,10 +89,26 @@
89 89 }
90 90  
91 91 code { padding: 0 4px; }
92   - h1 { margin-top: 30px;}
93   - h2 { margin-top: 25px;}
94   - h3 { margin-top: 20px;}
95   - h4 { margin-top: 15px;}
  92 +
  93 + h1 {
  94 + margin-top: 45px;
  95 + font-size: 2.5em;
  96 + }
  97 +
  98 + h2 {
  99 + margin-top: 40px;
  100 + font-size: 2em;
  101 + }
  102 +
  103 + h3 {
  104 + margin-top: 35px;
  105 + font-size: 2em;
  106 + }
  107 +
  108 + h4 {
  109 + margin-top: 30px;
  110 + font-size: 1.5em;
  111 + }
96 112  
97 113 blockquote p {
98 114 color: #888;
... ... @@ -107,6 +123,16 @@
107 123 background: #EEE;
108 124 }
109 125 }
  126 +
  127 + code {
  128 + font-size: inherit;
  129 + font-weight: inherit;
  130 + color: #555;
  131 + }
  132 +
  133 + li {
  134 + line-height: 1.5;
  135 + }
110 136 }
111 137  
112 138 @mixin page-title {
... ...
app/assets/stylesheets/gitlab_bootstrap/nav.scss
... ... @@ -15,18 +15,16 @@
15 15 > li > a {
16 16 border-left: 4px solid #EEE;
17 17 padding: 12px;
  18 + color: #777;
18 19 }
19 20 > .active > a {
20 21 border-color: $primary_color;
21   - border-radius: 0;
22   - background: #F1F1F1;
23   - color: $style_color;
24   - font-weight: bold;
25   - text-shadow: 0 1px 1px #fff;
  22 + background: none;
  23 + color: #333;
  24 + font-weight: bolder;
26 25 }
27 26  
28 27 &.nav-stacked-menu {
29   - background: #FAFAFA;
30 28 li > a {
31 29 padding: 16px;
32 30 }
... ... @@ -36,6 +34,7 @@
36 34 &.nav-pills-small {
37 35 > li > a {
38 36 padding: 8px 12px;
  37 + font-size: 12px;
39 38 }
40 39 }
41 40 }
... ...
app/assets/stylesheets/sections/admin.scss
... ... @@ -20,4 +20,19 @@
20 20 label { width: 110px; }
21 21 .controls { margin-left: 130px; }
22 22 .form-actions { padding-left: 130px; background: #fff }
  23 + .visibility-levels {
  24 + .controls {
  25 + margin-bottom: 9px;
  26 + }
  27 +
  28 + i {
  29 + color: inherit;
  30 + }
  31 + }
  32 +}
  33 +
  34 +.broadcast-messages {
  35 + .message {
  36 + line-height: 2;
  37 + }
23 38 }
... ...
app/assets/stylesheets/sections/commits.scss
... ... @@ -16,37 +16,29 @@
16 16  
17 17 .header {
18 18 @extend .clearfix;
  19 + background: #DDD;
  20 + border-bottom: 1px solid #CCC;
19 21 padding: 5px 5px 5px 10px;
20 22 color: #555;
21   - border-bottom: 1px solid #CCC;
22   - background: #eee;
23   - // TODO Replace with linear-gradient mixin
24   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
25   - background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
26   - background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
27   - background-image: -ms-linear-gradient(#eee 6.6%, #dfdfdf);
28   - background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
29   -
30   - a{
31   - color: $style_color;
32   - }
33 23  
34 24 > span {
35 25 font-family: $monospace_font;
36 26 font-size: 14px;
37   - line-height: 30px;
  27 + line-height: 2;
38 28 }
39 29  
40   - a.view-file{
  30 + .view-file {
41 31 font-weight: bold;
  32 + float: right;
  33 + background-color: #EEE;
42 34 }
43 35  
44   - .commit-short-id{
  36 + .commit-short-id {
45 37 font-family: $monospace_font;
46 38 font-size: smaller;
47 39 }
48 40  
49   - .file-mode{
  41 + .file-mode {
50 42 font-family: $monospace_font;
51 43 }
52 44 }
... ... @@ -56,13 +48,13 @@
56 48 background: #FFF;
57 49 color: #333;
58 50 font-size: 12px;
59   - .old{
60   - span.idiff{
  51 + .old {
  52 + span.idiff {
61 53 background-color: #FAA;
62 54 }
63 55 }
64   - .new{
65   - span.idiff{
  56 + .new {
  57 + span.idiff {
66 58 background-color: #AFA;
67 59 }
68 60 }
... ... @@ -78,7 +70,7 @@
78 70 font-size: 12px;
79 71 }
80 72 }
81   - .old_line, .new_line {
  73 + .old_line, .new_line, .diff_line {
82 74 margin: 0px;
83 75 padding: 0px;
84 76 border: none;
... ... @@ -100,6 +92,15 @@
100 92 text-decoration: underline;
101 93 }
102 94 }
  95 + &.new {
  96 + background: #CFD;
  97 + }
  98 + &.old {
  99 + background: #FDD;
  100 + }
  101 + }
  102 + .diff_line {
  103 + padding: 0;
103 104 }
104 105 .line_holder {
105 106 &.old .old_line,
... ... @@ -130,6 +131,11 @@
130 131 color: #ccc;
131 132 background: #fafafa;
132 133 }
  134 + &.parallel {
  135 + display: table-cell;
  136 + overflow: hidden;
  137 + width: 50%;
  138 + }
133 139 }
134 140 }
135 141 .image {
... ...
app/assets/stylesheets/sections/dashboard.scss
... ... @@ -51,7 +51,7 @@
51 51 li {
52 52 &.active {
53 53 a {
54   - @include linear-gradient(#f5f5f5, #eee);
  54 + background-color: #EEE;
55 55 border-bottom: 1px solid #EEE !important;
56 56 &:hover {
57 57 background: #eee;
... ... @@ -100,3 +100,21 @@
100 100 padding: 2px 5px;
101 101 }
102 102 }
  103 +
  104 +.project-access-icon {
  105 + margin-left: 10px;
  106 + float: left;
  107 + margin-right: 15px;
  108 + font-size: 20px;
  109 + margin-bottom: 15px;
  110 + border: 1px solid #EEE;
  111 + padding: 8px 12px;
  112 + border-radius: 50px;
  113 + background: #f5f5f5;
  114 + width: 16px;
  115 + text-align: center;
  116 +
  117 + i {
  118 + color: #BBB;
  119 + }
  120 +}
... ...
app/assets/stylesheets/sections/header.scss
... ... @@ -36,8 +36,8 @@ header {
36 36 float: left;
37 37 margin-right: 9px;
38 38 position: relative;
39   - top: -5px;
40   - padding-top: 5px;
  39 + top: -3px;
  40 + padding-top: 3px;
41 41  
42 42 a {
43 43 float: left;
... ... @@ -46,8 +46,8 @@ header {
46 46  
47 47 h1 {
48 48 margin: 0;
49   - background: url('logo-black.png') no-repeat center 1px;
50   - background-size: 38px;
  49 + background: url('logo-black.png') no-repeat center center;
  50 + background-size: 32px;
51 51 float: left;
52 52 height: 40px;
53 53 width: 40px;
... ... @@ -152,8 +152,8 @@ header {
152 152 .app_logo {
153 153 a {
154 154 h1 {
155   - background: url('logo-white.png') no-repeat center 1px;
156   - background-size: 38px;
  155 + background: url('logo-white.png') no-repeat center center;
  156 + background-size: 32px;
157 157 color: #fff;
158 158 text-shadow: 0 1px 1px #444;
159 159 }
... ...
app/assets/stylesheets/sections/issues.scss
... ... @@ -77,8 +77,8 @@ input.check_all_issues {
77 77 @media (min-width: 800px) { .issues_filters select { width: 160px; } }
78 78 @media (min-width: 1200px) { .issues_filters select { width: 220px; } }
79 79  
80   -@media (min-width: 800px) { .issues_bulk_update select { width: 120px; } }
81   -@media (min-width: 1200px) { .issues_bulk_update select { width: 160px; } }
  80 +@media (min-width: 800px) { .issues_bulk_update .chosen-container { min-width: 120px; } }
  81 +@media (min-width: 1200px) { .issues_bulk_update .chosen-container { min-width: 160px; } }
82 82  
83 83 .issues-holder {
84 84 .issues_filters {
... ... @@ -103,3 +103,19 @@ input.check_all_issues {
103 103 .participants {
104 104 margin-bottom: 10px;
105 105 }
  106 +
  107 +.issues_bulk_update {
  108 + .chosen-container {
  109 + text-shadow: none;
  110 + }
  111 +}
  112 +
  113 +.issue-search-form {
  114 + margin: 0;
  115 + height: 24px;
  116 +
  117 + .issue_search {
  118 + border: 1px solid #DDD !important;
  119 + background-color: #f4f4f4;
  120 + }
  121 +}
... ...
app/assets/stylesheets/sections/merge_requests.scss
... ... @@ -110,9 +110,29 @@
110 110  
111 111 .merge-request-angle {
112 112 text-align: center;
113   - margin: 0;
  113 + margin: 0 auto;
  114 + background: #eee;
  115 + border-radius: 100px;
  116 + width: 60px;
  117 + line-height: 60px;
  118 + color: #777;
  119 + text-shadow: 0 1px 2px #FFF;
114 120 }
115 121  
116 122 .merge-request-form-info {
117   - padding: 15px 0;
  123 + padding-top: 15px;
  124 +}
  125 +
  126 +.merge-request-branches {
  127 + .commit-row-message {
  128 + font-weight: normal !important;
  129 + }
  130 +
  131 + .chosen-container .chosen-single {
  132 + padding: 2px 0 2px 10px;
  133 + span {
  134 + font-weight: bold;
  135 + color: #555;
  136 + }
  137 + }
118 138 }
... ...
app/assets/stylesheets/sections/notes.scss
... ... @@ -130,6 +130,12 @@ ul.notes {
130 130 &.notes_line {
131 131 text-align: center;
132 132 padding: 10px 0;
  133 + background: #eee;
  134 + }
  135 + &.notes_line2 {
  136 + text-align: center;
  137 + padding: 10px 0;
  138 + border-left: 1px solid #ddd !important;
133 139 }
134 140 &.notes_content {
135 141 background-color: $white;
... ... @@ -270,10 +276,9 @@ ul.notes {
270 276  
271 277 // preview/edit buttons
272 278 > a {
273   - font-size: 24px;
274   - padding: 4px;
275 279 position: absolute;
276   - right: 10px;
  280 + right: 5px;
  281 + bottom: -60px;
277 282 }
278 283 .note_preview {
279 284 background: #f5f5f5;
... ... @@ -306,10 +311,8 @@ ul.notes {
306 311  
307 312 .common-note-form {
308 313 margin: 0;
309   - height: 140px;
310 314 background: #F9F9F9;
311 315 padding: 3px;
312   - padding-bottom: 25px;
313 316 border: 1px solid #DDD;
314 317 }
315 318  
... ... @@ -320,7 +323,7 @@ ul.notes {
320 323 padding: 0 5px;
321 324  
322 325 .note-form-option {
323   - margin-top: 10px;
  326 + margin-top: 8px;
324 327 margin-left: 30px;
325 328 @extend .pull-left;
326 329 }
... ... @@ -358,3 +361,7 @@ ul.notes {
358 361 .js-note-attachment-delete {
359 362 display: none;
360 363 }
  364 +
  365 +.parallel-comment {
  366 + padding: 6px;
  367 +}
... ...
app/assets/stylesheets/sections/profile.scss
... ... @@ -42,3 +42,8 @@
42 42 margin-right: 12px;
43 43 }
44 44  
  45 +.profile-avatar-form-option {
  46 + hr {
  47 + margin: 10px 0;
  48 + }
  49 +}
... ...
app/assets/stylesheets/sections/projects.scss
... ... @@ -16,9 +16,15 @@
16 16  
17 17 .project-home-panel {
18 18 border-bottom: 1px solid #DDD;
19   - padding-bottom: 30px;
  19 + padding-bottom: 25px;
20 20 margin-bottom: 30px;
21 21  
  22 + &.empty-project {
  23 + border-bottom: 0px;
  24 + padding-bottom: 15px;
  25 + margin-bottom: 0px;
  26 + }
  27 +
22 28 .project-home-title {
23 29 font-size: 18px;
24 30 color: #777;
... ... @@ -45,7 +51,7 @@
45 51 }
46 52 }
47 53  
48   - .public-label {
  54 + .visibility-level-label {
49 55 font-size: 14px;
50 56 background: #f1f1f1;
51 57 padding: 8px 10px;
... ... @@ -53,6 +59,10 @@
53 59 margin-left: 10px;
54 60 color: #888;
55 61 text-shadow: 0 1px 1px #FFF;
  62 +
  63 + i {
  64 + color: inherit;
  65 + }
56 66 }
57 67 }
58 68  
... ... @@ -87,9 +97,40 @@
87 97 }
88 98 }
89 99  
90   -.project-public-holder {
91   - .help-inline {
92   - padding-top: 7px;
  100 +.project-visibility-level-holder {
  101 + .controls {
  102 + padding-bottom: 9px;
  103 + }
  104 +
  105 + .controls {
  106 + input {
  107 + float: left;
  108 + }
  109 + .descr {
  110 + display: block;
  111 + margin-left: 1.5em;
  112 + &.restricted {
  113 + color: #888;
  114 + }
  115 +
  116 + label {
  117 + float: none;
  118 + padding: 0;
  119 + margin: 0;
  120 + text-align: left;
  121 + }
  122 + }
  123 + .info {
  124 + display: block;
  125 + margin-top: 5px;
  126 + }
  127 + strong {
  128 + display: inline-block;
  129 + width: 4em;
  130 + }
  131 + }
  132 + i {
  133 + color: inherit;
93 134 }
94 135 }
95 136  
... ... @@ -130,7 +171,8 @@ ul.nav.nav-projects-tabs {
130 171 margin: 0px;
131 172 }
132 173  
133   -.my-projects {
  174 +.my-projects,
  175 +.public-projects {
134 176 li {
135 177 .project-info {
136 178 margin-bottom: 10px;
... ... @@ -166,3 +208,61 @@ ul.nav.nav-projects-tabs {
166 208 color: #777;
167 209 }
168 210 }
  211 +
  212 +.project-side {
  213 + .btn-block {
  214 + background-image: none;
  215 + background-color: #F1f1f1;
  216 + border-color: #EEE;
  217 + &:hover {
  218 + background-color: #eee;
  219 + border-color: #DDD;
  220 + }
  221 + }
  222 + .project-fork-icon {
  223 + float: left;
  224 + font-size: 26px;
  225 + margin-right: 10px;
  226 + line-height: 1.5;
  227 + }
  228 +}
  229 +
  230 +.transfer-project .chosen-container {
  231 + min-width: 200px;
  232 +}
  233 +
  234 +/** Branch/tag selector **/
  235 +.project-refs-form {
  236 + margin: 0;
  237 + span {
  238 + background:none !important;
  239 + position:static !important;
  240 + width:auto !important;
  241 + height:auto !important;
  242 + }
  243 +}
  244 +.project-refs-select {
  245 + width: 120px;
  246 +}
  247 +
  248 +.project-refs-form .chosen-container {
  249 + position: relative;
  250 + top: 0;
  251 + left: 0;
  252 + margin-right: 10px;
  253 +
  254 + .chosen-single span {
  255 + font-weight: bold;
  256 + color: #555;
  257 + }
  258 +
  259 + &.chosen-container-active {
  260 + .chosen-drop {
  261 + min-width: 400px;
  262 + }
  263 +
  264 + .chosen-results {
  265 + max-height: 400px;
  266 + }
  267 + }
  268 +}
... ...
app/assets/stylesheets/selects.scss
1   -/* CHZN reset few styles */
2   -.chosen-container-single .chosen-single {
3   - background: #FFF;
4   - border: 1px solid #bbb;
5   - box-shadow: none;
6   -}
7   -.chosen-container-active .chosen-single {
8   - background: #fff;
9   -}
10   -
11   -.ajax-users-select {
12   - width: 400px;
13   -
14   - &.input-large {
15   - width: 210px;
16   - }
17   -}
18   -
19   -.user-result {
20   - .user-image {
21   - float: left;
22   - }
23   - .user-name {
24   - }
25   - .user-username {
26   - color: #999;
27   - }
28   -}
29   -
30   -/** Branch/tag selector **/
31   -.project-refs-form {
32   - margin: 0;
33   - span {
34   - background:none !important;
35   - position:static !important;
36   - width:auto !important;
37   - height:auto !important;
38   - }
39   -}
40   -.project-refs-select {
41   - width: 120px;
42   -}
43   -
44   -.project-refs-form .chosen-container {
45   - position: relative;
46   - top: 0;
47   - left: 0;
48   - margin-right: 10px;
49   -
50   - .chosen-drop {
51   - min-width: 400px;
52   - .chosen-results {
53   - max-height: 300px;
54   - }
55   - .chosen-search input {
56   - min-width: 365px;
57   - }
58   - }
59   -}
60   -
61   -/** Fix for Search Dropdown Border **/
  1 +/** Chosen.js selectbox style override **/
62 2 .chosen-container {
63 3 min-width: 100px;
64 4  
65   - .chosen-search {
66   - input:focus {
67   - @include box-shadow(none);
68   - }
  5 + .chosen-single {
  6 + background: #EEE !important;
  7 + border: 1px solid #DDD !important;
  8 + @include box-shadow(none !important);
  9 + @include border-radius(4px !important);
69 10 }
70 11  
71   - .chosen-drop {
72   - margin: 7px 0;
73   - min-width: 200px;
74   - border: 1px solid #bbb;
75   - @include border-radius(0);
76   -
77   - .chosen-results {
78   - margin-top: 5px;
79   - max-height: 300px;
80   -
81   - .group-result {
82   - color: $style_color;
83   - border-bottom: 1px solid #EEE;
84   - padding: 8px;
85   - }
86   - .active-result {
87   - @include border-radius(0);
88   -
89   - &.highlighted {
90   - background: $hover;
91   - color: $style_color;
92   - }
93   - &.result-selected {
94   - background: #EEE;
95   - border-left: 4px solid #CCC;
96   - }
97   - }
98   - }
99   -
100   - .chosen-search {
101   - @include bg-gray-gradient;
102   - input {
103   - min-width: 165px;
104   - border-color: #CCC;
105   - }
106   - }
  12 + .chosen-results li.highlighted {
  13 + background: #29b;
107 14 }
108   -}
109 15  
110   -.chosen-container .chosen-single,
111   -.chosen-container.chosen-with-drop .chosen-single {
112   - @include bg-light-gray-gradient;
113   -
114   - div {
115   - background: transparent;
116   - border-left: none;
  16 + .chosen-drop {
  17 + margin-top: 10px;
  18 + border: 1px solid #DDD !important;
  19 + @include border-radius(4px !important);
117 20 }
118 21  
119   - span {
120   - font-weight: normal;
  22 + .chosen-search input {
  23 + border: 1px solid #CCC !important;
  24 + @include box-shadow(none !important);
121 25 }
122 26 }
123 27  
124 28 /** Select2 styling **/
125 29 .select2-container .select2-choice {
126   - background: #f1f1f1;
127   - background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, whitesmoke), to(#e1e1e1));
128   - background-image: -webkit-linear-gradient(whitesmoke 6.6%, #e1e1e1);
129   - background-image: -moz-linear-gradient(whitesmoke 6.6%, #e1e1e1);
130   - background-image: -ms-linear-gradient(whitesmoke 6.6%, #e1e1e1);
131   - background-image: -o-linear-gradient(whitesmoke 6.6%, #e1e1e1);
  30 + @include bg-light-gray-gradient;
132 31 }
133 32  
134 33 .select2-container .select2-choice div {
... ...
app/assets/stylesheets/themes/ui_color.scss
... ... @@ -27,6 +27,12 @@
27 27 background: #435;
28 28 border-left: 1px solid #658;
29 29 }
  30 + .nav > li > a {
  31 + color: #98B;
  32 + }
  33 + .search-input {
  34 + border-color: #98B;
  35 + }
30 36 }
31 37 }
32 38 }
... ...
app/assets/stylesheets/themes/ui_mars.scss
... ... @@ -23,12 +23,17 @@
23 23 background-color: #373D47;
24 24 }
25 25 }
  26 + .separator {
  27 + background: #373D47;
  28 + border-left: 1px solid #575D67;
  29 + }
  30 + .nav > li > a {
  31 + color: #979DA7;
  32 + }
  33 + .search-input {
  34 + border-color: #979DA7;
  35 + }
26 36 }
27 37 }
28   -
29   - .separator {
30   - background: #31363E;
31   - border-left: 1px solid #666;
32   - }
33 38 }
34 39 }
... ...
app/assets/stylesheets/themes/ui_modern.scss
... ... @@ -27,6 +27,12 @@
27 27 background: #234;
28 28 border-left: 1px solid #456;
29 29 }
  30 + .nav > li > a {
  31 + color: #89A;
  32 + }
  33 + .search-input {
  34 + border-color: #89A;
  35 + }
30 36 }
31 37 }
32 38 }
... ...
app/contexts/files/create_context.rb
... ... @@ -15,29 +15,23 @@ module Files
15 15 return error("You can only create files if you are on top of a branch")
16 16 end
17 17  
18   - file_name = params[:file_name]
  18 + file_name = File.basename(path)
  19 + file_path = path
19 20  
20 21 unless file_name =~ Gitlab::Regex.path_regex
21 22 return error("Your changes could not be commited, because file name contains not allowed characters")
22 23 end
23 24  
24   - file_path = if path.blank?
25   - file_name
26   - else
27   - File.join(path, file_name)
28   - end
29   -
30 25 blob = repository.blob_at(ref, file_path)
31 26  
32 27 if blob
33 28 return error("Your changes could not be commited, because file with such name exists")
34 29 end
35 30  
36   - new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, path)
  31 + new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
37 32 created_successfully = new_file_action.commit!(
38 33 params[:content],
39   - params[:commit_message],
40   - file_name,
  34 + params[:commit_message]
41 35 )
42 36  
43 37 if created_successfully
... ...
app/contexts/files/delete_context.rb 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +module Files
  2 + class DeleteContext < BaseContext
  3 + def execute
  4 + allowed = if project.protected_branch?(ref)
  5 + can?(current_user, :push_code_to_protected_branches, project)
  6 + else
  7 + can?(current_user, :push_code, project)
  8 + end
  9 +
  10 + unless allowed
  11 + return error("You are not allowed to push into this branch")
  12 + end
  13 +
  14 + unless repository.branch_names.include?(ref)
  15 + return error("You can only create files if you are on top of a branch")
  16 + end
  17 +
  18 + blob = repository.blob_at(ref, path)
  19 +
  20 + unless blob
  21 + return error("You can only edit text files")
  22 + end
  23 +
  24 + delete_file_action = Gitlab::Satellite::DeleteFileAction.new(current_user, project, ref, path)
  25 +
  26 + deleted_successfully = delete_file_action.commit!(
  27 + nil,
  28 + params[:commit_message]
  29 + )
  30 +
  31 + if deleted_successfully
  32 + success
  33 + else
  34 + error("Your changes could not be commited, because the file has been changed")
  35 + end
  36 + end
  37 + end
  38 +end
... ...
app/contexts/files/update_context.rb
... ... @@ -24,8 +24,7 @@ module Files
24 24 new_file_action = Gitlab::Satellite::EditFileAction.new(current_user, project, ref, path)
25 25 created_successfully = new_file_action.commit!(
26 26 params[:content],
27   - params[:commit_message],
28   - params[:last_commit]
  27 + params[:commit_message]
29 28 )
30 29  
31 30 if created_successfully
... ...
app/contexts/issues/list_context.rb
... ... @@ -29,8 +29,26 @@ module Issues
29 29 if params[:milestone_id].present?
30 30 @issues = @issues.where(milestone_id: (params[:milestone_id] == '0' ? nil : params[:milestone_id]))
31 31 end
  32 +
  33 + # Sort by :sort param
  34 + @issues = sort(@issues, params[:sort])
32 35  
33 36 @issues
34 37 end
  38 +
  39 + private
  40 +
  41 + def sort(issues, condition)
  42 + case condition
  43 + when 'newest' then issues.except(:order).order('created_at DESC')
  44 + when 'oldest' then issues.except(:order).order('created_at ASC')
  45 + when 'recently_updated' then issues.except(:order).order('updated_at DESC')
  46 + when 'last_updated' then issues.except(:order).order('updated_at ASC')
  47 + when 'milestone_due_soon' then issues.except(:order).joins(:milestone).order("milestones.due_date ASC")
  48 + when 'milestone_due_later' then issues.except(:order).joins(:milestone).order("milestones.due_date DESC")
  49 + else issues
  50 + end
  51 + end
  52 +
35 53 end
36 54 end
... ...
app/contexts/projects/create_context.rb
... ... @@ -8,6 +8,11 @@ module Projects
8 8 # get namespace id
9 9 namespace_id = params.delete(:namespace_id)
10 10  
  11 + # check that user is allowed to set specified visibility_level
  12 + unless Gitlab::VisibilityLevel.allowed_for?(current_user, params[:visibility_level])
  13 + params.delete(:visibility_level)
  14 + end
  15 +
11 16 # Load default feature settings
12 17 default_features = Gitlab.config.gitlab.default_projects_features
13 18  
... ... @@ -17,7 +22,7 @@ module Projects
17 22 wall_enabled: default_features.wall,
18 23 snippets_enabled: default_features.snippets,
19 24 merge_requests_enabled: default_features.merge_requests,
20   - public: default_features.public
  25 + visibility_level: default_features.visibility_level
21 26 }.stringify_keys
22 27  
23 28 @project = Project.new(default_opts.merge(params))
... ... @@ -47,8 +52,6 @@ module Projects
47 52 @project.creator = current_user
48 53  
49 54 if @project.save
50   - @project.discover_default_branch
51   -
52 55 unless @project.group
53 56 @project.users_projects.create(
54 57 project_access: UsersProject::MASTER,
... ...
app/contexts/projects/update_context.rb
... ... @@ -2,7 +2,23 @@ module Projects
2 2 class UpdateContext < BaseContext
3 3 def execute(role = :default)
4 4 params[:project].delete(:namespace_id)
5   - params[:project].delete(:public) unless can?(current_user, :change_public_mode, project)
  5 + # check that user is allowed to set specified visibility_level
  6 + unless can?(current_user, :change_visibility_level, project) && Gitlab::VisibilityLevel.allowed_for?(current_user, params[:project][:visibility_level])
  7 + params[:project].delete(:visibility_level)
  8 + end
  9 +
  10 + new_branch = params[:project].delete(:default_branch)
  11 +
  12 + if project.repository.exists? && new_branch != project.default_branch
  13 + GitlabShellWorker.perform_async(
  14 + :update_repository_head,
  15 + project.path_with_namespace,
  16 + new_branch
  17 + )
  18 +
  19 + project.reload_default_branch
  20 + end
  21 +
6 22 project.update_attributes(params[:project], as: role)
7 23 end
8 24 end
... ...
app/contexts/search_context.rb
1 1 class SearchContext
2   - attr_accessor :project_ids, :params
  2 + attr_accessor :project_ids, :current_user, :params
3 3  
4   - def initialize(project_ids, params)
5   - @project_ids, @params = project_ids, params.dup
  4 + def initialize(project_ids, user, params)
  5 + @project_ids, @current_user, @params = project_ids, user, params.dup
6 6 end
7 7  
8 8 def execute
... ... @@ -10,7 +10,8 @@ class SearchContext
10 10 query = Shellwords.shellescape(query) if query.present?
11 11  
12 12 return result unless query.present?
13   - result[:projects] = Project.where("projects.id in (?) OR projects.public = true", project_ids).search(query).limit(20)
  13 + visibility_levels = @current_user ? [ Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PUBLIC ] : [ Gitlab::VisibilityLevel::PUBLIC ]
  14 + result[:projects] = Project.where("projects.id in (?) OR projects.visibility_level in (?)", project_ids, visibility_levels).search(query).limit(20)
14 15  
15 16 # Search inside single project
16 17 single_project_search(Project.where(id: project_ids), query)
... ...
app/controllers/admin/broadcast_messages_controller.rb 0 → 100644
... ... @@ -0,0 +1,32 @@
  1 +class Admin::BroadcastMessagesController < Admin::ApplicationController
  2 + before_filter :broadcast_messages
  3 +
  4 + def index
  5 + @broadcast_message = BroadcastMessage.new
  6 + end
  7 +
  8 + def create
  9 + @broadcast_message = BroadcastMessage.new(params[:broadcast_message])
  10 +
  11 + if @broadcast_message.save
  12 + redirect_to admin_broadcast_messages_path, notice: 'Broadcast Message was successfully created.'
  13 + else
  14 + render :index
  15 + end
  16 + end
  17 +
  18 + def destroy
  19 + BroadcastMessage.find(params[:id]).destroy
  20 +
  21 + respond_to do |format|
  22 + format.html { redirect_to :back }
  23 + format.js { render nothing: true }
  24 + end
  25 + end
  26 +
  27 + protected
  28 +
  29 + def broadcast_messages
  30 + @broadcast_messages ||= BroadcastMessage.order("starts_at DESC").page(params[:page])
  31 + end
  32 +end
... ...
app/controllers/admin/dashboard_controller.rb
... ... @@ -2,5 +2,6 @@ class Admin::DashboardController &lt; Admin::ApplicationController
2 2 def index
3 3 @projects = Project.order("created_at DESC").limit(10)
4 4 @users = User.order("created_at DESC").limit(10)
  5 + @groups = Group.order("created_at DESC").limit(10)
5 6 end
6 7 end
... ...
app/controllers/admin/projects_controller.rb
1 1 class Admin::ProjectsController < Admin::ApplicationController
2   - before_filter :project, only: [:edit, :show, :update, :destroy, :team_update]
  2 + before_filter :project, only: [:show, :transfer]
  3 + before_filter :group, only: [:show, :transfer]
  4 + before_filter :repository, only: [:show, :transfer]
3 5  
4 6 def index
5 7 owner_id = params[:owner_id]
6 8 user = User.find_by_id(owner_id)
7 9  
8 10 @projects = user ? user.owned_projects : Project.scoped
9   - @projects = @projects.where(public: true) if params[:public_only].present?
  11 + @projects = @projects.where("visibility_level IN (?)", params[:visibility_levels]) if params[:visibility_levels].present?
10 12 @projects = @projects.with_push if params[:with_push].present?
11 13 @projects = @projects.abandoned if params[:abandoned].present?
12 14 @projects = @projects.search(params[:name]) if params[:name].present?
... ... @@ -14,8 +16,16 @@ class Admin::ProjectsController &lt; Admin::ApplicationController
14 16 end
15 17  
16 18 def show
17   - @repository = @project.repository
18   - @group = @project.group
  19 + end
  20 +
  21 + def transfer
  22 + result = ::Projects::TransferContext.new(@project, current_user, project: params).execute(:admin)
  23 +
  24 + if result
  25 + redirect_to [:admin, @project]
  26 + else
  27 + render :show
  28 + end
19 29 end
20 30  
21 31 protected
... ... @@ -26,4 +36,12 @@ class Admin::ProjectsController &lt; Admin::ApplicationController
26 36 @project = Project.find_with_namespace(id)
27 37 @project || render_404
28 38 end
  39 +
  40 + def group
  41 + @group ||= project.group
  42 + end
  43 +
  44 + def repository
  45 + @repository ||= project.repository
  46 + end
29 47 end
... ...
app/controllers/application_controller.rb
... ... @@ -81,6 +81,9 @@ class ApplicationController &lt; ActionController::Base
81 81  
82 82 if @project and can?(current_user, :read_project, @project)
83 83 @project
  84 + elsif current_user.nil?
  85 + @project = nil
  86 + authenticate_user!
84 87 else
85 88 @project = nil
86 89 render_404 and return
... ... @@ -102,7 +105,7 @@ class ApplicationController &lt; ActionController::Base
102 105 end
103 106  
104 107 def authorize_code_access!
105   - return access_denied! unless can?(current_user, :download_code, project) or project.public?
  108 + return access_denied! unless can?(current_user, :download_code, project)
106 109 end
107 110  
108 111 def authorize_push!
... ... @@ -174,4 +177,26 @@ class ApplicationController &lt; ActionController::Base
174 177 filters = cookies['event_filter'].split(',') if cookies['event_filter'].present?
175 178 @event_filter ||= EventFilter.new(filters)
176 179 end
  180 +
  181 + # JSON for infinite scroll via Pager object
  182 + def pager_json(partial, count)
  183 + html = render_to_string(
  184 + partial,
  185 + layout: false,
  186 + formats: [:html]
  187 + )
  188 +
  189 + render json: {
  190 + html: html,
  191 + count: count
  192 + }
  193 + end
  194 +
  195 + def view_to_html_string(partial)
  196 + render_to_string(
  197 + partial,
  198 + layout: false,
  199 + formats: [:html]
  200 + )
  201 + end
177 202 end
... ...
app/controllers/dashboard_controller.rb
... ... @@ -22,7 +22,7 @@ class DashboardController &lt; ApplicationController
22 22  
23 23 respond_to do |format|
24 24 format.html
25   - format.js
  25 + format.json { pager_json("events/_events", @events.count) }
26 26 format.atom { render layout: false }
27 27 end
28 28 end
... ... @@ -40,6 +40,7 @@ class DashboardController &lt; ApplicationController
40 40 end
41 41  
42 42 @projects = @projects.where(namespace_id: Group.find_by_name(params[:group])) if params[:group].present?
  43 + @projects = @projects.where(visibility_level: params[:visibility_level]) if params[:visibility_level].present?
43 44 @projects = @projects.includes(:namespace).sorted_by_activity
44 45  
45 46 @labels = current_user.authorized_projects.tags_on(:labels)
... ...
app/controllers/groups_controller.rb
... ... @@ -38,7 +38,7 @@ class GroupsController &lt; ApplicationController
38 38  
39 39 respond_to do |format|
40 40 format.html
41   - format.js
  41 + format.json { pager_json("events/_events", @events.count) }
42 42 format.atom { render layout: false }
43 43 end
44 44 end
... ...
app/controllers/profiles/avatars_controller.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class Profiles::AvatarsController < ApplicationController
  2 + layout "profile"
  3 +
  4 + def destroy
  5 + @user = current_user
  6 + @user.remove_avatar!
  7 +
  8 + @user.save
  9 + redirect_to profile_path
  10 + end
  11 +end
... ...
app/controllers/profiles_controller.rb
... ... @@ -13,6 +13,8 @@ class ProfilesController &lt; ApplicationController
13 13 end
14 14  
15 15 def update
  16 + params[:user].delete(:email) if @user.ldap_user?
  17 +
16 18 if @user.update_attributes(params[:user])
17 19 flash[:notice] = "Profile was successfully updated"
18 20 else
... ...
app/controllers/projects/application_controller.rb
... ... @@ -10,7 +10,7 @@ class Projects::ApplicationController &lt; ApplicationController
10 10 id = params[:project_id] || params[:id]
11 11 @project = Project.find_with_namespace(id)
12 12  
13   - return if @project && @project.public
  13 + return if @project && @project.public?
14 14 end
15 15  
16 16 super
... ...
app/controllers/projects/blob_controller.rb
... ... @@ -7,9 +7,30 @@ class Projects::BlobController &lt; Projects::ApplicationController
7 7 before_filter :authorize_code_access!
8 8 before_filter :require_non_empty_project
9 9  
  10 + before_filter :blob
  11 +
10 12 def show
11   - @blob = @repository.blob_at(@commit.id, @path)
  13 + end
  14 +
  15 + def destroy
  16 + result = Files::DeleteContext.new(@project, current_user, params, @ref, @path).execute
  17 +
  18 + if result[:status] == :success
  19 + flash[:notice] = "Your changes have been successfully commited"
  20 + redirect_to project_tree_path(@project, @ref)
  21 + else
  22 + flash[:alert] = result[:error]
  23 + render :show
  24 + end
  25 + end
  26 +
  27 + private
  28 +
  29 + def blob
  30 + @blob ||= @repository.blob_at(@commit.id, @path)
  31 +
  32 + return not_found! unless @blob
12 33  
13   - not_found! unless @blob
  34 + @blob
14 35 end
15 36 end
... ...
app/controllers/projects/commits_controller.rb
... ... @@ -16,7 +16,7 @@ class Projects::CommitsController &lt; Projects::ApplicationController
16 16  
17 17 respond_to do |format|
18 18 format.html # index.html.erb
19   - format.js
  19 + format.json { pager_json("projects/commits/_commits", @commits.size) }
20 20 format.atom { render layout: false }
21 21 end
22 22 end
... ...
app/controllers/projects/issues_controller.rb
... ... @@ -11,7 +11,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController
11 11 # Allow modify issue
12 12 before_filter :authorize_modify_issue!, only: [:edit, :update]
13 13  
14   - respond_to :js, :html
  14 + respond_to :html
15 15  
16 16 def index
17 17 terms = params['issue_search']
... ... @@ -23,11 +23,18 @@ class Projects::IssuesController &lt; Projects::ApplicationController
23 23 assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
24 24 @assignee = @project.team.find(assignee_id) if assignee_id.present? && !assignee_id.to_i.zero?
25 25 @milestone = @project.milestones.find(milestone_id) if milestone_id.present? && !milestone_id.to_i.zero?
  26 + sort_param = params[:sort] || 'newest'
  27 + @sort = sort_param.humanize unless sort_param.empty?
  28 +
26 29  
27 30 respond_to do |format|
28   - format.html # index.html.erb
29   - format.js
  31 + format.html
30 32 format.atom { render layout: false }
  33 + format.json do
  34 + render json: {
  35 + html: view_to_html_string("projects/issues/_issues")
  36 + }
  37 + end
31 38 end
32 39 end
33 40  
... ... @@ -45,10 +52,7 @@ class Projects::IssuesController &lt; Projects::ApplicationController
45 52 @target_type = :issue
46 53 @target_id = @issue.id
47 54  
48   - respond_to do |format|
49   - format.html
50   - format.js
51   - end
  55 + respond_with(@issue)
52 56 end
53 57  
54 58 def create
... ...
app/controllers/projects/merge_requests_controller.rb
... ... @@ -2,8 +2,8 @@ require &#39;gitlab/satellite/satellite&#39;
2 2  
3 3 class Projects::MergeRequestsController < Projects::ApplicationController
4 4 before_filter :module_enabled
5   - before_filter :merge_request, only: [:edit, :update, :show, :commits, :diffs, :automerge, :automerge_check, :ci_status]
6   - before_filter :closes_issues, only: [:edit, :update, :show, :commits, :diffs]
  5 + before_filter :merge_request, only: [:edit, :update, :show, :diffs, :automerge, :automerge_check, :ci_status]
  6 + before_filter :closes_issues, only: [:edit, :update, :show, :diffs]
7 7 before_filter :validates_merge_request, only: [:show, :diffs]
8 8 before_filter :define_show_vars, only: [:show, :diffs]
9 9  
... ... @@ -26,8 +26,6 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
26 26 def show
27 27 respond_to do |format|
28 28 format.html
29   - format.js
30   -
31 29 format.diff { render text: @merge_request.to_diff(current_user) }
32 30 format.patch { render text: @merge_request.to_patch(current_user) }
33 31 end
... ... @@ -44,6 +42,11 @@ class Projects::MergeRequestsController &lt; Projects::ApplicationController
44 42 diff_line_count = Commit::diff_line_count(@merge_request.diffs)
45 43 @suppress_diff = Commit::diff_suppress?(@merge_request.diffs, diff_line_count) && !params[:force_show_diff]
46 44 @force_suppress_diff = Commit::diff_force_suppress?(@merge_request.diffs, diff_line_count)
  45 +
  46 + respond_to do |format|
  47 + format.html
  48 + format.json { render json: { html: view_to_html_string("projects/merge_requests/show/_diffs") } }
  49 + end
47 50 end
48 51  
49 52 def new
... ...
app/controllers/projects/milestones_controller.rb
... ... @@ -34,11 +34,6 @@ class Projects::MilestonesController &lt; Projects::ApplicationController
34 34 @issues = @milestone.issues
35 35 @users = @milestone.participants.uniq
36 36 @merge_requests = @milestone.merge_requests
37   -
38   - respond_to do |format|
39   - format.html
40   - format.js
41   - end
42 37 end
43 38  
44 39 def create
... ...
app/controllers/projects/new_tree_controller.rb
... ... @@ -5,11 +5,12 @@ class Projects::NewTreeController &lt; Projects::BaseTreeController
5 5 end
6 6  
7 7 def update
8   - result = Files::CreateContext.new(@project, current_user, params, @ref, @path).execute
  8 + file_path = File.join(@path, File.basename(params[:file_name]))
  9 + result = Files::CreateContext.new(@project, current_user, params, @ref, file_path).execute
9 10  
10 11 if result[:status] == :success
11 12 flash[:notice] = "Your changes have been successfully commited"
12   - redirect_to project_blob_path(@project, File.join(@id, params[:file_name]))
  13 + redirect_to project_blob_path(@project, File.join(@ref, file_path))
13 14 else
14 15 flash[:alert] = result[:error]
15 16 render :show
... ...
app/controllers/projects/notes_controller.rb
... ... @@ -14,7 +14,14 @@ class Projects::NotesController &lt; Projects::ApplicationController
14 14 @discussions = discussions_from_notes
15 15 end
16 16  
17   - respond_with(@notes)
  17 + respond_to do |format|
  18 + format.html { redirect_to :back }
  19 + format.json do
  20 + render json: {
  21 + html: view_to_html_string("projects/notes/_notes")
  22 + }
  23 + end
  24 + end
18 25 end
19 26  
20 27 def create
... ...
app/controllers/projects_controller.rb
... ... @@ -55,17 +55,13 @@ class ProjectsController &lt; ApplicationController
55 55 end
56 56  
57 57 def show
58   - return authenticate_user! unless @project.public || current_user
  58 + return authenticate_user! unless @project.public? || current_user
59 59  
60 60 limit = (params[:limit] || 20).to_i
61 61 @events = @project.events.recent
62 62 @events = event_filter.apply_filter(@events)
63 63 @events = @events.limit(limit).offset(params[:offset] || 0)
64 64  
65   - # Ensure project default branch is set if it possible
66   - # Normally it defined on push or during creation
67   - @project.discover_default_branch
68   -
69 65 respond_to do |format|
70 66 format.html do
71 67 if @project.empty_repo?
... ... @@ -77,7 +73,7 @@ class ProjectsController &lt; ApplicationController
77 73 render :show, layout: user_layout
78 74 end
79 75 end
80   - format.js
  76 + format.json { pager_json("events/_events", @events.count) }
81 77 end
82 78 end
83 79  
... ...
app/controllers/public/projects_controller.rb
... ... @@ -6,7 +6,7 @@ class Public::ProjectsController &lt; ApplicationController
6 6 layout 'public'
7 7  
8 8 def index
9   - @projects = Project.public_only
  9 + @projects = Project.public_or_internal_only(current_user)
10 10 @projects = @projects.search(params[:search]) if params[:search].present?
11 11 @projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
12 12 end
... ...
app/controllers/search_controller.rb
... ... @@ -14,7 +14,7 @@ class SearchController &lt; ApplicationController
14 14 project_ids.select! { |id| id == project_id.to_i}
15 15 end
16 16  
17   - result = SearchContext.new(project_ids, params).execute
  17 + result = SearchContext.new(project_ids, current_user, params).execute
18 18  
19 19 @projects = result[:projects]
20 20 @merge_requests = result[:merge_requests]
... ...
app/helpers/application_helper.rb
... ... @@ -84,8 +84,8 @@ module ApplicationHelper
84 84 repository = @project.repository
85 85  
86 86 options = [
87   - ["Branch", repository.branch_names ],
88   - [ "Tag", repository.tag_names ]
  87 + ["Branches", repository.branch_names],
  88 + ["Tags", repository.tag_names]
89 89 ]
90 90  
91 91 # If reference is commit id -
... ... @@ -126,6 +126,9 @@ module ApplicationHelper
126 126 # Skip if user already created appropriate MR
127 127 return false if project.merge_requests.where(source_branch: event.branch_name).opened.any?
128 128  
  129 + # Skip if user removed branch right after that
  130 + return false unless project.repository.branch_names.include?(event.branch_name)
  131 +
129 132 true
130 133 end
131 134  
... ... @@ -184,14 +187,6 @@ module ApplicationHelper
184 187 Gitlab.config.extra
185 188 end
186 189  
187   - def public_icon
188   - content_tag :i, nil, class: 'icon-globe cblue'
189   - end
190   -
191   - def private_icon
192   - content_tag :i, nil, class: 'icon-lock cgreen'
193   - end
194   -
195 190 def search_placeholder
196 191 if @project && @project.persisted?
197 192 "Search in this project"
... ... @@ -208,4 +203,16 @@ module ApplicationHelper
208 203 line += "..." if lines.size > 1
209 204 line
210 205 end
  206 +
  207 + def broadcast_message
  208 + BroadcastMessage.current
  209 + end
  210 +
  211 + def highlight_js(&block)
  212 + string = capture(&block)
  213 +
  214 + content_tag :div, class: user_color_scheme_class do
  215 + Pygments::Lexer[:js].highlight(string).html_safe
  216 + end
  217 + end
211 218 end
... ...
app/helpers/commits_helper.rb
... ... @@ -105,6 +105,10 @@ module CommitsHelper
105 105 branches.sort.map { |branch| link_to(branch, project_tree_path(project, branch)) }.join(", ").html_safe
106 106 end
107 107  
  108 + def get_old_file(project, commit, diff)
  109 + project.repository.blob_at(commit.parent_id, diff.old_path) if commit.parent_id
  110 + end
  111 +
108 112 protected
109 113  
110 114 # Private: Returns a link to a person. If the person has a matching user and
... ... @@ -125,7 +129,9 @@ module CommitsHelper
125 129 source_name
126 130 end
127 131  
128   - user = User.where('name like ? or email like ?', source_name, source_email).first
  132 + # Prefer email match over name match
  133 + user = User.where(email: source_email).first
  134 + user ||= User.where(name: source_name).first
129 135  
130 136 options = {
131 137 class: "commit-#{options[:source]}-link has_tooltip",
... ...
app/helpers/compare_helper.rb
1 1 module CompareHelper
2 2 def compare_to_mr_button?
3   - params[:from].present? && params[:to].present? &&
  3 + @project.merge_requests_enabled &&
  4 + params[:from].present? &&
  5 + params[:to].present? &&
4 6 @repository.branch_names.include?(params[:from]) &&
5 7 @repository.branch_names.include?(params[:to]) &&
6 8 params[:from] != params[:to] &&
... ...
app/helpers/events_helper.rb
... ... @@ -102,15 +102,11 @@ module EventsHelper
102 102 end
103 103 elsif event.note_project_snippet?
104 104 link_to(project_snippet_path(event.project, event.note_target)) do
105   - content_tag :strong do
106   - "#{event.note_target_type} ##{truncate event.note_target_id}"
107   - end
  105 + "#{event.note_target_type} ##{truncate event.note_target_id}"
108 106 end
109 107 else
110 108 link_to event_note_target_path(event) do
111   - content_tag :strong do
112   - "#{event.note_target_type} ##{truncate event.note_target_iid}"
113   - end
  109 + "#{event.note_target_type} ##{truncate event.note_target_iid}"
114 110 end
115 111 end
116 112 elsif event.wall_note?
... ...
app/helpers/gitlab_markdown_helper.rb
... ... @@ -64,7 +64,9 @@ module GitlabMarkdownHelper
64 64 # ref - name of the branch or reference, eg. stable
65 65 # requested_path - path of request, eg. doc/api/README.md, used in special case when path is pointing to the .md file were the original request is coming from
66 66 # wiki - whether the markdown is from wiki or not
67   - def create_relative_links(text, project_path_with_namespace, ref, requested_path, wiki = false)
  67 + def create_relative_links(text, project, ref, requested_path, wiki = false)
  68 + @path_to_satellite = project.satellite.path
  69 + project_path_with_namespace = project.path_with_namespace
68 70 paths = extract_paths(text)
69 71 paths.each do |file_path|
70 72 new_path = rebuild_path(project_path_with_namespace, file_path, requested_path, ref)
... ... @@ -145,13 +147,18 @@ module GitlabMarkdownHelper
145 147  
146 148 def file_exists?(path)
147 149 return false if path.nil? || path.empty?
148   - File.exists?(Rails.root.join(path))
  150 + File.exists?(path_on_fs(path))
149 151 end
150 152  
151 153 # Check if the path is pointing to a directory(tree) or a file(blob)
152 154 # eg. doc/api is directory and doc/README.md is file
153 155 def local_path(path)
154   - File.directory?(Rails.root.join(path)) ? "tree" : "blob"
  156 + File.directory?(path_on_fs(path)) ? "tree" : "blob"
  157 + end
  158 +
  159 + # Path to the file in the satellites repository on the filesystem
  160 + def path_on_fs(path)
  161 + [@path_to_satellite, path].join("/")
155 162 end
156 163  
157 164 # We will assume that if no ref exists we can point to master
... ...
app/helpers/groups_helper.rb
... ... @@ -2,4 +2,23 @@ module GroupsHelper
2 2 def remove_user_from_group_message(group, user)
3 3 "You are going to remove #{user.name} from #{group.name} Group. Are you sure?"
4 4 end
  5 +
  6 + def group_head_title
  7 + title = @group.name
  8 +
  9 + title = if current_action?(:issues)
  10 + "Issues - " + title
  11 + elsif current_action?(:merge_requests)
  12 + "Merge requests - " + title
  13 + elsif current_action?(:members)
  14 + "Members - " + title
  15 + elsif current_action?(:edit)
  16 + "Settings - " + title
  17 + else
  18 + title
  19 + end
  20 +
  21 + title
  22 +
  23 + end
5 24 end
... ...
app/helpers/icons_helper.rb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +module IconsHelper
  2 + def boolean_to_icon(value)
  3 + if value.to_s == "true"
  4 + content_tag :i, nil, class: 'icon-ok cgreen'
  5 + else
  6 + content_tag :i, nil, class: 'icon-off clgray'
  7 + end
  8 + end
  9 +
  10 + def public_icon
  11 + content_tag :i, nil, class: 'icon-globe'
  12 + end
  13 +
  14 + def internal_icon
  15 + content_tag :i, nil, class: 'icon-shield'
  16 + end
  17 +
  18 + def private_icon
  19 + content_tag :i, nil, class: 'icon-lock'
  20 + end
  21 +end
... ...
app/helpers/issues_helper.rb
... ... @@ -68,4 +68,12 @@ module IssuesHelper
68 68 false
69 69 end
70 70 end
  71 +
  72 + def bulk_update_milestone_options
  73 + options_for_select(["None (backlog)", nil]) + options_from_collection_for_select(project_active_milestones, "id", "title", params[:milestone_id])
  74 + end
  75 +
  76 + def bulk_update_assignee_options
  77 + options_for_select(["None (unassigned)", nil]) + options_from_collection_for_select(@project.team.members, "id", "name", params[:assignee_id])
  78 + end
71 79 end
... ...
app/helpers/namespaces_helper.rb
... ... @@ -16,4 +16,13 @@ module NamespacesHelper
16 16  
17 17 grouped_options_for_select(options, selected)
18 18 end
  19 +
  20 + def namespace_select_tag(id, opts = {})
  21 + css_class = "ajax-namespace-select "
  22 + css_class << "multiselect " if opts[:multiple]
  23 + css_class << (opts[:class] || '')
  24 + value = opts[:selected] || ''
  25 +
  26 + hidden_field_tag(id, value, class: css_class)
  27 + end
19 28 end
... ...
app/helpers/projects_helper.rb
... ... @@ -70,6 +70,8 @@ module ProjectsHelper
70 70 scope: params[:scope],
71 71 label_name: params[:label_name],
72 72 milestone_id: params[:milestone_id],
  73 + assignee_id: params[:assignee_id],
  74 + sort: params[:sort],
73 75 }
74 76  
75 77 options = exist_opts.merge(options)
... ... @@ -135,12 +137,46 @@ module ProjectsHelper
135 137 end
136 138 end
137 139  
138   - def repository_size
139   - "#{@project.repository.size} MB"
  140 + def repository_size(project = nil)
  141 + "#{(project || @project).repository.size} MB"
140 142 rescue
141 143 # In order to prevent 500 error
142 144 # when application cannot allocate memory
143 145 # to calculate repo size - just show 'Unknown'
144 146 'unknown'
145 147 end
  148 +
  149 + def project_head_title
  150 + title = @project.name_with_namespace
  151 +
  152 + title = if current_controller?(:tree)
  153 + "#{@project.path}\/#{@path} at #{@ref} - " + title
  154 + elsif current_controller?(:issues)
  155 + if current_action?(:show)
  156 + "Issue ##{@issue.iid} - " + title
  157 + else
  158 + "Issues - " + title
  159 + end
  160 + elsif current_controller?(:blob)
  161 + "#{@project.path}\/#{@blob.path} at #{@ref} - " + title
  162 + elsif current_controller?(:commits)
  163 + "Commits at #{@ref} - " + title
  164 + elsif current_controller?(:merge_requests)
  165 + if current_action?(:show)
  166 + "Merge request ##{@merge_request.iid} - " + title
  167 + else
  168 + "Merge requests - " + title
  169 + end
  170 + elsif current_controller?(:wikis)
  171 + "Wiki - " + title
  172 + elsif current_controller?(:network)
  173 + "Network graph - " + title
  174 + elsif current_controller?(:graphs)
  175 + "Graphs - " + title
  176 + else
  177 + title
  178 + end
  179 +
  180 + title
  181 + end
146 182 end
... ...
app/helpers/search_helper.rb
1 1 module SearchHelper
2 2 def search_autocomplete_source
3 3 return unless current_user
4   -
5 4 [
6 5 groups_autocomplete,
7 6 projects_autocomplete,
  7 + public_projects_autocomplete,
8 8 default_autocomplete,
9 9 project_autocomplete,
10 10 help_autocomplete
... ... @@ -75,4 +75,11 @@ module SearchHelper
75 75 { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
76 76 end
77 77 end
  78 +
  79 + # Autocomplete results for the current user's projects
  80 + def public_projects_autocomplete
  81 + Project.public_or_internal_only(current_user).map do |p|
  82 + { label: "project: #{simple_sanitize(p.name_with_namespace)}", url: project_path(p) }
  83 + end
  84 + end
78 85 end
... ...
app/helpers/visibility_level_helper.rb 0 → 100644
... ... @@ -0,0 +1,49 @@
  1 +module VisibilityLevelHelper
  2 + def visibility_level_color(level)
  3 + case level
  4 + when Gitlab::VisibilityLevel::PRIVATE
  5 + 'cgreen'
  6 + when Gitlab::VisibilityLevel::INTERNAL
  7 + 'camber'
  8 + when Gitlab::VisibilityLevel::PUBLIC
  9 + 'cblue'
  10 + end
  11 + end
  12 +
  13 + def visibility_level_description(level)
  14 + capture_haml do
  15 + haml_tag :span do
  16 + case level
  17 + when Gitlab::VisibilityLevel::PRIVATE
  18 + haml_concat "Project access must be granted explicitly for each user."
  19 + when Gitlab::VisibilityLevel::INTERNAL
  20 + haml_concat "The project can be cloned by"
  21 + haml_concat "any logged in user."
  22 + when Gitlab::VisibilityLevel::PUBLIC
  23 + haml_concat "The project can be cloned"
  24 + haml_concat "without any"
  25 + haml_concat "authentication."
  26 + end
  27 + end
  28 + end
  29 + end
  30 +
  31 + def visibility_level_icon(level)
  32 + case level
  33 + when Gitlab::VisibilityLevel::PRIVATE
  34 + private_icon
  35 + when Gitlab::VisibilityLevel::INTERNAL
  36 + internal_icon
  37 + when Gitlab::VisibilityLevel::PUBLIC
  38 + public_icon
  39 + end
  40 + end
  41 +
  42 + def visibility_level_label(level)
  43 + Project.visibility_levels.key(level)
  44 + end
  45 +
  46 + def restricted_visibility_levels
  47 + current_user.is_admin? ? [] : gitlab_config.restricted_visibility_levels
  48 + end
  49 +end
... ...
app/mailers/emails/groups.rb
... ... @@ -5,7 +5,7 @@ module Emails
5 5 @group = @membership.group
6 6  
7 7 mail(to: @membership.user.email,
8   - subject: subject("access to group was granted"))
  8 + subject: subject("Access to group was granted"))
9 9 end
10 10 end
11 11 end
... ...
app/mailers/emails/issues.rb
... ... @@ -3,14 +3,14 @@ module Emails
3 3 def new_issue_email(recipient_id, issue_id)
4 4 @issue = Issue.find(issue_id)
5 5 @project = @issue.project
6   - mail(to: recipient(recipient_id), subject: subject("new issue ##{@issue.iid}", @issue.title))
  6 + mail(to: recipient(recipient_id), subject: subject("New issue ##{@issue.iid}", @issue.title))
7 7 end
8 8  
9 9 def reassigned_issue_email(recipient_id, issue_id, previous_assignee_id)
10 10 @issue = Issue.find(issue_id)
11 11 @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
12 12 @project = @issue.project
13   - mail(to: recipient(recipient_id), subject: subject("changed issue ##{@issue.iid}", @issue.title))
  13 + mail(to: recipient(recipient_id), subject: subject("Changed issue ##{@issue.iid}", @issue.title))
14 14 end
15 15  
16 16 def closed_issue_email(recipient_id, issue_id, updated_by_user_id)
... ... @@ -27,7 +27,7 @@ module Emails
27 27 @project = @issue.project
28 28 @updated_by = User.find updated_by_user_id
29 29 mail(to: recipient(recipient_id),
30   - subject: subject("changed issue ##{@issue.iid}", @issue.title))
  30 + subject: subject("Changed issue ##{@issue.iid}", @issue.title))
31 31 end
32 32 end
33 33 end
... ...
app/mailers/emails/merge_requests.rb
... ... @@ -2,24 +2,24 @@ module Emails
2 2 module MergeRequests
3 3 def new_merge_request_email(recipient_id, merge_request_id)
4 4 @merge_request = MergeRequest.find(merge_request_id)
5   - mail(to: recipient(recipient_id), subject: subject("new merge request !#{@merge_request.iid}", @merge_request.title))
  5 + mail(to: recipient(recipient_id), subject: subject("New merge request ##{@merge_request.iid}", @merge_request.title))
6 6 end
7 7  
8 8 def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id)
9 9 @merge_request = MergeRequest.find(merge_request_id)
10 10 @previous_assignee = User.find_by_id(previous_assignee_id) if previous_assignee_id
11   - mail(to: recipient(recipient_id), subject: subject("changed merge request !#{@merge_request.iid}", @merge_request.title))
  11 + mail(to: recipient(recipient_id), subject: subject("Changed merge request ##{@merge_request.iid}", @merge_request.title))
12 12 end
13 13  
14 14 def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
15 15 @merge_request = MergeRequest.find(merge_request_id)
16 16 @updated_by = User.find updated_by_user_id
17   - mail(to: recipient(recipient_id), subject: subject("Closed merge request !#{@merge_request.iid}", @merge_request.title))
  17 + mail(to: recipient(recipient_id), subject: subject("Closed merge request ##{@merge_request.iid}", @merge_request.title))
18 18 end
19 19  
20 20 def merged_merge_request_email(recipient_id, merge_request_id)
21 21 @merge_request = MergeRequest.find(merge_request_id)
22   - mail(to: recipient(recipient_id), subject: subject("Accepted merge request !#{@merge_request.iid}", @merge_request.title))
  22 + mail(to: recipient(recipient_id), subject: subject("Accepted merge request ##{@merge_request.iid}", @merge_request.title))
23 23 end
24 24 end
25 25  
... ...
app/mailers/emails/notes.rb
... ... @@ -4,27 +4,27 @@ module Emails
4 4 @note = Note.find(note_id)
5 5 @commit = @note.noteable
6 6 @project = @note.project
7   - mail(to: recipient(recipient_id), subject: subject("note for commit #{@commit.short_id}", @commit.title))
  7 + mail(to: recipient(recipient_id), subject: subject("Note for commit #{@commit.short_id}", @commit.title))
8 8 end
9 9  
10 10 def note_issue_email(recipient_id, note_id)
11 11 @note = Note.find(note_id)
12 12 @issue = @note.noteable
13 13 @project = @note.project
14   - mail(to: recipient(recipient_id), subject: subject("note for issue ##{@issue.iid}"))
  14 + mail(to: recipient(recipient_id), subject: subject("Note for issue ##{@issue.iid}"))
15 15 end
16 16  
17 17 def note_merge_request_email(recipient_id, note_id)
18 18 @note = Note.find(note_id)
19 19 @merge_request = @note.noteable
20 20 @project = @note.project
21   - mail(to: recipient(recipient_id), subject: subject("note for merge request ##{@merge_request.iid}"))
  21 + mail(to: recipient(recipient_id), subject: subject("Note for merge request ##{@merge_request.iid}"))
22 22 end
23 23  
24 24 def note_wall_email(recipient_id, note_id)
25 25 @note = Note.find(note_id)
26 26 @project = @note.project
27   - mail(to: recipient(recipient_id), subject: subject("note on wall"))
  27 + mail(to: recipient(recipient_id), subject: subject("Note on wall"))
28 28 end
29 29 end
30 30 end
... ...
app/mailers/emails/projects.rb
... ... @@ -4,14 +4,14 @@ module Emails
4 4 @users_project = UsersProject.find user_project_id
5 5 @project = @users_project.project
6 6 mail(to: @users_project.user.email,
7   - subject: subject("access to project was granted"))
  7 + subject: subject("Access to project was granted"))
8 8 end
9 9  
10 10 def project_was_moved_email(project_id, user_id)
11 11 @user = User.find user_id
12 12 @project = Project.find project_id
13 13 mail(to: @user.email,
14   - subject: subject("project was moved"))
  14 + subject: subject("Project was moved"))
15 15 end
16 16 end
17 17 end
... ...
app/models/ability.rb
... ... @@ -29,7 +29,7 @@ class Ability
29 29 nil
30 30 end
31 31  
32   - if project && project.public
  32 + if project && project.public?
33 33 [
34 34 :read_project,
35 35 :read_wiki,
... ... @@ -71,7 +71,7 @@ class Ability
71 71 rules << project_guest_rules
72 72 end
73 73  
74   - if project.public?
  74 + if project.public? || project.internal?
75 75 rules << public_project_rules
76 76 end
77 77  
... ... @@ -89,7 +89,7 @@ class Ability
89 89 def public_project_rules
90 90 project_guest_rules + [
91 91 :download_code,
92   - :fork_project,
  92 + :fork_project
93 93 ]
94 94 end
95 95  
... ... @@ -145,7 +145,7 @@ class Ability
145 145 def project_admin_rules
146 146 project_master_rules + [
147 147 :change_namespace,
148   - :change_public_mode,
  148 + :change_visibility_level,
149 149 :rename_project,
150 150 :remove_project
151 151 ]
... ...
app/models/assembla_service.rb 0 → 100644
... ... @@ -0,0 +1,45 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: services
  4 +#
  5 +# id :integer not null, primary key
  6 +# type :string(255)
  7 +# title :string(255)
  8 +# token :string(255)
  9 +# project_id :integer not null
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +# active :boolean default(FALSE), not null
  13 +# project_url :string(255)
  14 +# subdomain :string(255)
  15 +# room :string(255)
  16 +#
  17 +
  18 +class AssemblaService < Service
  19 + include HTTParty
  20 +
  21 + validates :token, presence: true, if: :activated?
  22 +
  23 + def title
  24 + 'Assembla'
  25 + end
  26 +
  27 + def description
  28 + 'Project Management Software (Source Commits Endpoint)'
  29 + end
  30 +
  31 + def to_param
  32 + 'assembla'
  33 + end
  34 +
  35 + def fields
  36 + [
  37 + { type: 'text', name: 'token', placeholder: '' }
  38 + ]
  39 + end
  40 +
  41 + def execute(push)
  42 + url = "https://atlas.assembla.com/spaces/ouposp/github_tool?secret_key=#{token}"
  43 + AssemblaService.post(url, body: { payload: push }.to_json, headers: { 'Content-Type' => 'application/json' })
  44 + end
  45 +end
... ...
app/models/broadcast_message.rb 0 → 100644
... ... @@ -0,0 +1,24 @@
  1 +# == Schema Information
  2 +#
  3 +# Table name: broadcast_messages
  4 +#
  5 +# id :integer not null, primary key
  6 +# message :text default(""), not null
  7 +# starts_at :datetime
  8 +# ends_at :datetime
  9 +# alert_type :integer
  10 +# created_at :datetime not null
  11 +# updated_at :datetime not null
  12 +#
  13 +
  14 +class BroadcastMessage < ActiveRecord::Base
  15 + attr_accessible :alert_type, :ends_at, :message, :starts_at
  16 +
  17 + validates :message, presence: true
  18 + validates :starts_at, presence: true
  19 + validates :ends_at, presence: true
  20 +
  21 + def self.current
  22 + where("ends_at > :now AND starts_at < :now", now: Time.zone.now).last
  23 + end
  24 +end
... ...
app/models/concerns/issuable.rb
... ... @@ -111,4 +111,11 @@ module Issuable
111 111 end
112 112 users.concat(mentions.reduce([], :|)).uniq
113 113 end
  114 +
  115 + def to_hook_data
  116 + {
  117 + object_kind: self.class.name.underscore,
  118 + object_attributes: self.attributes
  119 + }
  120 + end
114 121 end
... ...
app/models/event.rb
... ... @@ -168,7 +168,7 @@ class Event &lt; ActiveRecord::Base
168 168 end
169 169  
170 170 def valid_push?
171   - data[:ref]
  171 + data[:ref] && ref_name.present?
172 172 rescue => ex
173 173 false
174 174 end
... ... @@ -223,7 +223,7 @@ class Event &lt; ActiveRecord::Base
223 223  
224 224 # Max 20 commits from push DESC
225 225 def commits
226   - @commits ||= data[:commits].reverse
  226 + @commits ||= (data[:commits] || []).reverse
227 227 end
228 228  
229 229 def commits_count
... ...
app/models/flowdock_service.rb
... ... @@ -11,6 +11,8 @@
11 11 # updated_at :datetime not null
12 12 # active :boolean default(FALSE), not null
13 13 # project_url :string(255)
  14 +# subdomain :string(255)
  15 +# room :string(255)
14 16 #
15 17  
16 18 require "flowdock-git-hook"
... ...
app/models/gollum_wiki.rb
... ... @@ -33,7 +33,7 @@ class GollumWiki
33 33 end
34 34  
35 35 def http_url_to_repo
36   - http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
  36 + [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
37 37 end
38 38  
39 39 # Returns the Gollum::Wiki object.
... ...
app/models/hipchat_service.rb
... ... @@ -25,7 +25,7 @@ class HipchatService &lt; Service
25 25 end
26 26  
27 27 def description
28   - 'Simple web-based real-time group chat'
  28 + 'Private group chat and IM'
29 29 end
30 30  
31 31 def to_param
... ...
app/models/issue.rb
... ... @@ -21,6 +21,8 @@ class Issue &lt; ActiveRecord::Base
21 21 include Issuable
22 22 include InternalId
23 23  
  24 + ActsAsTaggableOn.strict_case_match = true
  25 +
24 26 belongs_to :project
25 27 validates :project, presence: true
26 28  
... ...
app/models/namespace.rb
... ... @@ -87,4 +87,8 @@ class Namespace &lt; ActiveRecord::Base
87 87 def send_update_instructions
88 88 projects.each(&:send_move_instructions)
89 89 end
  90 +
  91 + def kind
  92 + type == 'Group' ? 'group' : 'user'
  93 + end
90 94 end
... ...
app/models/note.rb
... ... @@ -157,7 +157,8 @@ class Note &lt; ActiveRecord::Base
157 157 # otherwise false is returned
158 158 def downvote?
159 159 votable? && (note.start_with?('-1') ||
160   - note.start_with?(':-1:')
  160 + note.start_with?(':-1:') ||
  161 + note.start_with?(':thumbsdown:')
161 162 )
162 163 end
163 164  
... ... @@ -206,7 +207,8 @@ class Note &lt; ActiveRecord::Base
206 207 # otherwise false is returned
207 208 def upvote?
208 209 votable? && (note.start_with?('+1') ||
209   - note.start_with?(':+1:')
  210 + note.start_with?(':+1:') ||
  211 + note.start_with?(':thumbsup:')
210 212 )
211 213 end
212 214  
... ...
app/models/project.rb
... ... @@ -9,33 +9,37 @@
9 9 # created_at :datetime not null
10 10 # updated_at :datetime not null
11 11 # creator_id :integer
12   -# default_branch :string(255)
13 12 # issues_enabled :boolean default(TRUE), not null
14 13 # wall_enabled :boolean default(TRUE), not null
15 14 # merge_requests_enabled :boolean default(TRUE), not null
16 15 # wiki_enabled :boolean default(TRUE), not null
17 16 # namespace_id :integer
18   -# public :boolean default(FALSE), not null
19 17 # issues_tracker :string(255) default("gitlab"), not null
20 18 # issues_tracker_id :string(255)
21 19 # snippets_enabled :boolean default(TRUE), not null
22 20 # last_activity_at :datetime
23 21 # imported :boolean default(FALSE), not null
24 22 # import_url :string(255)
  23 +# visibility_level :integer default(0), not null
25 24 #
26 25  
27 26 class Project < ActiveRecord::Base
28 27 include Gitlab::ShellAdapter
  28 + include Gitlab::VisibilityLevel
29 29 extend Enumerize
30 30  
31   - attr_accessible :name, :path, :description, :default_branch, :issues_tracker, :label_list,
  31 + ActsAsTaggableOn.strict_case_match = true
  32 +
  33 + attr_accessible :name, :path, :description, :issues_tracker, :label_list,
32 34 :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id,
33   - :wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin]
  35 + :wiki_enabled, :visibility_level, :import_url, :last_activity_at, as: [:default, :admin]
34 36  
35 37 attr_accessible :namespace_id, :creator_id, as: :admin
36 38  
37 39 acts_as_taggable_on :labels, :issues_default_labels
38 40  
  41 + attr_accessor :new_default_branch
  42 +
39 43 # Relations
40 44 belongs_to :creator, foreign_key: "creator_id", class_name: "User"
41 45 belongs_to :group, foreign_key: "namespace_id", conditions: "type = 'Group'"
... ... @@ -47,6 +51,7 @@ class Project &lt; ActiveRecord::Base
47 51 has_one :pivotaltracker_service, dependent: :destroy
48 52 has_one :hipchat_service, dependent: :destroy
49 53 has_one :flowdock_service, dependent: :destroy
  54 + has_one :assembla_service, dependent: :destroy
50 55 has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
51 56 has_one :forked_from_project, through: :forked_project_link
52 57  
... ... @@ -104,7 +109,8 @@ class Project &lt; ActiveRecord::Base
104 109 scope :sorted_by_activity, -> { reorder("projects.last_activity_at DESC") }
105 110 scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
106 111 scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) }
107   - scope :public_only, -> { where(public: true) }
  112 + scope :public_only, -> { where(visibility_level: PUBLIC) }
  113 + scope :public_or_internal_only, ->(user) { where("visibility_level IN (:levels)", levels: user ? [ INTERNAL, PUBLIC ] : [ PUBLIC ]) }
108 114  
109 115 enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
110 116  
... ... @@ -136,6 +142,10 @@ class Project &lt; ActiveRecord::Base
136 142 where(path: id, namespace_id: nil).last
137 143 end
138 144 end
  145 +
  146 + def visibility_levels
  147 + Gitlab::VisibilityLevel.options
  148 + end
139 149 end
140 150  
141 151 def team
... ... @@ -143,7 +153,7 @@ class Project &lt; ActiveRecord::Base
143 153 end
144 154  
145 155 def repository
146   - @repository ||= Repository.new(path_with_namespace, default_branch)
  156 + @repository ||= Repository.new(path_with_namespace)
147 157 end
148 158  
149 159 def saved?
... ... @@ -221,7 +231,7 @@ class Project &lt; ActiveRecord::Base
221 231 end
222 232  
223 233 def available_services_names
224   - %w(gitlab_ci campfire hipchat pivotaltracker flowdock)
  234 + %w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla)
225 235 end
226 236  
227 237 def gitlab_ci?
... ... @@ -288,8 +298,10 @@ class Project &lt; ActiveRecord::Base
288 298 ProjectTransferService.new.transfer(self, new_namespace)
289 299 end
290 300  
291   - def execute_hooks(data)
292   - hooks.each { |hook| hook.async_execute(data) }
  301 + def execute_hooks(data, hooks_scope = :push_hooks)
  302 + hooks.send(hooks_scope).each do |hook|
  303 + hook.async_execute(data)
  304 + end
293 305 end
294 306  
295 307 def execute_services(data)
... ... @@ -300,14 +312,6 @@ class Project &lt; ActiveRecord::Base
300 312 end
301 313 end
302 314  
303   - def discover_default_branch
304   - # Discover the default branch, but only if it hasn't already been set to
305   - # something else
306   - if repository.exists? && default_branch.nil?
307   - update_attributes(default_branch: self.repository.discover_default_branch)
308   - end
309   - end
310   -
311 315 def update_merge_requests(oldrev, newrev, ref, user)
312 316 return true unless ref =~ /heads/
313 317 branch_name = ref.gsub("refs/heads/", "")
... ... @@ -390,7 +394,7 @@ class Project &lt; ActiveRecord::Base
390 394 end
391 395  
392 396 def http_url_to_repo
393   - http_url = [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
  397 + [Gitlab.config.gitlab.url, "/", path_with_namespace, ".git"].join('')
394 398 end
395 399  
396 400 # Check if current branch name is marked as protected in the system
... ... @@ -451,4 +455,17 @@ class Project &lt; ActiveRecord::Base
451 455 def project_member(user)
452 456 users_projects.where(user_id: user).first
453 457 end
  458 +
  459 + def default_branch
  460 + @default_branch ||= repository.root_ref if repository.exists?
  461 + end
  462 +
  463 + def reload_default_branch
  464 + @default_branch = nil
  465 + default_branch
  466 + end
  467 +
  468 + def visibility_level_field
  469 + visibility_level
  470 + end
454 471 end
... ...
app/models/project_hook.rb
... ... @@ -2,15 +2,24 @@
2 2 #
3 3 # Table name: web_hooks
4 4 #
5   -# id :integer not null, primary key
6   -# url :string(255)
7   -# project_id :integer
8   -# created_at :datetime not null
9   -# updated_at :datetime not null
10   -# type :string(255) default("ProjectHook")
11   -# service_id :integer
  5 +# id :integer not null, primary key
  6 +# url :string(255)
  7 +# project_id :integer
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +# type :string(255) default("ProjectHook")
  11 +# service_id :integer
  12 +# push_events :boolean default(TRUE), not null
  13 +# issues_events :boolean default(FALSE), not null
  14 +# merge_requests_events :boolean default(FALSE), not null
12 15 #
13 16  
14 17 class ProjectHook < WebHook
15 18 belongs_to :project
  19 +
  20 + attr_accessible :push_events, :issues_events, :merge_requests_events
  21 +
  22 + scope :push_hooks, -> { where(push_events: true) }
  23 + scope :issue_hooks, -> { where(issues_events: true) }
  24 + scope :merge_request_hooks, -> { where(merge_requests_events: true) }
16 25 end
... ...
app/models/repository.rb
... ... @@ -3,7 +3,7 @@ class Repository
3 3  
4 4 attr_accessor :raw_repository, :path_with_namespace
5 5  
6   - def initialize(path_with_namespace, default_branch)
  6 + def initialize(path_with_namespace, default_branch = nil)
7 7 @path_with_namespace = path_with_namespace
8 8 @raw_repository = Gitlab::Git::Repository.new(path_to_repo) if path_with_namespace
9 9 rescue Gitlab::Git::Repository::NoRepository
... ... @@ -57,7 +57,7 @@ class Repository
57 57  
58 58 def recent_branches(limit = 20)
59 59 branches.sort do |a, b|
60   - a.commit.committed_date <=> b.commit.committed_date
  60 + b.commit.committed_date <=> a.commit.committed_date
61 61 end[0..limit]
62 62 end
63 63  
... ... @@ -133,6 +133,7 @@ class Repository
133 133 Rails.cache.delete(cache_key(:tag_names))
134 134 Rails.cache.delete(cache_key(:commit_count))
135 135 Rails.cache.delete(cache_key(:graph_log))
  136 + Rails.cache.delete(cache_key(:readme))
136 137 end
137 138  
138 139 def graph_log
... ... @@ -159,4 +160,10 @@ class Repository
159 160 def blob_at(sha, path)
160 161 Gitlab::Git::Blob.find(self, sha, path)
161 162 end
  163 +
  164 + def readme
  165 + Rails.cache.fetch(cache_key(:readme)) do
  166 + Tree.new(self, self.root_ref).readme
  167 + end
  168 + end
162 169 end
... ...
app/models/service_hook.rb
... ... @@ -2,13 +2,16 @@
2 2 #
3 3 # Table name: web_hooks
4 4 #
5   -# id :integer not null, primary key
6   -# url :string(255)
7   -# project_id :integer
8   -# created_at :datetime not null
9   -# updated_at :datetime not null
10   -# type :string(255) default("ProjectHook")
11   -# service_id :integer
  5 +# id :integer not null, primary key
  6 +# url :string(255)
  7 +# project_id :integer
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +# type :string(255) default("ProjectHook")
  11 +# service_id :integer
  12 +# push_events :boolean default(TRUE), not null
  13 +# issues_events :boolean default(FALSE), not null
  14 +# merge_requests_events :boolean default(FALSE), not null
12 15 #
13 16  
14 17 class ServiceHook < WebHook
... ...
app/models/system_hook.rb
... ... @@ -2,13 +2,16 @@
2 2 #
3 3 # Table name: web_hooks
4 4 #
5   -# id :integer not null, primary key
6   -# url :string(255)
7   -# project_id :integer
8   -# created_at :datetime not null
9   -# updated_at :datetime not null
10   -# type :string(255) default("ProjectHook")
11   -# service_id :integer
  5 +# id :integer not null, primary key
  6 +# url :string(255)
  7 +# project_id :integer
  8 +# created_at :datetime not null
  9 +# updated_at :datetime not null
  10 +# type :string(255) default("ProjectHook")
  11 +# service_id :integer
  12 +# push_events :boolean default(TRUE), not null
  13 +# issues_events :boolean default(FALSE), not null
  14 +# merge_requests_events :boolean default(FALSE), not null
12 15 #
13 16  
14 17 class SystemHook < WebHook
... ...