diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00304dd3d64e47e73a9479b3bfc5004c87e81c1b..cff5e939f1190047f8aa88572251a84984c5f06f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,26 +1,76 @@ -# Contact & support +# Contribute to GitLab -If you want quick help, head over to our [Support Forum](https://groups.google.com/forum/#!forum/gitlabhq). -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. +If you have a question or want to contribute to GitLab this guide show you the appropriate channel to use. +## 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. -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. +**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. -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 -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. diff --git a/Gemfile b/Gemfile index 6652d1e35b2396ef01f0475feaa422b4ec36e275..cf1617c316a7c1aa8d29450c6d74eab6b8e579ca 100644 --- a/Gemfile +++ b/Gemfile @@ -15,16 +15,18 @@ gem "mysql2", group: :mysql gem "pg", group: :postgres # Auth -gem "devise", "~> 2.1.0" -gem 'omniauth', "~> 1.1.1" +gem "devise" +gem 'omniauth', "~> 1.1.3" gem 'omniauth-google-oauth2' gem 'omniauth-twitter' gem 'omniauth-github' -# GITLAB patched libs -gem "grit", git: "https://github.com/gitlabhq/grit.git", ref: '9e98418ce2d654485b967003726aa2706a10060b' -gem 'grack', git: "https://github.com/gitlabhq/grack.git", ref: 'ba46f3b0845c6a09d488ae6abdce6ede37e227e8' -gem 'grit_ext', git: "https://github.com/gitlabhq/grit_ext.git", ref: '8e6afc2da821354774aa4d1ee8a1aa2082f84a3e' +# Extracting information from a git repository +gem "gitlab-grit", '~> 1.0.0', require: 'grit' +gem 'grit_ext', '~> 0.6.2' + +# Ruby/Rack Git Smart-HTTP Server Handler +gem 'gitlab-grack', '~> 1.0.0', require: 'grack' # LDAP Auth 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" # 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 gem "github-linguist", "~> 2.3.4" , require: "linguist" @@ -46,14 +48,17 @@ gem "grape-entity", "~> 0.2.0" # based on human-friendly examples gem "stamp" +# Enumeration fields +gem 'enumerize' + # Pagination gem "kaminari", "~> 0.14.1" # HAML -gem "haml-rails", "~> 0.3.5" +gem "haml-rails" # Files attachments -gem "carrierwave", "~> 0.7.1" +gem "carrierwave" # Authorization gem "six" @@ -69,7 +74,7 @@ gem "redcarpet", "~> 2.2.2" gem "github-markup", "~> 0.7.4", require: 'github/markup' # Servers -gem "unicorn", "~> 4.4.0" +gem "unicorn" # State machine gem "state_machine" @@ -78,12 +83,12 @@ gem "state_machine" gem "acts-as-taggable-on", "2.3.3" # Decorators -gem "draper", "~> 0.18.0" +gem "draper" # Background jobs gem 'slim' gem 'sinatra', require: nil -gem 'sidekiq', '2.7.3' +gem 'sidekiq' # HTTP requests gem "httparty" @@ -113,6 +118,7 @@ group :assets do gem 'bootstrap-sass', "2.2.1.1" gem "font-awesome-sass-rails", "~> 3.0.0" gem "gemoji", "~> 1.2.1", require: 'emoji/railtie' + gem "gon" end group :development do @@ -140,7 +146,7 @@ group :development, :test do gem "capybara", '2.0.2' gem "pry" gem "awesome_print" - gem "database_cleaner", ref: "9f898fc50d87a5d51760f9dcf374bf5ffda21baf", git: "https://github.com/bmabey/database_cleaner.git" + gem "database_cleaner" gem "launchy" gem 'factory_girl_rails' diff --git a/Gemfile.lock b/Gemfile.lock index 93abf857cb83437558e3c2674ada494d96f83754..89882492b36fcf5a08d7a0a0a2b3411f1e3738f6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,10 +1,3 @@ -GIT - remote: https://github.com/bmabey/database_cleaner.git - revision: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf - ref: 9f898fc50d87a5d51760f9dcf374bf5ffda21baf - specs: - database_cleaner (0.9.1) - GIT remote: https://github.com/ctran/annotate_models.git revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e @@ -13,41 +6,6 @@ GIT activerecord (>= 2.3.0) 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 remote: https://github.com/gitlabhq/raphael-rails.git revision: cb2c92a040b9b941a5f1aa1ea866cc26e944fe58 @@ -89,12 +47,13 @@ GEM addressable (2.3.2) arel (3.0.2) awesome_print (1.1.0) - backports (2.6.5) + backports (2.6.7) bcrypt-ruby (3.0.1) better_errors (0.3.2) coderay (>= 1.0.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) sass (~> 3.2) builder (3.0.4) @@ -105,7 +64,7 @@ GEM rack-test (>= 0.5.4) selenium-webdriver (~> 2.0) xpath (~> 1.0.0) - carrierwave (0.7.1) + carrierwave (0.8.0) activemodel (>= 3.2.0) activesupport (>= 3.2.0) celluloid (0.12.4) @@ -132,18 +91,24 @@ GEM connection_pool (1.0.0) crack (0.3.1) 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) orm_adapter (~> 0.1) railties (~> 3.1) warden (~> 1.2.1) diff-lcs (1.1.3) - draper (0.18.0) - actionpack (~> 3.2) - activesupport (~> 3.2) + draper (1.1.0) + actionpack (>= 3.0) + activesupport (>= 3.0) + request_store (~> 1.0.3) email_spec (1.4.0) launchy (~> 2.1) mail (~> 2.2) + enumerize (0.5.1) + activesupport (>= 3.2) erubis (2.7.0) escape_utils (0.2.4) eventmachine (1.0.0) @@ -155,7 +120,7 @@ GEM factory_girl_rails (4.1.0) factory_girl (~> 4.1.0) railties (>= 3.0.0) - faraday (0.8.4) + faraday (0.8.6) multipart-post (~> 1.1) faye-websocket (0.4.7) eventmachine (>= 0.12.0) @@ -164,7 +129,7 @@ GEM font-awesome-sass-rails (3.0.0.1) railties (>= 3.1.1) sass-rails (>= 3.1.1) - foreman (0.60.2) + foreman (0.61.0) thor (>= 0.13.6) gemoji (1.2.1) gherkin-ruby (0.2.1) @@ -174,7 +139,16 @@ GEM escape_utils (~> 0.2.3) mime-types (~> 1.19) 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_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -182,17 +156,22 @@ GEM pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) - grape (0.3.1) + gon (4.0.2) + grape (0.3.2) activesupport - grape-entity (~> 0.2.0) - hashie (~> 1.2) + builder + hashie (>= 1.2.0) multi_json (>= 1.3.2) - multi_xml + multi_xml (>= 0.5.2) rack rack-accept rack-mount virtus 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) guard (1.5.4) listen (>= 0.4.2) @@ -205,20 +184,21 @@ GEM guard-spinach (0.0.2) guard (>= 1.1) spinach - haml (3.1.7) - haml-rails (0.3.5) + haml (4.0.0) + tilt + haml-rails (0.4) actionpack (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1) - haml (~> 3.1) + haml (>= 3.1, < 4.1) railties (>= 3.1, < 4.1) hashie (1.2.0) hike (1.2.1) http_parser.rb (0.5.3) - httparty (0.9.0) + httparty (0.10.2) multi_json (~> 1.0) - multi_xml + multi_xml (>= 0.5.2) httpauth (0.2.0) - i18n (0.6.1) + i18n (0.6.4) journey (1.0.4) jquery-atwho-rails (0.1.7) jquery-rails (2.1.3) @@ -233,7 +213,7 @@ GEM kaminari (0.14.1) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - kgio (2.7.4) + kgio (2.8.0) launchy (2.1.2) addressable (~> 2.3) letter_opener (1.0.0) @@ -250,22 +230,22 @@ GEM modernizr (2.6.2) sprockets (~> 2.0) multi_json (1.6.1) - multi_xml (0.5.1) - multipart-post (1.1.5) + multi_xml (0.5.3) + multipart-post (1.2.0) mysql2 (0.3.11) net-ldap (0.2.2) nokogiri (1.5.6) oauth (0.4.7) - oauth2 (0.8.0) + oauth2 (0.8.1) faraday (~> 0.8) httpauth (~> 0.1) jwt (~> 0.1.4) multi_json (~> 1.0) rack (~> 1.2) - omniauth (1.1.1) + omniauth (1.1.3) hashie (~> 1.2) rack - omniauth-github (1.0.3) + omniauth-github (1.1.0) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) omniauth-google-oauth2 (0.1.13) @@ -293,6 +273,9 @@ GEM coderay (~> 1.0.5) method_source (~> 0.8) 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) quiet_assets (1.0.1) railties (~> 3.1) @@ -305,7 +288,7 @@ GEM rack (>= 1.1.3) rack-mount (0.8.3) rack (>= 1.0.0) - rack-protection (1.3.2) + rack-protection (1.4.0) rack rack-ssl (1.3.3) rack @@ -342,12 +325,13 @@ GEM rb-fsevent (0.9.2) rb-inotify (0.8.8) ffi (>= 0.5.0) - rdoc (3.12.1) + rdoc (3.12.2) json (~> 1.4) redcarpet (2.2.2) redis (3.0.2) redis-namespace (1.2.1) redis (~> 3.0.0) + request_store (1.0.5) rspec (2.12.0) rspec-core (~> 2.12.0) rspec-expectations (~> 2.12.0) @@ -381,11 +365,11 @@ GEM multi_json (~> 1.0) rubyzip websocket (~> 1.0.4) - settingslogic (2.0.8) + settingslogic (2.0.9) sexp_processor (4.1.3) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) - sidekiq (2.7.3) + sidekiq (2.7.5) celluloid (~> 0.12.0) connection_pool (~> 1.0) multi_json (~> 1) @@ -395,9 +379,9 @@ GEM multi_json (~> 1.0) simplecov-html (~> 0.7.1) simplecov-html (0.7.1) - sinatra (1.3.3) - rack (~> 1.3, >= 1.3.6) - rack-protection (~> 1.2) + sinatra (1.3.5) + rack (~> 1.4) + rack-protection (~> 1.3) tilt (~> 1.3, >= 1.3.3) six (0.2.0) slim (1.3.6) @@ -416,7 +400,7 @@ GEM multi_json (~> 1.0) rack (~> 1.0) tilt (~> 1.1, != 1.3.0) - stamp (0.3.0) + stamp (0.5.0) state_machine (1.1.2) temple (0.5.5) test_after_commit (0.0.1) @@ -427,7 +411,7 @@ GEM eventmachine (>= 0.12.6) rack (>= 1.0.0) thor (0.17.0) - tilt (1.3.3) + tilt (1.3.4) timers (1.1.0) treetop (1.4.12) polyglot @@ -436,12 +420,13 @@ GEM uglifier (1.3.0) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) - unicorn (4.4.0) + unicorn (4.6.2) kgio (~> 2.6) rack raindrops (~> 0.7) - virtus (0.5.2) + virtus (0.5.4) backports (~> 2.6.1) + descendants_tracker (~> 0.0.1) warden (1.2.1) rack (>= 1.0) webmock (1.9.0) @@ -463,14 +448,15 @@ DEPENDENCIES binding_of_caller bootstrap-sass (= 2.2.1.1) capybara (= 2.0.2) - carrierwave (~> 0.7.1) + carrierwave chosen-rails (= 0.9.8) coffee-rails (~> 3.2.2) colored - database_cleaner! - devise (~> 2.1.0) - draper (~> 0.18.0) + database_cleaner + devise + draper email_spec + enumerize factory_girl_rails ffaker font-awesome-sass-rails (~> 3.0.0) @@ -479,18 +465,20 @@ DEPENDENCIES git github-linguist (~> 2.3.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_omniauth-ldap (= 1.0.2) gitlab_yaml_db (= 1.0.0) - grack! + gon grape (~> 0.3.1) grape-entity (~> 0.2.0) - grit! - grit_ext! + grit_ext (~> 0.6.2) growl guard-rspec guard-spinach - haml-rails (~> 0.3.5) + haml-rails httparty jquery-atwho-rails (= 0.1.7) jquery-rails (= 2.1.3) @@ -500,14 +488,13 @@ DEPENDENCIES letter_opener modernizr (= 2.6.2) mysql2 - omniauth (~> 1.1.1) + omniauth (~> 1.1.3) omniauth-github omniauth-google-oauth2 omniauth-twitter pg poltergeist (= 1.1.0) pry - pygments.rb! quiet_assets (~> 1.0.1) rack-mini-profiler rails (= 3.2.12) @@ -523,7 +510,7 @@ DEPENDENCIES seed-fu settingslogic shoulda-matchers (= 1.3.0) - sidekiq (= 2.7.3) + sidekiq simplecov sinatra six @@ -535,5 +522,5 @@ DEPENDENCIES therubyracer thin uglifier (~> 1.3.0) - unicorn (~> 4.4.0) + unicorn webmock diff --git a/README.md b/README.md index e910dc958cd8ed07f35b7451d4db4beb9dc899be..02b4722f4be319fe78cec2c8d84b156c2ee41f3e 100644 --- a/README.md +++ b/README.md @@ -1,41 +1,132 @@ -# Welcome to GitLab! Self hosted Git management software +## GitLab: self hosted Git management software + -## 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 + +* [](http://ci.gitlab.org/projects/1?ref=master) ci.gitlab.org (master branch) + +* [](https://travis-ci.org/gitlabhq/gitlabhq) travis-ci.org (master branch) + +* [](https://codeclimate.com/github/gitlabhq/gitlabhq) -* master: travis-ci.org [](https://travis-ci.org/gitlabhq/gitlabhq)a -* master: ci.gitlab.org [](http://ci.gitlab.org/projects/1?ref=master) -* [](https://codeclimate.com/github/gitlabhq/gitlabhq) * [](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 -* its completely free and open source -* distributed under the MIT License +* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server -## Requirements +### Requirements -* Ubuntu/Debian +* Ubuntu/Debian* * ruby 1.9.3+ * MySQL * git * gitlab-shell * 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) -Want to help - send a pull request. -We'll accept good pull requests. +* [Contact page](http://gitlab.org/contact/) diff --git a/ROADMAP.md b/ROADMAP.md index d148b518b0ee34028fcbcaa96874a335d48c0dda..bf4fe69543831bcce0ec75de03b500cca1d242b3 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -4,9 +4,4 @@ * Replace gitolite with gitlab-shell * Usability improvements -* Notification improvements - -### v4.2 February 22 - -* Teams - +* Notification improvements \ No newline at end of file diff --git a/app/assets/fonts/OFL.txt b/app/assets/fonts/OFL.txt deleted file mode 100644 index 3ce219f0126c2fc75b8c20217206e0b124f8637c..0000000000000000000000000000000000000000 --- a/app/assets/fonts/OFL.txt +++ /dev/null @@ -1,92 +0,0 @@ -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. diff --git a/app/assets/fonts/YanoneKaffeesatz-Light.ttf b/app/assets/fonts/YanoneKaffeesatz-Light.ttf deleted file mode 100644 index 5026d3bdbe2684ac46d7a651b340364157db2db1..0000000000000000000000000000000000000000 Binary files a/app/assets/fonts/YanoneKaffeesatz-Light.ttf and /dev/null differ diff --git a/vendor/assets/javascripts/branch-graph.js b/app/assets/javascripts/branch-graph.js similarity index 89% rename from vendor/assets/javascripts/branch-graph.js rename to app/assets/javascripts/branch-graph.js index fb22953acd284aa51761b0fc80bac6957824dca8..137e87de37f023614ef14206649bd759d3c2dccc 100644 --- a/vendor/assets/javascripts/branch-graph.js +++ b/app/assets/javascripts/branch-graph.js @@ -132,17 +132,31 @@ }); } else if (c.space < this.commits[i].space) { - r.path([ - "M", x - 5, y, - "l-5-2,0,4,5,-2", - "L", x - 10, y, - "L", x - 15, psy, - "L", cx + 5, psy, - "L", cx, cy]) - .attr({ - stroke: this.colors[this.commits[i].space], - "stroke-width": 2 - }); + if (y == psy) { + r.path([ + "M", x - 5, y, + "l-5,-2,0,4,5,-2", + "L", x - 10, y, + "L", x - 15, psy, + "L", cx + 5, psy, + "L", cx, cy]) + .attr({ + stroke: this.colors[this.commits[i].space], + "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 { r.path([ "M", x - 3, y + 6, @@ -306,15 +320,16 @@ }(this); Raphael.fn.commitTooltip = function(x, y, commit){ - var nameText, idText, messageText + var icon, nameText, idText, messageText , boxWidth = 300 , 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); 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", "font": "12px Monaco, monospace" }); diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index d789f54a4e6b32c4c718535870223331143a950b..d707657d4bffa2dee8d4ea8e2dff32cac97a4ff1 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -54,10 +54,10 @@ $ -> $(@).parents('form').submit() # Flash - if (flash = $("#flash-container")).length > 0 - flash.click -> $(@).slideUp("slow") - flash.slideDown "slow" - setTimeout (-> flash.slideUp("slow")), 3000 + if (flash = $(".flash-container")).length > 0 + flash.click -> $(@).fadeOut() + flash.show() + setTimeout (-> flash.fadeOut()), 3000 # Disable form buttons while a form is submitting $('body').on 'ajax:complete, ajax:beforeSend, submit', 'form', (e) -> diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee index d03a487c453c069a7abe2e150c4e0b79d4672aa2..24106c61b753ad7de5023d38c2abcc467cb66036 100644 --- a/app/assets/javascripts/projects.js.coffee +++ b/app/assets/javascripts/projects.js.coffee @@ -18,3 +18,18 @@ $ -> # Ref switcher $('.project-refs-select').on 'change', -> $(@).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') + diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index 7ac8c2dd91c35f86f5deb50cfe08e7595f2ba869..c967c2d1c1714e91a1115f426fe0ae1eaec71e42 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -67,27 +67,17 @@ table a code { } /** FLASH message **/ -#flash-container { - height: 50px; - position: fixed; - z-index: 10001; - top: 0px; - width: 100%; - margin-bottom: 15px; - overflow: hidden; - background: white; - cursor: pointer; - border-bottom: 1px solid #ccc; - text-align: center; +.flash-container { display: none; + .alert { + cursor: pointer; + margin: 0; + text-align: center; + border-radius: 0; - h4 { - color: #666; - font-size: 18px; - line-height: 38px; - padding-top: 5px; - margin: 2px; - font-weight: normal; + span { + font-size: 14px; + } } } @@ -203,10 +193,6 @@ input[type=text] { } } -input.git_clone_url { - width: 325px; -} - .merge-request-form-holder { select { width: 300px; diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index dcfd610e2c4f4d0ac816320341013b70322f5d76..9e015eb2b6ecb27f7d5b56305e414da8a49b2a76 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -30,6 +30,8 @@ border-color: #DDD; } +.well { padding: 15px; } + /** HELPERS **/ .nothing_here_message { text-align: center; diff --git a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss index a0c9a6c7b8aba9d7eeb6fa616bfe5a6bb21667c5..8cc9986415c974788a214212789fb000d4fb7b2a 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/fonts.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/fonts.scss @@ -1,7 +1,2 @@ -@font-face{ - font-family: Yanone; - src: font-url('YanoneKaffeesatz-Light.ttf'); -} - /** Typo **/ $monospace_font: 'Menlo', 'Liberation Mono', 'Consolas', 'Courier New', 'andale mono', 'lucida console', monospace; diff --git a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index f416be95deec6419f52a9b42c4fce618b895853a..1e5fff68bf817228c39bc86789c05e64ca069622 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -70,8 +70,19 @@ @mixin header-font { color: $style_color; text-shadow: 0 1px 1px #FFF; - font-family: 'Yanone', sans-serif; - font-size: 24px; - line-height: 36px; + font-size: 18px; + line-height: 42px; 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;} } diff --git a/app/assets/stylesheets/gitlab_bootstrap/typography.scss b/app/assets/stylesheets/gitlab_bootstrap/typography.scss index 781577c214754030f83d11b68794f024faa98d7d..1f0c480231834444be97b3570b8611898f85805d 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/typography.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/typography.scss @@ -87,16 +87,15 @@ a:focus { * */ .wiki { + @include md-typography; + 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; } ul { margin: 0 0 9px 25px !important; } } + +.md { + @include md-typography; +} diff --git a/app/assets/stylesheets/highlight/dark.scss b/app/assets/stylesheets/highlight/dark.scss index 6018ff7074d3340d80d164edc6c4679cbdd79474..4196ea7ad2973c382be65758836d6770ce4bccae 100644 --- a/app/assets/stylesheets/highlight/dark.scss +++ b/app/assets/stylesheets/highlight/dark.scss @@ -1,8 +1,7 @@ .black .highlight { - background-color: #333; pre { + background-color: #333; color: #eee; - background: inherit; } .hll { display: block; background-color: darken($hover, 65%) } diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index a389a9baa841914b0c5c42c415a90f0aed6f508c..0df39298c89768116290234f073f1ef53ae87b2d 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -100,8 +100,9 @@ } } .line_content { + display: block; white-space: pre; - height: 14px; + height: 18px; margin: 0px; padding: 0px; border: none; diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index df8fd8d64582b4077db80fb2c31cf3af809be4e9..94e1d0b609caee9f47014e328aba4c04c29a6f52 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -48,15 +48,13 @@ color: #666; } .event-note { - padding-top: 5px; - padding-left: 5px; - display: inline-block; color: #555; + margin-top: 5px; + margin-left: 40px; .note-file-attach { - margin-left: -25px; - float: left; .note-image-attach { + margin-top: 4px; margin-left: 0px; max-width: 200px; } @@ -66,8 +64,8 @@ color: #777; float: left; font-size: 16px; - line-height: 18px; - margin: 5px; + line-height: 16px; + margin-right: 5px; } } .avatar { diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss index 99c8275b5cfac3a29146d0aa6b3493fe46c71de5..645604731cac63f6e89f2898be65bca1a7425d56 100644 --- a/app/assets/stylesheets/sections/header.scss +++ b/app/assets/stylesheets/sections/header.scss @@ -67,7 +67,7 @@ header { position: relative; float: left; margin: 0; - margin-left: 15px; + margin-left: 10px; @include header-font; } diff --git a/app/assets/stylesheets/sections/login.scss b/app/assets/stylesheets/sections/login.scss index 89b8f1c0055322316b26d48ec58f3d9d60bb1749..e3fe0b436c3adbb811feeff40a6f4dba7d4bb1bb 100644 --- a/app/assets/stylesheets/sections/login.scss +++ b/app/assets/stylesheets/sections/login.scss @@ -1,7 +1,7 @@ /* Login Page */ body.login-page{ - padding-top: 7%; - background: #666; + background: #EEE; + .container .content { padding-top: 5%; } } .login-box{ diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 1f92a3a835dfd5e73c471c42966e5a119b07e8be..1b4280f4974ab36081232ba68372a8cf9d49b704 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -83,6 +83,7 @@ ul.notes { margin-top: -20px; } .note-body { + @include md-typography; margin-left: 45px; } .note-header { diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index b37830b138e24e590b1dc71e6dc20b0e6f07f123..ada0780eecea144128a5ebf321f19da252664b53 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -80,6 +80,7 @@ border: 1px solid #BBB; box-shadow: none; margin-left: -1px; + background: #FFF; } } diff --git a/app/contexts/issues_list_context.rb b/app/contexts/issues_list_context.rb index 0cc73f99535b05831229698e3d5ab0f035d27da5..0765b30c35487d686f2c4dbe23017d1bc441e585 100644 --- a/app/contexts/issues_list_context.rb +++ b/app/contexts/issues_list_context.rb @@ -7,12 +7,13 @@ def execute @issues = case params[:status] when issues_filter[:all] then @project.issues 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 end @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)? if params[:assignee_id].present? diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index e7dbcad568f66c4e304a73f9e07cc26c00d16537..e64698744190c5665f81c3296a771d6f3a79adc0 100644 --- a/app/controllers/admin/teams/members_controller.rb +++ b/app/controllers/admin/teams/members_controller.rb @@ -1,7 +1,7 @@ class Admin::Teams::MembersController < Admin::Teams::ApplicationController def new @users = User.potential_team_members(user_team) - @users = UserDecorator.decorate @users + @users = UserDecorator.decorate_collection @users end def create diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb index 2e7114e10a9f24860e030a04eef9736dd0cc0400..43e6f09904f3b1e7d837cc23aebce2ebdf36839e 100644 --- a/app/controllers/admin/users_controller.rb +++ b/app/controllers/admin/users_controller.rb @@ -45,7 +45,7 @@ def block end def unblock - if admin_user.update_attribute(:blocked, false) + if admin_user.activate redirect_to :back, alert: "Successfully unblocked" else redirect_to :back, alert: "Error occured. User was not unblocked" diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1f211bac9c220d34de02aa23901a23fa024fc89f..6b72f3252042b2c118ebc15fe56e9ebf183a4bb2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -5,6 +5,7 @@ class ApplicationController < ActionController::Base before_filter :add_abilities before_filter :dev_tools if Rails.env == 'development' before_filter :default_headers + before_filter :add_gon_variables protect_from_forgery @@ -29,7 +30,7 @@ def log_exception(exception) end def reject_blocked! - if current_user && current_user.blocked + if current_user && current_user.blocked? sign_out current_user flash[:alert] = "Your account is blocked. Retry when an admin unblock it." redirect_to new_user_session_path @@ -37,7 +38,7 @@ def reject_blocked! end 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 flash[:alert] = "Your account is blocked. Retry when an admin unblock it." new_user_session_path @@ -148,4 +149,8 @@ def default_headers headers['X-Frame-Options'] = 'DENY' headers['X-XSS-Protection'] = '1; mode=block' end + + def add_gon_variables + gon.default_issues_tracker = Project.issues_tracker.default_value + end end diff --git a/app/controllers/commits_controller.rb b/app/controllers/commits_controller.rb index 534ae1edd3136df5f81949c582d930ad617eb866..9dc0d96883e3351082497b7bd8ed6b863aa10e0f 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -13,7 +13,7 @@ def show @limit, @offset = (params[:limit] || 40), (params[:offset] || 0) @commits = @repo.commits(@ref, @path, @limit, @offset) - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) respond_to do |format| format.html # index.html.erb diff --git a/app/controllers/compare_controller.rb b/app/controllers/compare_controller.rb index ae20f9c0ba6dd0a62b28721060318aec056b1344..bd3f111517366c4183b1e9cb77e49c540939f60d 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -16,7 +16,7 @@ def show @refs_are_same = result[:same] @line_notes = [] - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) end def create diff --git a/app/controllers/graph_controller.rb b/app/controllers/graph_controller.rb index c370433e500a4c8cd6d050d952d4efb7fba503c0..33cb2d2dcb971584a5b3539c9821d325cb9a4754 100644 --- a/app/controllers/graph_controller.rb +++ b/app/controllers/graph_controller.rb @@ -1,5 +1,6 @@ class GraphController < ProjectResourceController include ExtractsPath + include ApplicationHelper # Authorize before_filter :authorize_read_project! @@ -20,7 +21,10 @@ def show respond_to do |format| format.html 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 end end diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index 67f9617833523d2c8cfbbaa0885da01c5e473a51..788f2c3a5cd7104b92185a7e5c6ec4ba98eb8586 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -81,7 +81,8 @@ def automerge_check end 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? @merge_request.should_remove_source_branch = params[:should_remove_source_branch] @merge_request.automerge!(current_user) @@ -142,6 +143,19 @@ def define_show_vars # Get commits from repository # or from cache if already merged @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 diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index 57f1e9e6bb341f965ff8d04889468a73c7c4fcdc..cdac28c1bde4eb132b4a5a8c24b91bc6ec510f01 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -32,7 +32,7 @@ def edit def show @issues = @milestone.issues - @users = UserDecorator.decorate(@milestone.participants) + @users = UserDecorator.decorate_collection(@milestone.participants) @merge_requests = @milestone.merge_requests respond_to do |format| diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 5da3fbf591cfcc23ae299e70cb6afe954cecd3f4..f703cf6bc1df11cff8a769211c1202ff6e5fc1a9 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -1,5 +1,3 @@ -require Rails.root.join('lib', 'gitlab', 'graph', 'json_builder') - class ProjectsController < ProjectResourceController skip_before_filter :project, only: [:new, :create] skip_before_filter :repository, only: [:new, :create] diff --git a/app/controllers/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index ead62e13afac8a6f8f8790eaf088f49ffb01b417..4bd70fd7247e6b020b9039738b0f78f1e9bccc15 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -8,7 +8,7 @@ def index def new @users = User.potential_team_members(user_team) - @users = UserDecorator.decorate @users + @users = UserDecorator.decorate_collection @users end def create diff --git a/app/decorators/application_decorator.rb b/app/decorators/application_decorator.rb index 3023699e7004fce9813d7d40317c3a4ba68cdcbc..b805b3479b84c4f39db83644217a7a323818b7d7 100644 --- a/app/decorators/application_decorator.rb +++ b/app/decorators/application_decorator.rb @@ -1,27 +1,28 @@ -class ApplicationDecorator < Draper::Base +class ApplicationDecorator < Draper::Decorator + delegate_all # Lazy Helpers # PRO: Call Rails helpers without the h. proxy # ex: number_to_currency(model.price) # CON: Add a bazillion methods into your decorator's namespace # and probably sacrifice performance/memory - # + # # Enable them by uncommenting this line: # lazy_helpers # Shared Decorations # Consider defining shared methods common to all your models. - # + # # Example: standardize the formatting of timestamps # # def formatted_timestamp(time) - # h.content_tag :span, time.strftime("%a %m/%d/%y"), - # class: 'timestamp' + # h.content_tag :span, time.strftime("%a %m/%d/%y"), + # class: 'timestamp' # end - # + # # def created_at # formatted_timestamp(model.created_at) # end - # + # # def updated_at # formatted_timestamp(model.updated_at) # end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index dad23471a9048dba9205aebdadfa97d9bbed2bba..955dbc1725499920c7670faf9d02ec9b1e90e577 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -164,7 +164,8 @@ def simple_sanitize str end 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 alias_method :url_to_image, :image_url diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index ed7e3e869c0db739f90f69d0bc911fbe0cab1639..54385117c26f948e2602816a36efa5c3157a6f41 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -27,6 +27,7 @@ def issues_filter all: "all", closed: "closed", to_me: "assigned-to-me", + by_me: "created-by-me", open: "open" } end @@ -40,4 +41,39 @@ def labels_autocomplete_source def issues_active_milestones @project.milestones.active.order("id desc").all 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 diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index 0f2b695e0adacce1157c2b148f79ffe6700edd4e..fab0085ba73dd93687b6000bcdc6408835eb834c 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -13,13 +13,15 @@ def render_tree(contents) tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? files.each do |f| - if f.respond_to?(:url) - # Object is a Submodule - tree += render partial: 'tree/submodule_item', object: f - else - # Object is a Blob - tree += render partial: 'tree/tree_item', object: f, locals: {type: 'file'} - end + html = if f.respond_to?(:url) + # Object is a Submodule + render partial: 'tree/submodule_item', object: f + else + # Object is a Blob + render partial: 'tree/tree_item', object: f, locals: {type: 'file'} + end + + tree += html if html.present? end tree.html_safe diff --git a/app/models/ability.rb b/app/models/ability.rb index 6fda2e52c7c6fdfc50371c01b35db4394785efa1..41f7127403c911a6bb603d7e97675f864e71e13f 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -91,7 +91,6 @@ def project_master_rules :admin_team_member, :admin_merge_request, :admin_note, - :accept_mr, :admin_wiki, :admin_project ] diff --git a/app/models/graph/commit.rb b/app/models/graph/commit.rb new file mode 100644 index 0000000000000000000000000000000000000000..8ed61f4b5afc383d30c9c7e36ffb1a8932b52e4c --- /dev/null +++ b/app/models/graph/commit.rb @@ -0,0 +1,59 @@ +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 diff --git a/app/models/graph/json_builder.rb b/app/models/graph/json_builder.rb new file mode 100644 index 0000000000000000000000000000000000000000..013d15fb7544231050e7a47e337860477844349a --- /dev/null +++ b/app/models/graph/json_builder.rb @@ -0,0 +1,291 @@ +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 diff --git a/app/models/group.rb b/app/models/group.rb index 8ba92980a9b2ec66b96a40a46613b1e8bf474a54..7651ce23cb650659aa8b6dbad0cdf63925379557 100644 --- a/app/models/group.rb +++ b/app/models/group.rb @@ -2,13 +2,14 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# id :integer not null, primary key +# name :string(255) not null +# description :string(255) not null +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) # class Group < Namespace diff --git a/app/models/issue.rb b/app/models/issue.rb index 112f43c4692b08dc0e1827010c94a10ff72b79ab..f01cad0a458eb82cf897307ac632d769cc9e0f9f 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -30,6 +30,10 @@ def cared(user) where('assignee_id = :user', user: user.id) end + def authored(user) + where('author_id = :user', user: user.id) + end + def open_for(user) opened.assigned(user) end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 385fa291b4800a5b9337c48ad1b953075631f093..c6b3e94d05dffdb63b77688769a68671fc858b8f 100644 --- a/app/models/namespace.rb +++ b/app/models/namespace.rb @@ -2,17 +2,18 @@ # # Table name: namespaces # -# id :integer not null, primary key -# name :string(255) not null -# path :string(255) not null -# owner_id :integer not null -# created_at :datetime not null -# updated_at :datetime not null -# type :string(255) +# id :integer not null, primary key +# name :string(255) not null +# description :string(255) not null +# path :string(255) not null +# owner_id :integer not null +# created_at :datetime not null +# updated_at :datetime not null +# type :string(255) # class Namespace < ActiveRecord::Base - attr_accessible :name, :path + attr_accessible :name, :description, :path has_many :projects, dependent: :destroy belongs_to :owner, class_name: "User" @@ -22,7 +23,7 @@ class Namespace < ActiveRecord::Base length: { within: 0..255 }, format: { with: Gitlab::Regex.name_regex, message: "only letters, digits, spaces & '_' '-' '.' allowed." } - + validates :description, length: { within: 0..255 } validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } diff --git a/app/models/project.rb b/app/models/project.rb index 7587ef189e30a13b596c32746c5ceb1a7cce448b..07ba7fc369eb3e0ef57271b0f9c3cdc93d258137 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -11,6 +11,7 @@ # creator_id :integer # default_branch :string(255) # issues_enabled :boolean default(TRUE), not null +# issues_tracker :string not null # wall_enabled :boolean default(TRUE), not null # merge_requests_enabled :boolean default(TRUE), not null # wiki_enabled :boolean default(TRUE), not null @@ -22,11 +23,12 @@ class Project < ActiveRecord::Base include Gitolited + extend Enumerize class TransferError < StandardError; end - attr_accessible :name, :path, :description, :default_branch, - :issues_enabled, :wall_enabled, :merge_requests_enabled, + attr_accessible :name, :path, :description, :default_branch, :issues_tracker, + :issues_enabled, :wall_enabled, :merge_requests_enabled, :issues_tracker_id, :wiki_enabled, :public, :import_url, as: [:default, :admin] attr_accessible :namespace_id, :creator_id, as: :admin @@ -43,7 +45,7 @@ class TransferError < StandardError; end has_many :events, 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 :users_projects, dependent: :destroy has_many :notes, dependent: :destroy @@ -72,6 +74,7 @@ class TransferError < StandardError; end message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } validates :issues_enabled, :wall_enabled, :merge_requests_enabled, :wiki_enabled, inclusion: { in: [true, false] } + validates :issues_tracker_id, length: { within: 0..255 } validates_uniqueness_of :name, scope: :namespace_id validates_uniqueness_of :path, scope: :namespace_id @@ -93,6 +96,8 @@ class TransferError < StandardError; end scope :joined, ->(user) { where("namespace_id != ?", user.namespace_id) } scope :public_only, -> { where(public: true) } + enumerize :issues_tracker, :in => (Gitlab.config.issues_tracker.keys).append(:gitlab), :default => :gitlab + class << self def abandoned project_ids = Event.select('max(created_at) as latest_date, project_id'). @@ -201,6 +206,22 @@ def issues_labels issues.tag_counts_on(:labels) 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 [gitlab_ci_service].compact end diff --git a/app/models/repository.rb b/app/models/repository.rb index a5ca5533e086d21d4fca488a8f5505999dc69d75..3feb31803471b94d8319af2af8f878d58b650c19 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -137,7 +137,7 @@ def archive_repo(ref) file_path = File.join(storage_path, self.path_with_namespace, file_name) # Put files into a directory before archiving - prefix = self.path_with_namespace + "/" + prefix = File.basename(self.path_with_namespace) + "/" # Create file if not exists unless File.exists?(file_path) diff --git a/app/models/user.rb b/app/models/user.rb index cd0754d7816a9d0f64c57585c5652b90978a4c42..a8c39f5fbdc8b6a41df0614f66394f4d431abe35 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -25,7 +25,7 @@ # dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# blocked :boolean default(FALSE), not null +# state :string(255) # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -46,10 +46,35 @@ class User < ActiveRecord::Base attr_accessor :force_random_password + # + # Relations + # + # 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 + + # 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 - has_many :keys, dependent: :destroy + # Projects has_many :users_projects, dependent: :destroy has_many :issues, dependent: :destroy, foreign_key: :author_id has_many :notes, dependent: :destroy, foreign_key: :author_id @@ -57,18 +82,16 @@ class User < ActiveRecord::Base 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_merge_requests, dependent: :destroy, foreign_key: :assignee_id, class_name: "MergeRequest" + has_many :projects, through: :users_projects - 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 :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 + has_many :recent_events, + class_name: "Event", + foreign_key: :author_id, + order: "id DESC" + # + # Validations + # validates :name, presence: true validates :email, presence: true, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/ } validates :bio, length: { within: 0..255 } @@ -87,10 +110,27 @@ class User < ActiveRecord::Base 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 scope :admins, -> { where(admin: true) } - scope :blocked, -> { where(blocked: true) } - scope :active, -> { where(blocked: false) } + scope :blocked, -> { with_state(:blocked) } + scope :active, -> { with_state(:active) } scope :alphabetically, -> { order('name ASC') } scope :in_team, ->(team){ where(id: team.member_ids) } scope :not_in_team, ->(team){ where('users.id NOT IN (:ids)', ids: team.member_ids) } @@ -260,17 +300,6 @@ def cared_merge_requests MergeRequest.cared(self) 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 return 100 if projects_limit.zero? (personal_projects.count.to_f / projects_limit) * 100 diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 2f3091c2353ab5d5d81120b046e66ddc4773c0ea..0cb84edd66d5277ded9eb08e89b4ebc0ce02d881 100644 --- a/app/models/user_team.rb +++ b/app/models/user_team.rb @@ -11,7 +11,7 @@ # class UserTeam < ActiveRecord::Base - attr_accessible :name, :owner_id, :path + attr_accessible :name, :description, :owner_id, :path belongs_to :owner, class_name: User @@ -26,6 +26,7 @@ class UserTeam < ActiveRecord::Base length: { within: 0..255 }, format: { with: Gitlab::Regex.name_regex, message: "only letters, digits, spaces & '_' '-' '.' allowed." } + validates :description, length: { within: 0..255 } validates :path, uniqueness: true, presence: true, length: { within: 1..255 }, format: { with: Gitlab::Regex.path_regex, message: "only letters, digits & '_' '-' '.' allowed. Letter should be first" } diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 592e2950f3785558013dc223cb8faa4dced3a057..29e24040378885bc14b2ef03e34590b13d52891d 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -27,7 +27,7 @@ def after_update(issue) def create_note(issue) 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) end end diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb index c1179ed78811f81c6c81c5c98017d6e34be22f41..6c461e07865ea666497e88f3050e41b3e85ea155 100644 --- a/app/observers/user_observer.rb +++ b/app/observers/user_observer.rb @@ -2,7 +2,8 @@ class UserObserver < ActiveRecord::Observer def after_create(user) 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 def after_destroy user diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb index 40d57c67573542659026606ad651809b94b0ffa9..208ccf699d29e3e51c3d3001524e4958407de7e3 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -19,6 +19,8 @@ def execute(project, user, oldrev, newrev, ref) # Collect data for this git push @push_data = post_receive_data(oldrev, newrev, ref) + create_push_event + project.ensure_satellite_exists project.discover_default_branch @@ -27,8 +29,6 @@ def execute(project, user, oldrev, newrev, ref) project.execute_hooks(@push_data.dup) project.execute_services(@push_data.dup) end - - create_push_event end # This method provide a sample data diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb index f91a3cd199272ba48307e6f9879abfed93836500..35d9517ad29e332e7a54b0bbf6c1202c6e395741 100644 --- a/app/services/project_transfer_service.rb +++ b/app/services/project_transfer_service.rb @@ -25,7 +25,7 @@ def transfer(project, new_namespace) Gitlab::ProjectMover.new(project, old_dir, new_dir).execute - save! + project.save! end rescue Gitlab::ProjectMover::ProjectMoveError => ex raise Project::TransferError.new(ex.message) diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index dce044956c36558805fd007e125a70cbdb3acf75..bb1398f66cd8bf12cd8316d998ef00f0cf61e6b6 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -1,4 +1,4 @@ -%h3.page_title Rename Group +%h3.page_title Edit Group %hr = form_for [:admin, @group] do |f| - if @group.errors.any? @@ -10,7 +10,10 @@ .input = 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 = f.label :path do @@ -24,5 +27,5 @@ %li It will change the git path to repositories under this group. .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" diff --git a/app/views/admin/groups/index.html.haml b/app/views/admin/groups/index.html.haml index 6d5a293ef7ff45f7fa2f5e2c41c8c81de2a33e52..b10a7394bd31b15a6ec01b9be95a9645a645265b 100644 --- a/app/views/admin/groups/index.html.haml +++ b/app/views/admin/groups/index.html.haml @@ -17,6 +17,7 @@ Name %i.icon-sort-down %th Path + %th Description %th Projects %th Owner %th.cred Danger Zone! @@ -25,11 +26,12 @@ %tr %td %strong= link_to group.name, [:admin, group] + %td= truncate group.description %td= group.path %td= group.projects.count %td = link_to group.owner_name, admin_user_path(group.owner) %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" = paginate @groups, theme: "admin" diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index 60c6fa5ad090683891ccc8b4792f9fe607ce7496..3fa63e1ba2531bbe2e325263bec25e269aaa51bd 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -9,8 +9,14 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - - = f.submit 'Create group', class: "btn btn-primary" + .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" + %hr .padded %ul diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 90f8fc0f81488c8b1247549a64126e0fe810ad23..63ea78fdd993a6ac882008d0beaaab7e8c701800 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -16,7 +16,13 @@ = link_to edit_admin_group_path(@group), class: "btn btn-small pull-right" do %i.icon-edit - Rename + Edit + %tr + %td + %b + Description: + %td + = @group.description %tr %td %b diff --git a/app/views/admin/projects/_form.html.haml b/app/views/admin/projects/_form.html.haml index ebf69924a2590e744d821c889cb4e94e3d22f653..29b90bdd4cba2aaefdec6cb9b43041020980000d 100644 --- a/app/views/admin/projects/_form.html.haml +++ b/app/views/admin/projects/_form.html.haml @@ -31,6 +31,15 @@ = f.label :issues_enabled, "Issues" .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 = f.label :merge_requests_enabled, "Merge Requests" .input= f.check_box :merge_requests_enabled diff --git a/app/views/admin/teams/edit.html.haml b/app/views/admin/teams/edit.html.haml index 9282398ce5bfbfa4be6754ceaaf3277fa1c980a5..0a3d993b132cda3c4de5dd944ff470af94b0e8a5 100644 --- a/app/views/admin/teams/edit.html.haml +++ b/app/views/admin/teams/edit.html.haml @@ -1,4 +1,4 @@ -%h3.page_title Rename Team +%h3.page_title Edit Team %hr = form_for @team, url: admin_team_path(@team), method: :put do |f| - if @team.errors.any? @@ -10,6 +10,11 @@ .input = 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 = f.label :path do %span.cred Team path is @@ -19,5 +24,5 @@ %li It will change web url for access team and team projects. .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" diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index bb0487d43e9c127d9bdd08f73fe6b02188d909e8..3690d6d9eb4805328f88cf56db7c82f44fed8cbf 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -16,6 +16,7 @@ %th Name %i.icon-sort-down + %th Description %th Path %th Projects %th Members @@ -26,13 +27,17 @@ %tr %td %strong= link_to team.name, admin_team_path(team) + %td= truncate team.description %td= team.path %td= team.projects.count %td= team.members.count %td - = link_to team.owner.name, admin_user_path(team.owner) + - if team.owner + = link_to team.owner.name, admin_user_path(team.owner) + - else + (deleted) %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" = paginate @teams, theme: "admin" diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index 5d55a7975eecb477afb2e2612639b02c9730029e..1c90cb20c108f47e9d9757111ebf094f6113207f 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -9,8 +9,15 @@ Team name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - - = f.submit 'Create team', class: "btn btn-primary" + + .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" + %hr .padded %ul diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index e5d079981c0f9b98d1c658ac09256e0144f2c21e..abdfada8c5e79ab8e09002dec12b1052a49e0599 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -16,7 +16,13 @@ = link_to edit_admin_team_path(@team), class: "btn btn-small pull-right" do %i.icon-edit - Rename + Edit + %tr + %td + %b + Description: + %td + = @team.description %tr %td %b diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 48876338a23bb771136bdb732610987cf4b153a9..1d1fe341c5bb6d530088c6667c0e2523400a3fcf 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -61,7 +61,7 @@ .span4 - unless @admin_user.new_record? .alert.alert-error - - if @admin_user.blocked + - if @admin_user.blocked? %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" - else diff --git a/app/views/admin/users/index.html.haml b/app/views/admin/users/index.html.haml index f5bb8b0681d731760111353b0fa8b2fca9f8a088..9da2871e99244a5f1f386e1b3cb01fe72bcafeed 100644 --- a/app/views/admin/users/index.html.haml +++ b/app/views/admin/users/index.html.haml @@ -53,7 +53,7 @@ = link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small" - 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" - 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" diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index c5d60194820da3dd9258ef124b8f0c369b00e04b..2129ceec5536633cc896ff05a606e7c476a86989 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -3,7 +3,7 @@ %h3.page_title = image_tag gravatar_icon(@admin_user.email, 90), class: "avatar s90" = @admin_user.name - - if @admin_user.blocked + - if @admin_user.blocked? %span.cred (Blocked) - if @admin_user.admin %span.cred (Admin) diff --git a/app/views/commits/_commits.html.haml b/app/views/commits/_commits.html.haml index 191320933d35ee94b3faa6080b83375f6b71bae5..869d1f9c769f06246cd7e074467a987fe071b11b 100644 --- a/app/views/commits/_commits.html.haml +++ b/app/views/commits/_commits.html.haml @@ -1,4 +1,4 @@ -- @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 %h5.title %i.icon-calendar diff --git a/app/views/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 19665ce0aeaebace6b5bbb1bbb2e0bb23198bb5a..199785e63ffb5f03b587ff4af49ac247bc89e391 100644 --- a/app/views/events/event/_note.html.haml +++ b/app/views/events/event/_note.html.haml @@ -21,9 +21,10 @@ = event.project_name .event-body - %i.icon-comment-alt.event-note-icon - %span.event-note - = markdown truncate(event.target.note, length: 70) + .event-note + .md + %i.icon-comment-alt.event-note-icon + = sanitize(markdown(truncate(event.target.note, length: 150)), tags: %w(a img b pre p)) - note = event.target - if note.attachment.url = link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml index 41ebf60698bab97f9c6c6a3d40c026795d3803b6..bf16b70c7f16dbc31897ab958b1306198baf2c0b 100644 --- a/app/views/groups/edit.html.haml +++ b/app/views/groups/edit.html.haml @@ -9,8 +9,15 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - - = f.submit 'Save group', class: "btn btn-save" + + .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" + %hr diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml index 73be474e2780821721906e49f9687231ae890abb..36ee4922731f6d1cfe0108429519ec01a9176ad8 100644 --- a/app/views/groups/new.html.haml +++ b/app/views/groups/new.html.haml @@ -9,9 +9,16 @@ Group name is .input = f.text_field :name, placeholder: "Ex. OpenSource", class: "xxlarge left" - - = f.submit 'Create group', class: "btn btn-create" - %hr + + .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" + + .padded %ul %li Group is kind of directory for several projects diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index a140b401b9d54048d7f092b5eb2dc0673cc50ff3..81694b88cc40f4aef53755341988bbfe7a6d1387 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -12,6 +12,9 @@ %p.nothing_here_message Project activity will be displayed here .loading.hide .side.span4 + - if @group.description.present? + .description.well.light + = @group.description = render "projects", projects: @projects %div %span.rss-icon diff --git a/app/views/issues/_filter.html.haml b/app/views/issues/_filter.html.haml index 21efaa5357cbef9d5b1fe3282856539854af28b8..b621f11bc5bdb89e5aaf3f6ea73c861c2ea3ea13 100644 --- a/app/views/issues/_filter.html.haml +++ b/app/views/issues/_filter.html.haml @@ -6,7 +6,10 @@ Open %li{class: ("active" if params[:status] == 'assigned-to-me')} = 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')} = link_to project_issues_path(@project, status: 'closed') do Closed diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index 9961ce8dd349dcff22d89c02566863a32aac31bc..a3bed593e1cc67ff0b15ae6282a243b5abc68d28 100644 --- a/app/views/layouts/_flash.html.haml +++ b/app/views/layouts/_flash.html.haml @@ -1,3 +1,8 @@ -- if text = alert || notice - #flash-container - %h4= text +.flash-container + - if alert + .alert + %span= alert + + - elsif notice + .alert.alert-info + %span= notice diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 4b4f5da33244f45a4d7fed5dad2e879dbcf7aee1..eb83fd2fd450230cab80a6be3f622407fece1ecc 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -7,6 +7,7 @@ = stylesheet_link_tag "application" = javascript_include_tag "application" = csrf_meta_tags + = include_gon -# Atom feed - if current_user diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8f4f3d7815f31b7a00876ee6d973e2e0e4c5521c..1f3ce2f40ef94667e558fbe4bf77b168b003316e 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -8,6 +8,9 @@ %span.separator %h1.project_name= title %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? %li = link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index a01886cdabf601cf3793784365edb6f1a2462c72..00a08e6131d111376fe01ad2b4f9240c5fe53c6d 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Admin area" %body{class: "#{app_theme} admin"} - = render "layouts/flash" = render "layouts/head_panel", title: "Admin area" + = render "layouts/flash" .container %ul.main_menu = nav_link(controller: :dashboard, html_options: {class: 'home'}) do diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 7ee44238d10bd0e8f0ca4faeb33f9a3a8b2b53a8..90c2653438dd7825c2b8eebf7b7388c5763f2664 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Dashboard" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "Dashboard" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 36c6b4c6c35d8617e1ee94811c66ed2a8e1e3bd6..a9758f19d3619bf420f72a79dc08ad620d335204 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -3,4 +3,6 @@ = render "layouts/head" %body.ui_basic.login-page = render "layouts/flash" - .container= yield + .container + .content + = yield diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml index 3554d88f10c0fd64092f374171af383ec5d4d90c..b9395873c337472c3b896973bd0583996ba0314b 100644 --- a/app/views/layouts/errors.html.haml +++ b/app/views/layouts/errors.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Error" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "" + = render "layouts/flash" .container .content %center.padded.prepend-top-20 diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 9057ad50ce68620c314925bb9c943eb8291a2c06..2c144de49b3ec1236009fba2c56195a6fbd74608 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "#{@group.name}" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "group: #{@group.name}" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'groups#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 57f250c775bcd3b9d2ccd78c05040c0a6c99fcbc..611063e8c994ef6d8c2037129601bc85374bc125 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "Profile" %body{class: "#{app_theme} profile"} - = render "layouts/flash" = render "layouts/head_panel", title: "Profile" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'profiles#show', html_options: {class: 'home'}) do diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 13fb8637bf6f0e70c6bf32a83f26648d124dc917..37d0f16fa20c7027d9e36ed7a2d140d13ea17096 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: @project.name_with_namespace %body{class: "#{app_theme} project"} - = render "layouts/flash" = render "layouts/head_panel", title: project_title(@project) + = render "layouts/flash" - if can?(current_user, :download_code, @project) = render 'shared/no_ssh' @@ -22,11 +22,12 @@ = nav_link(controller: %w(graph)) do = link_to "Network", project_graph_path(@project, @ref || @repository.root_ref) - - if @project.issues_enabled + - if @project.issues_enabled = nav_link(controller: %w(issues milestones labels)) do - = link_to project_issues_filter_path(@project) do + = link_to url_for_project_issues do Issues - %span.count.issue_counter= @project.issues.opened.count + - if @project.used_default_issues_tracker? + %span.count.issue_counter= @project.issues.opened.count - if @project.repo_exists? && @project.merge_requests_enabled = nav_link(controller: :merge_requests) do diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index 19bbc373f46378d0575fb384725b53753070b972..e5e08aab13ceaf01d96a632ab6a47e3dfe8221a2 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -2,8 +2,8 @@ %html{ lang: "en"} = render "layouts/head", title: "#{@team.name}" %body{class: "#{app_theme} application"} - = render "layouts/flash" = render "layouts/head_panel", title: "team: #{@team.name}" + = render "layouts/flash" .container %ul.main_menu = nav_link(path: 'teams#show', html_options: {class: 'home'}) do diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index 64f25a5118c635cdb76f9b4b9fc039cb590d770a..d4271c5551f575a2e6eb4442dd52fe15a80d9fc8 100644 --- a/app/views/merge_requests/show/_mr_accept.html.haml +++ b/app/views/merge_requests/show/_mr_accept.html.haml @@ -1,9 +1,9 @@ -- unless can?(current_user, :accept_mr, @project) +- unless @allowed_to_merge .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"} .alert.alert-success %span diff --git a/app/views/notify/issue_status_changed_email.text.erb b/app/views/notify/issue_status_changed_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..bbca3474d5053f4471c7ea88b850ece9f3df8b08 --- /dev/null +++ b/app/views/notify/issue_status_changed_email.text.erb @@ -0,0 +1,4 @@ +Issue was <%= @issue_status %> by <%= @updated_by.name %> + +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %> + diff --git a/app/views/notify/new_issue_email.text.erb b/app/views/notify/new_issue_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..5ed55c35b23511757ed0eeb51bb3498e77a82742 --- /dev/null +++ b/app/views/notify/new_issue_email.text.erb @@ -0,0 +1,4 @@ +New Issue was created and assigned to you. + + +Issue <%= @issue.id %>: <%= url_for(project_issue_url(@issue.project, @issue)) %> diff --git a/app/views/notify/new_merge_request_email.text.erb b/app/views/notify/new_merge_request_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..3393d8384f1a77c87b3906ead4f8d495fc790f1a --- /dev/null +++ b/app/views/notify/new_merge_request_email.text.erb @@ -0,0 +1,9 @@ +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 %> + diff --git a/app/views/notify/new_user_email.text.erb b/app/views/notify/new_user_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..94072d7fe5c908445a70da504aeac91d6102dbef --- /dev/null +++ b/app/views/notify/new_user_email.text.erb @@ -0,0 +1,10 @@ +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) %> diff --git a/app/views/notify/note_commit_email.text.erb b/app/views/notify/note_commit_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..aab8e5cfb6cf7b6f9ce2c7f632d74acb7ceb2cbc --- /dev/null +++ b/app/views/notify/note_commit_email.text.erb @@ -0,0 +1,9 @@ +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 %> + diff --git a/app/views/notify/note_issue_email.text.erb b/app/views/notify/note_issue_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..a476b286ae457707115410affac11a356dcbd412 --- /dev/null +++ b/app/views/notify/note_issue_email.text.erb @@ -0,0 +1,9 @@ +New comment for Issue <%= @issue.id %> + +<%= url_for(project_issue_url(@issue.project, @issue, anchor: "note_#{@note.id}")) %> + + +Author: <%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/note_merge_request_email.text.erb b/app/views/notify/note_merge_request_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..26c73bdaa38e875f6fc3ac93f1a66308a000aded --- /dev/null +++ b/app/views/notify/note_merge_request_email.text.erb @@ -0,0 +1,9 @@ +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 %> + diff --git a/app/views/notify/note_wall_email.text.erb b/app/views/notify/note_wall_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..ea1b7efbe84756c6a818820a94e8bf8e19671c08 --- /dev/null +++ b/app/views/notify/note_wall_email.text.erb @@ -0,0 +1,9 @@ +New message on the project wall <%= @note.project %> + +<%= url_for(wall_project_url(@note.project, anchor: "note_#{@note.id}")) %> + + +<%= @note.author_name %> + +<%= @note.note %> + diff --git a/app/views/notify/project_access_granted_email.text.erb b/app/views/notify/project_access_granted_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..077c3b8a7dec82026dc08a71431d52876d68ead0 --- /dev/null +++ b/app/views/notify/project_access_granted_email.text.erb @@ -0,0 +1,4 @@ + +You have been granted <%= @users_project.project_access_human %> access to project <%= @project.name_with_namespace %> + +<%= url_for(project_url(@project)) %> diff --git a/app/views/notify/project_was_moved_email.text.erb b/app/views/notify/project_was_moved_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..da123c2f89cbc98dc5637a515b50c98f98b0a689 --- /dev/null +++ b/app/views/notify/project_was_moved_email.text.erb @@ -0,0 +1,8 @@ +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 %> diff --git a/app/views/notify/reassigned_issue_email.text.erb b/app/views/notify/reassigned_issue_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..497044184dc69bbad9e8d1d373fa7c7d3cbf97ad --- /dev/null +++ b/app/views/notify/reassigned_issue_email.text.erb @@ -0,0 +1,7 @@ +Reassigned Issue <%= @issue.id %> + +<%= url_for(project_issue_url(@issue.project, @issue)) %> + + +Assignee changed from <%= @previous_assignee.name %> to <%= @issue.assignee_name %> + diff --git a/app/views/notify/reassigned_merge_request_email.text.erb b/app/views/notify/reassigned_merge_request_email.text.erb new file mode 100644 index 0000000000000000000000000000000000000000..1af4ab559f633c54b65e387ceca2d06a832302d7 --- /dev/null +++ b/app/views/notify/reassigned_merge_request_email.text.erb @@ -0,0 +1,7 @@ +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 %> + diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 0336654dc698d488cea77bd2f209eab6c9143dbc..b78c70be18affa28368cf84d2160bfc2f64ece81 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -24,6 +24,15 @@ = f.check_box :issues_enabled %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 = f.label :merge_requests_enabled, "Merge Requests", class: 'control-label' .controls diff --git a/app/views/projects/empty.html.haml b/app/views/projects/empty.html.haml index 22aaaf0f2b2b29ff10d071cb9c5866ec294cbf8d..07132e678722b65c4efeb95ed82ad4409c75c5c9 100644 --- a/app/views/projects/empty.html.haml +++ b/app/views/projects/empty.html.haml @@ -5,14 +5,14 @@ %fieldset %legend Git global setup: %pre.dark - = preserve do + :preserve git config --global user.name "#{current_user.name}" git config --global user.email "#{current_user.email}" %fieldset %legend Create Repository %pre.dark - = preserve do + :preserve mkdir #{@project.path} cd #{@project.path} git init @@ -25,7 +25,7 @@ %fieldset %legend Existing Git Repo? %pre.dark - = preserve do + :preserve cd existing_git_repo git remote add origin #{@project.url_to_repo} git push -u origin master diff --git a/app/views/public/projects/index.html.haml b/app/views/public/projects/index.html.haml index 21e9d2e6029c93036f3d2a07ff5df988cd8447ab..52e01c3d56e9c02799385f3ee3acc99611e58260 100644 --- a/app/views/public/projects/index.html.haml +++ b/app/views/public/projects/index.html.haml @@ -12,5 +12,7 @@ .pull-right %pre.dark.tiny git clone #{project.http_url_to_repo} + - unless @projects.present? + %h3.nothing_here_message No public projects = paginate @projects, theme: "admin" diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index 7b5de4a62748d1549f1c430c431ef45e920c6dc6..bd9ca72935241f184a9f6a28727dc4ef5ad13a71 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -1,5 +1,4 @@ .input-prepend.project_clone_holder %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 - - = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge" + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select input-xxlarge", readonly: true diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml index e7cba0b349cb7c70230bdfd4c8067a18c42a7ad6..e0485f408bc021569e4730bea5170e53cdc1e9c5 100644 --- a/app/views/team_members/_team_member.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -20,7 +20,7 @@ %span.label This is you! - if @project.namespace_owner == user %span.label Owner - - elsif user.blocked + - elsif user.blocked? %span.label Blocked - 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 diff --git a/app/views/teams/edit.html.haml b/app/views/teams/edit.html.haml index 751fe94c6542fad9aff10572aa02916e1ef697b8..95c91b5044d4dfe89ec750c57c237d42cfd52245 100644 --- a/app/views/teams/edit.html.haml +++ b/app/views/teams/edit.html.haml @@ -12,13 +12,19 @@ .input = 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 = f.label :path do Team path is .input = f.text_field :path, placeholder: "opensource", class: "xlarge left" + .form-actions - = f.submit 'Save team changes', class: "btn btn-save" + = f.submit 'Save team changes', class: "btn btn-primary" .span5 .ui-box %h5.title Remove team @@ -26,4 +32,3 @@ %p 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" - diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 3aa2db866ad999e891f59d21cab70a1b1a4f2c43..597581090367c6982e834a93298789b28c32abef 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -23,7 +23,7 @@ %span.btn.disabled This is you! - if @team.owner == user %span.btn.disabled Owner - - elsif user.blocked + - elsif user.blocked? %span.btn.disabled.blocked Blocked - 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 diff --git a/app/views/teams/new.html.haml b/app/views/teams/new.html.haml index 7089f7915586ae28307f85dba8d6fc00a03f0735..99d308217e007cc9bc1de630e197e8629c3cc4db 100644 --- a/app/views/teams/new.html.haml +++ b/app/views/teams/new.html.haml @@ -9,9 +9,15 @@ Team name is .input = f.text_field :name, placeholder: "Ex. Ruby Developers", class: "xxlarge left" - - = f.submit 'Create team', class: "btn btn-create" - %hr + + .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" + .padded %ul %li All created teams are public (users can view who enter into team and which project are assigned for this team) diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index d6e80e2a51e23e82e3e53e1a6876ec793fa5d364..43cc026a5cf8e7e3d9214e7774b58e0c13ec05b2 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -11,6 +11,9 @@ %p.nothing_here_message Projects activity will be displayed here .loading.hide .side.span4 + - if @team.description.present? + .description.well.light + = @team.description = render "projects", projects: @projects %div %span.rss-icon diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 62761c80cbbf3e89582620ea0b5dc18007b2e723..3fb173862cd1aaf65aedf9c20ea12afe5756ef4a 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -1,5 +1,5 @@ # # # # # # # # # # # # # # # # # # -# Gitlab application config file # +# GitLab application config file # # # # # # # # # # # # # # # # # # # # # How to use: @@ -37,9 +37,25 @@ production: &base # 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 + + ## 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: - 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 # ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm @@ -60,22 +76,21 @@ production: &base bind_dn: '_the_full_dn_of_the_user_you_will_bind_with' password: '_the_password_of_the_bind_user' - ## Omniauth settings + ## OmniAuth settings omniauth: - # Enable ability for users - # Allow logging in via Twitter, Google, etc. using Omniauth providers + # Allow login via Twitter, Google, etc. using OmniAuth providers enabled: false # 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. 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 ## Auth providers - # Uncomment the 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: + # 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 use others: # 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 # arguments, followed by optional 'args' which can be either a hash or an array. @@ -114,7 +129,7 @@ production: &base upload_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 ## Git settings @@ -122,10 +137,10 @@ production: &base # Use the default values unless you really know what you are doing git: bin_path: /usr/bin/git - # Max size of git object like commit, in bytes - # This value can be increased if you have a very large commits + # Max size of a git object (e.g. a commit), in bytes + # This value can be increased if you have very large commits max_size: 5242880 # 5.megabytes - # Git timeout to read commit, in seconds + # Git timeout to read a commit, in seconds timeout: 10 development: @@ -133,6 +148,10 @@ development: test: <<: *base + issues_tracker: + redmine: + project_url: "http://redmine/projects/:issues_tracker_id" + issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" staging: <<: *base diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index f7d18e671481e97e383d73ad957aad556b1594d5..ac35eef42181982e8e24a38f1939c68b5a7045d1 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -42,6 +42,8 @@ def build_gitlab_url Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['providers'] ||= [] +Settings['issues_tracker'] ||= {} + # # GitLab # @@ -50,7 +52,7 @@ def build_gitlab_url Settings.gitlab['host'] ||= 'localhost' Settings.gitlab['https'] = false if Settings.gitlab['https'].nil? 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['email_from'] ||= "gitlab@#{Settings.gitlab.host}" Settings.gitlab['support_email'] ||= Settings.gitlab.email_from diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 97946c54b40dad0976660da805da4d9102f81083..9c3976335ff6ec2bdd1cc8d84f1c6e941c0d0cda 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -99,7 +99,7 @@ # ==> Configuration for :validatable # 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 # an one (and only one) @ exists in the given string. This is mainly diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml index 3b763cf410de7e0a0965b4e300f91ad0cf1ceaf8..275273a0b127133eac73389d2e7c13fc7727e7fb 100644 --- a/config/locales/devise.en.yml +++ b/config/locales/devise.en.yml @@ -17,6 +17,7 @@ en: unauthenticated: 'You need to sign in before continuing.' unconfirmed: 'You have to confirm your account before continuing.' locked: 'Your account is locked.' + not_found_in_database: 'Invalid email or password.' invalid: 'Invalid email or password.' invalid_token: 'Invalid authentication token.' timeout: 'Your session expired, please sign in again to continue.' diff --git a/config/routes.rb b/config/routes.rb index 10536a6e5296ee4ecce39b5ee91eeba0c6d0ab67..c8e7c8ee4f841d4625a1292dc3127af9d172579a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -49,7 +49,7 @@ # # 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 diff --git a/db/migrate/20130123114545_add_issues_tracker_to_project.rb b/db/migrate/20130123114545_add_issues_tracker_to_project.rb new file mode 100644 index 0000000000000000000000000000000000000000..288d0f07c9ae58c6d973cf128dd4241edc6071ff --- /dev/null +++ b/db/migrate/20130123114545_add_issues_tracker_to_project.rb @@ -0,0 +1,5 @@ +class AddIssuesTrackerToProject < ActiveRecord::Migration + def change + add_column :projects, :issues_tracker, :string, default: :gitlab, null: false + end +end diff --git a/db/migrate/20130206084024_add_description_to_namsespace.rb b/db/migrate/20130206084024_add_description_to_namsespace.rb new file mode 100644 index 0000000000000000000000000000000000000000..ef02e489d03088e33a910f487d8a6677f90575c8 --- /dev/null +++ b/db/migrate/20130206084024_add_description_to_namsespace.rb @@ -0,0 +1,5 @@ +class AddDescriptionToNamsespace < ActiveRecord::Migration + def change + add_column :namespaces, :description, :string, default: '', null: false + end +end diff --git a/db/migrate/20130207104426_add_description_to_teams.rb b/db/migrate/20130207104426_add_description_to_teams.rb new file mode 100644 index 0000000000000000000000000000000000000000..6d03777901c44333ba34990af2ecef9a62977813 --- /dev/null +++ b/db/migrate/20130207104426_add_description_to_teams.rb @@ -0,0 +1,5 @@ +class AddDescriptionToTeams < ActiveRecord::Migration + def change + add_column :user_teams, :description, :string, default: '', null: false + end +end diff --git a/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb b/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb new file mode 100644 index 0000000000000000000000000000000000000000..71763d18aee5be037148417d05d72016dbd6c4ae --- /dev/null +++ b/db/migrate/20130211085435_add_issues_tracker_id_to_project.rb @@ -0,0 +1,5 @@ +class AddIssuesTrackerIdToProject < ActiveRecord::Migration + def change + add_column :projects, :issues_tracker_id, :string + end +end diff --git a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb index 0614a5c00643109512443ac090eb42d15ce73e2d..9fa96203ffdd96f34e592e4897ae5c6845e08cb3 100644 --- a/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb +++ b/db/migrate/20130218141258_convert_closed_to_state_in_issue.rb @@ -1,14 +1,14 @@ class ConvertClosedToStateInIssue < ActiveRecord::Migration def up Issue.transaction do - Issue.where(closed: true).update_all("state = 'closed'") - Issue.where(closed: false).update_all("state = 'opened'") + Issue.where(closed: true).update_all(state: :closed) + Issue.where(closed: false).update_all(state: :opened) end end def down Issue.transaction do - Issue.where(state: :closed).update_all("closed = 1") + Issue.where(state: :closed).update_all(closed: true) end end end diff --git a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb index 5e7477d84e17bff4adfcc40b5b0c72a65c7c4425..ebb7ae585e68b8cc26bf14dc473a74ac2c33ecfc 100644 --- a/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb +++ b/db/migrate/20130218141327_convert_closed_to_state_in_merge_request.rb @@ -1,9 +1,9 @@ class ConvertClosedToStateInMergeRequest < ActiveRecord::Migration def up MergeRequest.transaction do - MergeRequest.where(closed: true, merged: true).update_all("state = 'merged'") - MergeRequest.where(closed: true, merged: true).update_all("state = 'closed'") - MergeRequest.where(closed: false).update_all("state = 'opened'") + MergeRequest.where(closed: true, merged: true).update_all(state: :merged) + MergeRequest.where(closed: true, merged: false).update_all(state: :closed) + MergeRequest.where(closed: false).update_all(state: :opened) end end diff --git a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb index 78096666393eb1ace606e3a10758d5e2b84be779..1978ea8915390ac6a76e6ccdc49d143e2ce53a7e 100644 --- a/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb +++ b/db/migrate/20130218141344_convert_closed_to_state_in_milestone.rb @@ -1,14 +1,14 @@ class ConvertClosedToStateInMilestone < ActiveRecord::Migration def up Milestone.transaction do - Milestone.where(closed: false).update_all("state = 'opened'") - Milestone.where(closed: false).update_all("state = 'active'") + Milestone.where(closed: true).update_all(state: :closed) + Milestone.where(closed: false).update_all(state: :active) end end def down Milestone.transaction do - Milestone.where(state: :closed).update_all("closed = 1") + Milestone.where(state: :closed).update_all(closed: true) end end end diff --git a/db/migrate/20130304104623_add_state_to_user.rb b/db/migrate/20130304104623_add_state_to_user.rb new file mode 100644 index 0000000000000000000000000000000000000000..8154c21065f711403a241d218916146dd6f5e146 --- /dev/null +++ b/db/migrate/20130304104623_add_state_to_user.rb @@ -0,0 +1,5 @@ +class AddStateToUser < ActiveRecord::Migration + def change + add_column :users, :state, :string + end +end diff --git a/db/migrate/20130304104740_convert_blocked_to_state.rb b/db/migrate/20130304104740_convert_blocked_to_state.rb new file mode 100644 index 0000000000000000000000000000000000000000..e8d5257ac96e88e49d3722d59dbf4c09ec2c87c9 --- /dev/null +++ b/db/migrate/20130304104740_convert_blocked_to_state.rb @@ -0,0 +1,14 @@ +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 diff --git a/db/migrate/20130304105317_remove_blocked_from_user.rb b/db/migrate/20130304105317_remove_blocked_from_user.rb new file mode 100644 index 0000000000000000000000000000000000000000..e010474538c5b22d76b7ec00ce030a3583b2a1b2 --- /dev/null +++ b/db/migrate/20130304105317_remove_blocked_from_user.rb @@ -0,0 +1,9 @@ +class RemoveBlockedFromUser < ActiveRecord::Migration + def up + remove_column :users, :blocked + end + + def down + add_column :users, :blocked, :boolean + end +end diff --git a/db/schema.rb b/db/schema.rb index 74d5f9a360c30be1497b631d9fa6859303268c8c..2250f418bddd08bf83ca29e396b8f850c115b39b 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # 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| t.string "target_type" @@ -112,6 +112,7 @@ t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.string "type" + t.string "description", :default => "", :null => false end add_index "namespaces", ["name"], :name => "index_namespaces_on_name" @@ -152,6 +153,8 @@ t.boolean "wiki_enabled", :default => true, :null => false t.integer "namespace_id" t.boolean "public", :default => false, :null => false + t.string "issues_tracker", :default => "gitlab", :null => false + t.string "issues_tracker_id" end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" @@ -232,6 +235,7 @@ t.integer "owner_id" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false + t.string "description", :default => "", :null => false end create_table "users", :force => true do |t| @@ -257,7 +261,6 @@ t.boolean "dark_scheme", :default => false, :null => false t.integer "theme_id", :default => 1, :null => false t.string "bio" - t.boolean "blocked", :default => false, :null => false t.integer "failed_attempts", :default => 0 t.datetime "locked_at" t.string "extern_uid" @@ -265,10 +268,10 @@ t.string "username" t.boolean "can_create_group", :default => true, :null => false t.boolean "can_create_team", :default => true, :null => false + t.string "state" end 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", ["extern_uid", "provider"], :name => "index_users_on_extern_uid_and_provider", :unique => true add_index "users", ["name"], :name => "index_users_on_name" diff --git a/doc/install/databases.md b/doc/install/databases.md index 61882602bba3455fc41b293ca4a9a326ca25df50..2c4fb9dbfff40716c109a4164c3adadf555ac031 100644 --- a/doc/install/databases.md +++ b/doc/install/databases.md @@ -12,7 +12,7 @@ GitLab supports the following databases: sudo apt-get install -y mysql-server mysql-client libmysqlclient-dev # Login to MySQL - $ mysql -u root -p + mysql -u root -p # Create a user for GitLab. (change $password to a real password) mysql> CREATE USER 'gitlab'@'localhost' IDENTIFIED BY '$password'; diff --git a/doc/install/installation.md b/doc/install/installation.md index 4d2ab63b2e93cfd12379833be8633a46a05598bc..d0f586af6b40e39d01039910ef5bca334a25c340 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -1,7 +1,6 @@ -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. +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. +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:** The following steps have been known to work. @@ -92,21 +91,29 @@ Create a `git` user for Gitlab: sudo adduser --disabled-login --gecos 'GitLab' git + # 4. GitLab shell - # Login as git +GitLab Shell is a ssh access and repository management software developed specially for GitLab. + + # Login as git sudo su git - # Go to home directory + # Go to home directory cd /home/git # Clone gitlab shell git clone https://github.com/gitlabhq/gitlab-shell.git - # Setup cd gitlab-shell cp config.yml.example config.yml - ./bin/install + + # Edit config and replace gitlab_url + # with something like 'http://domain.com/' + vim config.yml + + # Do setup + ./bin/install # 5. Database @@ -124,9 +131,9 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install # Clone GitLab repository sudo -u git -H git clone https://github.com/gitlabhq/gitlabhq.git gitlab - # Go to gitlab dir + # Go to gitlab dir cd /home/git/gitlab - + # Checkout to stable release sudo -u git -H git checkout 5-0-stable @@ -157,7 +164,7 @@ do so with caution! # Create directory for pids and make sure GitLab can write to it sudo -u git -H mkdir tmp/pids/ sudo chmod -R u+rwX tmp/pids/ - + # Copy the example Unicorn config sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb @@ -188,7 +195,7 @@ Make sure to update username/password in config/database.yml. ## Initialise Database and Activate Advanced Features - + sudo -u git -H bundle exec rake db:setup RAILS_ENV=production sudo -u git -H bundle exec rake db:seed_fu RAILS_ENV=production sudo -u git -H bundle exec rake gitlab:setup RAILS_ENV=production @@ -286,7 +293,7 @@ a different host, you can configure its connection string via the ## Custom SSH Connection If you are running SSH on a non-standard port, you must change the gitlab user's SSH config. - + # Add to /home/git/.ssh/config host localhost # Give your setup a name (here: override localhost) user git # Your remote git user diff --git a/features/project/network.feature b/features/project/network.feature index 31ce5ad327959822e2e635567c24e414ee9383ae..a6cbd2c4781135ba17dea743458d9649462abacc 100644 --- a/features/project/network.feature +++ b/features/project/network.feature @@ -7,3 +7,19 @@ Feature: Project Network Graph @javascript Scenario: I should see project network 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 diff --git a/features/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index cbca2daa70182a9abd0204551c8d41424a8dd52e..167763b691209f192f82b54023abc04365f38fbe 100644 --- a/features/steps/admin/admin_groups.rb +++ b/features/steps/admin/admin_groups.rb @@ -25,11 +25,13 @@ class AdminGroups < Spinach::FeatureSteps And 'submit form with new group info' do fill_in 'group_name', :with => 'gitlab' + fill_in 'group_description', :with => 'Group description' click_button "Create group" end Then 'I should see newly created group' do page.should have_content "Group: gitlab" + page.should have_content "Group description" end Then 'I should be redirected to group page' do diff --git a/features/steps/admin/admin_teams.rb b/features/steps/admin/admin_teams.rb index 637fc4e58f3799aac28f5d49a5e934146e6296bd..6423f3dfd9b553bf157df72632573b95daed29e5 100644 --- a/features/steps/admin/admin_teams.rb +++ b/features/steps/admin/admin_teams.rb @@ -18,6 +18,7 @@ class AdminTeams < Spinach::FeatureSteps And 'submit form with new team info' do fill_in 'user_team_name', with: 'gitlab' + fill_in 'user_team_description', with: 'description' click_button 'Create team' end @@ -27,6 +28,7 @@ class AdminTeams < Spinach::FeatureSteps And 'I should see newly created team' do page.should have_content "Team: gitlab" + page.should have_content "description" end When 'I visit admin teams page' do diff --git a/features/steps/group/group.rb b/features/steps/group/group.rb index 5cfa4756ac35e4002176a70a3050853b9ae41283..5ac958e3fc2c1ffa8acb37976f0c9e6acc3a9471 100644 --- a/features/steps/group/group.rb +++ b/features/steps/group/group.rb @@ -28,7 +28,7 @@ class Groups < Spinach::FeatureSteps Then 'I should see merge requests from this group assigned to me' do assigned_to_me(:merge_requests).each do |issue| - page.should have_content issue.title + page.should have_content issue.title[0..80] end end @@ -69,12 +69,14 @@ class Groups < Spinach::FeatureSteps end 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" end Then 'I should see newly created group' do 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" end diff --git a/features/steps/project/project_merge_requests.rb b/features/steps/project/project_merge_requests.rb index ff95a47d4cff35cacc68baaa5288d117b5775724..4c22119b07eebaed49f8542a4131dc6d9fc3892d 100644 --- a/features/steps/project/project_merge_requests.rb +++ b/features/steps/project/project_merge_requests.rb @@ -25,8 +25,8 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see closed merge request "Bug NS-04"' do - mr = MergeRequest.find_by_title("Bug NS-04") - mr.closed?.should be_true + merge_request = MergeRequest.find_by_title!("Bug NS-04") + merge_request.closed?.should be_true page.should have_content "Closed by" end @@ -63,7 +63,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'project "Shop" have "Bug NS-04" open merge request' do - project = Project.find_by_name("Shop") create(:merge_request, title: "Bug NS-04", project: project, @@ -71,7 +70,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end 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, title: "Bug NS-05", project: project, @@ -79,7 +77,6 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'project "Shop" have "Feature NS-03" closed merge request' do - project = Project.find_by_name("Shop") create(:closed_merge_request, title: "Feature NS-03", project: project, @@ -87,18 +84,16 @@ class ProjectMergeRequests < Spinach::FeatureSteps end And 'I switch to the diff tab' do - mr = MergeRequest.find_by_title("Bug NS-05") - visit diffs_project_merge_request_path(mr.project, mr) + visit diffs_project_merge_request_path(project, merge_request) end And 'I switch to the merge request\'s comments tab' do - mr = MergeRequest.find_by_title("Bug NS-05") - visit project_merge_request_path(mr.project, mr) + visit project_merge_request_path(project, merge_request) end 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 And 'I leave a comment on the diff page' do @@ -121,8 +116,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on line 185' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.commits.first + first_commit = merge_request.commits.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 "#{first_diff.b_path}:L185" @@ -130,8 +124,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on commit bcf03b5de6c:L185' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.commits.first + first_commit = merge_request.commits.first first_diff = first_commit.diffs.first page.should have_content "#{current_user.name} started a discussion on commit" page.should have_content first_commit.short_id(8) @@ -140,12 +133,19 @@ class ProjectMergeRequests < Spinach::FeatureSteps end Then 'I should see a discussion has started on commit bcf03b5de6c' do - mr = MergeRequest.find_by_title("Bug NS-05") - first_commit = mr.st_commits.first + first_commit = merge_request.st_commits.first first_diff = first_commit.diffs.first 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 "One comment to rule them all" page.should have_content "#{first_diff.b_path}:L185" end + + def project + @project ||= Project.find_by_name!("Shop") + end + + def merge_request + @merge_request ||= MergeRequest.find_by_title!("Bug NS-05") + end end diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index f26deff9367821611cc01f19cc68434495aa970e..2ca629883a972f5afe39182e90852857d33f95ff 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -4,16 +4,51 @@ class ProjectNetworkGraph < Spinach::FeatureSteps Then 'page should have network graph' do page.should have_content "Project Network Graph" - within ".graph" do - page.should have_content "master" - end + page.should have_selector ".graph" 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) - Gitlab::Graph::JsonBuilder.stub(max_count: 10) + Graph::JsonBuilder.stub(max_count: 10) project = Project.find_by_name("Shop") visit project_graph_path(project, "master") 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 diff --git a/features/steps/shared/paths.rb b/features/steps/shared/paths.rb index 40786f6e6d4cae6a4333739c2475fc706eff61d4..431d5299d8fde3a6973eba23250336e8f3bd2c1d 100644 --- a/features/steps/shared/paths.rb +++ b/features/steps/shared/paths.rb @@ -143,7 +143,7 @@ module SharedPaths Given "I visit my project's network page" do # 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) end diff --git a/features/steps/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 1abb0f49122057a0a599219cecd6b0bec57cc60c..862259dcb4e457ef83656ae0fd3778889f19349c 100644 --- a/features/steps/userteams/userteams.rb +++ b/features/steps/userteams/userteams.rb @@ -44,9 +44,16 @@ class Userteams < Spinach::FeatureSteps And 'I submit form with new team info' do fill_in 'name', with: 'gitlab' + + fill_in 'user_team_description', with: 'team description' click_button 'Create team' 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 team = UserTeam.last current_path.should == team_path(team) diff --git a/features/support/env.rb b/features/support/env.rb index da40b38b79ca2a8d0f3ff866c59e2ebc2666f2d7..2fd7ffdb81307984bdad1dd856644840a7464cbd 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -34,6 +34,7 @@ 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.mkdir_p Gitlab.config.gitlab_shell.repos_path + DatabaseCleaner.start end Spinach.hooks.after_scenario do diff --git a/features/teams/team.feature b/features/teams/team.feature index 9255e0daadb42ebcd260776dcdc06dd4c2479317..f7774597dc3954d94bfa2c9c6959e6e7097f9fdc 100644 --- a/features/teams/team.feature +++ b/features/teams/team.feature @@ -20,6 +20,7 @@ Feature: UserTeams When I click to "New team" link And I submit form with new team info Then I should be redirected to new team page + Then I should see newly created team Scenario: I should see team dashboard list When I have teams with projects and members diff --git a/lib/api/entities.rb b/lib/api/entities.rb index 1cae1d337fee907756a37ee8dd237545ea72d827..088c9959804fd770a6a94d1af9adf5b37b380229 100644 --- a/lib/api/entities.rb +++ b/lib/api/entities.rb @@ -2,11 +2,11 @@ module Gitlab module Entities class User < Grape::Entity 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 class UserBasic < Grape::Entity - expose :id, :username, :email, :name, :blocked, :created_at + expose :id, :username, :email, :name, :state, :created_at end class UserLogin < UserBasic diff --git a/lib/api/projects.rb b/lib/api/projects.rb index abd115d31b04a2ef1a66c78725aa8d450354c507..6df00db70a02299970724011f187dbb561473e10 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -52,8 +52,8 @@ def handle_project_member_errors(errors) :issues_enabled, :wall_enabled, :merge_requests_enabled, - :wiki_enabled] - + :wiki_enabled, + :namespace_id] @project = ::Projects::CreateContext.new(current_user, attrs).execute if @project.saved? present @project, with: Entities::Project diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index fb595e18b2401123d9b47d4ff2a29c1c9136ca6d..fd0050cfd5fdacd215bdc8b6fc6a3f1e9878f40d 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -126,7 +126,7 @@ def assign_ref_vars @tree = TreeDecorator.new(@tree) raise InvalidPathError if @tree.invalid? - rescue NoMethodError, InvalidPathError + rescue RuntimeError, NoMethodError, InvalidPathError not_found! end end diff --git a/lib/gitlab/auth.rb b/lib/gitlab/auth.rb index d0e792befbb178ea6c3f5b5be520de106cdbb6c5..0fee33dbeb0ef4548a91a9c3662de510ca76e91a 100644 --- a/lib/gitlab/auth.rb +++ b/lib/gitlab/auth.rb @@ -41,10 +41,12 @@ def create_from_omniauth(auth, ldap = false) password_confirmation: password, projects_limit: Gitlab.config.gitlab.default_projects_limit, }, as: :admin) + @user.save! + if Gitlab.config.omniauth['block_auto_created_users'] && !ldap - @user.blocked = true + @user.block end - @user.save! + @user end diff --git a/lib/gitlab/graph/commit.rb b/lib/gitlab/graph/commit.rb deleted file mode 100644 index 13c8ebc9952b32b1f7f708f8490639e0be9ce3a8..0000000000000000000000000000000000000000 --- a/lib/gitlab/graph/commit.rb +++ /dev/null @@ -1,52 +0,0 @@ -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 diff --git a/lib/gitlab/graph/json_builder.rb b/lib/gitlab/graph/json_builder.rb deleted file mode 100644 index cc971a245a7044a36ced79bea36d52fc2b6a75ab..0000000000000000000000000000000000000000 --- a/lib/gitlab/graph/json_builder.rb +++ /dev/null @@ -1,268 +0,0 @@ -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 diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb index e7d6e3e6bd963715507f7d8f7156d0fb36ccbcfb..280f9f9730aa6da24c0f1a3f38a1ab7e85b1c5f6 100644 --- a/lib/gitlab/markdown.rb +++ b/lib/gitlab/markdown.rb @@ -25,6 +25,8 @@ module Gitlab # >> gfm(":trollface:") # => "<img alt=\":trollface:\" class=\"emoji\" src=\"/images/trollface.png" title=\":trollface:\" /> module Markdown + include IssuesHelper + attr_reader :html_options # Public: Parse the provided text with GitLab-Flavored Markdown @@ -163,8 +165,11 @@ def reference_user(identifier) end def reference_issue(identifier) - if issue = @project.issues.where(id: identifier).first - link_to("##{identifier}", project_issue_url(@project, issue), html_options.merge(title: "Issue: #{issue.title}", class: "gfm gfm-issue #{html_options[:class]}")) + if @project.issue_exists? identifier + 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 diff --git a/lib/tasks/sidekiq.rake b/lib/tasks/sidekiq.rake index cf99951e02795df1139e866b0a61fe7ef28466c0..d0e9dfe46a160279cbbcf3ad650d8c34678ea63b 100644 --- a/lib/tasks/sidekiq.rake +++ b/lib/tasks/sidekiq.rake @@ -1,19 +1,19 @@ namespace :sidekiq do desc "GITLAB | Stop sidekiq" task :stop do - run "bundle exec sidekiqctl stop #{pidfile}" + system "bundle exec sidekiqctl stop #{pidfile}" end desc "GITLAB | Start sidekiq" 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 - + desc "GITLAB | Start sidekiq with launchd on Mac OS X" 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 - + def pidfile Rails.root.join("tmp", "pids", "sidekiq.pid") end diff --git a/spec/factories.rb b/spec/factories.rb index b81984b5d5350cd603dbdbce9dc8aaafe64ab3f2..41766859468475aa6954c5dfcc361a17699dcc9e 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -29,6 +29,11 @@ creator end + factory :redmine_project, parent: :project do + issues_tracker { "redmine" } + issues_tracker_id { "project_name_in_redmine" } + end + factory :group do sequence(:name) { |n| "group#{n}" } path { name.downcase.gsub(/\s/, '_') } diff --git a/spec/factories/user_teams.rb b/spec/factories/user_teams.rb index 1a9ae8e885c3cf924219bef7ba49d893884d52cc..8d1ee11ee752e0caf096afce8b8fda99964fda29 100644 --- a/spec/factories/user_teams.rb +++ b/spec/factories/user_teams.rb @@ -15,6 +15,7 @@ FactoryGirl.define do factory :user_team do sequence(:name) { |n| "team#{n}" } + sequence(:description) { |n| "team_description#{n}" } path { name.downcase.gsub(/\s/, '_') } owner end diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 77d6e9e37959c990a9c1c0a594637ce3ed941a2e..22d1ee914802a8bafb020569f1588d059e171ffd 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -55,8 +55,8 @@ user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") - email.body.should have_content(user.email) - email.body.should have_content(@password) + email.text_part.body.should have_content(user.email) + email.text_part.body.should have_content(@password) end end @@ -67,8 +67,8 @@ user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") - email.body.should have_content(user.email) - email.body.should_not have_content(@password) + email.text_part.body.should have_content(user.email) + email.text_part.body.should_not have_content(@password) end end end diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb index 1b067972c8167b913f289c679453c026c10be09b..1f5fabfbb8ea065198b104b1df518400aaafc860 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -2,6 +2,7 @@ describe GitlabMarkdownHelper do include ApplicationHelper + include IssuesHelper let!(:project) { create(:project) } diff --git a/spec/helpers/issues_helper_spec.rb b/spec/helpers/issues_helper_spec.rb new file mode 100644 index 0000000000000000000000000000000000000000..c9eb65915610b855535f88614a8b1410e22fc837 --- /dev/null +++ b/spec/helpers/issues_helper_spec.rb @@ -0,0 +1,79 @@ +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 diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 23f1c6df0cf92832710720e767bf5cf871ee86f7..545908b214d4c1d00a6b79b1b6a5c9acbbea8ac4 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -60,6 +60,7 @@ 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(: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 project.stub(:creator).and_return(double(can_create_project?: false, projects_limit: 1)) @@ -190,4 +191,57 @@ Project.new(path: "empty").repository.should be_nil 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 diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 40047b351da45e9143ce95656a441ab832ba7614..cb39b6fc63f56cda93ba69a9e48f8844ead9ab80 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -25,7 +25,7 @@ # dark_scheme :boolean default(FALSE), not null # theme_id :integer default(1), not null # bio :string(255) -# blocked :boolean default(FALSE), not null +# state :string(255) default(FALSE), not null # failed_attempts :integer default(0) # locked_at :datetime # extern_uid :string(255) @@ -140,7 +140,7 @@ it "should block user" do user.block - user.blocked.should be_true + user.blocked?.should be_true end end @@ -149,7 +149,7 @@ User.delete_all @user = create :user @admin = create :user, admin: true - @blocked = create :user, blocked: true + @blocked = create :user, state: :blocked end it { User.filter("admins").should == [@admin] } diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb index bffa5fcfd6920b696f4af2e2c7e9daddfa443f6e..b58c5647ca6745f472ab6eebd7c9ccde4bdbc2b5 100644 --- a/spec/observers/user_observer_spec.rb +++ b/spec/observers/user_observer_spec.rb @@ -15,7 +15,13 @@ create(:user) end + it 'no email for external' do + Notify.should_not_receive(:new_user_email) + create(:user, extern_uid: '32442eEfsafada') + end + 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) create(:user) end