Commit 61cfa2a7 authored by Sebastian Ziebell's avatar Sebastian Ziebell

Merge branch 'master' into fixes/api

Conflicts:
	lib/api/projects.rb
parents d269d107 6beae84e
# Contact & support # Contribute to GitLab
If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq). If you have a question or want to contribute to GitLab this guide show you the appropriate channel to use.
Otherwise you can follow our [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) for a more systematic and thorough guide to solving your issues.
## Ruling out common errors
Some errors are common and it may so happen, that you are not the only one who stumbled over a particular issue. We have [collected several of those and documented quick solutions](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide) for them.
# Contribute to GitLab ## Support forum
Please visit our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) for any kind of question regarding the usage or adiministration/configuration of GitLab.
### Use the support forum if ...
## Recipes * You get permission denied errors
* You can't see your repos
* You have issues cloning, pulling or pushing
* You have issues with web_hooks not firing
We collect user submitted installation scripts and config file templates for platforms we don't support officially. **Search** for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved.
We believe there is merit in allowing a certain amount of diversity.
You can get and submit your solution to running/configuring GitLab with your favorite OS/distro, database, web server, cloud hoster, configuration management tool, etc.
Help us improve the collection of [GitLab Recipes](https://github.com/gitlabhq/gitlab-recipes/) ## Paid support
Community support in the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) is done by volunteers. Paid support is available from [GitLab.com](http://blog.gitlab.com/services/)
## Feature suggestions ## Feature suggestions
Follow the [Issue Submission Guide](https://github.com/gitlabhq/gitlabhq/wiki/Issue-Submission-Guide) and support other peoples ideas or propose your own. Feature suggestions don't belong in issues but can go to [Feedback forum](http://gitlab.uservoice.com/forums/176466-general) where they can be voted on.
## Pull requests
Code speaks louder than words. If you can please submit a pull request with the fix including tests. The workflow to make a pull request is as follows:
1. Fork the project on GitHub
1. Create a feature branch
1. Write tests and code
1. If you have multiple commits please combine them into one commit by [squashing them](http://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)
1. Push the commit to your fork
1. Submit a pull request
We will accept pull requests if:
* The code has proper tests and all tests pass
* It can be merged without problems (if not please use: git rebase master)
* It doesn't break any existing functionality
* It's quality code that conforms to the [Rails style guide](https://github.com/bbatsov/rails-style-guide) and best practices
* The description includes a motive for your change and the method you used to achieve it
* It keeps the GitLab code base clean and well structured
* We think other users will need the same functionality
* If it makes changes to the UI the pull request should include screenshots
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).
## Submitting via GitHub's issue tracker
* For obvious bugs or misbehavior in GitLab in the master branch. Please include the revision id and a reproducible test case.
* For problematic or insufficient documentation. Please give a suggestion on how to improve it.
If you're unsure where to post, post it to the [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq) first.
There are a lot of helpful GitLab users there who may be able to help you quickly.
If your particular issue turns out to be a bug, it will find its way from there to the [issue tracker on GitHub](https://github.com/gitlabhq/gitlabhq/issues).
### When submitting an issue
**Search** for similar entries before submitting your own, there's a good chance somebody else had the same issue or idea. Show your support with `:+1:` and/or join the discussion.
Please consider the following points when submitting an **issue**:
* Summarize your issue in one sentence (what happened wrong, when you did/expected something else)
* Describe your issue in detail (including steps to reproduce)
* Add logs or screen shots when possible
* Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`)
## Code ## Thank you!
Follow our [Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) to set you up for hacking on GitLab. By taking the time to use the right channel, you help the development team to organize and prioritize issues and suggestions in order to make GitLab a better product for us all.
...@@ -15,16 +15,18 @@ gem "mysql2", group: :mysql ...@@ -15,16 +15,18 @@ gem "mysql2", group: :mysql
gem "pg", group: :postgres gem "pg", group: :postgres
# Auth # Auth
gem "devise", "~> 2.1.0" gem "devise"
gem 'omniauth', "~> 1.1.1" gem 'omniauth', "~> 1.1.3"
gem 'omniauth-google-oauth2' gem 'omniauth-google-oauth2'
gem 'omniauth-twitter' gem 'omniauth-twitter'
gem 'omniauth-github' gem 'omniauth-github'
# GITLAB patched libs # Extracting information from a git repository
gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' gem "gitlab-grit", '~> 1.0.0', require: 'grit'
gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' gem 'grit_ext', '~> 0.6.2'
gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 1.0.0', require: 'grack'
# LDAP Auth # LDAP Auth
gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap"
...@@ -33,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" ...@@ -33,7 +35,7 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap"
gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db" gem 'gitlab_yaml_db', '1.0.0', require: "yaml_db"
# Syntax highlighter # Syntax highlighter
gem "pygments.rb", git: "https://github.com/gitlabhq/pygments.rb.git", branch: "master" gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb'
# Language detection # Language detection
gem "github-linguist", "~> 2.3.4" , require: "linguist" gem "github-linguist", "~> 2.3.4" , require: "linguist"
...@@ -46,14 +48,17 @@ gem "grape-entity", "~> 0.2.0" ...@@ -46,14 +48,17 @@ gem "grape-entity", "~> 0.2.0"
# based on human-friendly examples # based on human-friendly examples
gem "stamp" gem "stamp"
# Enumeration fields
gem 'enumerize'
# Pagination # Pagination
gem "kaminari", "~> 0.14.1" gem "kaminari", "~> 0.14.1"
# HAML # HAML
gem "haml-rails", "~> 0.3.5" gem "haml-rails"
# Files attachments # Files attachments
gem "carrierwave", "~> 0.7.1" gem "carrierwave"
# Authorization # Authorization
gem "six" gem "six"
...@@ -69,7 +74,7 @@ gem "redcarpet", "~> 2.2.2" ...@@ -69,7 +74,7 @@ gem "redcarpet", "~> 2.2.2"
gem "github-markup", "~> 0.7.4", require: 'github/markup' gem "github-markup", "~> 0.7.4", require: 'github/markup'
# Servers # Servers
gem "unicorn", "~> 4.4.0" gem "unicorn"
# State machine # State machine
gem "state_machine" gem "state_machine"
...@@ -78,12 +83,12 @@ gem "state_machine" ...@@ -78,12 +83,12 @@ gem "state_machine"
gem "acts-as-taggable-on", "2.3.3" gem "acts-as-taggable-on", "2.3.3"
# Decorators # Decorators
gem "draper", "~> 0.18.0" gem "draper"
# Background jobs # Background jobs
gem 'slim' gem 'slim'
gem 'sinatra', require: nil gem 'sinatra', require: nil
gem 'sidekiq', '2.7.3' gem 'sidekiq'
# HTTP requests # HTTP requests
gem "httparty" gem "httparty"
...@@ -113,6 +118,7 @@ group :assets do ...@@ -113,6 +118,7 @@ group :assets do
gem 'bootstrap-sass', "2.2.1.1" gem 'bootstrap-sass', "2.2.1.1"
gem "font-awesome-sass-rails", "~> 3.0.0" gem "font-awesome-sass-rails", "~> 3.0.0"
gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' gem "gemoji", "~> 1.2.1", require: 'emoji/railtie'
gem "gon"
end end
group :development do group :development do
...@@ -140,7 +146,7 @@ group :development, :test do ...@@ -140,7 +146,7 @@ group :development, :test do
gem "capybara", '2.0.2' gem "capybara", '2.0.2'
gem "pry" gem "pry"
gem "awesome_print" gem "awesome_print"
gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git" gem "database_cleaner"
gem "launchy" gem "launchy"
gem 'factory_girl_rails' gem 'factory_girl_rails'
......
GIT
remote: https://github.com/bmabey/database_cleaner.git
revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf
specs:
database_cleaner (0.9.1)
GIT GIT
remote: https://github.com/ctran/annotate_models.git remote: https://github.com/ctran/annotate_models.git
revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e
...@@ -13,41 +6,6 @@ GIT ...@@ -13,41 +6,6 @@ GIT
activerecord (>= 2.3.0) activerecord (>= 2.3.0)
rake (>= 0.8.7) rake (>= 0.8.7)
GIT
remote: https://github.com/gitlabhq/grack.git
revision: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
ref: ba46f3b0845c6a09d488ae6abdce6ede37e227e8
specs:
grack (1.0.0)
rack (~> 1.4.1)
GIT
remote: https://github.com/gitlabhq/grit.git
revision: 9e98418ce2d654485b967003726aa2706a10060b
ref: 9e98418ce2d654485b967003726aa2706a10060b
specs:
grit (2.5.0)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
GIT
remote: https://github.com/gitlabhq/grit_ext.git
revision: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
ref: 8e6afc2da821354774aa4d1ee8a1aa2082f84a3e
specs:
grit_ext (0.6.1)
charlock_holmes (~> 0.6.9)
GIT
remote: https://github.com/gitlabhq/pygments.rb.git
revision: db1da0343adf86b49bdc3add04d02d2e80438d38
branch: master
specs:
pygments.rb (0.3.2)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
GIT GIT
remote: https://github.com/gitlabhq/raphael-rails.git remote: https://github.com/gitlabhq/raphael-rails.git
revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58
...@@ -89,12 +47,13 @@ GEM ...@@ -89,12 +47,13 @@ GEM
addressable (2.3.2) addressable (2.3.2)
arel (3.0.2) arel (3.0.2)
awesome_print (1.1.0) awesome_print (1.1.0)
backports (2.6.5) backports (2.6.7)
bcrypt-ruby (3.0.1) bcrypt-ruby (3.0.1)
better_errors (0.3.2) better_errors (0.3.2)
coderay (>= 1.0.0) coderay (>= 1.0.0)
erubis (>= 2.7.0) erubis (>= 2.7.0)
binding_of_caller (0.6.8) binding_of_caller (0.7.1)
debug_inspector (>= 0.0.1)
bootstrap-sass (2.2.1.1) bootstrap-sass (2.2.1.1)
sass (~> 3.2) sass (~> 3.2)
builder (3.0.4) builder (3.0.4)
...@@ -105,7 +64,7 @@ GEM ...@@ -105,7 +64,7 @@ GEM
rack-test (>= 0.5.4) rack-test (>= 0.5.4)
selenium-webdriver (~> 2.0) selenium-webdriver (~> 2.0)
xpath (~> 1.0.0) xpath (~> 1.0.0)
carrierwave (0.7.1) carrierwave (0.8.0)
activemodel (>= 3.2.0) activemodel (>= 3.2.0)
activesupport (>= 3.2.0) activesupport (>= 3.2.0)
celluloid (0.12.4) celluloid (0.12.4)
...@@ -132,18 +91,24 @@ GEM ...@@ -132,18 +91,24 @@ GEM
connection_pool (1.0.0) connection_pool (1.0.0)
crack (0.3.1) crack (0.3.1)
daemons (1.1.9) daemons (1.1.9)
devise (2.1.2) database_cleaner (0.9.1)
debug_inspector (0.0.2)
descendants_tracker (0.0.1)
devise (2.2.3)
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)
diff-lcs (1.1.3) diff-lcs (1.1.3)
draper (0.18.0) draper (1.1.0)
actionpack (~> 3.2) actionpack (>= 3.0)
activesupport (~> 3.2) activesupport (>= 3.0)
request_store (~> 1.0.3)
email_spec (1.4.0) email_spec (1.4.0)
launchy (~> 2.1) launchy (~> 2.1)
mail (~> 2.2) mail (~> 2.2)
enumerize (0.5.1)
activesupport (>= 3.2)
erubis (2.7.0) erubis (2.7.0)
escape_utils (0.2.4) escape_utils (0.2.4)
eventmachine (1.0.0) eventmachine (1.0.0)
...@@ -155,7 +120,7 @@ GEM ...@@ -155,7 +120,7 @@ GEM
factory_girl_rails (4.1.0) factory_girl_rails (4.1.0)
factory_girl (~> 4.1.0) factory_girl (~> 4.1.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faraday (0.8.4) faraday (0.8.6)
multipart-post (~> 1.1) multipart-post (~> 1.1)
faye-websocket (0.4.7) faye-websocket (0.4.7)
eventmachine (>= 0.12.0) eventmachine (>= 0.12.0)
...@@ -164,7 +129,7 @@ GEM ...@@ -164,7 +129,7 @@ GEM
font-awesome-sass-rails (3.0.0.1) font-awesome-sass-rails (3.0.0.1)
railties (>= 3.1.1) railties (>= 3.1.1)
sass-rails (>= 3.1.1) sass-rails (>= 3.1.1)
foreman (0.60.2) foreman (0.61.0)
thor (>= 0.13.6) thor (>= 0.13.6)
gemoji (1.2.1) gemoji (1.2.1)
gherkin-ruby (0.2.1) gherkin-ruby (0.2.1)
...@@ -174,7 +139,16 @@ GEM ...@@ -174,7 +139,16 @@ GEM
escape_utils (~> 0.2.3) escape_utils (~> 0.2.3)
mime-types (~> 1.19) mime-types (~> 1.19)
pygments.rb (>= 0.2.13) pygments.rb (>= 0.2.13)
github-markup (0.7.4) github-markup (0.7.5)
gitlab-grack (1.0.0)
rack (~> 1.4.1)
gitlab-grit (1.0.0)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
posix-spawn (~> 0.3.6)
gitlab-pygments.rb (0.3.2)
posix-spawn (~> 0.3.6)
yajl-ruby (~> 1.1.0)
gitlab_meta (5.0) gitlab_meta (5.0)
gitlab_omniauth-ldap (1.0.2) gitlab_omniauth-ldap (1.0.2)
net-ldap (~> 0.2.2) net-ldap (~> 0.2.2)
...@@ -182,17 +156,22 @@ GEM ...@@ -182,17 +156,22 @@ GEM
pyu-ruby-sasl (~> 0.0.3.1) pyu-ruby-sasl (~> 0.0.3.1)
rubyntlm (~> 0.1.1) rubyntlm (~> 0.1.1)
gitlab_yaml_db (1.0.0) gitlab_yaml_db (1.0.0)
grape (0.3.1) gon (4.0.2)
grape (0.3.2)
activesupport activesupport
grape-entity (~> 0.2.0) builder
hashie (~> 1.2) hashie (>= 1.2.0)
multi_json (>= 1.3.2) multi_json (>= 1.3.2)
multi_xml multi_xml (>= 0.5.2)
rack rack
rack-accept rack-accept
rack-mount rack-mount
virtus virtus
grape-entity (0.2.0) grape-entity (0.2.0)
activesupport
multi_json (>= 1.3.2)
grit_ext (0.6.2)
charlock_holmes (~> 0.6.9)
growl (1.0.3) growl (1.0.3)
guard (1.5.4) guard (1.5.4)
listen (>= 0.4.2) listen (>= 0.4.2)
...@@ -205,20 +184,21 @@ GEM ...@@ -205,20 +184,21 @@ GEM
guard-spinach (0.0.2) guard-spinach (0.0.2)
guard (>= 1.1) guard (>= 1.1)
spinach spinach
haml (3.1.7) haml (4.0.0)
haml-rails (0.3.5) tilt
haml-rails (0.4)
actionpack (>= 3.1, < 4.1) actionpack (>= 3.1, < 4.1)
activesupport (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1)
haml (~> 3.1) haml (>= 3.1, < 4.1)
railties (>= 3.1, < 4.1) railties (>= 3.1, < 4.1)
hashie (1.2.0) hashie (1.2.0)
hike (1.2.1) hike (1.2.1)
http_parser.rb (0.5.3) http_parser.rb (0.5.3)
httparty (0.9.0) httparty (0.10.2)
multi_json (~> 1.0) multi_json (~> 1.0)
multi_xml multi_xml (>= 0.5.2)
httpauth (0.2.0) httpauth (0.2.0)
i18n (0.6.1) i18n (0.6.4)
journey (1.0.4) journey (1.0.4)
jquery-atwho-rails (0.1.7) jquery-atwho-rails (0.1.7)
jquery-rails (2.1.3) jquery-rails (2.1.3)
...@@ -233,7 +213,7 @@ GEM ...@@ -233,7 +213,7 @@ GEM
kaminari (0.14.1) kaminari (0.14.1)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
kgio (2.7.4) kgio (2.8.0)
launchy (2.1.2) launchy (2.1.2)
addressable (~> 2.3) addressable (~> 2.3)
letter_opener (1.0.0) letter_opener (1.0.0)
...@@ -250,22 +230,22 @@ GEM ...@@ -250,22 +230,22 @@ GEM
modernizr (2.6.2) modernizr (2.6.2)
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.6.1) multi_json (1.6.1)
multi_xml (0.5.1) multi_xml (0.5.3)
multipart-post (1.1.5) multipart-post (1.2.0)
mysql2 (0.3.11) mysql2 (0.3.11)
net-ldap (0.2.2) net-ldap (0.2.2)
nokogiri (1.5.6) nokogiri (1.5.6)
oauth (0.4.7) oauth (0.4.7)
oauth2 (0.8.0) oauth2 (0.8.1)
faraday (~> 0.8) faraday (~> 0.8)
httpauth (~> 0.1) httpauth (~> 0.1)
jwt (~> 0.1.4) jwt (~> 0.1.4)
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.2) rack (~> 1.2)
omniauth (1.1.1) omniauth (1.1.3)
hashie (~> 1.2) hashie (~> 1.2)
rack rack
omniauth-github (1.0.3) omniauth-github (1.1.0)
omniauth (~> 1.0) omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1) omniauth-oauth2 (~> 1.1)
omniauth-google-oauth2 (0.1.13) omniauth-google-oauth2 (0.1.13)
...@@ -293,6 +273,9 @@ GEM ...@@ -293,6 +273,9 @@ GEM
coderay (~> 1.0.5) coderay (~> 1.0.5)
method_source (~> 0.8) method_source (~> 0.8)
slop (~> 3.3.1) slop (~> 3.3.1)
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.1) quiet_assets (1.0.1)
railties (~> 3.1) railties (~> 3.1)
...@@ -305,7 +288,7 @@ GEM ...@@ -305,7 +288,7 @@ GEM
rack (>= 1.1.3) rack (>= 1.1.3)
rack-mount (0.8.3) rack-mount (0.8.3)
rack (>= 1.0.0) rack (>= 1.0.0)
rack-protection (1.3.2) rack-protection (1.4.0)
rack rack
rack-ssl (1.3.3) rack-ssl (1.3.3)
rack rack
...@@ -342,12 +325,13 @@ GEM ...@@ -342,12 +325,13 @@ GEM
rb-fsevent (0.9.2) rb-fsevent (0.9.2)
rb-inotify (0.8.8) rb-inotify (0.8.8)
ffi (>= 0.5.0) ffi (>= 0.5.0)
rdoc (3.12.1) rdoc (3.12.2)
json (~> 1.4) json (~> 1.4)
redcarpet (2.2.2) redcarpet (2.2.2)
redis (3.0.2) redis (3.0.2)
redis-namespace (1.2.1) redis-namespace (1.2.1)
redis (~> 3.0.0) redis (~> 3.0.0)
request_store (1.0.5)
rspec (2.12.0) rspec (2.12.0)
rspec-core (~> 2.12.0) rspec-core (~> 2.12.0)
rspec-expectations (~> 2.12.0) rspec-expectations (~> 2.12.0)
...@@ -381,11 +365,11 @@ GEM ...@@ -381,11 +365,11 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
rubyzip rubyzip
websocket (~> 1.0.4) websocket (~> 1.0.4)
settingslogic (2.0.8) settingslogic (2.0.9)
sexp_processor (4.1.3) sexp_processor (4.1.3)
shoulda-matchers (1.3.0) shoulda-matchers (1.3.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
sidekiq (2.7.3) sidekiq (2.7.5)
celluloid (~> 0.12.0) celluloid (~> 0.12.0)
connection_pool (~> 1.0) connection_pool (~> 1.0)
multi_json (~> 1) multi_json (~> 1)
...@@ -395,9 +379,9 @@ GEM ...@@ -395,9 +379,9 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
simplecov-html (~> 0.7.1) simplecov-html (~> 0.7.1)
simplecov-html (0.7.1) simplecov-html (0.7.1)
sinatra (1.3.3) sinatra (1.3.5)
rack (~> 1.3, >= 1.3.6) rack (~> 1.4)
rack-protection (~> 1.2) rack-protection (~> 1.3)
tilt (~> 1.3, >= 1.3.3) tilt (~> 1.3, >= 1.3.3)
six (0.2.0) six (0.2.0)
slim (1.3.6) slim (1.3.6)
...@@ -416,7 +400,7 @@ GEM ...@@ -416,7 +400,7 @@ GEM
multi_json (~> 1.0) multi_json (~> 1.0)
rack (~> 1.0) rack (~> 1.0)
tilt (~> 1.1, != 1.3.0) tilt (~> 1.1, != 1.3.0)
stamp (0.3.0) stamp (0.5.0)
state_machine (1.1.2) state_machine (1.1.2)
temple (0.5.5) temple (0.5.5)
test_after_commit (0.0.1) test_after_commit (0.0.1)
...@@ -427,7 +411,7 @@ GEM ...@@ -427,7 +411,7 @@ GEM
eventmachine (>= 0.12.6) eventmachine (>= 0.12.6)
rack (>= 1.0.0) rack (>= 1.0.0)
thor (0.17.0) thor (0.17.0)
tilt (1.3.3) tilt (1.3.4)
timers (1.1.0) timers (1.1.0)
treetop (1.4.12) treetop (1.4.12)
polyglot polyglot
...@@ -436,12 +420,13 @@ GEM ...@@ -436,12 +420,13 @@ GEM
uglifier (1.3.0) uglifier (1.3.0)
execjs (>= 0.3.0) execjs (>= 0.3.0)
multi_json (~> 1.0, >= 1.0.2) multi_json (~> 1.0, >= 1.0.2)
unicorn (4.4.0) unicorn (4.6.2)
kgio (~> 2.6) kgio (~> 2.6)
rack rack
raindrops (~> 0.7) raindrops (~> 0.7)
virtus (0.5.2) virtus (0.5.4)
backports (~> 2.6.1) backports (~> 2.6.1)
descendants_tracker (~> 0.0.1)
warden (1.2.1) warden (1.2.1)
rack (>= 1.0) rack (>= 1.0)
webmock (1.9.0) webmock (1.9.0)
...@@ -463,14 +448,15 @@ DEPENDENCIES ...@@ -463,14 +448,15 @@ DEPENDENCIES
binding_of_caller binding_of_caller
bootstrap-sass (= 2.2.1.1) bootstrap-sass (= 2.2.1.1)
capybara (= 2.0.2) capybara (= 2.0.2)
carrierwave (~> 0.7.1) carrierwave
chosen-rails (= 0.9.8) chosen-rails (= 0.9.8)
coffee-rails (~> 3.2.2) coffee-rails (~> 3.2.2)
colored colored
database_cleaner! database_cleaner
devise (~> 2.1.0) devise
draper (~> 0.18.0) draper
email_spec email_spec
enumerize
factory_girl_rails factory_girl_rails
ffaker ffaker
font-awesome-sass-rails (~> 3.0.0) font-awesome-sass-rails (~> 3.0.0)
...@@ -479,18 +465,20 @@ DEPENDENCIES ...@@ -479,18 +465,20 @@ DEPENDENCIES
git git
github-linguist (~> 2.3.4) github-linguist (~> 2.3.4)
github-markup (~> 0.7.4) github-markup (~> 0.7.4)
gitlab-grack (~> 1.0.0)
gitlab-grit (~> 1.0.0)
gitlab-pygments.rb (~> 0.3.2)
gitlab_meta (= 5.0) gitlab_meta (= 5.0)
gitlab_omniauth-ldap (= 1.0.2) gitlab_omniauth-ldap (= 1.0.2)
gitlab_yaml_db (= 1.0.0) gitlab_yaml_db (= 1.0.0)
grack! gon
grape (~> 0.3.1) grape (~> 0.3.1)
grape-entity (~> 0.2.0) grape-entity (~> 0.2.0)
grit! grit_ext (~> 0.6.2)
grit_ext!
growl growl
guard-rspec guard-rspec
guard-spinach guard-spinach
haml-rails (~> 0.3.5) haml-rails
httparty httparty
jquery-atwho-rails (= 0.1.7) jquery-atwho-rails (= 0.1.7)
jquery-rails (= 2.1.3) jquery-rails (= 2.1.3)
...@@ -500,14 +488,13 @@ DEPENDENCIES ...@@ -500,14 +488,13 @@ DEPENDENCIES
letter_opener letter_opener
modernizr (= 2.6.2) modernizr (= 2.6.2)
mysql2 mysql2
omniauth (~> 1.1.1) omniauth (~> 1.1.3)
omniauth-github omniauth-github
omniauth-google-oauth2 omniauth-google-oauth2
omniauth-twitter omniauth-twitter
pg pg
poltergeist (= 1.1.0) poltergeist (= 1.1.0)
pry pry
pygments.rb!
quiet_assets (~> 1.0.1) quiet_assets (~> 1.0.1)
rack-mini-profiler rack-mini-profiler
rails (= 3.2.12) rails (= 3.2.12)
...@@ -523,7 +510,7 @@ DEPENDENCIES ...@@ -523,7 +510,7 @@ DEPENDENCIES
seed-fu seed-fu
settingslogic settingslogic
shoulda-matchers (= 1.3.0) shoulda-matchers (= 1.3.0)
sidekiq (= 2.7.3) sidekiq
simplecov simplecov
sinatra sinatra
six six
...@@ -535,5 +522,5 @@ DEPENDENCIES ...@@ -535,5 +522,5 @@ DEPENDENCIES
therubyracer therubyracer
thin thin
uglifier (~> 1.3.0) uglifier (~> 1.3.0)
unicorn (~> 4.4.0) unicorn
webmock webmock
# Welcome to GitLab! Self hosted Git management software ## GitLab: self hosted Git management software
![logo](https://raw.github.com/gitlabhq/gitlabhq/master/public/gitlab_logo.png)
## Badges: ### GitLab allows you to
* keep your code secure on your own server
* manage repositories, users and access permissions
* communicate though issues, line-comments and wiki's
* perform code reviews with merge requests
### GitLab is
* powered by Ruby on Rails
* completely free and open source (MIT license)
* used by 10.000 organization to keep their code secure
### Code status
* [![build status](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master) ci.gitlab.org (master branch)
* [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq) travis-ci.org (master branch)
* [![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
* master: travis-ci.org [![build status](https://secure.travis-ci.org/gitlabhq/gitlabhq.png)](https://travis-ci.org/gitlabhq/gitlabhq)a
* master: ci.gitlab.org [![CI](http://ci.gitlab.org/projects/1/status?ref=master)](http://ci.gitlab.org/projects/1?ref=master)
* [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/gitlabhq/gitlabhq)
* [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq) * [![Dependency Status](https://gemnasium.com/gitlabhq/gitlabhq.png)](https://gemnasium.com/gitlabhq/gitlabhq)
GitLab is a free project and repository management application ### Resources
* GitLab.org community site: [Homepage](http://gitlab.org) [Screenshots](http://gitlab.org/screenshots/) [Blog](http://blog.gitlab.org/) [Demo](http://demo.gitlabhq.com/users/sign_in)
## Application details * GitLab.com: [Homepage](http://blog.gitlab.com/) [Hosted pricing](http://blog.gitlab.com/pricing/) [Services](http://blog.gitlab.com/services/) [Blog](http://blog.gitlab.com/blog/)
* powered by Ruby on Rails * GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server
* its completely free and open source
* distributed under the MIT License
## Requirements ### Requirements
* Ubuntu/Debian * Ubuntu/Debian*
* ruby 1.9.3+ * ruby 1.9.3+
* MySQL * MySQL
* git * git
* gitlab-shell * gitlab-shell
* redis * redis
## Install * More details are in the [requirements doc](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/requirements.md)
### Installation
You can either follow the "ordinary" Installation guide to install it on a machine or use the Vagrant virtual machine. The Installation guide is recommended to set up a production server. The Vargrant virtual machine is recommended for development since it makes it much easier to set up all the dependencies for integration testing.
* [Installation guide for latest stable release](https://github.com/gitlabhq/gitlabhq/blob/4-2-stable/doc/install/installation.md)
* [Installation guide for the current master branch](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md)
* [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm)
### Starting
1. The Installation guide contains instructions to download an init script and run that on boot. With the init script you can also start GitLab with:
sudo service gitlab start
or
sudo /etc/init.d/gitlab restart
2. Start it with [Foreman](https://github.com/ddollar/foreman) in development model
bundle exec foreman start -p 3000
3. Start it manually in development mode
bundle exec rails s
bundle exec rake sidekiq:start
### Running the tests
* Seed the database with
bundle exec rake db:setup RAILS_ENV=test
bundle exec rake db:seed_fu RAILS_ENV=test
* Run all tests
bundle exec rake gitlab:test
* Rspec unit and functional tests
bundle exec rake spec
* Spinach integration tests
bundle exec rake spinach
### Getting help
* [Troubleshooting guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide)
* [Support forum](https://groups.google.com/forum/#!forum/gitlabhq)
* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general)
* [Paid support](http://blog.gitlab.com/support/)
* [Paid services](http://blog.gitlab.com/services/)
### New versions and the API
Each month on the 22th a new version is released together with an upgrade guide.
* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki)
* [Roadmap](https://github.com/gitlabhq/gitlabhq/blob/master/ROADMAP.md)
### Other documentation
* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md)
* [Rake tasks](https://github.com/gitlabhq/gitlabhq/tree/master/doc/raketasks)
* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes)
### Getting in touch
Checkout [wiki](https://github.com/gitlabhq/gitlabhq/wiki) pages for installation information, migration, etc. * [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md)
## [Community](http://gitlab.org/community/) * [Core team](https://github.com/gitlabhq?tab=members)
## [Contact](http://gitlab.org/contact/) * [Contributors](https://github.com/gitlabhq/gitlabhq/graphs/contributors)
## Contribute * [Leader](https://github.com/randx)
[Developer Guide](https://github.com/gitlabhq/gitlabhq/wiki/Developer-Guide) * [Contact page](http://gitlab.org/contact/)
Want to help - send a pull request.
We'll accept good pull requests.
...@@ -5,8 +5,3 @@ ...@@ -5,8 +5,3 @@
* Replace gitolite with gitlab-shell * Replace gitolite with gitlab-shell
* Usability improvements * Usability improvements
* Notification improvements * Notification improvements
### v4.2 February 22
* Teams
Copyright (c) 2010, Jan Gerner (post@yanone.de)
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.
...@@ -132,9 +132,10 @@ ...@@ -132,9 +132,10 @@
}); });
} else if (c.space < this.commits[i].space) { } else if (c.space < this.commits[i].space) {
if (y == psy) {
r.path([ r.path([
"M", x - 5, y, "M", x - 5, y,
"l-5-2,0,4,5,-2", "l-5,-2,0,4,5,-2",
"L", x - 10, y, "L", x - 10, y,
"L", x - 15, psy, "L", x - 15, psy,
"L", cx + 5, psy, "L", cx + 5, psy,
...@@ -143,6 +144,19 @@ ...@@ -143,6 +144,19 @@
stroke: this.colors[this.commits[i].space], stroke: this.colors[this.commits[i].space],
"stroke-width": 2 "stroke-width": 2
}); });
} else {
r.path([
"M", x - 3, y - 6,
"l-4,-3,4,-2,0,5",
"L", x - 5, y - 10,
"L", x - 10, psy,
"L", cx + 5, psy,
"L", cx, cy])
.attr({
stroke: this.colors[this.commits[i].space],
"stroke-width": 2
});
}
} else { } else {
r.path([ r.path([
"M", x - 3, y + 6, "M", x - 3, y + 6,
...@@ -306,15 +320,16 @@ ...@@ -306,15 +320,16 @@
}(this); }(this);
Raphael.fn.commitTooltip = function(x, y, commit){ Raphael.fn.commitTooltip = function(x, y, commit){
var nameText, idText, messageText var icon, nameText, idText, messageText
, boxWidth = 300 , boxWidth = 300
, boxHeight = 200; , boxHeight = 200;
nameText = this.text(x, y + 10, commit.author.name); icon = this.image(commit.author.icon, x, y, 20, 20);
nameText = this.text(x + 25, y + 10, commit.author.name);
idText = this.text(x, y + 35, commit.id); idText = this.text(x, y + 35, commit.id);
messageText = this.text(x, y + 50, commit.message); messageText = this.text(x, y + 50, commit.message);
textSet = this.set(nameText, idText, messageText).attr({ textSet = this.set(icon, nameText, idText, messageText).attr({
"text-anchor": "start", "text-anchor": "start",
"font": "12px Monaco, monospace" "font": "12px Monaco, monospace"
}); });
......
...@@ -54,10 +54,10 @@ $ -> ...@@ -54,10 +54,10 @@ $ ->
$(@).parents('form').submit() $(@).parents('form').submit()
# Flash # Flash
if (flash = $("#flash-container")).length > 0 if (flash = $(".flash-container")).length > 0
flash.click -> $(@).slideUp("slow") flash.click -> $(@).fadeOut()
flash.slideDown "slow" flash.show()
setTimeout (-> flash.slideUp("slow")), 3000 setTimeout (-> flash.fadeOut()), 3000
# Disable form buttons while a form is submitting # Disable form buttons while a form is submitting
$('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) ->
......
...@@ -18,3 +18,18 @@ $ -> ...@@ -18,3 +18,18 @@ $ ->
# Ref switcher # Ref switcher
$('.project-refs-select').on 'change', -> $('.project-refs-select').on 'change', ->
$(@).parents('form').submit() $(@).parents('form').submit()
$('#project_issues_enabled').change ->
if ($(this).is(':checked') == true)
$('#project_issues_tracker').removeAttr('disabled')
else
$('#project_issues_tracker').attr('disabled', 'disabled')
$('#project_issues_tracker').change()
$('#project_issues_tracker').change ->
if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
$('#project_issues_tracker_id').attr('disabled', 'disabled')
else
$('#project_issues_tracker_id').removeAttr('disabled')
...@@ -67,27 +67,17 @@ table a code { ...@@ -67,27 +67,17 @@ table a code {
} }
/** FLASH message **/ /** FLASH message **/
#flash-container { .flash-container {
height: 50px; display: none;
position: fixed; .alert {
z-index: 10001;
top: 0px;
width: 100%;
margin-bottom: 15px;
overflow: hidden;
background: white;
cursor: pointer; cursor: pointer;
border-bottom: 1px solid #ccc; margin: 0;
text-align: center; text-align: center;
display: none; border-radius: 0;
h4 { span {
color: #666; font-size: 14px;
font-size: 18px; }
line-height: 38px;
padding-top: 5px;
margin: 2px;
font-weight: normal;
} }
} }
...@@ -203,10 +193,6 @@ input[type=text] { ...@@ -203,10 +193,6 @@ input[type=text] {
} }
} }
input.git_clone_url {
width: 325px;
}
.merge-request-form-holder { .merge-request-form-holder {
select { select {
width: 300px; width: 300px;
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
border-color: #DDD; border-color: #DDD;
} }
.well { padding: 15px; }
/** HELPERS **/ /** HELPERS **/
.nothing_here_message { .nothing_here_message {
text-align: center; text-align: center;
......
@font-face{
font-family: Yanone;
src: font-url('YanoneKaffeesatz-Light.ttf');
}
/** Typo **/ /** Typo **/
$monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace;
...@@ -70,8 +70,19 @@ ...@@ -70,8 +70,19 @@
@mixin header-font { @mixin header-font {
color: $style_color; color: $style_color;
text-shadow: 0 1px 1px #FFF; text-shadow: 0 1px 1px #FFF;
font-family: 'Yanone', sans-serif; font-size: 18px;
font-size: 24px; line-height: 42px;
line-height: 36px;
font-weight: normal; font-weight: normal;
letter-spacing: -1px;
}
@mixin md-typography {
code { padding: 0 4px; }
p { font-size: 13px; }
h1 { font-size: 26px; line-height: 40px; margin: 10px 0;}
h2 { font-size: 22px; line-height: 40px; margin: 10px 0;}
h3 { font-size: 18px; line-height: 40px; margin: 10px 0;}
h4 { font-size: 16px; line-height: 20px; margin: 10px 0;}
h5 { font-size: 14px; line-height: 20px; margin: 10px 0;}
h6 { font-size: 12px; line-height: 20px; margin: 10px 0;}
} }
...@@ -87,16 +87,15 @@ a:focus { ...@@ -87,16 +87,15 @@ a:focus {
* *
*/ */
.wiki { .wiki {
@include md-typography;
font-size: 13px; font-size: 13px;
line-height: 20px;
code { padding: 0 4px; }
p { font-size: 13px; }
h1 { font-size: 32px; line-height: 40px; margin: 10px 0;}
h2 { font-size: 26px; line-height: 40px; margin: 10px 0;}
h3 { font-size: 22px; line-height: 40px; margin: 10px 0;}
h4 { font-size: 18px; line-height: 20px; margin: 10px 0;}
h5 { font-size: 14px; line-height: 20px; margin: 10px 0;}
h6 { font-size: 12px; line-height: 20px; margin: 10px 0;}
.white .highlight pre { background: #f5f5f5; } .white .highlight pre { background: #f5f5f5; }
ul { margin: 0 0 9px 25px !important; } ul { margin: 0 0 9px 25px !important; }
} }
.md {
@include md-typography;
}
.black .highlight { .black .highlight {
background-color: #333;
pre { pre {
background-color: #333;
color: #eee; color: #eee;
background: inherit;
} }
.hll { display: block; background-color: darken($hover, 65%) } .hll { display: block; background-color: darken($hover, 65%) }
......
...@@ -100,8 +100,9 @@ ...@@ -100,8 +100,9 @@
} }
} }
.line_content { .line_content {
display: block;
white-space: pre; white-space: pre;
height: 14px; height: 18px;
margin: 0px; margin: 0px;
padding: 0px; padding: 0px;
border: none; border: none;
......
...@@ -48,15 +48,13 @@ ...@@ -48,15 +48,13 @@
color: #666; color: #666;
} }
.event-note { .event-note {
padding-top: 5px;
padding-left: 5px;
display: inline-block;
color: #555; color: #555;
margin-top: 5px;
margin-left: 40px;
.note-file-attach { .note-file-attach {
margin-left: -25px;
float: left;
.note-image-attach { .note-image-attach {
margin-top: 4px;
margin-left: 0px; margin-left: 0px;
max-width: 200px; max-width: 200px;
} }
...@@ -66,8 +64,8 @@ ...@@ -66,8 +64,8 @@
color: #777; color: #777;
float: left; float: left;
font-size: 16px; font-size: 16px;
line-height: 18px; line-height: 16px;
margin: 5px; margin-right: 5px;
} }
} }
.avatar { .avatar {
......
...@@ -67,7 +67,7 @@ header { ...@@ -67,7 +67,7 @@ header {
position: relative; position: relative;
float: left; float: left;
margin: 0; margin: 0;
margin-left: 15px; margin-left: 10px;
@include header-font; @include header-font;
} }
......
/* Login Page */ /* Login Page */
body.login-page{ body.login-page{
padding-top: 7%; background: #EEE;
background: #666; .container .content { padding-top: 5%; }
} }
.login-box{ .login-box{
......
...@@ -83,6 +83,7 @@ ul.notes { ...@@ -83,6 +83,7 @@ ul.notes {
margin-top: -20px; margin-top: -20px;
} }
.note-body { .note-body {
@include md-typography;
margin-left: 45px; margin-left: 45px;
} }
.note-header { .note-header {
......
...@@ -80,6 +80,7 @@ ...@@ -80,6 +80,7 @@
border: 1px solid #BBB; border: 1px solid #BBB;
box-shadow: none; box-shadow: none;
margin-left: -1px; margin-left: -1px;
background: #FFF;
} }
} }
......
...@@ -7,12 +7,13 @@ class IssuesListContext < BaseContext ...@@ -7,12 +7,13 @@ class IssuesListContext < BaseContext
@issues = case params[:status] @issues = case params[:status]
when issues_filter[:all] then @project.issues when issues_filter[:all] then @project.issues
when issues_filter[:closed] then @project.issues.closed when issues_filter[:closed] then @project.issues.closed
when issues_filter[:to_me] then @project.issues.opened.assigned(current_user) when issues_filter[:to_me] then @project.issues.assigned(current_user)
when issues_filter[:by_me] then @project.issues.authored(current_user)
else @project.issues.opened else @project.issues.opened
end end
@issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present? @issues = @issues.tagged_with(params[:label_name]) if params[:label_name].present?
@issues = @issues.includes(:author, :project).order("updated_at") @issues = @issues.includes(:author, :project)
# Filter by specific assignee_id (or lack thereof)? # Filter by specific assignee_id (or lack thereof)?
if params[:assignee_id].present? if params[:assignee_id].present?
......
class Admin::Teams::MembersController < Admin::Teams::ApplicationController class Admin::Teams::MembersController < Admin::Teams::ApplicationController
def new def new
@users = User.potential_team_members(user_team) @users = User.potential_team_members(user_team)
@users = UserDecorator.decorate @users @users = UserDecorator.decorate_collection @users
end end
def create def create
......
...@@ -45,7 +45,7 @@ class Admin::UsersController < Admin::ApplicationController ...@@ -45,7 +45,7 @@ class Admin::UsersController < Admin::ApplicationController
end end
def unblock def unblock
if admin_user.update_attribute(:blocked, false) if admin_user.activate
redirect_to :back, alert: "Successfully unblocked" redirect_to :back, alert: "Successfully unblocked"
else else
redirect_to :back, alert: "Error occured. User was not unblocked" redirect_to :back, alert: "Error occured. User was not unblocked"
......
...@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base ...@@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base
before_filter :add_abilities before_filter :add_abilities
before_filter :dev_tools if Rails.env == 'development' before_filter :dev_tools if Rails.env == 'development'
before_filter :default_headers before_filter :default_headers
before_filter :add_gon_variables
protect_from_forgery protect_from_forgery
...@@ -29,7 +30,7 @@ class ApplicationController < ActionController::Base ...@@ -29,7 +30,7 @@ class ApplicationController < ActionController::Base
end end
def reject_blocked! def reject_blocked!
if current_user && current_user.blocked if current_user && current_user.blocked?
sign_out current_user sign_out current_user
flash[:alert] = "Your account is blocked. Retry when an admin unblock it." flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
redirect_to new_user_session_path redirect_to new_user_session_path
...@@ -37,7 +38,7 @@ class ApplicationController < ActionController::Base ...@@ -37,7 +38,7 @@ class ApplicationController < ActionController::Base
end end
def after_sign_in_path_for resource def after_sign_in_path_for resource
if resource.is_a?(User) && resource.respond_to?(:blocked) && resource.blocked if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
sign_out resource sign_out resource
flash[:alert] = "Your account is blocked. Retry when an admin unblock it." flash[:alert] = "Your account is blocked. Retry when an admin unblock it."
new_user_session_path new_user_session_path
...@@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base ...@@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base
headers['X-Frame-Options'] = 'DENY' headers['X-Frame-Options'] = 'DENY'
headers['X-XSS-Protection'] = '1; mode=block' headers['X-XSS-Protection'] = '1; mode=block'
end end
def add_gon_variables
gon.default_issues_tracker = Project.issues_tracker.default_value
end
end end
...@@ -13,7 +13,7 @@ class CommitsController < ProjectResourceController ...@@ -13,7 +13,7 @@ class CommitsController < ProjectResourceController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset) @commits = @repo.commits(@ref, @path, @limit, @offset)
@commits = CommitDecorator.decorate(@commits) @commits = CommitDecorator.decorate_collection(@commits)
respond_to do |format| respond_to do |format|
format.html # index.html.erb format.html # index.html.erb
......
...@@ -16,7 +16,7 @@ class CompareController < ProjectResourceController ...@@ -16,7 +16,7 @@ class CompareController < ProjectResourceController
@refs_are_same = result[:same] @refs_are_same = result[:same]
@line_notes = [] @line_notes = []
@commits = CommitDecorator.decorate(@commits) @commits = CommitDecorator.decorate_collection(@commits)
end end
def create def create
......
class GraphController < ProjectResourceController class GraphController < ProjectResourceController
include ExtractsPath include ExtractsPath
include ApplicationHelper
# Authorize # Authorize
before_filter :authorize_read_project! before_filter :authorize_read_project!
...@@ -20,7 +21,10 @@ class GraphController < ProjectResourceController ...@@ -20,7 +21,10 @@ class GraphController < ProjectResourceController
respond_to do |format| respond_to do |format|
format.html format.html
format.json do format.json do
graph = Gitlab::Graph::JsonBuilder.new(project, @ref, @commit) graph = Graph::JsonBuilder.new(project, @ref, @commit)
graph.commits.each do |c|
c.icon = gravatar_icon(c.author.email)
end
render :json => graph.to_json render :json => graph.to_json
end end
end end
......
...@@ -81,7 +81,8 @@ class MergeRequestsController < ProjectResourceController ...@@ -81,7 +81,8 @@ class MergeRequestsController < ProjectResourceController
end end
def automerge def automerge
return access_denied! unless can?(current_user, :accept_mr, @project) return access_denied! unless allowed_to_merge?
if @merge_request.opened? && @merge_request.can_be_merged? if @merge_request.opened? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch] @merge_request.should_remove_source_branch = params[:should_remove_source_branch]
@merge_request.automerge!(current_user) @merge_request.automerge!(current_user)
...@@ -142,6 +143,19 @@ class MergeRequestsController < ProjectResourceController ...@@ -142,6 +143,19 @@ class MergeRequestsController < ProjectResourceController
# Get commits from repository # Get commits from repository
# or from cache if already merged # or from cache if already merged
@commits = @merge_request.commits @commits = @merge_request.commits
@commits = CommitDecorator.decorate(@commits) @commits = CommitDecorator.decorate_collection(@commits)
@allowed_to_merge = allowed_to_merge?
@show_merge_controls = @merge_request.opened? && @commits.any? && @allowed_to_merge
end
def allowed_to_merge?
action = if project.protected_branch?(@merge_request.target_branch)
:push_code_to_protected_branches
else
:push_code
end
can?(current_user, action, @project)
end end
end end
...@@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController ...@@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController
def show def show
@issues = @milestone.issues @issues = @milestone.issues
@users = UserDecorator.decorate(@milestone.participants) @users = UserDecorator.decorate_collection(@milestone.participants)
@merge_requests = @milestone.merge_requests @merge_requests = @milestone.merge_requests
respond_to do |format| respond_to do |format|
......
require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder')
class ProjectsController < ProjectResourceController class ProjectsController < ProjectResourceController
skip_before_filter :project, only: [:new, :create] skip_before_filter :project, only: [:new, :create]
skip_before_filter :repository, only: [:new, :create] skip_before_filter :repository, only: [:new, :create]
......
...@@ -8,7 +8,7 @@ class Teams::MembersController < Teams::ApplicationController ...@@ -8,7 +8,7 @@ class Teams::MembersController < Teams::ApplicationController
def new def new
@users = User.potential_team_members(user_team) @users = User.potential_team_members(user_team)
@users = UserDecorator.decorate @users @users = UserDecorator.decorate_collection @users
end end
def create def create
......
class ApplicationDecorator < Draper::Base class ApplicationDecorator < Draper::Decorator
delegate_all
# Lazy Helpers # Lazy Helpers
# PRO: Call Rails helpers without the h. proxy # PRO: Call Rails helpers without the h. proxy
# ex: number_to_currency(model.price) # ex: number_to_currency(model.price)
......
...@@ -164,7 +164,8 @@ module ApplicationHelper ...@@ -164,7 +164,8 @@ module ApplicationHelper
end end
def image_url(source) def image_url(source)
root_url + path_to_image(source) # prevent relative_root_path being added twice (it's part of root_url and path_to_image)
root_url.sub(/#{root_path}$/, path_to_image(source))
end end
alias_method :url_to_image, :image_url alias_method :url_to_image, :image_url
......
...@@ -27,6 +27,7 @@ module IssuesHelper ...@@ -27,6 +27,7 @@ module IssuesHelper
all: "all", all: "all",
closed: "closed", closed: "closed",
to_me: "assigned-to-me", to_me: "assigned-to-me",
by_me: "created-by-me",
open: "open" open: "open"
} }
end end
...@@ -40,4 +41,39 @@ module IssuesHelper ...@@ -40,4 +41,39 @@ module IssuesHelper
def issues_active_milestones def issues_active_milestones
@project.milestones.active.order("id desc").all @project.milestones.active.order("id desc").all
end end
def url_for_project_issues
return "" if @project.nil?
if @project.used_default_issues_tracker?
project_issues_filter_path(@project)
else
url = Settings[:issues_tracker][@project.issues_tracker]["project_url"]
url.gsub(':project_id', @project.id.to_s)
.gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
end
end
def url_for_issue(issue_id)
return "" if @project.nil?
if @project.used_default_issues_tracker?
url = project_issue_url project_id: @project, id: issue_id
else
url = Settings[:issues_tracker][@project.issues_tracker]["issues_url"]
url.gsub(':id', issue_id.to_s)
.gsub(':project_id', @project.id.to_s)
.gsub(':issues_tracker_id', @project.issues_tracker_id.to_s)
end
end
def title_for_issue(issue_id)
return "" if @project.nil?
if @project.used_default_issues_tracker? && issue = @project.issues.where(id: issue_id).first
issue.title
else
""
end
end
end end
...@@ -13,13 +13,15 @@ module TreeHelper ...@@ -13,13 +13,15 @@ module TreeHelper
tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present?
files.each do |f| files.each do |f|
if f.respond_to?(:url) html = if f.respond_to?(:url)
# Object is a Submodule # Object is a Submodule
tree += render partial: 'tree/submodule_item', object: f render partial: 'tree/submodule_item', object: f
else else
# Object is a Blob # Object is a Blob
tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'} render partial: 'tree/tree_item', object: f, locals: {type: 'file'}
end end
tree += html if html.present?
end end
tree.html_safe tree.html_safe
......
...@@ -91,7 +91,6 @@ class Ability ...@@ -91,7 +91,6 @@ class Ability
:admin_team_member, :admin_team_member,
:admin_merge_request, :admin_merge_request,
:admin_note, :admin_note,
:accept_mr,
:admin_wiki, :admin_wiki,
:admin_project :admin_project
] ]
......
require "grit"
module Graph
class Commit
include ActionView::Helpers::TagHelper
attr_accessor :time, :spaces, :refs, :parent_spaces, :icon
def initialize(commit)
@_commit = commit
@time = -1
@spaces = []
@parent_spaces = []
end
def method_missing(m, *args, &block)
@_commit.send(m, *args, &block)
end
def to_graph_hash
h = {}
h[:parents] = self.parents.collect do |p|
[p.id,0,0]
end
h[:author] = {
name: author.name,
email: author.email,
icon: icon
}
h[:time] = time
h[:space] = spaces.first
h[:parent_spaces] = parent_spaces
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
h[:message] = message
h
end
def add_refs(ref_cache, repo)
if ref_cache.empty?
repo.refs.each do |ref|
ref_cache[ref.commit.id] ||= []
ref_cache[ref.commit.id] << ref
end
end
@refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
@refs ||= []
end
def space
if @spaces.size > 0
@spaces.first
else
0
end
end
end
end
require "grit"
module Graph
class JsonBuilder
attr_accessor :days, :commits, :ref_cache, :repo
def self.max_count
@max_count ||= 650
end
def initialize project, ref, commit
@project = project
@ref = ref
@commit = commit
@repo = project.repo
@ref_cache = {}
@commits = collect_commits
@days = index_commits
end
def to_json(*args)
{
days: @days.compact.map { |d| [d.day, d.strftime("%b")] },
commits: @commits.map(&:to_graph_hash)
}.to_json(*args)
end
protected
# Get commits from repository
#
def collect_commits
@commits = Grit::Commit.find_all(repo, nil, {date_order: true, max_count: self.class.max_count, skip: to_commit}).dup
# Decorate with app/models/commit.rb
@commits.map! { |commit| Commit.new(commit) }
# Decorate with lib/gitlab/graph/commit.rb
@commits.map! { |commit| Graph::Commit.new(commit) }
# add refs to each commit
@commits.each { |commit| commit.add_refs(ref_cache, repo) }
@commits
end
# Method is adding time and space on the
# list of commits. As well as returns date list
# corelated with time set on commits.
#
# @param [Array<Graph::Commit>] commits to index
#
# @return [Array<TimeDate>] list of commit dates corelated with time on commits
def index_commits
days, times = [], []
map = {}
commits.reverse.each_with_index do |c,i|
c.time = i
days[i] = c.committed_date
map[c.id] = c
times[i] = c
end
@_reserved = {}
days.each_index do |i|
@_reserved[i] = []
end
commits_sort_by_ref.each do |commit|
if map.include? commit.id then
place_chain(map[commit.id], map)
end
end
# find parent spaces for not overlap lines
times.each do |c|
c.parent_spaces.concat(find_free_parent_spaces(c, map, times))
end
days
end
# Skip count that the target commit is displayed in center.
def to_commit
commits = Grit::Commit.find_all(repo, nil, {date_order: true})
commit_index = commits.index do |c|
c.id == @commit.id
end
if commit_index && (self.class.max_count / 2 < commit_index) then
# get max index that commit is displayed in the center.
commit_index - self.class.max_count / 2
else
0
end
end
def commits_sort_by_ref
commits.sort do |a,b|
if include_ref?(a)
-1
elsif include_ref?(b)
1
else
b.committed_date <=> a.committed_date
end
end
end
def include_ref?(commit)
heads = commit.refs.select do |ref|
ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag)
end
heads.map! do |head|
head.name
end
heads.include?(@ref)
end
def find_free_parent_spaces(commit, map, times)
spaces = []
commit.parents.each do |p|
if map.include?(p.id) then
parent = map[p.id]
range = if commit.time < parent.time then
commit.time..parent.time
else
parent.time..commit.time
end
space = if commit.space >= parent.space then
find_free_parent_space(range, parent.space, -1, commit.space, times)
else
find_free_parent_space(range, commit.space, -1, parent.space, times)
end
mark_reserved(range, space)
spaces << space
end
end
spaces
end
def find_free_parent_space(range, space_base, space_step, space_default, times)
if is_overlap?(range, times, space_default) then
find_free_space(range, space_step, space_base, space_default)
else
space_default
end
end
def is_overlap?(range, times, overlap_space)
range.each do |i|
if i != range.first &&
i != range.last &&
times[i].spaces.include?(overlap_space) then
return true;
end
end
false
end
# Add space mark on commit and its parents
#
# @param [Graph::Commit] the commit object.
# @param [Hash<String,Graph::Commit>] map of commits
def place_chain(commit, map, parent_time = nil)
leaves = take_left_leaves(commit, map)
if leaves.empty?
return
end
time_range = leaves.last.time..leaves.first.time
space_base = get_space_base(leaves, map)
space = find_free_space(time_range, 2, space_base)
leaves.each do |l|
l.spaces << space
# Also add space to parent
l.parents.each do |p|
if map.include?(p.id)
parent = map[p.id]
if parent.space > 0
parent.spaces << space
end
end
end
end
# and mark it as reserved
min_time = leaves.last.time
parents = leaves.last.parents.collect
parents.each do |p|
if map.include? p.id
parent = map[p.id]
if parent.time < min_time
min_time = parent.time
end
end
end
if parent_time.nil?
max_time = leaves.first.time
else
max_time = parent_time - 1
end
mark_reserved(min_time..max_time, space)
# Visit branching chains
leaves.each do |l|
parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?}
for p in parents
place_chain(map[p.id], map, l.time)
end
end
end
def get_space_base(leaves, map)
space_base = 1
if leaves.last.parents.size > 0
first_parent = leaves.last.parents.first
if map.include?(first_parent.id)
first_p = map[first_parent.id]
if first_p.space > 0
space_base = first_p.space
end
end
end
space_base
end
def mark_reserved(time_range, space)
for day in time_range
@_reserved[day].push(space)
end
end
def find_free_space(time_range, space_step, space_base = 1, space_default = nil)
space_default ||= space_base
reserved = []
for day in time_range
reserved += @_reserved[day]
end
reserved.uniq!
space = space_default
while reserved.include?(space) do
space += space_step
if space < space_base then
space_step *= -1
space = space_base + space_step
end
end
space
end
# Takes most left subtree branch of commits
# which don't have space mark yet.
#
# @param [Graph::Commit] the commit object.
# @param [Hash<String,Graph::Commit>] map of commits
#
# @return [Array<Graph::Commit>] list of branch commits
def take_left_leaves(commit, map)
leaves = []
leaves.push(commit) if commit.space.zero?
while true
return leaves if commit.parents.count.zero?
return leaves unless map.include? commit.parents.first.id
commit = map[commit.parents.first.id]
return leaves unless commit.space.zero?
leaves.push(commit)
end
end
end
end
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# description :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer not null
# created_at :datetime not null # created_at :datetime not null
......
...@@ -30,6 +30,10 @@ class Issue < ActiveRecord::Base ...@@ -30,6 +30,10 @@ class Issue < ActiveRecord::Base
where('assignee_id = :user', user: user.id) where('assignee_id = :user', user: user.id)
end end
def authored(user)
where('author_id = :user', user: user.id)
end
def open_for(user) def open_for(user)
opened.assigned(user) opened.assigned(user)
end end
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
# #
# id :integer not null, primary key # id :integer not null, primary key
# name :string(255) not null # name :string(255) not null
# description :string(255) not null
# path :string(255) not null # path :string(255) not null
# owner_id :integer not null # owner_id :integer not null
# created_at :datetime not null # created_at :datetime not null
...@@ -12,7 +13,7 @@ ...@@ -12,7 +13,7 @@
# #
class Namespace < ActiveRecord::Base class Namespace < ActiveRecord::Base
attr_accessible :name, :path attr_accessible :name, :description, :path
has_many :projects, dependent: :destroy has_many :projects, dependent: :destroy
belongs_to :owner, class_name: "User" belongs_to :owner, class_name: "User"
...@@ -22,7 +23,7 @@ class Namespace < ActiveRecord::Base ...@@ -22,7 +23,7 @@ class Namespace < ActiveRecord::Base
length: { within: 0..255 }, length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex, format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." } message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :description, length: { within: 0..255 }
validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
format: { with: Gitlab::Regex.path_regex, format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
# creator_id :integer # creator_id :integer
# default_branch :string(255) # default_branch :string(255)
# issues_enabled :boolean default(TRUE), not null # issues_enabled :boolean default(TRUE), not null
# issues_tracker :string 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
...@@ -22,11 +23,12 @@ require "grit" ...@@ -22,11 +23,12 @@ require "grit"
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
include Gitolited include Gitolited
extend Enumerize
class TransferError < StandardError; end class TransferError < StandardError; end
attr_accessible :name, :path, :description, :default_branch, attr_accessible :name, :path, :description, :default_branch, :issues_tracker,
:issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id,
:wiki_enabled, :public, :import_url, as: [:default, :admin] :wiki_enabled, :public, :import_url, as: [:default, :admin]
attr_accessible :namespace_id, :creator_id, as: :admin attr_accessible :namespace_id, :creator_id, as: :admin
...@@ -43,7 +45,7 @@ class Project < ActiveRecord::Base ...@@ -43,7 +45,7 @@ class Project < ActiveRecord::Base
has_many :events, dependent: :destroy has_many :events, dependent: :destroy
has_many :merge_requests, dependent: :destroy has_many :merge_requests, dependent: :destroy
has_many :issues, dependent: :destroy, order: "state, created_at DESC" has_many :issues, dependent: :destroy, order: "state DESC, created_at DESC"
has_many :milestones, dependent: :destroy has_many :milestones, dependent: :destroy
has_many :users_projects, dependent: :destroy has_many :users_projects, dependent: :destroy
has_many :notes, dependent: :destroy has_many :notes, dependent: :destroy
...@@ -72,6 +74,7 @@ class Project < ActiveRecord::Base ...@@ -72,6 +74,7 @@ class Project < ActiveRecord::Base
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
validates :issues_enabled, :wall_enabled, :merge_requests_enabled, validates :issues_enabled, :wall_enabled, :merge_requests_enabled,
:wiki_enabled, inclusion: { in: [true, false] } :wiki_enabled, inclusion: { in: [true, false] }
validates :issues_tracker_id, length: { within: 0..255 }
validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :name, scope: :namespace_id
validates_uniqueness_of :path, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id
...@@ -93,6 +96,8 @@ class Project < ActiveRecord::Base ...@@ -93,6 +96,8 @@ class Project < ActiveRecord::Base
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(public: true) }
enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab
class << self class << self
def abandoned def abandoned
project_ids = Event.select('max(created_at) as latest_date, project_id'). project_ids = Event.select('max(created_at) as latest_date, project_id').
...@@ -201,6 +206,22 @@ class Project < ActiveRecord::Base ...@@ -201,6 +206,22 @@ class Project < ActiveRecord::Base
issues.tag_counts_on(:labels) issues.tag_counts_on(:labels)
end end
def issue_exists?(issue_id)
if used_default_issues_tracker?
self.issues.where(id: issue_id).first.present?
else
true
end
end
def used_default_issues_tracker?
self.issues_tracker == Project.issues_tracker.default_value
end
def can_have_issues_tracker_id?
self.issues_enabled && !self.used_default_issues_tracker?
end
def services def services
[gitlab_ci_service].compact [gitlab_ci_service].compact
end end
......
...@@ -137,7 +137,7 @@ class Repository ...@@ -137,7 +137,7 @@ class Repository
file_path = File.join(storage_path, self.path_with_namespace, file_name) file_path = File.join(storage_path, self.path_with_namespace, file_name)
# Put files into a directory before archiving # Put files into a directory before archiving
prefix = self.path_with_namespace + "/" prefix = File.basename(self.path_with_namespace) + "/"
# Create file if not exists # Create file if not exists
unless File.exists?(file_path) unless File.exists?(file_path)
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
# dark_scheme :boolean default(FALSE), not null # dark_scheme :boolean default(FALSE), not null
# theme_id :integer default(1), not null # theme_id :integer default(1), not null
# bio :string(255) # bio :string(255)
# blocked :boolean default(FALSE), not null # state :string(255)
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255) # extern_uid :string(255)
...@@ -46,10 +46,35 @@ class User < ActiveRecord::Base ...@@ -46,10 +46,35 @@ class User < ActiveRecord::Base
attr_accessor :force_random_password attr_accessor :force_random_password
#
# Relations
#
# Namespace for personal projects # Namespace for personal projects
has_one :namespace, dependent: :destroy, foreign_key: :owner_id, class_name: "Namespace", conditions: 'type IS NULL' has_one :namespace,
dependent: :destroy,
foreign_key: :owner_id,
class_name: "Namespace",
conditions: 'type IS NULL'
# Profile
has_many :keys, dependent: :destroy has_many :keys, dependent: :destroy
# Groups
has_many :groups, class_name: "Group", foreign_key: :owner_id
# Teams
has_many :own_teams,
class_name: "UserTeam",
foreign_key: :owner_id,
dependent: :destroy
has_many :user_team_user_relationships, dependent: :destroy
has_many :user_teams, through: :user_team_user_relationships
has_many :user_team_project_relationships, through: :user_teams
has_many :team_projects, through: :user_team_project_relationships
# Projects
has_many :users_projects, dependent: :destroy has_many :users_projects, dependent: :destroy
has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :issues, dependent: :destroy, foreign_key: :author_id
has_many :notes, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id
...@@ -57,18 +82,16 @@ class User < ActiveRecord::Base ...@@ -57,18 +82,16 @@ class User < ActiveRecord::Base
has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event" has_many :events, dependent: :destroy, foreign_key: :author_id, class_name: "Event"
has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue" has_many :assigned_issues, dependent: :destroy, foreign_key: :assignee_id, class_name: "Issue"
has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" has_many :assigned_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest"
has_many :groups, class_name: "Group", foreign_key: :owner_id
has_many :recent_events, class_name: "Event", foreign_key: :author_id, order: "id DESC"
has_many :projects, through: :users_projects has_many :projects, through: :users_projects
has_many :user_team_user_relationships, dependent: :destroy has_many :recent_events,
class_name: "Event",
has_many :user_teams, through: :user_team_user_relationships foreign_key: :author_id,
has_many :user_team_project_relationships, through: :user_teams order: "id DESC"
has_many :team_projects, through: :user_team_project_relationships
#
# Validations
#
validates :name, presence: true validates :name, presence: true
validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ }
validates :bio, length: { within: 0..255 } validates :bio, length: { within: 0..255 }
...@@ -87,10 +110,27 @@ class User < ActiveRecord::Base ...@@ -87,10 +110,27 @@ class User < ActiveRecord::Base
delegate :path, to: :namespace, allow_nil: true, prefix: true delegate :path, to: :namespace, allow_nil: true, prefix: true
state_machine :state, initial: :active do
after_transition any => :blocked do |user, transition|
# Remove user from all projects and
user.users_projects.find_each do |membership|
return false unless membership.destroy
end
end
event :block do
transition active: :blocked
end
event :activate do
transition blocked: :active
end
end
# Scopes # Scopes
scope :admins, -> { where(admin: true) } scope :admins, -> { where(admin: true) }
scope :blocked, -> { where(blocked: true) } scope :blocked, -> { with_state(:blocked) }
scope :active, -> { where(blocked: false) } scope :active, -> { with_state(:active) }
scope :alphabetically, -> { order('name ASC') } scope :alphabetically, -> { order('name ASC') }
scope :in_team, ->(team){ where(id: team.member_ids) } scope :in_team, ->(team){ where(id: team.member_ids) }
scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) }
...@@ -260,17 +300,6 @@ class User < ActiveRecord::Base ...@@ -260,17 +300,6 @@ class User < ActiveRecord::Base
MergeRequest.cared(self) MergeRequest.cared(self)
end end
# Remove user from all projects and
# set blocked attribute to true
def block
users_projects.find_each do |membership|
return false unless membership.destroy
end
self.blocked = true
save
end
def projects_limit_percent def projects_limit_percent
return 100 if projects_limit.zero? return 100 if projects_limit.zero?
(personal_projects.count.to_f / projects_limit) * 100 (personal_projects.count.to_f / projects_limit) * 100
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
class UserTeam < ActiveRecord::Base class UserTeam < ActiveRecord::Base
attr_accessible :name, :owner_id, :path attr_accessible :name, :description, :owner_id, :path
belongs_to :owner, class_name: User belongs_to :owner, class_name: User
...@@ -26,6 +26,7 @@ class UserTeam < ActiveRecord::Base ...@@ -26,6 +26,7 @@ class UserTeam < ActiveRecord::Base
length: { within: 0..255 }, length: { within: 0..255 },
format: { with: Gitlab::Regex.name_regex, format: { with: Gitlab::Regex.name_regex,
message: "only letters, digits, spaces & '_' '-' '.' allowed." } message: "only letters, digits, spaces & '_' '-' '.' allowed." }
validates :description, length: { within: 0..255 }
validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, validates :path, uniqueness: true, presence: true, length: { within: 1..255 },
format: { with: Gitlab::Regex.path_regex, format: { with: Gitlab::Regex.path_regex,
message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" }
......
...@@ -27,7 +27,7 @@ class IssueObserver < ActiveRecord::Observer ...@@ -27,7 +27,7 @@ class IssueObserver < ActiveRecord::Observer
def create_note(issue) def create_note(issue)
Note.create_status_change_note(issue, current_user, issue.state) Note.create_status_change_note(issue, current_user, issue.state)
[issue.author, issue.assignee].compact.each do |recipient| [issue.author, issue.assignee].compact.uniq.each do |recipient|
Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id) Notify.delay.issue_status_changed_email(recipient.id, issue.id, issue.state, current_user.id)
end end
end end
......
...@@ -2,7 +2,8 @@ class UserObserver < ActiveRecord::Observer ...@@ -2,7 +2,8 @@ class UserObserver < ActiveRecord::Observer
def after_create(user) def after_create(user)
log_info("User \"#{user.name}\" (#{user.email}) was created") log_info("User \"#{user.name}\" (#{user.email}) was created")
Notify.delay.new_user_email(user.id, user.password) # Dont email omniauth created users
Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid?
end end
def after_destroy user def after_destroy user
......
...@@ -19,6 +19,8 @@ class GitPushService ...@@ -19,6 +19,8 @@ class GitPushService
# Collect data for this git push # Collect data for this git push
@push_data = post_receive_data(oldrev, newrev, ref) @push_data = post_receive_data(oldrev, newrev, ref)
create_push_event
project.ensure_satellite_exists project.ensure_satellite_exists
project.discover_default_branch project.discover_default_branch
...@@ -27,8 +29,6 @@ class GitPushService ...@@ -27,8 +29,6 @@ class GitPushService
project.execute_hooks(@push_data.dup) project.execute_hooks(@push_data.dup)
project.execute_services(@push_data.dup) project.execute_services(@push_data.dup)
end end
create_push_event
end end
# This method provide a sample data # This method provide a sample data
......
...@@ -25,7 +25,7 @@ class ProjectTransferService ...@@ -25,7 +25,7 @@ class ProjectTransferService
Gitlab::ProjectMover.new(project, old_dir, new_dir).execute Gitlab::ProjectMover.new(project, old_dir, new_dir).execute
save! project.save!
end end
rescue Gitlab::ProjectMover::ProjectMoveError => ex rescue Gitlab::ProjectMover::ProjectMoveError => ex
raise Project::TransferError.new(ex.message) raise Project::TransferError.new(ex.message)
......
%h3.page_title Rename Group %h3.page_title Edit Group
%hr %hr
= form_for [:admin, @group] do |f| = form_for [:admin, @group] do |f|
- if @group.errors.any? - if @group.errors.any?
...@@ -10,7 +10,10 @@ ...@@ -10,7 +10,10 @@
.input .input
= f.text_field :name, placeholder: "Example Group", class: "xxlarge" = f.text_field :name, placeholder: "Example Group", class: "xxlarge"
.clearfix.group-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.clearfix.group_name_holder .clearfix.group_name_holder
= f.label :path do = f.label :path do
...@@ -24,5 +27,5 @@ ...@@ -24,5 +27,5 @@
%li It will change the git path to repositories under this group. %li It will change the git path to repositories under this group.
.form-actions .form-actions
= f.submit 'Rename group', class: "btn btn-remove" = f.submit 'Edit group', class: "btn btn-remove"
= link_to 'Cancel', admin_groups_path, class: "btn btn-cancel" = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel"
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
Name Name
%i.icon-sort-down %i.icon-sort-down
%th Path %th Path
%th Description
%th Projects %th Projects
%th Owner %th Owner
%th.cred Danger Zone! %th.cred Danger Zone!
...@@ -25,11 +26,12 @@ ...@@ -25,11 +26,12 @@
%tr %tr
%td %td
%strong= link_to group.name, [:admin, group] %strong= link_to group.name, [:admin, group]
%td= truncate group.description
%td= group.path %td= group.path
%td= group.projects.count %td= group.projects.count
%td %td
= link_to group.owner_name, admin_user_path(group.owner) = link_to group.owner_name, admin_user_path(group.owner)
%td.bgred %td.bgred
= link_to 'Rename', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small" = link_to 'Edit', edit_admin_group_path(group), id: "edit_#{dom_id(group)}", class: "btn btn-small"
= link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = link_to 'Destroy', [:admin, group], confirm: "REMOVE #{group.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
= paginate @groups, theme: "admin" = paginate @groups, theme: "admin"
...@@ -9,8 +9,14 @@ ...@@ -9,8 +9,14 @@
Group name is Group name is
.input .input
= f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
&nbsp; .clearfix.group-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
= f.submit 'Create group', class: "btn btn-primary" = f.submit 'Create group', class: "btn btn-primary"
%hr %hr
.padded .padded
%ul %ul
......
...@@ -16,7 +16,13 @@ ...@@ -16,7 +16,13 @@
&nbsp; &nbsp;
= link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do = link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do
%i.icon-edit %i.icon-edit
Rename Edit
%tr
%td
%b
Description:
%td
= @group.description
%tr %tr
%td %td
%b %b
......
...@@ -31,6 +31,15 @@ ...@@ -31,6 +31,15 @@
= f.label :issues_enabled, "Issues" = f.label :issues_enabled, "Issues"
.input= f.check_box :issues_enabled .input= f.check_box :issues_enabled
- if Project.issues_tracker.values.count > 1
.clearfix
= f.label :issues_tracker, "Issues tracker", class: 'control-label'
.input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
.clearfix
= f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
.input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
.clearfix .clearfix
= f.label :merge_requests_enabled, "Merge Requests" = f.label :merge_requests_enabled, "Merge Requests"
.input= f.check_box :merge_requests_enabled .input= f.check_box :merge_requests_enabled
......
%h3.page_title Rename Team %h3.page_title Edit Team
%hr %hr
= form_for @team, url: admin_team_path(@team), method: :put do |f| = form_for @team, url: admin_team_path(@team), method: :put do |f|
- if @team.errors.any? - if @team.errors.any?
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
.input .input
= f.text_field :name, placeholder: "Example Team", class: "xxlarge" = f.text_field :name, placeholder: "Example Team", class: "xxlarge"
.clearfix.team-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.clearfix.team_name_holder .clearfix.team_name_holder
= f.label :path do = f.label :path do
%span.cred Team path is %span.cred Team path is
...@@ -19,5 +24,5 @@ ...@@ -19,5 +24,5 @@
%li It will change web url for access team and team projects. %li It will change web url for access team and team projects.
.form-actions .form-actions
= f.submit 'Rename team', class: "btn btn-remove" = f.submit 'Edit team', class: "btn btn-remove"
= link_to 'Cancel', admin_teams_path, class: "btn btn-cancel" = link_to 'Cancel', admin_teams_path, class: "btn btn-cancel"
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
%th %th
Name Name
%i.icon-sort-down %i.icon-sort-down
%th Description
%th Path %th Path
%th Projects %th Projects
%th Members %th Members
...@@ -26,13 +27,17 @@ ...@@ -26,13 +27,17 @@
%tr %tr
%td %td
%strong= link_to team.name, admin_team_path(team) %strong= link_to team.name, admin_team_path(team)
%td= truncate team.description
%td= team.path %td= team.path
%td= team.projects.count %td= team.projects.count
%td= team.members.count %td= team.members.count
%td %td
- if team.owner
= link_to team.owner.name, admin_user_path(team.owner) = link_to team.owner.name, admin_user_path(team.owner)
- else
(deleted)
%td.bgred %td.bgred
= link_to 'Rename', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small" = link_to 'Edit', edit_admin_team_path(team), id: "edit_#{dom_id(team)}", class: "btn btn-small"
= link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove" = link_to 'Destroy', admin_team_path(team), confirm: "REMOVE #{team.name}? Are you sure?", method: :delete, class: "btn btn-small btn-remove"
= paginate @teams, theme: "admin" = paginate @teams, theme: "admin"
...@@ -9,8 +9,15 @@ ...@@ -9,8 +9,15 @@
Team name is Team name is
.input .input
= f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
&nbsp;
.clearfix.team-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
= f.submit 'Create team', class: "btn btn-primary" = f.submit 'Create team', class: "btn btn-primary"
%hr %hr
.padded .padded
%ul %ul
......
...@@ -16,7 +16,13 @@ ...@@ -16,7 +16,13 @@
&nbsp; &nbsp;
= link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do = link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do
%i.icon-edit %i.icon-edit
Rename Edit
%tr
%td
%b
Description:
%td
= @team.description
%tr %tr
%td %td
%b %b
......
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
.span4 .span4
- unless @admin_user.new_record? - unless @admin_user.new_record?
.alert.alert-error .alert.alert-error
- if @admin_user.blocked - if @admin_user.blocked?
%p This user is blocked and is not able to login to GitLab %p This user is blocked and is not able to login to GitLab
= link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small" = link_to 'Unblock User', unblock_admin_user_path(@admin_user), method: :put, class: "btn btn-small"
- else - else
......
...@@ -53,7 +53,7 @@ ...@@ -53,7 +53,7 @@
&nbsp; &nbsp;
= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small"
- unless user == current_user - unless user == current_user
- if user.blocked - if user.blocked?
= link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success" = link_to 'Unblock', unblock_admin_user_path(user), method: :put, class: "btn btn-small success"
- else - else
= link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove" = link_to 'Block', block_admin_user_path(user), confirm: 'USER WILL BE BLOCKED! Are you sure?', method: :put, class: "btn btn-small btn-remove"
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
%h3.page_title %h3.page_title
= image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90"
= @admin_user.name = @admin_user.name
- if @admin_user.blocked - if @admin_user.blocked?
%span.cred (Blocked) %span.cred (Blocked)
- if @admin_user.admin - if @admin_user.admin
%span.cred (Admin) %span.cred (Admin)
......
- @commits.group_by { |c| c.committed_date.to_date }.each do |day, commits| - @commits.group_by { |c| c.committed_date.to_date }.sort.reverse.each do |day, commits|
%div.ui-box %div.ui-box
%h5.title %h5.title
%i.icon-calendar %i.icon-calendar
......
...@@ -21,9 +21,10 @@ ...@@ -21,9 +21,10 @@
= event.project_name = event.project_name
.event-body .event-body
.event-note
.md
%i.icon-comment-alt.event-note-icon %i.icon-comment-alt.event-note-icon
%span.event-note = sanitize(markdown(truncate(event.target.note, length: 150)), tags: %w(a img b pre p))
= markdown truncate(event.target.note, length: 70)
- note = event.target - note = event.target
- if note.attachment.url - if note.attachment.url
= link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do
......
...@@ -9,8 +9,15 @@ ...@@ -9,8 +9,15 @@
Group name is Group name is
.input .input
= f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
&nbsp;
.clearfix.group-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
= f.submit 'Save group', class: "btn btn-save" = f.submit 'Save group', class: "btn btn-save"
%hr %hr
......
...@@ -9,9 +9,16 @@ ...@@ -9,9 +9,16 @@
Group name is Group name is
.input .input
= f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left"
&nbsp;
.clearfix.group-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
= f.submit 'Create group', class: "btn btn-create" = f.submit 'Create group', class: "btn btn-create"
%hr
.padded .padded
%ul %ul
%li Group is kind of directory for several projects %li Group is kind of directory for several projects
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
%p.nothing_here_message Project activity will be displayed here %p.nothing_here_message Project activity will be displayed here
.loading.hide .loading.hide
.side.span4 .side.span4
- if @group.description.present?
.description.well.light
= @group.description
= render "projects", projects: @projects = render "projects", projects: @projects
%div %div
%span.rss-icon %span.rss-icon
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
Open Open
%li{class: ("active" if params[:status] == 'assigned-to-me')} %li{class: ("active" if params[:status] == 'assigned-to-me')}
= link_to project_issues_path(@project, status: 'assigned-to-me') do = link_to project_issues_path(@project, status: 'assigned-to-me') do
Assigned To Me Assigned to me
%li{class: ("active" if params[:status] == 'created-by-me')}
= link_to project_issues_path(@project, status: 'created-by-me') do
Created by me
%li{class: ("active" if params[:status] == 'closed')} %li{class: ("active" if params[:status] == 'closed')}
= link_to project_issues_path(@project, status: 'closed') do = link_to project_issues_path(@project, status: 'closed') do
Closed Closed
......
- if text = alert || notice .flash-container
#flash-container - if alert
%h4= text .alert
%span= alert
- elsif notice
.alert.alert-info
%span= notice
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
= stylesheet_link_tag "application" = stylesheet_link_tag "application"
= javascript_include_tag "application" = javascript_include_tag "application"
= csrf_meta_tags = csrf_meta_tags
= include_gon
-# Atom feed -# Atom feed
- if current_user - if current_user
......
...@@ -8,6 +8,9 @@ ...@@ -8,6 +8,9 @@
%span.separator %span.separator
%h1.project_name= title %h1.project_name= title
%ul.nav %ul.nav
%li
= link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
%i.icon-globe
- if current_user.is_admin? - if current_user.is_admin?
%li %li
= link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Admin area" = render "layouts/head", title: "Admin area"
%body{class: "#{app_theme} admin"} %body{class: "#{app_theme} admin"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Admin area" = render "layouts/head_panel", title: "Admin area"
= render "layouts/flash"
.container .container
%ul.main_menu %ul.main_menu
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Dashboard" = render "layouts/head", title: "Dashboard"
%body{class: "#{app_theme} application"} %body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Dashboard" = render "layouts/head_panel", title: "Dashboard"
= render "layouts/flash"
.container .container
%ul.main_menu %ul.main_menu
= nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
......
...@@ -3,4 +3,6 @@ ...@@ -3,4 +3,6 @@
= render "layouts/head" = render "layouts/head"
%body.ui_basic.login-page %body.ui_basic.login-page
= render "layouts/flash" = render "layouts/flash"
.container= yield .container
.content
= yield
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Error" = render "layouts/head", title: "Error"
%body{class: "#{app_theme} application"} %body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "" = render "layouts/head_panel", title: ""
= render "layouts/flash"
.container .container
.content .content
%center.padded.prepend-top-20 %center.padded.prepend-top-20
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "#{@group.name}" = render "layouts/head", title: "#{@group.name}"
%body{class: "#{app_theme} application"} %body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "group: #{@group.name}" = render "layouts/head_panel", title: "group: #{@group.name}"
= render "layouts/flash"
.container .container
%ul.main_menu %ul.main_menu
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do = nav_link(path: 'groups#show', html_options: {class: 'home'}) do
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "Profile" = render "layouts/head", title: "Profile"
%body{class: "#{app_theme} profile"} %body{class: "#{app_theme} profile"}
= render "layouts/flash"
= render "layouts/head_panel", title: "Profile" = render "layouts/head_panel", title: "Profile"
= render "layouts/flash"
.container .container
%ul.main_menu %ul.main_menu
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: @project.name_with_namespace = render "layouts/head", title: @project.name_with_namespace
%body{class: "#{app_theme} project"} %body{class: "#{app_theme} project"}
= render "layouts/flash"
= render "layouts/head_panel", title: project_title(@project) = render "layouts/head_panel", title: project_title(@project)
= render "layouts/flash"
- if can?(current_user, :download_code, @project) - if can?(current_user, :download_code, @project)
= render 'shared/no_ssh' = render 'shared/no_ssh'
...@@ -24,8 +24,9 @@ ...@@ -24,8 +24,9 @@
- if @project.issues_enabled - if @project.issues_enabled
= nav_link(controller: %w(issues milestones labels)) do = nav_link(controller: %w(issues milestones labels)) do
= link_to project_issues_filter_path(@project) do = link_to url_for_project_issues do
Issues Issues
- if @project.used_default_issues_tracker?
%span.count.issue_counter= @project.issues.opened.count %span.count.issue_counter= @project.issues.opened.count
- if @project.repo_exists? && @project.merge_requests_enabled - if @project.repo_exists? && @project.merge_requests_enabled
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
%html{ lang: "en"} %html{ lang: "en"}
= render "layouts/head", title: "#{@team.name}" = render "layouts/head", title: "#{@team.name}"
%body{class: "#{app_theme} application"} %body{class: "#{app_theme} application"}
= render "layouts/flash"
= render "layouts/head_panel", title: "team: #{@team.name}" = render "layouts/head_panel", title: "team: #{@team.name}"
= render "layouts/flash"
.container .container
%ul.main_menu %ul.main_menu
= nav_link(path: 'teams#show', html_options: {class: 'home'}) do = nav_link(path: 'teams#show', html_options: {class: 'home'}) do
......
- unless can?(current_user, :accept_mr, @project) - unless @allowed_to_merge
.alert .alert
%strong Only masters can accept MR %strong You don't have enough permissions to merge this MR
- if @merge_request.opened? && @commits.any? && can?(current_user, :accept_mr, @project) - if @show_merge_controls
.automerge_widget.can_be_merged{style: "display:none"} .automerge_widget.can_be_merged{style: "display:none"}
.alert.alert-success .alert.alert-success
%span %span
......
Issue was <%= @issue_status %> by <%= @updated_by.name %>
Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
New Issue was created and assigned to you.
Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %>
New Merge Request <%= @merge_request.id %>
<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %>
Branches: <%= @merge_request.source_branch %> to <%= @merge_request.target_branch %>
Author: <%= @merge_request.author_name %>
Asignee: <%= @merge_request.assignee_name %>
Hi <%= @user.name %>!
Administrator created account for you. Now you are a member of company GitLab application.
login.................. <%= @user.email %>
<% unless Gitlab.config.gitlab.signup_enabled %>
password............... <%= @password %>
<% end %>
Click here to login: <%= url_for(root_url) %>
New comment for Commit <%= @commit.short_id %>
<%= url_for(project_commit_url(@note.project, id: @commit.id, anchor: "note_#{@note.id}")) %>
Author: <%= @note.author_name %>
<%= @note.note %>
New comment for Issue <%= @issue.id %>
<%= url_for(project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")) %>
Author: <%= @note.author_name %>
<%= @note.note %>
New comment for Merge Request <%= @merge_request.id %>
<%= url_for(project_merge_request_url(@merge_request.project, @merge_request, anchor: "note_#{@note.id}")) %>
<%= @note.author_name %>
<%= @note.note %>
New message on the project wall <%= @note.project %>
<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %>
<%= @note.author_name %>
<%= @note.note %>
You have been granted <%= @users_project.project_access_human %> access to project <%= @project.name_with_namespace %>
<%= url_for(project_url(@project)) %>
Project was moved to another location
The project is now located under
<%= url_for(link_to project_url(@project)) %>
To update the remote url in your local repository run:
git remote set-url origin <%= @project.ssh_url_to_repo %>
Reassigned Issue <%= @issue.id %>
<%= url_for(project_issue_url(@issue.project, @issue)) %>
Assignee changed from <%= @previous_assignee.name %> to <%= @issue.assignee_name %>
Reassigned Merge Request <%= @merge_request.id %>
<%= url_for(project_merge_request_url(@merge_request.project, @merge_request)) %>
Assignee changed from <%= @previous_assignee.name %> to <%= @merge_request.assignee_name %>
...@@ -24,6 +24,15 @@ ...@@ -24,6 +24,15 @@
= f.check_box :issues_enabled = f.check_box :issues_enabled
%span.descr Lightweight issue tracking system for this project %span.descr Lightweight issue tracking system for this project
- if Project.issues_tracker.values.count > 1
.control-group
= f.label :issues_tracker, "Issues tracker", class: 'control-label'
.input= f.select(:issues_tracker, Project.issues_tracker.values, {}, { disabled: !@project.issues_enabled })
.clearfix
= f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
.input= f.text_field :issues_tracker_id, class: "xxlarge", disabled: !@project.can_have_issues_tracker_id?
.control-group .control-group
= f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
.controls .controls
......
...@@ -5,14 +5,14 @@ ...@@ -5,14 +5,14 @@
%fieldset %fieldset
%legend Git global setup: %legend Git global setup:
%pre.dark %pre.dark
= preserve do :preserve
git config --global user.name "#{current_user.name}" git config --global user.name "#{current_user.name}"
git config --global user.email "#{current_user.email}" git config --global user.email "#{current_user.email}"
%fieldset %fieldset
%legend Create Repository %legend Create Repository
%pre.dark %pre.dark
= preserve do :preserve
mkdir #{@project.path} mkdir #{@project.path}
cd #{@project.path} cd #{@project.path}
git init git init
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
%fieldset %fieldset
%legend Existing Git Repo? %legend Existing Git Repo?
%pre.dark %pre.dark
= preserve do :preserve
cd existing_git_repo cd existing_git_repo
git remote add origin #{@project.url_to_repo} git remote add origin #{@project.url_to_repo}
git push -u origin master git push -u origin master
......
...@@ -12,5 +12,7 @@ ...@@ -12,5 +12,7 @@
.pull-right .pull-right
%pre.dark.tiny git clone #{project.http_url_to_repo} %pre.dark.tiny git clone #{project.http_url_to_repo}
- unless @projects.present?
%h3.nothing_here_message No public projects
= paginate @projects, theme: "admin" = paginate @projects, theme: "admin"
.input-prepend.project_clone_holder .input-prepend.project_clone_holder
%button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH %button{class: "btn active", :"data-clone" => @project.ssh_url_to_repo} SSH
%button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase %button{class: "btn", :"data-clone" => @project.http_url_to_repo}= Gitlab.config.gitlab.protocol.upcase
= text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge", readonly: true
= text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge"
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
%span.label This is you! %span.label This is you!
- if @project.namespace_owner == user - if @project.namespace_owner == user
%span.label Owner %span.label Owner
- elsif user.blocked - elsif user.blocked?
%span.label Blocked %span.label Blocked
- elsif allow_admin - elsif allow_admin
= link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove" do
......
...@@ -12,13 +12,19 @@ ...@@ -12,13 +12,19 @@
.input .input
= f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left" = f.text_field :name, placeholder: "Ex. OpenSource", class: "xlarge left"
.clearfix.team-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xlarge js-gfm-input", rows: 4
.clearfix .clearfix
= f.label :path do = f.label :path do
Team path is Team path is
.input .input
= f.text_field :path, placeholder: "opensource", class: "xlarge left" = f.text_field :path, placeholder: "opensource", class: "xlarge left"
.form-actions .form-actions
= f.submit 'Save team changes', class: "btn btn-save" = f.submit 'Save team changes', class: "btn btn-primary"
.span5 .span5
.ui-box .ui-box
%h5.title Remove team %h5.title Remove team
...@@ -26,4 +32,3 @@ ...@@ -26,4 +32,3 @@
%p %p
Removed team can not be restored! Removed team can not be restored!
= link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small" = link_to 'Remove team', team_path(@team), method: :delete, confirm: "You are sure?", class: "btn btn-remove btn-small"
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
%span.btn.disabled This is you! %span.btn.disabled This is you!
- if @team.owner == user - if @team.owner == user
%span.btn.disabled Owner %span.btn.disabled Owner
- elsif user.blocked - elsif user.blocked?
%span.btn.disabled.blocked Blocked %span.btn.disabled.blocked Blocked
- elsif allow_admin - elsif allow_admin
= link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do
......
...@@ -9,9 +9,15 @@ ...@@ -9,9 +9,15 @@
Team name is Team name is
.input .input
= f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left" = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left"
&nbsp;
.clearfix.team-description-holder
= f.label :description, "Details"
.input
= f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4
.form-actions
= f.submit 'Create team', class: "btn btn-create" = f.submit 'Create team', class: "btn btn-create"
%hr
.padded .padded
%ul %ul
%li All created teams are public (users can view who enter into team and which project are assigned for this team) %li All created teams are public (users can view who enter into team and which project are assigned for this team)
......
...@@ -11,6 +11,9 @@ ...@@ -11,6 +11,9 @@
%p.nothing_here_message Projects activity will be displayed here %p.nothing_here_message Projects activity will be displayed here
.loading.hide .loading.hide
.side.span4 .side.span4
- if @team.description.present?
.description.well.light
= @team.description
= render "projects", projects: @projects = render "projects", projects: @projects
%div %div
%span.rss-icon %span.rss-icon
......
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# Gitlab application config file # # GitLab application config file #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# How to use: # How to use:
...@@ -37,9 +37,25 @@ production: &base ...@@ -37,9 +37,25 @@ production: &base
# signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled. # signup_enabled: true # default: false - Account passwords are not sent via the email if signup is enabled.
# username_changing_enabled: false # default: true - User can change her username/namespace # username_changing_enabled: false # default: true - User can change her username/namespace
## External issues trackers
issues_tracker:
redmine:
## If not nil, link 'Issues' on project page will be replaced with this
## Use placeholders:
## :project_id - GitLab project identifier
## :issues_tracker_id - Project Name or Id in external issue tracker
project_url: "http://redmine.sample/projects/:issues_tracker_id"
## If not nil, links from /#\d/ entities from commit messages will replaced with this
## Use placeholders:
## :project_id - GitLab project identifier
## :issues_tracker_id - Project Name or Id in external issue tracker
## :id - Issue id (from commit messages)
issues_url: "http://redmine.sample/issues/:id"
## Gravatar ## Gravatar
gravatar: gravatar:
enabled: true # Use user avatar images from Gravatar.com (default: true) enabled: true # Use user avatar image from Gravatar.com (default: true)
# plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm # plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
# ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
...@@ -60,22 +76,21 @@ production: &base ...@@ -60,22 +76,21 @@ production: &base
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user' password: '_the_password_of_the_bind_user'
## Omniauth settings ## OmniAuth settings
omniauth: omniauth:
# Enable ability for users # Allow login via Twitter, Google, etc. using OmniAuth providers
# Allow logging in via Twitter, Google, etc. using Omniauth providers
enabled: false enabled: false
# CAUTION! # CAUTION!
# This allows users to login without having a user account first (default: false) # This allows users to login without having a user account first (default: false).
# User accounts will be created automatically when authentication was successful. # User accounts will be created automatically when authentication was successful.
allow_single_sign_on: false allow_single_sign_on: false
# Locks down those users until they have been cleared by the admin (default: true) # Locks down those users until they have been cleared by the admin (default: true).
block_auto_created_users: true block_auto_created_users: true
## Auth providers ## Auth providers
# Uncomment the lines and fill in the data of the auth provider you want to use # Uncomment the following lines and fill in the data of the auth provider you want to use
# If your favorite auth provider is not listed you can user others: # If your favorite auth provider is not listed you can use others:
# see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers # see https://github.com/gitlabhq/gitlabhq/wiki/Using-Custom-Omniauth-Providers
# The 'app_id' and 'app_secret' parameters are always passed as the first two # The 'app_id' and 'app_secret' parameters are always passed as the first two
# arguments, followed by optional 'args' which can be either a hash or an array. # arguments, followed by optional 'args' which can be either a hash or an array.
...@@ -114,7 +129,7 @@ production: &base ...@@ -114,7 +129,7 @@ production: &base
upload_pack: true upload_pack: true
receive_pack: true receive_pack: true
# If you use non-standart ssh port you need to specify it # If you use non-standard ssh port you need to specify it
# ssh_port: 22 # ssh_port: 22
## Git settings ## Git settings
...@@ -122,10 +137,10 @@ production: &base ...@@ -122,10 +137,10 @@ production: &base
# Use the default values unless you really know what you are doing # Use the default values unless you really know what you are doing
git: git:
bin_path: /usr/bin/git bin_path: /usr/bin/git
# Max size of git object like commit, in bytes # Max size of a git object (e.g. a commit), in bytes
# This value can be increased if you have a very large commits # This value can be increased if you have very large commits
max_size: 5242880 # 5.megabytes max_size: 5242880 # 5.megabytes
# Git timeout to read commit, in seconds # Git timeout to read a commit, in seconds
timeout: 10 timeout: 10
development: development:
...@@ -133,6 +148,10 @@ development: ...@@ -133,6 +148,10 @@ development:
test: test:
<<: *base <<: *base
issues_tracker:
redmine:
project_url: "http://redmine/projects/:issues_tracker_id"
issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
staging: staging:
<<: *base <<: *base
...@@ -42,6 +42,8 @@ Settings['omniauth'] ||= Settingslogic.new({}) ...@@ -42,6 +42,8 @@ Settings['omniauth'] ||= Settingslogic.new({})
Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil?
Settings.omniauth['providers'] ||= [] Settings.omniauth['providers'] ||= []
Settings['issues_tracker'] ||= {}
# #
# GitLab # GitLab
# #
...@@ -50,7 +52,7 @@ Settings.gitlab['default_projects_limit'] ||= 10 ...@@ -50,7 +52,7 @@ Settings.gitlab['default_projects_limit'] ||= 10
Settings.gitlab['host'] ||= 'localhost' Settings.gitlab['host'] ||= 'localhost'
Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? Settings.gitlab['https'] = false if Settings.gitlab['https'].nil?
Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80 Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80
Settings.gitlab['relative_url_root'] ||= '' Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || ''
Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http" Settings.gitlab['protocol'] ||= Settings.gitlab.https ? "https" : "http"
Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}" Settings.gitlab['email_from'] ||= "gitlab@#{Settings.gitlab.host}"
Settings.gitlab['support_email'] ||= Settings.gitlab.email_from Settings.gitlab['support_email'] ||= Settings.gitlab.email_from
......
...@@ -99,7 +99,7 @@ Devise.setup do |config| ...@@ -99,7 +99,7 @@ Devise.setup do |config|
# ==> Configuration for :validatable # ==> Configuration for :validatable
# Range for password length. Default is 6..128. # Range for password length. Default is 6..128.
# config.password_length = 6..128 config.password_length = 6..128
# Email regex used to validate email formats. It simply asserts that # Email regex used to validate email formats. It simply asserts that
# an one (and only one) @ exists in the given string. This is mainly # an one (and only one) @ exists in the given string. This is mainly
......
...@@ -17,6 +17,7 @@ en: ...@@ -17,6 +17,7 @@ en:
unauthenticated: 'You need to sign in before continuing.' unauthenticated: 'You need to sign in before continuing.'
unconfirmed: 'You have to confirm your account before continuing.' unconfirmed: 'You have to confirm your account before continuing.'
locked: 'Your account is locked.' locked: 'Your account is locked.'
not_found_in_database: 'Invalid email or password.'
invalid: 'Invalid email or password.' invalid: 'Invalid email or password.'
invalid_token: 'Invalid authentication token.' invalid_token: 'Invalid authentication token.'
timeout: 'Your session expired, please sign in again to continue.' timeout: 'Your session expired, please sign in again to continue.'
......
...@@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do ...@@ -49,7 +49,7 @@ Gitlab::Application.routes.draw do
# #
# Attachments serving # Attachments serving
# #
get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /[a-zA-Z.0-9_\-\+]+/ } get 'files/:type/:id/:filename' => 'files#download', constraints: { id: /\d+/, type: /[a-z]+/, filename: /.+/ }
# #
# Admin Area # Admin Area
......
class AddIssuesTrackerToProject < ActiveRecord::Migration
def change
add_column :projects, :issues_tracker, :string, default: :gitlab, null: false
end
end
class AddDescriptionToNamsespace < ActiveRecord::Migration
def change
add_column :namespaces, :description, :string, default: '', null: false
end
end
class AddDescriptionToTeams < ActiveRecord::Migration
def change
add_column :user_teams, :description, :string, default: '', null: false
end
end
class AddIssuesTrackerIdToProject < ActiveRecord::Migration
def change
add_column :projects, :issues_tracker_id, :string
end
end
class ConvertClosedToStateInIssue < ActiveRecord::Migration class ConvertClosedToStateInIssue < ActiveRecord::Migration
def up def up
Issue.transaction do Issue.transaction do
Issue.where(closed: true).update_all("state = 'closed'") Issue.where(closed: true).update_all(state: :closed)
Issue.where(closed: false).update_all("state = 'opened'") Issue.where(closed: false).update_all(state: :opened)
end end
end end
def down def down
Issue.transaction do Issue.transaction do
Issue.where(state: :closed).update_all("closed = 1") Issue.where(state: :closed).update_all(closed: true)
end end
end end
end end
class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration
def up def up
MergeRequest.transaction do MergeRequest.transaction do
MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'") MergeRequest.where(closed: true, merged: true).update_all(state: :merged)
MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'") MergeRequest.where(closed: true, merged: false).update_all(state: :closed)
MergeRequest.where(closed: false).update_all("state = 'opened'") MergeRequest.where(closed: false).update_all(state: :opened)
end end
end end
......
class ConvertClosedToStateInMilestone < ActiveRecord::Migration class ConvertClosedToStateInMilestone < ActiveRecord::Migration
def up def up
Milestone.transaction do Milestone.transaction do
Milestone.where(closed: false).update_all("state = 'opened'") Milestone.where(closed: true).update_all(state: :closed)
Milestone.where(closed: false).update_all("state = 'active'") Milestone.where(closed: false).update_all(state: :active)
end end
end end
def down def down
Milestone.transaction do Milestone.transaction do
Milestone.where(state: :closed).update_all("closed = 1") Milestone.where(state: :closed).update_all(closed: true)
end end
end end
end end
class AddStateToUser < ActiveRecord::Migration
def change
add_column :users, :state, :string
end
end
class ConvertBlockedToState < ActiveRecord::Migration
def up
User.transaction do
User.where(blocked: true).update_all(state: :blocked)
User.where(blocked: false).update_all(state: :active)
end
end
def down
User.transaction do
User.where(state: :blocked).update_all(blocked: :true)
end
end
end
class RemoveBlockedFromUser < ActiveRecord::Migration
def up
remove_column :users, :blocked
end
def down
add_column :users, :blocked, :boolean
end
end
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
# #
# It's strongly recommended to check this file into your version control system. # It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130220133245) do ActiveRecord::Schema.define(:version => 20130304105317) do
create_table "events", :force => true do |t| create_table "events", :force => true do |t|
t.string "target_type" t.string "target_type"
...@@ -112,6 +112,7 @@ ActiveRecord::Schema.define(:version => 20130220133245) do ...@@ -112,6 +112,7 @@ ActiveRecord::Schema.define(:version => 20130220133245) do
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
t.string "type" t.string "type"
t.string "description", :default => "", :null => false
end end
add_index "namespaces", ["name"], :name => "index_namespaces_on_name" add_index "namespaces", ["name"], :name => "index_namespaces_on_name"
...@@ -152,6 +153,8 @@ ActiveRecord::Schema.define(:version => 20130220133245) do ...@@ -152,6 +153,8 @@ ActiveRecord::Schema.define(:version => 20130220133245) do
t.boolean "wiki_enabled", :default => true, :null => false t.boolean "wiki_enabled", :default => true, :null => false
t.integer "namespace_id" t.integer "namespace_id"
t.boolean "public", :default => false, :null => false t.boolean "public", :default => false, :null => false
t.string "issues_tracker", :default => "gitlab", :null => false
t.string "issues_tracker_id"
end end
add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id"
...@@ -232,6 +235,7 @@ ActiveRecord::Schema.define(:version => 20130220133245) do ...@@ -232,6 +235,7 @@ ActiveRecord::Schema.define(:version => 20130220133245) do
t.integer "owner_id" t.integer "owner_id"
t.datetime "created_at", :null => false t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false t.datetime "updated_at", :null => false
t.string "description", :default => "", :null => false
end end
create_table "users", :force => true do |t| create_table "users", :force => true do |t|
...@@ -257,7 +261,6 @@ ActiveRecord::Schema.define(:version => 20130220133245) do ...@@ -257,7 +261,6 @@ ActiveRecord::Schema.define(:version => 20130220133245) do
t.boolean "dark_scheme", :default => false, :null => false t.boolean "dark_scheme", :default => false, :null => false
t.integer "theme_id", :default => 1, :null => false t.integer "theme_id", :default => 1, :null => false
t.string "bio" t.string "bio"
t.boolean "blocked", :default => false, :null => false
t.integer "failed_attempts", :default => 0 t.integer "failed_attempts", :default => 0
t.datetime "locked_at" t.datetime "locked_at"
t.string "extern_uid" t.string "extern_uid"
...@@ -265,10 +268,10 @@ ActiveRecord::Schema.define(:version => 20130220133245) do ...@@ -265,10 +268,10 @@ ActiveRecord::Schema.define(:version => 20130220133245) do
t.string "username" t.string "username"
t.boolean "can_create_group", :default => true, :null => false t.boolean "can_create_group", :default => true, :null => false
t.boolean "can_create_team", :default => true, :null => false t.boolean "can_create_team", :default => true, :null => false
t.string "state"
end end
add_index "users", ["admin"], :name => "index_users_on_admin" add_index "users", ["admin"], :name => "index_users_on_admin"
add_index "users", ["blocked"], :name => "index_users_on_blocked"
add_index "users", ["email"], :name => "index_users_on_email", :unique => true add_index "users", ["email"], :name => "index_users_on_email", :unique => true
add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true add_index "users", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true
add_index "users", ["name"], :name => "index_users_on_name" add_index "users", ["name"], :name => "index_users_on_name"
......
...@@ -12,7 +12,7 @@ GitLab supports the following databases: ...@@ -12,7 +12,7 @@ GitLab supports the following databases:
sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev
# Login to MySQL # Login to MySQL
$ mysql -u root -p mysql -u root -p
# Create a user for GitLab. (change $password to a real password) # Create a user for GitLab. (change $password to a real password)
mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password'; mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password';
......
This installation guide was created for Debian/Ubuntu and tested on it. This installation guide was created for Debian/Ubuntu and tested on it. Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements.
Please read [`doc/install/requirements.md`](./requirements.md) for hardware and platform requirements.
This installation guide is recommended to set up a production server. If you want a development environment please use the [Vargrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) since it makes it much easier to set up all the dependencies for integration testing.
**Important Note:** **Important Note:**
The following steps have been known to work. The following steps have been known to work.
...@@ -92,8 +91,11 @@ Create a `git` user for Gitlab: ...@@ -92,8 +91,11 @@ Create a `git` user for Gitlab:
sudo adduser --disabled-login --gecos 'GitLab' git sudo adduser --disabled-login --gecos 'GitLab' git
# 4. GitLab shell # 4. GitLab shell
GitLab Shell is a ssh access and repository management software developed specially for GitLab.
# Login as git # Login as git
sudo su git sudo su git
...@@ -103,9 +105,14 @@ Create a `git` user for Gitlab: ...@@ -103,9 +105,14 @@ Create a `git` user for Gitlab:
# Clone gitlab shell # Clone gitlab shell
git clone https://github.com/gitlabhq/gitlab-shell.git git clone https://github.com/gitlabhq/gitlab-shell.git
# Setup
cd gitlab-shell cd gitlab-shell
cp config.yml.example config.yml cp config.yml.example config.yml
# Edit config and replace gitlab_url
# with something like 'http://domain.com/'
vim config.yml
# Do setup
./bin/install ./bin/install
......
...@@ -7,3 +7,19 @@ Feature: Project Network Graph ...@@ -7,3 +7,19 @@ Feature: Project Network Graph
@javascript @javascript
Scenario: I should see project network Scenario: I should see project network
Then page should have network graph Then page should have network graph
And page should select "master" in select box
And page should have "master" on graph
@javascript
Scenario: I should switch ref to "stable"
When I switch ref to "stable"
Then page should have network graph
And page should select "stable" in select box
And page should have "stable" on graph
@javascript
Scenario: I should looking for a commit by SHA of "v2.1.0"
When I looking for a commit by SHA of "v2.1.0"
Then page should have network graph
And page should select "master" in select box
And page should have "v2.1.0" on graph
...@@ -25,11 +25,13 @@ class AdminGroups < Spinach::FeatureSteps ...@@ -25,11 +25,13 @@ class AdminGroups < Spinach::FeatureSteps
And 'submit form with new group info' do And 'submit form with new group info' do
fill_in 'group_name', :with => 'gitlab' fill_in 'group_name', :with => 'gitlab'
fill_in 'group_description', :with => 'Group description'
click_button "Create group" click_button "Create group"
end end
Then 'I should see newly created group' do Then 'I should see newly created group' do
page.should have_content "Group: gitlab" page.should have_content "Group: gitlab"
page.should have_content "Group description"
end end
Then 'I should be redirected to group page' do Then 'I should be redirected to group page' do
......
...@@ -18,6 +18,7 @@ class AdminTeams < Spinach::FeatureSteps ...@@ -18,6 +18,7 @@ class AdminTeams < Spinach::FeatureSteps
And 'submit form with new team info' do And 'submit form with new team info' do
fill_in 'user_team_name', with: 'gitlab' fill_in 'user_team_name', with: 'gitlab'
fill_in 'user_team_description', with: 'description'
click_button 'Create team' click_button 'Create team'
end end
...@@ -27,6 +28,7 @@ class AdminTeams < Spinach::FeatureSteps ...@@ -27,6 +28,7 @@ class AdminTeams < Spinach::FeatureSteps
And 'I should see newly created team' do And 'I should see newly created team' do
page.should have_content "Team: gitlab" page.should have_content "Team: gitlab"
page.should have_content "description"
end end
When 'I visit admin teams page' do When 'I visit admin teams page' do
......
...@@ -28,7 +28,7 @@ class Groups < Spinach::FeatureSteps ...@@ -28,7 +28,7 @@ class Groups < Spinach::FeatureSteps
Then 'I should see merge requests from this group assigned to me' do Then 'I should see merge requests from this group assigned to me' do
assigned_to_me(:merge_requests).each do |issue| assigned_to_me(:merge_requests).each do |issue|
page.should have_content issue.title page.should have_content issue.title[0..80]
end end
end end
...@@ -69,12 +69,14 @@ class Groups < Spinach::FeatureSteps ...@@ -69,12 +69,14 @@ class Groups < Spinach::FeatureSteps
end end
And 'submit form with new group info' do And 'submit form with new group info' do
fill_in 'group_name', :with => 'Samurai' fill_in 'group_name', with: 'Samurai'
fill_in 'group_description', with: 'Tokugawa Shogunate'
click_button "Create group" click_button "Create group"
end end
Then 'I should see newly created group' do Then 'I should see newly created group' do
page.should have_content "Samurai" page.should have_content "Samurai"
page.should have_content "Tokugawa Shogunate"
page.should have_content "You will only see events from projects in this group" page.should have_content "You will only see events from projects in this group"
end end
......
...@@ -25,8 +25,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -25,8 +25,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
Then 'I should see closed merge request "Bug NS-04"' do Then 'I should see closed merge request "Bug NS-04"' do
mr = MergeRequest.find_by_title("Bug NS-04") merge_request = MergeRequest.find_by_title!("Bug NS-04")
mr.closed?.should be_true merge_request.closed?.should be_true
page.should have_content "Closed by" page.should have_content "Closed by"
end end
...@@ -63,7 +63,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -63,7 +63,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
And 'project "Shop" have "Bug NS-04" open merge request' do And 'project "Shop" have "Bug NS-04" open merge request' do
project = Project.find_by_name("Shop")
create(:merge_request, create(:merge_request,
title: "Bug NS-04", title: "Bug NS-04",
project: project, project: project,
...@@ -71,7 +70,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -71,7 +70,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do And 'project "Shop" have "Bug NS-05" open merge request with diffs inside' do
project = Project.find_by_name("Shop")
create(:merge_request_with_diffs, create(:merge_request_with_diffs,
title: "Bug NS-05", title: "Bug NS-05",
project: project, project: project,
...@@ -79,7 +77,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -79,7 +77,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
And 'project "Shop" have "Feature NS-03" closed merge request' do And 'project "Shop" have "Feature NS-03" closed merge request' do
project = Project.find_by_name("Shop")
create(:closed_merge_request, create(:closed_merge_request,
title: "Feature NS-03", title: "Feature NS-03",
project: project, project: project,
...@@ -87,18 +84,16 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -87,18 +84,16 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
And 'I switch to the diff tab' do And 'I switch to the diff tab' do
mr = MergeRequest.find_by_title("Bug NS-05") visit diffs_project_merge_request_path(project, merge_request)
visit diffs_project_merge_request_path(mr.project, mr)
end end
And 'I switch to the merge request\'s comments tab' do And 'I switch to the merge request\'s comments tab' do
mr = MergeRequest.find_by_title("Bug NS-05") visit project_merge_request_path(project, merge_request)
visit project_merge_request_path(mr.project, mr)
end end
And 'I click on the first commit in the merge request' do And 'I click on the first commit in the merge request' do
mr = MergeRequest.find_by_title("Bug NS-05")
click_link mr.commits.first.short_id(8) click_link merge_request.commits.first.short_id(8)
end end
And 'I leave a comment on the diff page' do And 'I leave a comment on the diff page' do
...@@ -121,8 +116,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -121,8 +116,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
Then 'I should see a discussion has started on line 185' do Then 'I should see a discussion has started on line 185' do
mr = MergeRequest.find_by_title("Bug NS-05") first_commit = merge_request.commits.first
first_commit = mr.commits.first
first_diff = first_commit.diffs.first first_diff = first_commit.diffs.first
page.should have_content "#{current_user.name} started a discussion on this merge request diff" page.should have_content "#{current_user.name} started a discussion on this merge request diff"
page.should have_content "#{first_diff.b_path}:L185" page.should have_content "#{first_diff.b_path}:L185"
...@@ -130,8 +124,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -130,8 +124,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
Then 'I should see a discussion has started on commit bcf03b5de6c:L185' do Then 'I should see a discussion has started on commit bcf03b5de6c:L185' do
mr = MergeRequest.find_by_title("Bug NS-05") first_commit = merge_request.commits.first
first_commit = mr.commits.first
first_diff = first_commit.diffs.first first_diff = first_commit.diffs.first
page.should have_content "#{current_user.name} started a discussion on commit" page.should have_content "#{current_user.name} started a discussion on commit"
page.should have_content first_commit.short_id(8) page.should have_content first_commit.short_id(8)
...@@ -140,12 +133,19 @@ class ProjectMergeRequests < Spinach::FeatureSteps ...@@ -140,12 +133,19 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end end
Then 'I should see a discussion has started on commit bcf03b5de6c' do Then 'I should see a discussion has started on commit bcf03b5de6c' do
mr = MergeRequest.find_by_title("Bug NS-05") first_commit = merge_request.st_commits.first
first_commit = mr.st_commits.first
first_diff = first_commit.diffs.first first_diff = first_commit.diffs.first
page.should have_content "#{current_user.name} started a discussion on commit bcf03b5de6c" page.should have_content "#{current_user.name} started a discussion on commit bcf03b5de6c"
page.should have_content first_commit.short_id(8) page.should have_content first_commit.short_id(8)
page.should have_content "One comment to rule them all" page.should have_content "One comment to rule them all"
page.should have_content "#{first_diff.b_path}:L185" page.should have_content "#{first_diff.b_path}:L185"
end end
def project
@project ||= Project.find_by_name!("Shop")
end
def merge_request
@merge_request ||= MergeRequest.find_by_title!("Bug NS-05")
end
end end
...@@ -4,16 +4,51 @@ class ProjectNetworkGraph < Spinach::FeatureSteps ...@@ -4,16 +4,51 @@ class ProjectNetworkGraph < Spinach::FeatureSteps
Then 'page should have network graph' do Then 'page should have network graph' do
page.should have_content "Project Network Graph" page.should have_content "Project Network Graph"
within ".graph" do page.should have_selector ".graph"
page.should have_content "master"
end
end end
And 'I visit project "Shop" network page' do When 'I visit project "Shop" network page' do
# Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650)
Gitlab::Graph::JsonBuilder.stub(max_count: 10) Graph::JsonBuilder.stub(max_count: 10)
project = Project.find_by_name("Shop") project = Project.find_by_name("Shop")
visit project_graph_path(project, "master") visit project_graph_path(project, "master")
end end
And 'page should select "master" in select box' do
page.should have_selector '#ref_chzn span', :text => "master"
end
And 'page should have "master" on graph' do
within '.graph' do
page.should have_content 'master'
end
end
And 'I switch ref to "stable"' do
page.select 'stable', :from => 'ref'
end
And 'page should select "stable" in select box' do
page.should have_selector '#ref_chzn span', :text => "stable"
end
And 'page should have "stable" on graph' do
within '.graph' do
page.should have_content 'stable'
end
end
And 'I looking for a commit by SHA of "v2.1.0"' do
within ".content .search" do
fill_in 'q', :with => '98d6492'
find('button').click
end
end
And 'page should have "v2.1.0" on graph' do
within '.graph' do
page.should have_content 'v2.1.0'
end
end
end end
...@@ -143,7 +143,7 @@ module SharedPaths ...@@ -143,7 +143,7 @@ module SharedPaths
Given "I visit my project's network page" do Given "I visit my project's network page" do
# Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650) # Stub Graph::JsonBuilder max_size to speed up test (10 commits vs. 650)
Gitlab::Graph::JsonBuilder.stub(max_count: 10) Graph::JsonBuilder.stub(max_count: 10)
visit project_graph_path(@project, root_ref) visit project_graph_path(@project, root_ref)
end end
......
...@@ -44,9 +44,16 @@ class Userteams < Spinach::FeatureSteps ...@@ -44,9 +44,16 @@ class Userteams < Spinach::FeatureSteps
And 'I submit form with new team info' do And 'I submit form with new team info' do
fill_in 'name', with: 'gitlab' fill_in 'name', with: 'gitlab'
fill_in 'user_team_description', with: 'team description'
click_button 'Create team' click_button 'Create team'
end end
And 'I should see newly created team' do
page.should have_content "gitlab"
page.should have_content "team description"
end
Then 'I should be redirected to new team page' do Then 'I should be redirected to new team page' do
team = UserTeam.last team = UserTeam.last
current_path.should == team_path(team) current_path.should == team_path(team)
......
...@@ -34,6 +34,7 @@ Spinach.hooks.before_scenario do ...@@ -34,6 +34,7 @@ Spinach.hooks.before_scenario do
Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path')) Gitlab.config.gitlab_shell.stub(repos_path: Rails.root.join('tmp', 'test-git-base-path'))
FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path FileUtils.rm_rf Gitlab.config.gitlab_shell.repos_path
FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path FileUtils.mkdir_p Gitlab.config.gitlab_shell.repos_path
DatabaseCleaner.start
end end
Spinach.hooks.after_scenario do Spinach.hooks.after_scenario do
......
...@@ -20,6 +20,7 @@ Feature: UserTeams ...@@ -20,6 +20,7 @@ Feature: UserTeams
When I click to "New team" link When I click to "New team" link
And I submit form with new team info And I submit form with new team info
Then I should be redirected to new team page Then I should be redirected to new team page
Then I should see newly created team
Scenario: I should see team dashboard list Scenario: I should see team dashboard list
When I have teams with projects and members When I have teams with projects and members
......
...@@ -2,11 +2,11 @@ module Gitlab ...@@ -2,11 +2,11 @@ module Gitlab
module Entities module Entities
class User < Grape::Entity class User < Grape::Entity
expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter, expose :id, :username, :email, :name, :bio, :skype, :linkedin, :twitter,
:dark_scheme, :theme_id, :blocked, :created_at, :extern_uid, :provider :dark_scheme, :theme_id, :state, :created_at, :extern_uid, :provider
end end
class UserBasic < Grape::Entity class UserBasic < Grape::Entity
expose :id, :username, :email, :name, :blocked, :created_at expose :id, :username, :email, :name, :state, :created_at
end end
class UserLogin < UserBasic class UserLogin < UserBasic
......
...@@ -52,8 +52,8 @@ module Gitlab ...@@ -52,8 +52,8 @@ module Gitlab
:issues_enabled, :issues_enabled,
:wall_enabled, :wall_enabled,
:merge_requests_enabled, :merge_requests_enabled,
:wiki_enabled] :wiki_enabled,
:namespace_id]
@project = ::Projects::CreateContext.new(current_user, attrs).execute @project = ::Projects::CreateContext.new(current_user, attrs).execute
if @project.saved? if @project.saved?
present @project, with: Entities::Project present @project, with: Entities::Project
......
...@@ -126,7 +126,7 @@ module ExtractsPath ...@@ -126,7 +126,7 @@ module ExtractsPath
@tree = TreeDecorator.new(@tree) @tree = TreeDecorator.new(@tree)
raise InvalidPathError if @tree.invalid? raise InvalidPathError if @tree.invalid?
rescue NoMethodError, InvalidPathError rescue RuntimeError, NoMethodError, InvalidPathError
not_found! not_found!
end end
end end
...@@ -41,10 +41,12 @@ module Gitlab ...@@ -41,10 +41,12 @@ module Gitlab
password_confirmation: password, password_confirmation: password,
projects_limit: Gitlab.config.gitlab.default_projects_limit, projects_limit: Gitlab.config.gitlab.default_projects_limit,
}, as: :admin) }, as: :admin)
@user.save!
if Gitlab.config.omniauth['block_auto_created_users'] && !ldap if Gitlab.config.omniauth['block_auto_created_users'] && !ldap
@user.blocked = true @user.block
end end
@user.save!
@user @user
end end
......
require "grit"
module Gitlab
module Graph
class Commit
include ActionView::Helpers::TagHelper
attr_accessor :time, :space, :refs, :parent_spaces
def initialize(commit)
@_commit = commit
@time = -1
@space = 0
@parent_spaces = []
end
def method_missing(m, *args, &block)
@_commit.send(m, *args, &block)
end
def to_graph_hash
h = {}
h[:parents] = self.parents.collect do |p|
[p.id,0,0]
end
h[:author] = {
name: author.name,
email: author.email
}
h[:time] = time
h[:space] = space
h[:parent_spaces] = parent_spaces
h[:refs] = refs.collect{|r|r.name}.join(" ") unless refs.nil?
h[:id] = sha
h[:date] = date
h[:message] = message
h
end
def add_refs(ref_cache, repo)
if ref_cache.empty?
repo.refs.each do |ref|
ref_cache[ref.commit.id] ||= []
ref_cache[ref.commit.id] << ref
end
end
@refs = ref_cache[@_commit.id] if ref_cache.include?(@_commit.id)
@refs ||= []
end
end
end
end
require "grit"
module Gitlab
module Graph
class JsonBuilder
attr_accessor :days, :commits, :ref_cache, :repo
def self.max_count
@max_count ||= 650
end
def initialize project, ref, commit
@project = project
@ref = ref
@commit = commit
@repo = project.repo
@ref_cache = {}
@commits = collect_commits
@days = index_commits
end
def to_json(*args)
{
days: @days.compact.map { |d| [d.day, d.strftime("%b")] },
commits: @commits.map(&:to_graph_hash)
}.to_json(*args)
end
protected
# Get commits from repository
#
def collect_commits
@commits = Grit::Commit.find_all(repo, nil, {topo_order: true, max_count: self.class.max_count, skip: to_commit}).dup
# Decorate with app/models/commit.rb
@commits.map! { |commit| ::Commit.new(commit) }
# Decorate with lib/gitlab/graph/commit.rb
@commits.map! { |commit| Gitlab::Graph::Commit.new(commit) }
# add refs to each commit
@commits.each { |commit| commit.add_refs(ref_cache, repo) }
@commits
end
# Method is adding time and space on the
# list of commits. As well as returns date list
# corelated with time set on commits.
#
# @param [Array<Graph::Commit>] commits to index
#
# @return [Array<TimeDate>] list of commit dates corelated with time on commits
def index_commits
days, times = [], []
map = {}
commits.reverse.each_with_index do |c,i|
c.time = i
days[i] = c.committed_date
map[c.id] = c
times[i] = c
end
@_reserved = {}
days.each_index do |i|
@_reserved[i] = []
end
commits_sort_by_ref.each do |commit|
if map.include? commit.id then
place_chain(map[commit.id], map)
end
end
# find parent spaces for not overlap lines
times.each do |c|
c.parent_spaces.concat(find_free_parent_spaces(c, map, times))
end
days
end
# Skip count that the target commit is displayed in center.
def to_commit
commits = Grit::Commit.find_all(repo, nil, {topo_order: true})
commit_index = commits.index do |c|
c.id == @commit.id
end
if commit_index && (self.class.max_count / 2 < commit_index) then
# get max index that commit is displayed in the center.
commit_index - self.class.max_count / 2
else
0
end
end
def commits_sort_by_ref
commits.sort do |a,b|
if include_ref?(a)
-1
elsif include_ref?(b)
1
else
b.committed_date <=> a.committed_date
end
end
end
def include_ref?(commit)
heads = commit.refs.select do |ref|
ref.is_a?(Grit::Head) or ref.is_a?(Grit::Remote) or ref.is_a?(Grit::Tag)
end
heads.map! do |head|
head.name
end
heads.include?(@ref)
end
def find_free_parent_spaces(commit, map, times)
spaces = []
commit.parents.each do |p|
if map.include?(p.id) then
parent = map[p.id]
range = if commit.time < parent.time then
commit.time..parent.time
else
parent.time..commit.time
end
space = if commit.space >= parent.space then
find_free_parent_space(range, parent.space, 1, commit.space, times)
else
find_free_parent_space(range, parent.space, -1, parent.space, times)
end
mark_reserved(range, space)
spaces << space
end
end
spaces
end
def find_free_parent_space(range, space_base, space_step, space_default, times)
if is_overlap?(range, times, space_default) then
find_free_space(range, space_base, space_step)
else
space_default
end
end
def is_overlap?(range, times, overlap_space)
range.each do |i|
if i != range.first &&
i != range.last &&
times[i].space == overlap_space then
return true;
end
end
false
end
# Add space mark on commit and its parents
#
# @param [Graph::Commit] the commit object.
# @param [Hash<String,Graph::Commit>] map of commits
def place_chain(commit, map, parent_time = nil)
leaves = take_left_leaves(commit, map)
if leaves.empty?
return
end
# and mark it as reserved
min_time = leaves.last.time
max_space = 1
parents = leaves.last.parents.collect
parents.each do |p|
if map.include? p.id
parent = map[p.id]
if parent.time < min_time
min_time = parent.time
end
if max_space < parent.space then
max_space = parent.space
end
end
end
if parent_time.nil?
max_time = leaves.first.time
else
max_time = parent_time - 1
end
time_range = leaves.last.time..leaves.first.time
space = find_free_space(time_range, max_space, 2)
leaves.each{|l| l.space = space}
mark_reserved(min_time..max_time, space)
# Visit branching chains
leaves.each do |l|
parents = l.parents.collect.select{|p| map.include? p.id and map[p.id].space.zero?}
for p in parents
place_chain(map[p.id], map, l.time)
end
end
end
def mark_reserved(time_range, space)
for day in time_range
@_reserved[day].push(space)
end
end
def find_free_space(time_range, space_base, space_step)
reserved = []
for day in time_range
reserved += @_reserved[day]
end
reserved.uniq!
space = space_base
while reserved.include?(space) do
space += space_step
if space <= 0 then
space_step *= -1
space = space_base + space_step
end
end
space
end
# Takes most left subtree branch of commits
# which don't have space mark yet.
#
# @param [Graph::Commit] the commit object.
# @param [Hash<String,Graph::Commit>] map of commits
#
# @return [Array<Graph::Commit>] list of branch commits
def take_left_leaves(commit, map)
leaves = []
leaves.push(commit) if commit.space.zero?
while true
return leaves if commit.parents.count.zero?
return leaves unless map.include? commit.parents.first.id
commit = map[commit.parents.first.id]
return leaves unless commit.space.zero?
leaves.push(commit)
end
end
end
end
end
...@@ -25,6 +25,8 @@ module Gitlab ...@@ -25,6 +25,8 @@ module Gitlab
# >> gfm(":trollface:") # >> gfm(":trollface:")
# => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" /> # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" />
module Markdown module Markdown
include IssuesHelper
attr_reader :html_options attr_reader :html_options
# Public: Parse the provided text with GitLab-Flavored Markdown # Public: Parse the provided text with GitLab-Flavored Markdown
...@@ -163,8 +165,11 @@ module Gitlab ...@@ -163,8 +165,11 @@ module Gitlab
end end
def reference_issue(identifier) def reference_issue(identifier)
if issue = @project.issues.where(id: identifier).first if @project.issue_exists? identifier
link_to("##{identifier}", project_issue_url(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) url = url_for_issue(identifier)
title = title_for_issue(identifier)
link_to("##{identifier}", url, html_options.merge(title: "Issue: #{title}", class: "gfm gfm-issue #{html_options[:class]}"))
end end
end end
......
namespace :sidekiq do namespace :sidekiq do
desc "GITLAB | Stop sidekiq" desc "GITLAB | Stop sidekiq"
task :stop do task :stop do
run "bundle exec sidekiqctl stop #{pidfile}" system "bundle exec sidekiqctl stop #{pidfile}"
end end
desc "GITLAB | Start sidekiq" desc "GITLAB | Start sidekiq"
task :start do task :start do
run "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &" system "nohup bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1 &"
end end
desc "GITLAB | Start sidekiq with launchd on Mac OS X" desc "GITLAB | Start sidekiq with launchd on Mac OS X"
task :launchd do task :launchd do
run "bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1" system "bundle exec sidekiq -q post_receive,mailer,system_hook,project_web_hook,gitlab_shell,common,default -e #{Rails.env} -P #{pidfile} >> #{Rails.root.join("log", "sidekiq.log")} 2>&1"
end end
def pidfile def pidfile
......
...@@ -29,6 +29,11 @@ FactoryGirl.define do ...@@ -29,6 +29,11 @@ FactoryGirl.define do
creator creator
end end
factory :redmine_project, parent: :project do
issues_tracker { "redmine" }
issues_tracker_id { "project_name_in_redmine" }
end
factory :group do factory :group do
sequence(:name) { |n| "group#{n}" } sequence(:name) { |n| "group#{n}" }
path { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
FactoryGirl.define do FactoryGirl.define do
factory :user_team do factory :user_team do
sequence(:name) { |n| "team#{n}" } sequence(:name) { |n| "team#{n}" }
sequence(:description) { |n| "team_description#{n}" }
path { name.downcase.gsub(/\s/, '_') } path { name.downcase.gsub(/\s/, '_') }
owner owner
end end
......
...@@ -55,8 +55,8 @@ describe "Admin::Users" do ...@@ -55,8 +55,8 @@ describe "Admin::Users" do
user = User.last user = User.last
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.subject.should have_content("Account was created") email.subject.should have_content("Account was created")
email.body.should have_content(user.email) email.text_part.body.should have_content(user.email)
email.body.should have_content(@password) email.text_part.body.should have_content(@password)
end end
end end
...@@ -67,8 +67,8 @@ describe "Admin::Users" do ...@@ -67,8 +67,8 @@ describe "Admin::Users" do
user = User.last user = User.last
email = ActionMailer::Base.deliveries.last email = ActionMailer::Base.deliveries.last
email.subject.should have_content("Account was created") email.subject.should have_content("Account was created")
email.body.should have_content(user.email) email.text_part.body.should have_content(user.email)
email.body.should_not have_content(@password) email.text_part.body.should_not have_content(@password)
end end
end end
end end
......
...@@ -2,6 +2,7 @@ require "spec_helper" ...@@ -2,6 +2,7 @@ require "spec_helper"
describe GitlabMarkdownHelper do describe GitlabMarkdownHelper do
include ApplicationHelper include ApplicationHelper
include IssuesHelper
let!(:project) { create(:project) } let!(:project) { create(:project) }
......
require "spec_helper"
describe IssuesHelper do
let(:project) { create :project }
let(:issue) { create :issue, project: project }
let(:ext_project) { create :redmine_project }
describe :title_for_issue do
it "should return issue title if used internal tracker" do
@project = project
title_for_issue(issue.id).should eq issue.title
end
it "should always return empty string if used external tracker" do
@project = ext_project
title_for_issue(rand(100)).should eq ""
end
it "should always return empty string if project nil" do
@project = nil
title_for_issue(rand(100)).should eq ""
end
end
describe :url_for_project_issues do
let(:project_url) { Gitlab.config.issues_tracker.redmine.project_url}
let(:ext_expected) do
project_url.gsub(':project_id', ext_project.id.to_s)
.gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
end
let(:int_expected) { polymorphic_path([project]) }
it "should return internal path if used internal tracker" do
@project = project
url_for_project_issues.should match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
url_for_project_issues.should match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
url_for_project_issues.should eq ""
end
end
describe :url_for_issue do
let(:issue_id) { 3 }
let(:issues_url) { Gitlab.config.issues_tracker.redmine.issues_url}
let(:ext_expected) do
issues_url.gsub(':id', issue_id.to_s)
.gsub(':project_id', ext_project.id.to_s)
.gsub(':issues_tracker_id', ext_project.issues_tracker_id.to_s)
end
let(:int_expected) { polymorphic_path([project, issue]) }
it "should return internal path if used internal tracker" do
@project = project
url_for_issue(issue.id).should match(int_expected)
end
it "should return path to external tracker" do
@project = ext_project
url_for_issue(issue_id).should match(ext_expected)
end
it "should return empty string if project nil" do
@project = nil
url_for_issue(issue.id).should eq ""
end
end
end
...@@ -60,6 +60,7 @@ describe Project do ...@@ -60,6 +60,7 @@ describe Project do
it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) } it { should ensure_inclusion_of(:wall_enabled).in_array([true, false]) }
it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) } it { should ensure_inclusion_of(:merge_requests_enabled).in_array([true, false]) }
it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) } it { should ensure_inclusion_of(:wiki_enabled).in_array([true, false]) }
it { should ensure_length_of(:issues_tracker_id).is_within(0..255) }
it "should not allow new projects beyond user limits" do it "should not allow new projects beyond user limits" do
project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1))
...@@ -190,4 +191,57 @@ describe Project do ...@@ -190,4 +191,57 @@ describe Project do
Project.new(path: "empty").repository.should be_nil Project.new(path: "empty").repository.should be_nil
end end
end end
describe :issue_exists? do
let(:project) { create(:project) }
let(:existed_issue) { create(:issue, project: project) }
let(:not_existed_issue) { create(:issue) }
let(:ext_project) { create(:redmine_project) }
it "should be true or if used internal tracker and issue exists" do
project.issue_exists?(existed_issue.id).should be_true
end
it "should be false or if used internal tracker and issue not exists" do
project.issue_exists?(not_existed_issue.id).should be_false
end
it "should always be true if used other tracker" do
ext_project.issue_exists?(rand(100)).should be_true
end
end
describe :used_default_issues_tracker? do
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
it "should be true if used internal tracker" do
project.used_default_issues_tracker?.should be_true
end
it "should be false if used other tracker" do
ext_project.used_default_issues_tracker?.should be_false
end
end
describe :can_have_issues_tracker_id? do
let(:project) { create(:project) }
let(:ext_project) { create(:redmine_project) }
it "should be true for projects with external issues tracker if issues enabled" do
ext_project.can_have_issues_tracker_id?.should be_true
end
it "should be false for projects with internal issue tracker if issues enabled" do
project.can_have_issues_tracker_id?.should be_false
end
it "should be always false if issues disbled" do
project.issues_enabled = false
ext_project.issues_enabled = false
project.can_have_issues_tracker_id?.should be_false
ext_project.can_have_issues_tracker_id?.should be_false
end
end
end end
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
# dark_scheme :boolean default(FALSE), not null # dark_scheme :boolean default(FALSE), not null
# theme_id :integer default(1), not null # theme_id :integer default(1), not null
# bio :string(255) # bio :string(255)
# blocked :boolean default(FALSE), not null # state :string(255) default(FALSE), not null
# failed_attempts :integer default(0) # failed_attempts :integer default(0)
# locked_at :datetime # locked_at :datetime
# extern_uid :string(255) # extern_uid :string(255)
...@@ -140,7 +140,7 @@ describe User do ...@@ -140,7 +140,7 @@ describe User do
it "should block user" do it "should block user" do
user.block user.block
user.blocked.should be_true user.blocked?.should be_true
end end
end end
...@@ -149,7 +149,7 @@ describe User do ...@@ -149,7 +149,7 @@ describe User do
User.delete_all User.delete_all
@user = create :user @user = create :user
@admin = create :user, admin: true @admin = create :user, admin: true
@blocked = create :user, blocked: true @blocked = create :user, state: :blocked
end end
it { User.filter("admins").should == [@admin] } it { User.filter("admins").should == [@admin] }
......
...@@ -15,7 +15,13 @@ describe UserObserver do ...@@ -15,7 +15,13 @@ describe UserObserver do
create(:user) create(:user)
end end
it 'no email for external' do
Notify.should_not_receive(:new_user_email)
create(:user, extern_uid: '32442eEfsafada')
end
it 'trigger logger' do it 'trigger logger' do
user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false)
Gitlab::AppLogger.should_receive(:info) Gitlab::AppLogger.should_receive(:info)
create(:user) create(:user)
end end
......
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