diff options
134 files changed, 1316 insertions, 539 deletions
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00304dd3d64..cff5e939f11 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. @@ -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,26 +35,30 @@ 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" # API -gem "grape", "~> 0.2.1" +gem "grape", "~> 0.3.1" +gem "grape-entity", "~> 0.2.0" # Format dates and times # 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" @@ -68,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" @@ -77,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" @@ -112,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 @@ -139,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 3ca39aeae28..89882492b36 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,11 +1,4 @@ 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 specs: @@ -14,41 +7,6 @@ GIT 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 specs: @@ -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,15 +156,22 @@ GEM pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.1.1) gitlab_yaml_db (1.0.0) - grape (0.2.2) + gon (4.0.2) + grape (0.3.2) activesupport - 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) @@ -203,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) @@ -231,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) @@ -248,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) @@ -291,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) @@ -303,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 @@ -340,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) @@ -379,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) @@ -393,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) @@ -414,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) @@ -425,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 @@ -434,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) @@ -461,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) @@ -477,17 +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! - grape (~> 0.2.1) - grit! - grit_ext! + gon + grape (~> 0.3.1) + grape-entity (~> 0.2.0) + 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) @@ -497,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) @@ -520,7 +510,7 @@ DEPENDENCIES seed-fu settingslogic shoulda-matchers (= 1.3.0) - sidekiq (= 2.7.3) + sidekiq simplecov sinatra six @@ -532,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 ee029f9bfcb..02b4722f4be 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,132 @@ -# Welcome to GitLab [](https://travis-ci.org/gitlabhq/gitlabhq) [](https://travis-ci.org/gitlabhq/grit) [](https://codeclimate.com/github/gitlabhq/gitlabhq) [](https://gemnasium.com/gitlabhq/gitlabhq) +## GitLab: self hosted Git management software -GitLab is a free project and repository management application + -[](http://ci.gitlab.org/projects/1?ref=master) +### 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 -## Application details +### GitLab is -* based on Ruby on Rails -* distributed under the MIT License -* works with gitolite +* powered by Ruby on Rails +* completely free and open source (MIT license) +* used by 10.000 organization to keep their code secure -## Requirements +### Code status -* Ubuntu/Debian +* [](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) + +* [](https://gemnasium.com/gitlabhq/gitlabhq) + +### 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) + +* 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/) + +* GitLab CI: [Readme](https://github.com/gitlabhq/gitlab-ci/blob/master/README.md) of the GitLab open-source continuous integration server + +### Requirements + +* Ubuntu/Debian* * ruby 1.9.3+ * MySQL * git -* gitolite +* 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) -Checkout wiki pages for installation information, migration, etc. +### Other documentation -## Community +* [GitLab API](https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/README.md) -[Google Group](https://groups.google.com/group/gitlabhq) +* [Rake tasks](https://github.com/gitlabhq/gitlabhq/tree/master/doc/raketasks) -## Contacts +* [GitLab recipes](https://github.com/gitlabhq/gitlab-recipes) -Twitter: +### Getting in touch - * @gitlabhq - * @dzaporozhets +* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) -Email +* [Core team](https://github.com/gitlabhq?tab=members) - * m@gitlabhq.com +* [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 d148b518b0e..bf4fe695438 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/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index d789f54a4e6..d707657d4bf 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 d03a487c453..24106c61b75 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 7ac8c2dd91c..c967c2d1c17 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 dcfd610e2c4..9e015eb2b6e 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/mixins.scss b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss index f416be95dee..0a27a8350b7 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/mixins.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/mixins.scss @@ -75,3 +75,14 @@ line-height: 36px; font-weight: normal; } + +@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 781577c2147..1f0c4802318 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 6018ff7074d..4196ea7ad29 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 a389a9baa84..0df39298c89 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 df8fd8d6458..94e1d0b609c 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/login.scss b/app/assets/stylesheets/sections/login.scss index 89b8f1c0055..e3fe0b436c3 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 1f92a3a835d..1b4280f4974 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 b37830b138e..ada0780eece 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 0cc73f99535..0765b30c354 100644 --- a/app/contexts/issues_list_context.rb +++ b/app/contexts/issues_list_context.rb @@ -7,12 +7,13 @@ class IssuesListContext < BaseContext @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/contexts/test_hook_context.rb b/app/contexts/test_hook_context.rb index d2d82a52cf5..63eda6c7d06 100644 --- a/app/contexts/test_hook_context.rb +++ b/app/contexts/test_hook_context.rb @@ -1,8 +1,7 @@ class TestHookContext < BaseContext def execute hook = project.hooks.find(params[:id]) - commits = project.repository.commits(project.default_branch, nil, 3) - data = project.post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}", current_user) + data = GitPushService.new.sample_data(project, current_user) hook.execute(data) end end diff --git a/app/controllers/admin/teams/members_controller.rb b/app/controllers/admin/teams/members_controller.rb index e7dbcad568f..e6469874419 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/application_controller.rb b/app/controllers/application_controller.rb index 1f211bac9c2..5b886227bc9 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 @@ -148,4 +149,8 @@ class ApplicationController < ActionController::Base 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 534ae1edd31..9dc0d96883e 100644 --- a/app/controllers/commits_controller.rb +++ b/app/controllers/commits_controller.rb @@ -13,7 +13,7 @@ class CommitsController < ProjectResourceController @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 ae20f9c0ba6..bd3f1115173 100644 --- a/app/controllers/compare_controller.rb +++ b/app/controllers/compare_controller.rb @@ -16,7 +16,7 @@ class CompareController < ProjectResourceController @refs_are_same = result[:same] @line_notes = [] - @commits = CommitDecorator.decorate(@commits) + @commits = CommitDecorator.decorate_collection(@commits) end def create diff --git a/app/controllers/merge_requests_controller.rb b/app/controllers/merge_requests_controller.rb index f92d9976b43..788f2c3a5cd 100644 --- a/app/controllers/merge_requests_controller.rb +++ b/app/controllers/merge_requests_controller.rb @@ -75,13 +75,14 @@ class MergeRequestsController < ProjectResourceController if @merge_request.unchecked? @merge_request.check_if_can_be_merged end - render json: {merge_status: @merge_request.human_merge_status} + render json: {merge_status: @merge_request.merge_status_name} rescue Gitlab::SatelliteNotExistError render json: {merge_status: :no_satellite} 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 @@ class MergeRequestsController < ProjectResourceController # 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 57f1e9e6bb3..cdac28c1bde 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController 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/teams/members_controller.rb b/app/controllers/teams/members_controller.rb index ead62e13afa..4bd70fd7247 100644 --- a/app/controllers/teams/members_controller.rb +++ b/app/controllers/teams/members_controller.rb @@ -8,7 +8,7 @@ class Teams::MembersController < 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/decorators/application_decorator.rb b/app/decorators/application_decorator.rb index 3023699e700..b805b3479b8 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/commits_helper.rb b/app/helpers/commits_helper.rb index 6d2ce2feea3..acdd48e04eb 100644 --- a/app/helpers/commits_helper.rb +++ b/app/helpers/commits_helper.rb @@ -57,6 +57,31 @@ module CommitsHelper end end + def each_diff_line_near(diff, index, expected_line_code) + max_number_of_lines = 16 + + prev_match_line = nil + prev_lines = [] + + each_diff_line(diff, index) do |full_line, type, line_code, line_new, line_old| + line = [full_line, type, line_code, line_new, line_old] + if line_code != expected_line_code + if type == "match" + prev_lines.clear + prev_match_line = line + else + prev_lines.push(line) + prev_lines.shift if prev_lines.length >= max_number_of_lines + end + else + yield(prev_match_line) if !prev_match_line.nil? + prev_lines.each { |ln| yield(ln) } + yield(line) + break + end + end + end + def image_diff_class(diff) if diff.deleted_file "deleted" diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index ed7e3e869c0..54385117c26 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -27,6 +27,7 @@ module IssuesHelper all: "all", closed: "closed", to_me: "assigned-to-me", + by_me: "created-by-me", open: "open" } end @@ -40,4 +41,39 @@ module IssuesHelper 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/models/ability.rb b/app/models/ability.rb index 6fda2e52c7c..41f7127403c 100644 --- a/app/models/ability.rb +++ b/app/models/ability.rb @@ -91,7 +91,6 @@ class Ability :admin_team_member, :admin_merge_request, :admin_note, - :accept_mr, :admin_wiki, :admin_project ] diff --git a/app/models/group.rb b/app/models/group.rb index 8ba92980a9b..7651ce23cb6 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 112f43c4692..f01cad0a458 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -30,6 +30,10 @@ class Issue < ActiveRecord::Base 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/key.rb b/app/models/key.rb index edb0bcd61fd..53eee511e13 100644 --- a/app/models/key.rb +++ b/app/models/key.rb @@ -21,7 +21,6 @@ class Key < ActiveRecord::Base attr_accessible :key, :title before_validation :strip_white_space - before_save :set_identifier validates :title, presence: true, length: { within: 0..255 } validates :key, presence: true, length: { within: 0..5000 }, format: { :with => /ssh-.{3} / }, uniqueness: true @@ -48,14 +47,6 @@ class Key < ActiveRecord::Base errors.add(:key, "can't be fingerprinted") if $?.exitstatus != 0 end - def set_identifier - if is_deploy_key - self.identifier = "deploy_#{Digest::MD5.hexdigest(key)}" - else - self.identifier = "#{user.identifier}_#{Time.now.to_i}" - end - end - def is_deploy_key !!project_id end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 1bc3428476e..c26d40c5703 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -24,6 +24,8 @@ require Rails.root.join("lib/static_model") class MergeRequest < ActiveRecord::Base include Issuable + BROKEN_DIFF = "--broken-diff" + attr_accessible :title, :assignee_id, :target_branch, :source_branch, :milestone_id, :author_id_of_changes, :state_event @@ -51,52 +53,42 @@ class MergeRequest < ActiveRecord::Base state :merged end - BROKEN_DIFF = "--broken-diff" + state_machine :merge_status, initial: :unchecked do + event :mark_as_unchecked do + transition [:can_be_merged, :cannot_be_merged] => :unchecked + end + + event :mark_as_mergeable do + transition unchecked: :can_be_merged + end + + event :mark_as_unmergeable do + transition unchecked: :cannot_be_merged + end + + state :unchecked - UNCHECKED = 1 - CAN_BE_MERGED = 2 - CANNOT_BE_MERGED = 3 + state :can_be_merged + + state :cannot_be_merged + end serialize :st_commits serialize :st_diffs validates :source_branch, presence: true validates :target_branch, presence: true - validate :validate_branches + validate :validate_branches scope :merged, -> { with_state(:merged) } + scope :by_branch, ->(branch_name) { where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) } + scope :cared, ->(user) { where('assignee_id = :user OR author_id = :user', user: user.id) } + scope :by_milestone, ->(milestone) { where(milestone_id: milestone) } # Closed scope for merge request should return # both merged and closed mr's scope :closed, -> { with_states(:closed, :merged) } - class << self - def find_all_by_branch(branch_name) - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) - end - - def cared(user) - where('assignee_id = :user OR author_id = :user', user: user.id) - end - - def find_all_by_branch(branch_name) - where("source_branch LIKE :branch OR target_branch LIKE :branch", branch: branch_name) - end - - def find_all_by_milestone(milestone) - where("milestone_id = :milestone_id", milestone_id: milestone) - end - end - - def human_merge_status - merge_statuses = { - CAN_BE_MERGED => "can_be_merged", - CANNOT_BE_MERGED => "cannot_be_merged", - UNCHECKED => "unchecked" - } - merge_statuses[self.merge_status] - end - def validate_branches if target_branch == source_branch errors.add :base, "You can not use same branch for source and target branches" @@ -108,26 +100,12 @@ class MergeRequest < ActiveRecord::Base self.reloaded_diffs end - def unchecked? - merge_status == UNCHECKED - end - - def mark_as_unchecked - self.merge_status = UNCHECKED - self.save - end - - def can_be_merged? - merge_status == CAN_BE_MERGED - end - def check_if_can_be_merged - self.merge_status = if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? - CAN_BE_MERGED - else - CANNOT_BE_MERGED - end - self.save + if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged? + mark_as_mergeable + else + mark_as_unmergeable + end end def diffs @@ -182,11 +160,6 @@ class MergeRequest < ActiveRecord::Base commits.any? && opened? end - def mark_as_unmergable - self.merge_status = CANNOT_BE_MERGED - self.save - end - def reloaded_commits if opened? && unmerged_commits.any? self.st_commits = unmerged_commits @@ -204,15 +177,8 @@ class MergeRequest < ActiveRecord::Base end def merge!(user_id) + self.author_id_of_changes = user_id self.merge - - Event.create( - project: self.project, - action: Event::MERGED, - target_id: self.id, - target_type: "MergeRequest", - author_id: user_id - ) end def automerge!(current_user) @@ -221,7 +187,7 @@ class MergeRequest < ActiveRecord::Base true end rescue - self.mark_as_unmergable + mark_as_unmergeable false end diff --git a/app/models/namespace.rb b/app/models/namespace.rb index 385fa291b48..c6b3e94d05d 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 28f564164e3..02f1df13f9c 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 @@ require "grit" 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 Project < ActiveRecord::Base 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 Project < ActiveRecord::Base 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 Project < ActiveRecord::Base 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 @@ class Project < ActiveRecord::Base 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 @@ -247,32 +268,6 @@ class Project < ActiveRecord::Base users_projects.find_by_user_id(user_id) end - def transfer(new_namespace) - Project.transaction do - old_namespace = namespace - self.namespace = new_namespace - - old_dir = old_namespace.try(:path) || '' - new_dir = new_namespace.try(:path) || '' - - old_repo = if old_dir.present? - File.join(old_dir, self.path) - else - self.path - end - - if Project.where(path: self.path, namespace_id: new_namespace.try(:id)).present? - raise TransferError.new("Project with same path in target namespace already exists") - end - - Gitlab::ProjectMover.new(self, old_dir, new_dir).execute - - save! - end - rescue Gitlab::ProjectMover::ProjectMoveError => ex - raise Project::TransferError.new(ex.message) - end - def name_with_namespace @name_with_namespace ||= begin if namespace @@ -295,6 +290,10 @@ class Project < ActiveRecord::Base end end + def transfer(new_namespace) + ProjectTransferService.new.transfer(self, new_namespace) + end + def execute_hooks(data) hooks.each { |hook| hook.async_execute(data) } end @@ -321,7 +320,7 @@ class Project < ActiveRecord::Base c_ids = self.repository.commits_between(oldrev, newrev).map(&:id) # Update code for merge requests - mrs = self.merge_requests.opened.find_all_by_branch(branch_name).all + mrs = self.merge_requests.opened.by_branch(branch_name).all mrs.each { |merge_request| merge_request.reload_code; merge_request.mark_as_unchecked } # Close merge requests diff --git a/app/models/project_team.rb b/app/models/project_team.rb index c2cf83c0ca8..f3e5c0e5354 100644 --- a/app/models/project_team.rb +++ b/app/models/project_team.rb @@ -66,28 +66,6 @@ class ProjectTeam members.masters.map(&:user) end - def repository_readers - repository_members[UsersProject::REPORTER] - end - - def repository_writers - repository_members[UsersProject::DEVELOPER] - end - - def repository_masters - repository_members[UsersProject::MASTER] - end - - def repository_members - keys = Hash.new {|h,k| h[k] = [] } - UsersProject.select("keys.identifier, project_access"). - joins(user: :keys).where(project_id: project.id). - each {|row| keys[row.project_access] << [row.identifier] } - - keys[UsersProject::REPORTER] += project.deploy_keys.pluck(:identifier) - keys - end - def import(source_project) target_project = project diff --git a/app/models/user.rb b/app/models/user.rb index 4ed31c7edce..cd0754d7816 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -70,6 +70,7 @@ class User < ActiveRecord::Base has_many :team_projects, through: :user_team_project_relationships 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 } validates :extern_uid, allow_blank: true, uniqueness: {scope: :provider} validates :projects_limit, presence: true, numericality: {greater_than_or_equal_to: 0} @@ -215,17 +216,6 @@ class User < ActiveRecord::Base UsersProject.where(project_id: authorized_projects.map(&:id), user_id: self.id) end - # Returns a string for use as a Gitolite user identifier - # - # Note that Gitolite 2.x requires the following pattern for users: - # - # ^@?[0-9a-zA-Z][0-9a-zA-Z._\@+-]*$ - def identifier - # Replace non-word chars with underscores, then make sure it starts with - # valid chars - email.gsub(/\W/, '_').gsub(/\A([\W\_])+/, '') - end - def is_admin? admin end diff --git a/app/models/user_team.rb b/app/models/user_team.rb index 2f3091c2353..0cb84edd66d 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/activity_observer.rb b/app/observers/activity_observer.rb index 919a50f00c8..152e497794b 100644 --- a/app/observers/activity_observer.rb +++ b/app/observers/activity_observer.rb @@ -39,4 +39,18 @@ class ActivityObserver < ActiveRecord::Observer author_id: record.author_id_of_changes ) end + + def after_merge(record, transition) + # Since MR can be merged via sidekiq + # to prevent event duplication do this check + return true if record.merge_event + + Event.create( + project: record.project, + target_id: record.id, + target_type: record.class.name, + action: Event::MERGED, + author_id: record.author_id_of_changes + ) + end end diff --git a/app/observers/issue_observer.rb b/app/observers/issue_observer.rb index 592e2950f37..29e24040378 100644 --- a/app/observers/issue_observer.rb +++ b/app/observers/issue_observer.rb @@ -27,7 +27,7 @@ class IssueObserver < ActiveRecord::Observer 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/services/git_push_service.rb b/app/services/git_push_service.rb index 55cf31cd8f8..208ccf699d2 100644 --- a/app/services/git_push_service.rb +++ b/app/services/git_push_service.rb @@ -19,6 +19,8 @@ class GitPushService # 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,16 @@ class GitPushService project.execute_hooks(@push_data.dup) project.execute_services(@push_data.dup) end + end - create_push_event + # This method provide a sample data + # generated with post_receive_data method + # for given project + # + def sample_data(project, user) + @project, @user = project, user + commits = project.repository.commits(project.default_branch, nil, 3) + post_receive_data(commits.last.id, commits.first.id, "refs/heads/#{project.default_branch}") end protected diff --git a/app/services/project_transfer_service.rb b/app/services/project_transfer_service.rb new file mode 100644 index 00000000000..35d9517ad29 --- /dev/null +++ b/app/services/project_transfer_service.rb @@ -0,0 +1,34 @@ +# ProjectTransferService class +# +# Used for transfer project to another namespace +# +class ProjectTransferService + attr_accessor :project + + def transfer(project, new_namespace) + Project.transaction do + old_namespace = project.namespace + project.namespace = new_namespace + + old_dir = old_namespace.try(:path) || '' + new_dir = new_namespace.try(:path) || '' + + old_repo = if old_dir.present? + File.join(old_dir, project.path) + else + project.path + end + + if Project.where(path: project.path, namespace_id: new_namespace.try(:id)).present? + raise TransferError.new("Project with same path in target namespace already exists") + end + + Gitlab::ProjectMover.new(project, old_dir, new_dir).execute + + project.save! + end + rescue Gitlab::ProjectMover::ProjectMoveError => ex + raise Project::TransferError.new(ex.message) + end +end + diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index dce044956c3..bb1398f66cd 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 6d5a293ef7f..1b4ffcb6e02 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= 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 60c6fa5ad09..3fa63e1ba25 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 90f8fc0f814..63ea78fdd99 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 ebf69924a25..29b90bdd4cb 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 9282398ce5b..0a3d993b132 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 bb0487d43e9..62af4b50936 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,14 @@ %tr %td %strong= link_to team.name, admin_team_path(team) + %td= team.description %td= team.path %td= team.projects.count %td= team.members.count %td = link_to team.owner.name, admin_user_path(team.owner) %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 5d55a7975ee..1c90cb20c10 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 e5d079981c0..abdfada8c5e 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/events/event/_note.html.haml b/app/views/events/event/_note.html.haml index 19665ce0aea..199785e63ff 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 41ebf60698b..bf16b70c7f1 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 73be474e278..36ee4922731 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 a140b401b9d..81694b88cc4 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 21efaa5357c..b621f11bc5b 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/issues/show.html.haml b/app/views/issues/show.html.haml index 2997cde1ed2..70f94e52942 100644 --- a/app/views/issues/show.html.haml +++ b/app/views/issues/show.html.haml @@ -12,10 +12,9 @@ - else = link_to 'Close', project_issue_path(@project, @issue, issue: {state_event: :close }, status_only: true), method: :put, class: "btn grouped close_issue", title: "Close Issue" - - if can?(current_user, :admin_issue, @issue) = link_to edit_project_issue_path(@project, @issue), class: "btn grouped" do %i.icon-edit - Edit + Edit .pull-right .span3#votes= render 'votes/votes_block', votable: @issue diff --git a/app/views/layouts/_flash.html.haml b/app/views/layouts/_flash.html.haml index 9961ce8dd34..a3bed593e1c 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 4b4f5da3324..eb83fd2fd45 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 8f4f3d7815f..1f3ce2f40ef 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 a01886cdabf..00a08e6131d 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 7ee44238d10..90c2653438d 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 36c6b4c6c35..a9758f19d36 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 3554d88f10c..b9395873c33 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 9057ad50ce6..2c144de49b3 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 57f250c775b..611063e8c99 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 13fb8637bf6..37d0f16fa20 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 19bbc373f46..e5e08aab13c 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.html.haml b/app/views/merge_requests/_show.html.haml index ae2cfe924ec..08b80172645 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -29,10 +29,10 @@ $(function(){ merge_request = new MergeRequest({ url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", - check_enable: #{@merge_request.merge_status == MergeRequest::UNCHECKED ? "true" : "false"}, + check_enable: #{@merge_request.unchecked? ? "true" : "false"}, url_to_ci_check: "#{ci_status_project_merge_request_path(@project, @merge_request)}", ci_enable: #{@project.gitlab_ci? ? "true" : "false"}, - current_status: "#{@merge_request.human_merge_status}", + current_status: "#{@merge_request.merge_status_name}", action: "#{controller.action_name}" }); }); diff --git a/app/views/merge_requests/show/_mr_accept.html.haml b/app/views/merge_requests/show/_mr_accept.html.haml index 64f25a5118c..d4271c5551f 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/notes/_discussion_diff.html.haml b/app/views/notes/_discussion_diff.html.haml index 790b77333d5..20bdb3f3562 100644 --- a/app/views/notes/_discussion_diff.html.haml +++ b/app/views/notes/_discussion_diff.html.haml @@ -9,7 +9,7 @@ %br/ .content %table - - each_diff_line(diff, note.diff_file_index) do |line, type, line_code, line_new, line_old| + - each_diff_line_near(diff, note.diff_file_index, note.line_code) do |line, type, line_code, line_new, line_old| %tr.line_holder{ id: line_code } - if type == "match" %td.old_line= "..." @@ -22,4 +22,3 @@ - if line_code == note.line_code = render "notes/diff_notes_with_reply", notes: discussion_notes - - break # cut off diff after notes 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 00000000000..bbca3474d50 --- /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 00000000000..5ed55c35b23 --- /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 00000000000..3393d8384f1 --- /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 00000000000..94072d7fe5c --- /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 00000000000..aab8e5cfb6c --- /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 00000000000..a476b286ae4 --- /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 00000000000..26c73bdaa38 --- /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 00000000000..ea1b7efbe84 --- /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 00000000000..077c3b8a7de --- /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 00000000000..da123c2f89c --- /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 00000000000..497044184dc --- /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 00000000000..1af4ab559f6 --- /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 0336654dc69..b78c70be18a 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 22aaaf0f2b2..07132e67872 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 21e9d2e6029..52e01c3d56e 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 7b5de4a6274..bd9ca729352 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/teams/edit.html.haml b/app/views/teams/edit.html.haml index 751fe94c654..95c91b5044d 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/new.html.haml b/app/views/teams/new.html.haml index 7089f791558..99d308217e0 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 d6e80e2a51e..43cc026a5cf 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 62761c80cbb..3fb173862cd 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 f7d18e67148..a656b02171f 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -42,6 +42,8 @@ Settings['omniauth'] ||= Settingslogic.new({}) Settings.omniauth['enabled'] = false if Settings.omniauth['enabled'].nil? Settings.omniauth['providers'] ||= [] +Settings['issues_tracker'] ||= {} + # # GitLab # diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 97946c54b40..9c3976335ff 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -99,7 +99,7 @@ Devise.setup do |config| # ==> 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 3b763cf410d..275273a0b12 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 7537a11de96..57eefe23abb 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -48,7 +48,7 @@ Gitlab::Application.routes.draw do # # 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 00000000000..288d0f07c9a --- /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 00000000000..ef02e489d03 --- /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 00000000000..6d03777901c --- /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 00000000000..71763d18aee --- /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 0614a5c0064..9fa96203ffd 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 5e7477d84e1..ebb7ae585e6 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 78096666393..1978ea89153 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/20130220124204_add_new_merge_status_to_merge_request.rb b/db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb new file mode 100644 index 00000000000..d78bd0ae923 --- /dev/null +++ b/db/migrate/20130220124204_add_new_merge_status_to_merge_request.rb @@ -0,0 +1,5 @@ +class AddNewMergeStatusToMergeRequest < ActiveRecord::Migration + def change + add_column :merge_requests, :new_merge_status, :string + end +end diff --git a/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb b/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb new file mode 100644 index 00000000000..b310b35e373 --- /dev/null +++ b/db/migrate/20130220125544_convert_merge_status_in_merge_request.rb @@ -0,0 +1,17 @@ +class ConvertMergeStatusInMergeRequest < ActiveRecord::Migration + def up + MergeRequest.transaction do + MergeRequest.where(merge_status: 1).update_all("new_merge_status = 'unchecked'") + MergeRequest.where(merge_status: 2).update_all("new_merge_status = 'can_be_merged'") + MergeRequest.where(merge_status: 3).update_all("new_merge_status = 'cannot_be_merged'") + end + end + + def down + MergeRequest.transaction do + MergeRequest.where(new_merge_status: :unchecked).update_all("merge_status = 1") + MergeRequest.where(new_merge_status: :can_be_merged).update_all("merge_status = 2") + MergeRequest.where(new_merge_status: :cannot_be_merged).update_all("merge_status = 3") + end + end +end diff --git a/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb b/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb new file mode 100644 index 00000000000..9083183beb0 --- /dev/null +++ b/db/migrate/20130220125545_remove_merge_status_from_merge_request.rb @@ -0,0 +1,9 @@ +class RemoveMergeStatusFromMergeRequest < ActiveRecord::Migration + def up + remove_column :merge_requests, :merge_status + end + + def down + add_column :merge_requests, :merge_status, :integer + end +end diff --git a/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb b/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb new file mode 100644 index 00000000000..3f8f38dc979 --- /dev/null +++ b/db/migrate/20130220133245_rename_new_merge_status_to_merge_status_in_milestone.rb @@ -0,0 +1,5 @@ +class RenameNewMergeStatusToMergeStatusInMilestone < ActiveRecord::Migration + def change + rename_column :merge_requests, :new_merge_status, :merge_status + end +end diff --git a/db/schema.rb b/db/schema.rb index f837e6edf98..04ed7984619 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 => 20130218141554) do +ActiveRecord::Schema.define(:version => 20130220133245) do create_table "events", :force => true do |t| t.string "target_type" @@ -68,19 +68,19 @@ ActiveRecord::Schema.define(:version => 20130218141554) do add_index "keys", ["user_id"], :name => "index_keys_on_user_id" create_table "merge_requests", :force => true do |t| - t.string "target_branch", :null => false - t.string "source_branch", :null => false - t.integer "project_id", :null => false + t.string "target_branch", :null => false + t.string "source_branch", :null => false + t.integer "project_id", :null => false t.integer "author_id" t.integer "assignee_id" t.string "title" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.text "st_commits", :limit => 2147483647 t.text "st_diffs", :limit => 2147483647 - t.integer "merge_status", :default => 1, :null => false t.integer "milestone_id" t.string "state" + t.string "merge_status" end add_index "merge_requests", ["assignee_id"], :name => "index_merge_requests_on_assignee_id" @@ -106,12 +106,13 @@ ActiveRecord::Schema.define(:version => 20130218141554) do add_index "milestones", ["project_id"], :name => "index_milestones_on_project_id" create_table "namespaces", :force => true do |t| - t.string "name", :null => false - t.string "path", :null => false - t.integer "owner_id", :null => false - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.string "name", :null => false + t.string "path", :null => false + t.integer "owner_id", :null => false + 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" @@ -142,16 +143,18 @@ ActiveRecord::Schema.define(:version => 20130218141554) do t.string "name" t.string "path" t.text "description" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false t.integer "creator_id" t.string "default_branch" - t.boolean "issues_enabled", :default => true, :null => false - t.boolean "wall_enabled", :default => true, :null => false - t.boolean "merge_requests_enabled", :default => true, :null => false - t.boolean "wiki_enabled", :default => true, :null => false + t.boolean "issues_enabled", :default => true, :null => false + t.boolean "wall_enabled", :default => true, :null => false + t.boolean "merge_requests_enabled", :default => true, :null => false + t.boolean "wiki_enabled", :default => true, :null => false t.integer "namespace_id" - t.boolean "public", :default => false, :null => false + t.boolean "public", :default => false, :null => false + t.string "issues_tracker", :default => "gitlab", :null => false + t.string "issues_tracker_id" end add_index "projects", ["creator_id"], :name => "index_projects_on_owner_id" @@ -230,8 +233,9 @@ ActiveRecord::Schema.define(:version => 20130218141554) do t.string "name" t.string "path" t.integer "owner_id" - t.datetime "created_at", :null => false - t.datetime "updated_at", :null => false + 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| diff --git a/doc/install/installation.md b/doc/install/installation.md index 4d2ab63b2e9..d0f586af6b4 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/steps/admin/admin_groups.rb b/features/steps/admin/admin_groups.rb index cbca2daa701..167763b6912 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 637fc4e58f3..6423f3dfd9b 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 5cfa4756ac3..5ac958e3fc2 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 ff95a47d4cf..4c22119b07e 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/userteams/userteams.rb b/features/steps/userteams/userteams.rb index 1abb0f49122..862259dcb4e 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 da40b38b79c..2fd7ffdb813 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -34,6 +34,7 @@ Spinach.hooks.before_scenario do 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 9255e0daadb..f7774597dc3 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.rb b/lib/api.rb index d9dce7c70cc..da31a1519dd 100644 --- a/lib/api.rb +++ b/lib/api.rb @@ -9,7 +9,6 @@ module Gitlab end format :json - error_format :json helpers APIHelpers mount Groups diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 5d74a761c05..d4f72d70d92 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -5,6 +5,12 @@ module Gitlab # # Check if ssh key has access to project code # + # Params: + # key_id - SSH Key id + # project - project path with namespace + # action - git action (git-upload-pack or git-receive-pack) + # ref - branch name + # get "/allowed" do key = Key.find(params[:key_id]) project = Project.find_with_namespace(params[:project]) diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 631ed535459..8f57e5ac79f 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -42,7 +42,8 @@ module Gitlab :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 @@ -292,7 +293,7 @@ module Gitlab authorize! :download_code, user_project page = params[:page] || 0 - per_page = params[:per_page] || 20 + per_page = (params[:per_page] || 20).to_i ref = params[:ref_name] || user_project.try(:default_branch) || 'master' commits = user_project.repository.commits(ref, nil, per_page, page * per_page) diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index fb595e18b24..fd0050cfd5f 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -126,7 +126,7 @@ module ExtractsPath @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/markdown.rb b/lib/gitlab/markdown.rb index e7d6e3e6bd9..280f9f9730a 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 @@ module Gitlab 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 cf99951e027..d0e9dfe46a1 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 b81984b5d53..41766859468 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -29,6 +29,11 @@ FactoryGirl.define do 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 1a9ae8e885c..8d1ee11ee75 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 77d6e9e3795..22d1ee91480 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -55,8 +55,8 @@ describe "Admin::Users" do 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 @@ describe "Admin::Users" do 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 1b067972c81..1f5fabfbb8e 100644 --- a/spec/helpers/gitlab_markdown_helper_spec.rb +++ b/spec/helpers/gitlab_markdown_helper_spec.rb @@ -2,6 +2,7 @@ require "spec_helper" 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 00000000000..c9eb6591561 --- /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/lib/popen_spec.rb b/spec/lib/popen_spec.rb new file mode 100644 index 00000000000..4791be41613 --- /dev/null +++ b/spec/lib/popen_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'Gitlab::Popen', no_db: true do + let (:path) { Rails.root.join('tmp').to_s } + + before do + @klass = Class.new(Object) + @klass.send(:include, Gitlab::Popen) + end + + context 'zero status' do + before do + @output, @status = @klass.new.popen('ls', path) + end + + it { @status.should be_zero } + it { @output.should include('cache') } + end + + context 'non-zero status' do + before do + @output, @status = @klass.new.popen('cat NOTHING', path) + end + + it { @status.should == 1 } + it { @output.should include('No such file or directory') } + end +end + diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index e61bf44ce53..dbae019e7d8 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -32,6 +32,12 @@ describe MergeRequest do it { should_not allow_mass_assignment_of(:project_id) } end + describe "Respond to" do + it { should respond_to(:unchecked?) } + it { should respond_to(:can_be_merged?) } + it { should respond_to(:cannot_be_merged?) } + end + describe 'modules' do it { should include_module(Issuable) } end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 48432eac147..44f4cd4a737 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -60,6 +60,7 @@ describe Project do 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 @@ describe Project do 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/project_team_spec.rb b/spec/models/project_team_spec.rb index 7803811f395..3e3543e85e1 100644 --- a/spec/models/project_team_spec.rb +++ b/spec/models/project_team_spec.rb @@ -10,9 +10,6 @@ describe ProjectTeam do it { should respond_to(:masters) } it { should respond_to(:reporters) } it { should respond_to(:guests) } - it { should respond_to(:repository_writers) } - it { should respond_to(:repository_masters) } - it { should respond_to(:repository_readers) } end end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 8ab0a0343bb..40047b351da 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -69,28 +69,10 @@ describe User do describe "Respond to" do it { should respond_to(:is_admin?) } - it { should respond_to(:identifier) } it { should respond_to(:name) } it { should respond_to(:private_token) } end - describe '#identifier' do - it "should return valid identifier" do - user = build(:user, email: "test@mail.com") - user.identifier.should == "test_mail_com" - end - - it "should return identifier without + sign" do - user = build(:user, email: "test+foo@mail.com") - user.identifier.should == "test_foo_mail_com" - end - - it "should conform to Gitolite's required identifier pattern" do - user = build(:user, email: "_test@example.com") - user.identifier.should == 'test_example_com' - end - end - describe '#generate_password' do it "should execute callback when force_random_password specified" do user = build(:user, force_random_password: true) diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb new file mode 100644 index 00000000000..d63429df1b0 --- /dev/null +++ b/spec/requests/api/internal_spec.rb @@ -0,0 +1,103 @@ +require 'spec_helper' + +describe Gitlab::API do + include ApiHelpers + + let(:user) { create(:user) } + let(:key) { create(:key, user: user) } + let(:project) { create(:project) } + + describe "GET /internal/check", no_db: true do + it do + get api("/internal/check") + + response.status.should == 200 + json_response['api_version'].should == Gitlab::API.version + end + end + + describe "GET /internal/discover" do + it do + get(api("/internal/discover"), key_id: key.id) + + response.status.should == 200 + + json_response['email'].should == user.email + end + end + + describe "GET /internal/allowed" do + context "access granted" do + before do + project.team << [user, :developer] + end + + context "git pull" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-upload-pack' + ) + + response.status.should == 200 + response.body.should == 'true' + end + end + + context "git push" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-receive-pack' + ) + + response.status.should == 200 + response.body.should == 'true' + end + end + end + + context "access denied" do + before do + project.team << [user, :guest] + end + + context "git pull" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-upload-pack' + ) + + response.status.should == 200 + response.body.should == 'false' + end + end + + context "git push" do + it do + get( + api("/internal/allowed"), + ref: 'master', + key_id: key.id, + project: project.path_with_namespace, + action: 'git-receive-pack' + ) + + response.status.should == 200 + response.body.should == 'false' + end + end + end + + end +end diff --git a/spec/support/db_cleaner.rb b/spec/support/db_cleaner.rb index f1e072aa15f..8c9c74f14bd 100644 --- a/spec/support/db_cleaner.rb +++ b/spec/support/db_cleaner.rb @@ -9,10 +9,14 @@ RSpec.configure do |config| DatabaseCleaner.strategy = :transaction end - DatabaseCleaner.start + unless example.metadata[:no_db] + DatabaseCleaner.start + end end config.after do - DatabaseCleaner.clean + unless example.metadata[:no_db] + DatabaseCleaner.clean + end end end |
