Commit 906c65b6 authored by Crom (Thibaut CHARLES)'s avatar Crom (Thibaut CHARLES)

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

Conflicts:
	config/application.rb
	config/gitlab.yml.example
	config/unicorn.rb.example
parents 87fc3507 dbf8ae73
...@@ -9,7 +9,6 @@ env: ...@@ -9,7 +9,6 @@ env:
- TASK=jasmine:ci - TASK=jasmine:ci
before_install: before_install:
- sudo apt-get install libicu-dev -y - sudo apt-get install libicu-dev -y
- gem install charlock_holmes -v="0.6.9"
branches: branches:
only: only:
- 'master' - 'master'
...@@ -17,9 +16,12 @@ rvm: ...@@ -17,9 +16,12 @@ rvm:
- 2.0.0 - 2.0.0
services: services:
- mysql - mysql
- redis-server
before_script: before_script:
- "cp config/database.yml.$DB config/database.yml" - "cp config/database.yml.$DB config/database.yml"
- "cp config/gitlab.yml.example config/gitlab.yml" - "cp config/gitlab.yml.example config/gitlab.yml"
- "bundle exec rake db:setup" - "bundle exec rake db:setup"
- "bundle exec rake db:seed_fu" - "bundle exec rake db:seed_fu"
script: "bundle exec rake $TASK --trace" script: "bundle exec rake $TASK --trace"
notifications:
email: false
v 6.4.0
- Added sorting to project issues page (Jason Blanchard)
- Assembla integration (Carlos Paramio)
- Fixed another 500 error with submodules
- UI: More compact issues page
- Minimal password length increased to 8 symbols
- Side-by-side diff view (Steven Thonus)
- Internal projects (Jason Hollingsworth)
- Allow removal of avatar (Drew Blessing)
- Project web hooks now support issues and merge request events
- Visiting project page while not logged in will redirect to sign-in instead of 404 (Jason Hollingsworth)
v 6.3.0 v 6.3.0
- API for adding gitlab-ci service - API for adding gitlab-ci service
- Init script now waits for pids to appear after (re)starting before reporting status (Rovanion Luckey) - 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,6 +21,34 @@ v 6.3.0
- Fixed issue with 500 error when group did not exist - Fixed issue with 500 error when group did not exist
- Ability to leave project - Ability to leave project
- You can create file in repo using UI - You can create file in repo using UI
- You can remove file from repo using UI
- API: dropped default_branch attribute from project during creation
- Project default_branch is not stored in db any more. It takes from repo now.
- Admin broadcast messages
- UI improvements
- Dont show last push widget if user removed this branch
- Fix 500 error for repos with newline in file name
- Extended html titles
- API: create/update/delete repo files
- Admin can transfer project to any namespace
- API: projects/all for admin users
- Fix recent branches order
v 6.2.4
- Security: Cast API private_token to string (CVE-2013-4580)
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
- Fix for Git SSH access for LDAP users
v 6.2.3
- Security: More protection against CVE-2013-4489
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
- Fix sidekiq rake tasks
v 6.2.2
- Security: Update gitlab_git (CVE-2013-4489)
v 6.2.1
- Security: Fix issue with generated passwords for new users
v 6.2.0 v 6.2.0
- Public project pages are now visible to everyone (files, issues, wik, etc.) - Public project pages are now visible to everyone (files, issues, wik, etc.)
...@@ -30,7 +70,7 @@ v 6.2.0 ...@@ -30,7 +70,7 @@ v 6.2.0
- Avatar upload on profile page with a maximum of 100KB (Steven Thonus) - Avatar upload on profile page with a maximum of 100KB (Steven Thonus)
- Store the sessions in Redis instead of the cookie store - Store the sessions in Redis instead of the cookie store
- Fixed relative links in markdown - Fixed relative links in markdown
- User must confirm his email if signup enabled - User must confirm their email if signup enabled
- User must confirm changed email - User must confirm changed email
v 6.1.0 v 6.1.0
...@@ -52,7 +92,7 @@ v 6.1.0 ...@@ -52,7 +92,7 @@ v 6.1.0
- Add links to create branch/tag from project home page - Add links to create branch/tag from project home page
- Add public-project? checkbox to new-project view - Add public-project? checkbox to new-project view
- Improved compare page. Added link to proceed into Merge Request - Improved compare page. Added link to proceed into Merge Request
- Send email to user when he was added to group - Send an email to a user when they are added to group
- New landing page when you have 0 projects - New landing page when you have 0 projects
v 6.0.0 v 6.0.0
...@@ -95,6 +135,14 @@ v 6.0.0 ...@@ -95,6 +135,14 @@ v 6.0.0
- Improved MR comments logic - Improved MR comments logic
- Render readme file for projects in public area - Render readme file for projects in public area
v 5.4.2
- Security: Cast API private_token to string (CVE-2013-4580)
- Security: Require gitlab-shell 1.7.8 (CVE-2013-4581, CVE-2013-4582, CVE-2013-4583)
v 5.4.1
- Security: Fixes for CVE-2013-4489
- Security: Require gitlab-shell 1.7.4 (CVE-2013-4490, CVE-2013-4546)
v 5.4.0 v 5.4.0
- Ability to edit own comments - Ability to edit own comments
- Documentation improvements - Documentation improvements
......
...@@ -9,6 +9,14 @@ This guide details how to use issues and pull requests to improve GitLab. ...@@ -9,6 +9,14 @@ This guide details how to use issues and pull requests to improve GitLab.
If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md). If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md).
## Contributor license agreement
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).
## Security vulnerability disclosure
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.
## Closing policy for issues and pull requests ## Closing policy for issues and pull requests
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. 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,6 +82,3 @@ We will accept pull requests if:
* It is a single commit (please use `git rebase -i` to squash commits) * It is a single commit (please use `git rebase -i` to squash commits)
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). 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).
## Security vulnerabilities
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.
...@@ -8,7 +8,7 @@ def linux_only(require_as) ...@@ -8,7 +8,7 @@ def linux_only(require_as)
RUBY_PLATFORM.include?('linux') && require_as RUBY_PLATFORM.include?('linux') && require_as
end end
gem "rails", "3.2.15" gem "rails", "3.2.16"
# Supported DBs # Supported DBs
gem "mysql2", group: :mysql gem "mysql2", group: :mysql
...@@ -24,26 +24,27 @@ gem 'omniauth-github' ...@@ -24,26 +24,27 @@ gem 'omniauth-github'
# Extracting information from a git repository # Extracting information from a git repository
# Provide access to Gitlab::Git library # Provide access to Gitlab::Git library
gem "gitlab_git", "~> 3.0.0.rc2" gem "gitlab_git", "~> 3.1.0"
# Ruby/Rack Git Smart-HTTP Server Handler # Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.1', require: 'grack' gem 'gitlab-grack', '~> 1.1.0', require: 'grack'
# LDAP Auth # LDAP Auth
gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap" gem 'gitlab_omniauth-ldap', '1.0.3', require: "omniauth-ldap"
# Syntax highlighter # Syntax highlighter
gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' gem "gitlab-pygments.rb", '~> 0.5.4', require: 'pygments.rb'
# Git Wiki # Git Wiki
gem "gitlab-gollum-lib", "~> 1.0.1", require: 'gollum-lib' gem "gitlab-gollum-lib", "~> 1.0.2", require: 'gollum-lib'
# Language detection # Language detection
gem "github-linguist", require: "linguist" gem "gitlab-linguist", "~> 2.9.6", require: "linguist"
# API # API
gem "grape", "~> 0.4.1" gem "grape", "~> 0.4.1"
gem "grape-entity", "~> 0.3.0" gem "grape-entity", "~> 0.3.0"
gem 'rack-cors', require: 'rack/cors'
# Format dates and times # Format dates and times
# based on human-friendly examples # based on human-friendly examples
...@@ -135,7 +136,7 @@ group :assets do ...@@ -135,7 +136,7 @@ group :assets do
gem 'turbolinks' gem 'turbolinks'
gem 'jquery-turbolinks' gem 'jquery-turbolinks'
gem 'chosen-rails', "1.0.0" gem 'chosen-rails', "1.0.1"
gem 'select2-rails' gem 'select2-rails'
gem 'jquery-atwho-rails', "0.3.0" gem 'jquery-atwho-rails', "0.3.0"
gem "jquery-rails", "2.1.3" gem "jquery-rails", "2.1.3"
......
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actionmailer (3.2.15) actionmailer (3.2.16)
actionpack (= 3.2.15) actionpack (= 3.2.16)
mail (~> 2.5.4) mail (~> 2.5.4)
actionpack (3.2.15) actionpack (3.2.16)
activemodel (= 3.2.15) activemodel (= 3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
builder (~> 3.0.0) builder (~> 3.0.0)
erubis (~> 2.7.0) erubis (~> 2.7.0)
journey (~> 1.0.4) journey (~> 1.0.4)
...@@ -14,18 +14,18 @@ GEM ...@@ -14,18 +14,18 @@ GEM
rack-cache (~> 1.2) rack-cache (~> 1.2)
rack-test (~> 0.6.1) rack-test (~> 0.6.1)
sprockets (~> 2.2.1) sprockets (~> 2.2.1)
activemodel (3.2.15) activemodel (3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
builder (~> 3.0.0) builder (~> 3.0.0)
activerecord (3.2.15) activerecord (3.2.16)
activemodel (= 3.2.15) activemodel (= 3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
arel (~> 3.0.2) arel (~> 3.0.2)
tzinfo (~> 0.3.29) tzinfo (~> 0.3.29)
activeresource (3.2.15) activeresource (3.2.16)
activemodel (= 3.2.15) activemodel (= 3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
activesupport (3.2.15) activesupport (3.2.16)
i18n (~> 0.6, >= 0.6.4) i18n (~> 0.6, >= 0.6.4)
multi_json (~> 1.0) multi_json (~> 1.0)
acts-as-taggable-on (2.4.1) acts-as-taggable-on (2.4.1)
...@@ -34,11 +34,11 @@ GEM ...@@ -34,11 +34,11 @@ GEM
annotate (2.6.0.beta2) annotate (2.6.0.beta2)
activerecord (>= 2.3.0) activerecord (>= 2.3.0)
rake (>= 0.8.7) rake (>= 0.8.7)
arel (3.0.2) arel (3.0.3)
asciidoctor (0.1.3) asciidoctor (0.1.3)
awesome_print (1.2.0) awesome_print (1.2.0)
backports (3.3.2) backports (3.3.2)
bcrypt-ruby (3.1.1) bcrypt-ruby (3.1.2)
better_errors (1.0.1) better_errors (1.0.1)
coderay (>= 1.0.0) coderay (>= 1.0.0)
erubis (>= 2.6.6) erubis (>= 2.6.6)
...@@ -61,12 +61,12 @@ GEM ...@@ -61,12 +61,12 @@ GEM
charlock_holmes (0.6.9.4) charlock_holmes (0.6.9.4)
childprocess (0.3.9) childprocess (0.3.9)
ffi (~> 1.0, >= 1.0.11) ffi (~> 1.0, >= 1.0.11)
chosen-rails (1.0.0) chosen-rails (1.0.1)
coffee-rails (>= 3.2) coffee-rails (>= 3.2)
compass-rails (>= 1.0) compass-rails (>= 1.0)
railties (>= 3.0) railties (>= 3.0)
sass-rails (>= 3.2) sass-rails (>= 3.2)
chunky_png (1.2.8) chunky_png (1.2.9)
cliver (0.2.1) cliver (0.2.1)
code_analyzer (0.4.3) code_analyzer (0.4.3)
sexp_processor sexp_processor
...@@ -77,7 +77,7 @@ GEM ...@@ -77,7 +77,7 @@ GEM
coffee-script (2.2.0) coffee-script (2.2.0)
coffee-script-source coffee-script-source
execjs execjs
coffee-script-source (1.6.2) coffee-script-source (1.6.3)
colored (1.2) colored (1.2)
colorize (0.5.8) colorize (0.5.8)
compass (0.12.2) compass (0.12.2)
...@@ -101,14 +101,14 @@ GEM ...@@ -101,14 +101,14 @@ GEM
database_cleaner (1.1.1) database_cleaner (1.1.1)
debug_inspector (0.0.2) debug_inspector (0.0.2)
descendants_tracker (0.0.1) descendants_tracker (0.0.1)
devise (2.2.5) devise (2.2.8)
bcrypt-ruby (~> 3.0) bcrypt-ruby (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (~> 3.1) railties (~> 3.1)
warden (~> 1.2.1) warden (~> 1.2.1)
devise-async (0.8.0) devise-async (0.8.0)
devise (>= 2.2, < 3.2) devise (>= 2.2, < 3.2)
diff-lcs (1.2.4) diff-lcs (1.2.5)
dotenv (0.8.0) dotenv (0.8.0)
email_spec (1.4.0) email_spec (1.4.0)
launchy (~> 2.1) launchy (~> 2.1)
...@@ -119,8 +119,7 @@ GEM ...@@ -119,8 +119,7 @@ GEM
escape_utils (0.2.4) escape_utils (0.2.4)
eventmachine (1.0.3) eventmachine (1.0.3)
excon (0.13.4) excon (0.13.4)
execjs (1.4.0) execjs (2.0.2)
multi_json (~> 1.0)
factory_girl (4.2.0) factory_girl (4.2.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
factory_girl_rails (4.2.1) factory_girl_rails (4.2.1)
...@@ -151,38 +150,39 @@ GEM ...@@ -151,38 +150,39 @@ GEM
fssm (0.2.10) fssm (0.2.10)
gemoji (1.2.1) gemoji (1.2.1)
gherkin-ruby (0.3.0) gherkin-ruby (0.3.0)
github-linguist (2.3.4) github-markdown (0.5.5)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.3)
mime-types (~> 1.19)
pygments.rb (>= 0.2.13)
github-markdown (0.5.3)
github-markup (0.7.5) github-markup (0.7.5)
gitlab-flowdock-git-hook (0.4.2.2) gitlab-flowdock-git-hook (0.4.2.2)
gitlab-grit (>= 2.4.1) gitlab-grit (>= 2.4.1)
multi_json multi_json
gitlab-gollum-lib (1.0.1) gitlab-gollum-lib (1.0.2)
github-markdown (~> 0.5.3) github-markdown (~> 0.5.3)
github-markup (>= 0.7.5, < 1.0.0) github-markup (>= 0.7.5, < 1.0.0)
gitlab-grit (>= 2.5.1) gitlab-grit (~> 2.6.1)
gitlab-pygments.rb (~> 0.5.4)
nokogiri (~> 1.5.9) nokogiri (~> 1.5.9)
pygments.rb (~> 0.4.2)
sanitize (~> 2.0.3) sanitize (~> 2.0.3)
stringex (~> 1.5.1) stringex (~> 1.5.1)
gitlab-grack (1.0.1) gitlab-grack (1.1.0)
rack (~> 1.4.1) rack (~> 1.4.1)
gitlab-grit (2.6.1) gitlab-grit (2.6.3)
charlock_holmes (~> 0.6.9) charlock_holmes (~> 0.6.9)
diff-lcs (~> 1.1) diff-lcs (~> 1.1)
mime-types (~> 1.15) mime-types (~> 1.15)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
gitlab-pygments.rb (0.3.2) gitlab-linguist (2.9.6)
charlock_holmes (~> 0.6.6)
escape_utils (~> 0.2.4)
gitlab-pygments.rb (~> 0.5.4)
mime-types (~> 1.19)
gitlab-pygments.rb (0.5.4)
posix-spawn (~> 0.3.6) posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0) yajl-ruby (~> 1.1.0)
gitlab_git (3.0.0.rc2) gitlab_git (3.1.0)
activesupport (~> 3.2.13) activesupport (~> 3.2.13)
github-linguist (~> 2.3.4)
gitlab-grit (~> 2.6.1) gitlab-grit (~> 2.6.1)
gitlab-linguist (~> 2.9.5)
gitlab-pygments.rb (~> 0.5.4)
gitlab_meta (6.0) gitlab_meta (6.0)
gitlab_omniauth-ldap (1.0.3) gitlab_omniauth-ldap (1.0.3)
net-ldap (~> 0.3.1) net-ldap (~> 0.3.1)
...@@ -235,7 +235,7 @@ GEM ...@@ -235,7 +235,7 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpauth (0.2.0) httpauth (0.2.0)
i18n (0.6.5) i18n (0.6.9)
jasmine (1.3.2) jasmine (1.3.2)
jasmine-core (~> 1.3.1) jasmine-core (~> 1.3.1)
rack (~> 1.0) rack (~> 1.0)
...@@ -274,7 +274,7 @@ GEM ...@@ -274,7 +274,7 @@ GEM
mime-types (~> 1.16) mime-types (~> 1.16)
treetop (~> 1.4.8) treetop (~> 1.4.8)
method_source (0.8.1) method_source (0.8.1)
mime-types (1.25) mime-types (1.25.1)
minitest (4.7.4) minitest (4.7.4)
modernizr (2.6.2) modernizr (2.6.2)
sprockets (~> 2.0) sprockets (~> 2.0)
...@@ -312,7 +312,7 @@ GEM ...@@ -312,7 +312,7 @@ GEM
omniauth-twitter (0.0.17) omniauth-twitter (0.0.17)
multi_json (~> 1.3) multi_json (~> 1.3)
omniauth-oauth (~> 1.0) omniauth-oauth (~> 1.0)
orm_adapter (0.4.0) orm_adapter (0.5.0)
pg (0.15.1) pg (0.15.1)
poltergeist (1.4.1) poltergeist (1.4.1)
capybara (~> 2.1.0) capybara (~> 2.1.0)
...@@ -325,9 +325,6 @@ GEM ...@@ -325,9 +325,6 @@ GEM
coderay (~> 1.0.5) coderay (~> 1.0.5)
method_source (~> 0.8) method_source (~> 0.8)
slop (~> 3.4) slop (~> 3.4)
pygments.rb (0.4.2)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
pyu-ruby-sasl (0.0.3.3) pyu-ruby-sasl (0.0.3.3)
quiet_assets (1.0.2) quiet_assets (1.0.2)
railties (>= 3.1, < 5.0) railties (>= 3.1, < 5.0)
...@@ -338,6 +335,7 @@ GEM ...@@ -338,6 +335,7 @@ GEM
rack rack
rack-cache (1.2) rack-cache (1.2)
rack (>= 0.4) rack (>= 0.4)
rack-cors (0.2.9)
rack-mini-profiler (0.1.31) rack-mini-profiler (0.1.31)
rack (>= 1.1.3) rack (>= 1.1.3)
rack-mount (0.8.3) rack-mount (0.8.3)
...@@ -348,14 +346,14 @@ GEM ...@@ -348,14 +346,14 @@ GEM
rack rack
rack-test (0.6.2) rack-test (0.6.2)
rack (>= 1.0) rack (>= 1.0)
rails (3.2.15) rails (3.2.16)
actionmailer (= 3.2.15) actionmailer (= 3.2.16)
actionpack (= 3.2.15) actionpack (= 3.2.16)
activerecord (= 3.2.15) activerecord (= 3.2.16)
activeresource (= 3.2.15) activeresource (= 3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
bundler (~> 1.0) bundler (~> 1.0)
railties (= 3.2.15) railties (= 3.2.16)
rails-dev-tweaks (0.6.1) rails-dev-tweaks (0.6.1)
actionpack (~> 3.1) actionpack (~> 3.1)
railties (~> 3.1) railties (~> 3.1)
...@@ -368,9 +366,9 @@ GEM ...@@ -368,9 +366,9 @@ GEM
i18n i18n
require_all require_all
ruby-progressbar ruby-progressbar
railties (3.2.15) railties (3.2.16)
actionpack (= 3.2.15) actionpack (= 3.2.16)
activesupport (= 3.2.15) activesupport (= 3.2.16)
rack-ssl (~> 1.3.2) rack-ssl (~> 1.3.2)
rake (>= 0.8.7) rake (>= 0.8.7)
rdoc (~> 3.4) rdoc (~> 3.4)
...@@ -431,7 +429,7 @@ GEM ...@@ -431,7 +429,7 @@ GEM
safe_yaml (0.9.3) safe_yaml (0.9.3)
sanitize (2.0.3) sanitize (2.0.3)
nokogiri (>= 1.4.4, < 1.6) nokogiri (>= 1.4.4, < 1.6)
sass (3.2.11) sass (3.2.12)
sass-rails (3.2.6) sass-rails (3.2.6)
railties (~> 3.2.0) railties (~> 3.2.0)
sass (>= 3.1.10) sass (>= 3.1.10)
...@@ -559,7 +557,7 @@ DEPENDENCIES ...@@ -559,7 +557,7 @@ DEPENDENCIES
bootstrap-sass bootstrap-sass
capybara capybara
carrierwave carrierwave
chosen-rails (= 1.0.0) chosen-rails (= 1.0.1)
coffee-rails coffee-rails
colored colored
coveralls coveralls
...@@ -575,13 +573,13 @@ DEPENDENCIES ...@@ -575,13 +573,13 @@ DEPENDENCIES
font-awesome-rails font-awesome-rails
foreman foreman
gemoji (~> 1.2.1) gemoji (~> 1.2.1)
github-linguist
github-markup (~> 0.7.4) github-markup (~> 0.7.4)
gitlab-flowdock-git-hook (~> 0.4.2) gitlab-flowdock-git-hook (~> 0.4.2)
gitlab-gollum-lib (~> 1.0.1) gitlab-gollum-lib (~> 1.0.2)
gitlab-grack (~> 1.0.1) gitlab-grack (~> 1.1.0)
gitlab-pygments.rb (~> 0.3.2) gitlab-linguist (~> 2.9.6)
gitlab_git (~> 3.0.0.rc2) gitlab-pygments.rb (~> 0.5.4)
gitlab_git (~> 3.1.0)
gitlab_meta (= 6.0) gitlab_meta (= 6.0)
gitlab_omniauth-ldap (= 1.0.3) gitlab_omniauth-ldap (= 1.0.3)
gon gon
...@@ -613,8 +611,9 @@ DEPENDENCIES ...@@ -613,8 +611,9 @@ DEPENDENCIES
pry pry
quiet_assets (~> 1.0.1) quiet_assets (~> 1.0.1)
rack-attack rack-attack
rack-cors
rack-mini-profiler rack-mini-profiler
rails (= 3.2.15) rails (= 3.2.16)
rails-dev-tweaks rails-dev-tweaks
rails_best_practices rails_best_practices
raphael-rails (~> 2.1.2) raphael-rails (~> 2.1.2)
......
...@@ -32,7 +32,9 @@ ...@@ -32,7 +32,9 @@
* 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/) * 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/)
* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server * [GitLab Enterprise Edition](https://www.gitlab.com/features/) offers additional features that are useful for larger organizations (100+ users).
* [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.
### Requirements ### Requirements
...@@ -44,31 +46,24 @@ ...@@ -44,31 +46,24 @@
** More details are in the [requirements doc](doc/install/requirements.md) ** More details are in the [requirements doc](doc/install/requirements.md)
### Installation ### Official installation methods
#### Official production installation
* [Installation guide for a production server](doc/install/installation.md)
* [Manual installation guide for a production server](doc/install/installation.md)
#### Official development installation * [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.
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. ### Third party one-click installers
* [Vagrant virtual machine for development](https://github.com/gitlabhq/gitlab-vagrant-vm) * [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.
* [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.).
#### Unofficial production installations #### Unofficial installation methods
* [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. * [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.
* [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. * [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.
* [BitNami one-click installers](http://bitnami.com/stack/gitlab)
* [TurnKey Linux virtual appliance](http://www.turnkeylinux.org/gitlab)
### New versions and upgrading ### New versions and upgrading
Since 2011 GitLab is released on the 22nd of every month. Every new release includes an upgrade guide. 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,7 +74,6 @@ Since 2011 GitLab is released on the 22nd of every month. Every new release incl
* 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). * 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).
### Run in production mode ### Run in production mode
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: 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,7 +104,7 @@ or start each component separately
* Run all tests * Run all tests
bundle exec rake gitlab:test bundle exec rake gitlab:test RAILS_ENV=test
* [RSpec](http://rspec.info/) unit and functional tests * [RSpec](http://rspec.info/) unit and functional tests
...@@ -147,15 +141,17 @@ or start each component separately ...@@ -147,15 +141,17 @@ or start each component separately
* [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. * [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.
* [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.
* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab. * [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab.
* [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. * [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.
* [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions. * [Support subscription](http://www.gitlab.com/subscription/) connects you to the knowledge of GitLab experts that will resolve your issues and answer your questions.
* [Consultancy](http://www.gitlab.com/consultancy/) allows you hire GitLab experts for installations, upgrades and customizations. * [Consultancy](http://www.gitlab.com/consultancy/) from the GitLab experts for installations, upgrades and customizations.
* [#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.
* [Book](http://www.packtpub.com/gitlab-repository-management/book) written by GitLab enthusiast Jonathan M. Hethey is unofficial but it offers a good overview.
### Getting in touch ### Getting in touch
......
6.3.0.pre 6.4.0.pre
app/assets/images/favicon.ico

1.12 KB | W: | H:

app/assets/images/favicon.ico

32.2 KB | W: | H:

app/assets/images/favicon.ico
app/assets/images/favicon.ico
app/assets/images/favicon.ico
app/assets/images/favicon.ico
  • 2-up
  • Swipe
  • Onion skin
app/assets/images/logo-black.png

3.01 KB | W: | H:

app/assets/images/logo-black.png

2.95 KB | W: | H:

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

5.59 KB | W: | H:

app/assets/images/logo-white.png

8.14 KB | W: | H:

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