diff options
172 files changed, 2033 insertions, 1623 deletions
diff --git a/CHANGELOG b/CHANGELOG index d4deb97099e..f01b5e87c5e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,15 @@ +v 5.2.0 + - Turbolinks + - Git over http with ldap credentials + - Diff with better colors and some spacing on the corners + - Default values for project features + - Fixed huge_commit view + - Restyle project clone panel + - Move Gitlab::Git code to gitlab_git gem + - Move update docs in repo + - requires gitlab-shell v1.4.0 + - fixed submodules listing under file tab + v 5.1.0 - You can login with email or username now - Corrected project transfer rollback when repository cannot be moved @@ -11,7 +23,16 @@ v 5.1.0 - Restyled Issues list. Show milestone version in issue row - Restyled Merge Request list - Backup now dump/restore uploads - - Improved perfomance of dashboard + - Improved perfomance of dashboard (Andrew Kumanyaev) + - File history now tracks renames (Akzhan Abdulin) + - Drop wiki migration tools + - Drop sqlite migration tools + - project tagging + - Paginate users in API + - Restyled network graph (Hiroyuki Sato) + +v 5.0.1 + - Fixed issue with gitlab-grit being overrided by grit v 5.0.0 - Replaced gitolite with gitlab-shell diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f322a81ca5a..79e57558084 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,31 @@ # Contribute to GitLab -This guide details how to use pull requests and the issues to improve GitLab. +This guide details how to use issues and pull requests to improve GitLab. -## Closing policy for pull requests and issues +## Closing policy for issues and pull requests -Pull requests and issues not in line with the guidelines listed in this document will be closed with just a link to this paragraph. GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. To get support for your problems please use other channels as detailed in [the getting help section of the readme](https://github.com/gitlabhq/gitlabhq#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/). +Issues and pull requests not in line with the guidelines listed in this document will be closed with just a link to this paragraph. GitLab is a popular open source project and the capacity to deal with issues and pull requests is limited. To get support for your problems please use other channels as detailed in [the getting help section of the readme](https://github.com/gitlabhq/gitlabhq#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/). + +## Issue tracker + +The [issue tracker](https://github.com/gitlabhq/gitlabhq/issues) is only for obvious bugs or misbehavior in the master branch of GitLab. When submitting an issue please conform to the issue submission guidelines listed below. + +Do not use the issue tracker for feature requests. We have a specific +[Feedback and suggestions forum](http://feedback.gitlab.com) for this purpose. + +Please send a pull request with a tested solution or a pull request with a failing test instead of opening an issue if you can. If you're unsure where to post, post 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. + +### Issue tracker guidelines + +**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. + +* Summarize your issue in one sentence (what goes wrong, what did you expect to happen) +* Describe your issue in detail +* How can we reproduce the issue on the [GitLab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) (start with: vagrant destroy && vagrant up && vagrant ssh) +* Add the last commit sha1 of the GitLab version you used to replicate the issue +* Add logs or screen shots when possible +* Link to the line of code that might be responsible for the problem +* Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`) ## Pull requests @@ -33,21 +54,3 @@ We will accept pull requests if: * 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). - -## Issue tracker - -The [issue tracker](https://github.com/gitlabhq/gitlabhq/issues) is only for obvious bugs or misbehavior in the master branch of GitLab. When submitting an issue please conform to the issue submission guidelines listed below. - -Please send a pull request with a tested solution or a pull request with a failing test instead of opening an issue if you can. If you're unsure where to post, post 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. - -### Issue tracker guidelines - -**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. - -* Summarize your issue in one sentence (what goes wrong, what did you expect to happen) -* Describe your issue in detail -* How can we reproduce the issue on the [GitLab Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) (start with: vagrant destroy && vagrant up && vagrant ssh) -* Add the last commit sha1 of the GitLab version you used to replicate the issue -* Add logs or screen shots when possible -* Link to the line of code that might be responsible for the problem -* Describe your setup (use relevant parts from `sudo -u gitlab -H bundle exec rake gitlab:env:info`) @@ -22,9 +22,9 @@ gem 'omniauth-twitter' gem 'omniauth-github' # Extracting information from a git repository -# Since gollum requires grit we cannot use gitlab-grit gem name any more. Use grit instead +# We cannot use original git since some bugs gem "grit", '~> 2.5.0', git: 'https://github.com/gitlabhq/grit.git', ref: '42297cdcee16284d2e4eff23d41377f52fc28b9d' -gem 'grit_ext', '~> 0.8.1' +gem 'gitlab_git', '~> 1.0.6' # Ruby/Rack Git Smart-HTTP Server Handler gem 'gitlab-grack', '~> 1.0.0', require: 'grack' @@ -36,11 +36,11 @@ gem 'gitlab_omniauth-ldap', '1.0.2', require: "omniauth-ldap" gem "gitlab-pygments.rb", '~> 0.3.2', require: 'pygments.rb' # Language detection -gem "github-linguist", "~> 2.3.4" , require: "linguist" +gem "github-linguist", require: "linguist" # API -gem "grape", "~> 0.3.1" -gem "grape-entity", "~> 0.2.0" +gem "grape" +gem "grape-entity" # Format dates and times # based on human-friendly examples @@ -57,6 +57,8 @@ gem "haml-rails" # Files attachments gem "carrierwave" +# for aws storage +# gem "fog", "~> 1.3.1" # Authorization gem "six" @@ -69,13 +71,13 @@ gem "redcarpet", "~> 2.2.2" gem "github-markup", "~> 0.7.4", require: 'github/markup' # Servers -gem "puma", '~> 2.0.0.b7' +gem "puma", '~> 2.0.1' # State machine gem "state_machine" # Issue tags -gem "acts-as-taggable-on", "2.3.3" +gem "acts-as-taggable-on" # Background jobs gem 'slim' @@ -101,10 +103,12 @@ gem "foreman" gem "redis-rails" group :assets do - gem "sass-rails", "~> 3.2.5" - gem "coffee-rails", "~> 3.2.2" - gem "uglifier", "~> 1.3.0" + gem "sass-rails" + gem "coffee-rails" + gem "uglifier" gem "therubyracer" + gem 'turbolinks' + gem 'jquery-turbolinks' gem 'chosen-rails', "0.9.8" gem 'select2-rails' diff --git a/Gemfile.lock b/Gemfile.lock index c8d75f9dc89..c06a1bd09cc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/ctran/annotate_models.git - revision: be4e26825b521f0b2d86b181e2dff89901aa9b1e + revision: 8bd159c7a484093fde84beaa9e6398f25ddacf09 specs: annotate (2.6.0.beta1) activerecord (>= 2.3.0) @@ -62,16 +62,16 @@ GEM activesupport (3.2.13) i18n (= 0.6.1) multi_json (~> 1.0) - acts-as-taggable-on (2.3.3) + acts-as-taggable-on (2.4.0) rails (~> 3.0) - addressable (2.3.2) + addressable (2.3.4) arel (3.0.2) awesome_print (1.1.0) backports (2.6.7) bcrypt-ruby (3.0.1) - better_errors (0.3.2) + better_errors (0.8.0) coderay (>= 1.0.0) - erubis (>= 2.7.0) + erubis (>= 2.6.6) binding_of_caller (0.7.1) debug_inspector (>= 0.0.1) bootstrap-sass (2.2.1.1) @@ -86,10 +86,9 @@ GEM carrierwave (0.8.0) activemodel (>= 3.2.0) activesupport (>= 3.2.0) - celluloid (0.12.4) - facter (>= 1.6.12) + celluloid (0.13.0) timers (>= 1.0.0) - charlock_holmes (0.6.9) + charlock_holmes (0.6.9.4) chosen-rails (0.9.8) railties (~> 3.0) thor (~> 0.14) @@ -102,11 +101,11 @@ GEM coffee-script (2.2.0) coffee-script-source execjs - coffee-script-source (1.4.0) + coffee-script-source (1.6.2) colored (1.2) colorize (0.5.8) connection_pool (1.0.0) - coveralls (0.6.2) + coveralls (0.6.7) colorize multi_json (~> 1.3) rest-client @@ -122,7 +121,8 @@ GEM orm_adapter (~> 0.1) railties (~> 3.1) warden (~> 1.2.1) - diff-lcs (1.2.1) + diff-lcs (1.2.4) + dotenv (0.7.0) email_spec (1.4.0) launchy (~> 2.1) mail (~> 2.2) @@ -130,28 +130,29 @@ GEM activesupport (>= 3.2) erubis (2.7.0) escape_utils (0.2.4) - eventmachine (1.0.0) + eventmachine (1.0.3) execjs (1.4.0) multi_json (~> 1.0) - facter (1.6.18) - factory_girl (4.1.0) + factory_girl (4.2.0) activesupport (>= 3.0.0) - factory_girl_rails (4.1.0) - factory_girl (~> 4.1.0) + factory_girl_rails (4.2.1) + factory_girl (~> 4.2.0) railties (>= 3.0.0) - faraday (0.8.6) + faraday (0.8.7) multipart-post (~> 1.1) faye-websocket (0.4.7) eventmachine (>= 0.12.0) - ffaker (1.15.0) - ffi (1.6.0) + ffaker (1.16.0) + ffi (1.8.1) font-awesome-sass-rails (3.0.2.2) railties (>= 3.1.1) sass-rails (>= 3.1.1) - foreman (0.62.0) + foreman (0.63.0) + dotenv (>= 0.7) thor (>= 0.13.6) + formatador (0.2.4) gemoji (1.2.1) - gherkin-ruby (0.2.1) + gherkin-ruby (0.3.0) github-linguist (2.3.4) charlock_holmes (~> 0.6.6) escape_utils (~> 0.2.3) @@ -164,6 +165,11 @@ GEM gitlab-pygments.rb (0.3.2) posix-spawn (~> 0.3.6) yajl-ruby (~> 1.1.0) + gitlab_git (1.0.6) + activesupport (~> 3.2.13) + github-linguist (~> 2.3.4) + grit (~> 2.5.0) + grit_ext (~> 0.8.1) gitlab_meta (5.0) gitlab_omniauth-ldap (1.0.2) net-ldap (~> 0.2.2) @@ -178,46 +184,48 @@ GEM pygments.rb (~> 0.4.2) sanitize (~> 2.0.3) stringex (~> 1.5.1) - gon (4.0.2) - grape (0.3.2) + gon (4.1.0) + actionpack (>= 2.3.0) + json + grape (0.4.1) activesupport builder hashie (>= 1.2.0) multi_json (>= 1.3.2) multi_xml (>= 0.5.2) - rack + rack (>= 1.3.0) rack-accept rack-mount virtus - grape-entity (0.2.0) + grape-entity (0.3.0) activesupport multi_json (>= 1.3.2) grit_ext (0.8.1) charlock_holmes (~> 0.6.9) growl (1.0.3) - guard (1.6.2) - listen (>= 0.6.0) + guard (1.8.0) + formatador (>= 0.2.4) + listen (>= 1.0.0) lumberjack (>= 1.0.2) pry (>= 0.9.10) - terminal-table (>= 1.4.3) thor (>= 0.14.6) - guard-rspec (2.5.1) - guard (>= 1.1) - rspec (~> 2.11) + guard-rspec (2.6.0) + guard (>= 1.8) + rspec (~> 2.13) guard-spinach (0.0.2) guard (>= 1.1) spinach - haml (4.0.0) + haml (4.0.2) tilt haml-rails (0.4) actionpack (>= 3.1, < 4.1) activesupport (>= 3.1, < 4.1) haml (>= 3.1, < 4.1) railties (>= 3.1, < 4.1) - hashie (1.2.0) + hashie (2.0.4) hike (1.2.2) http_parser.rb (0.5.3) - httparty (0.10.2) + httparty (0.11.0) multi_json (~> 1.0) multi_xml (>= 0.5.2) httpauth (0.2.0) @@ -227,33 +235,39 @@ GEM jquery-rails (2.1.3) railties (>= 3.1.0, < 5.0) thor (~> 0.14) + jquery-turbolinks (1.0.0) + railties (>= 3.1.0) + turbolinks jquery-ui-rails (2.0.2) jquery-rails railties (>= 3.1.0) json (1.7.7) - jwt (0.1.5) - multi_json (>= 1.0) + jwt (0.1.8) + multi_json (>= 1.5) kaminari (0.14.1) actionpack (>= 3.0.0) activesupport (>= 3.0.0) - launchy (2.1.2) + launchy (2.2.0) addressable (~> 2.3) - letter_opener (1.0.0) - launchy (>= 2.0.4) + letter_opener (1.1.0) + launchy (~> 2.2.0) libv8 (3.11.8.17) - listen (0.7.3) + listen (1.0.3) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + rb-kqueue (>= 0.2) lumberjack (1.0.3) mail (2.5.3) i18n (>= 0.4.0) mime-types (~> 1.16) treetop (~> 1.4.8) method_source (0.8.1) - mime-types (1.22) + mime-types (1.23) modernizr (2.6.2) sprockets (~> 2.0) multi_json (1.7.2) multi_xml (0.5.3) - multipart-post (1.1.5) + multipart-post (1.2.0) mysql2 (0.3.11) net-ldap (0.2.2) nokogiri (1.5.9) @@ -264,13 +278,13 @@ GEM jwt (~> 0.1.4) multi_json (~> 1.0) rack (~> 1.2) - omniauth (1.1.3) - hashie (~> 1.2) + omniauth (1.1.4) + hashie (>= 1.2, < 3) rack omniauth-github (1.1.0) omniauth (~> 1.0) omniauth-oauth2 (~> 1.1) - omniauth-google-oauth2 (0.1.13) + omniauth-google-oauth2 (0.1.17) omniauth (~> 1.0) omniauth-oauth2 omniauth-oauth (1.0.1) @@ -279,31 +293,31 @@ GEM omniauth-oauth2 (1.1.1) oauth2 (~> 0.8.0) omniauth (~> 1.0) - omniauth-twitter (0.0.14) + omniauth-twitter (0.0.16) multi_json (~> 1.3) omniauth-oauth (~> 1.0) orm_adapter (0.4.0) - pg (0.14.1) + pg (0.15.1) polyglot (0.3.3) posix-spawn (0.3.6) - pry (0.9.12) + pry (0.9.12.1) coderay (~> 1.0.5) method_source (~> 0.8) slop (~> 3.4) - puma (2.0.0.b7) + puma (2.0.1) rack (>= 1.1, < 2.0) 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) + quiet_assets (1.0.2) + railties (>= 3.1, < 5.0) rack (1.4.5) rack-accept (0.4.5) rack (>= 0.4) rack-cache (1.2) rack (>= 0.4) - rack-mini-profiler (0.1.23) + rack-mini-profiler (0.1.26) rack (>= 1.1.3) rack-mount (0.8.3) rack (>= 1.0.0) @@ -340,13 +354,15 @@ GEM rdoc (~> 3.4) thor (>= 0.14.6, < 2.0) rake (10.0.4) - rb-fsevent (0.9.2) - rb-inotify (0.8.8) + rb-fsevent (0.9.3) + rb-inotify (0.9.0) + ffi (>= 0.5.0) + rb-kqueue (0.2.0) ffi (>= 0.5.0) rdoc (3.12.2) json (~> 1.4) redcarpet (2.2.2) - redis (3.0.3) + redis (3.0.4) redis-actionpack (3.2.3) actionpack (~> 3.2.3) redis-rack (~> 1.4.0) @@ -375,8 +391,8 @@ GEM rspec-core (2.13.1) rspec-expectations (2.13.0) diff-lcs (>= 1.1.3, < 2.0) - rspec-mocks (2.13.0) - rspec-rails (2.13.0) + rspec-mocks (2.13.1) + rspec-rails (2.13.1) actionpack (>= 3.0) activesupport (>= 3.0) railties (>= 3.0) @@ -387,7 +403,7 @@ GEM rubyntlm (0.1.1) sanitize (2.0.3) nokogiri (>= 1.4.4, < 1.6) - sass (3.2.7) + sass (3.2.8) sass-rails (3.2.6) railties (~> 3.2.0) sass (>= 3.1.10) @@ -402,11 +418,11 @@ GEM sass-rails (>= 3.2) thor (~> 0.14) settingslogic (2.0.9) - sexp_processor (4.2.0) + sexp_processor (4.2.1) shoulda-matchers (1.3.0) activesupport (>= 3.0.0) - sidekiq (2.9.0) - celluloid (~> 0.12.0) + sidekiq (2.11.1) + celluloid (~> 0.13.0) connection_pool (~> 1.0) multi_json (~> 1) redis (~> 3) @@ -420,15 +436,15 @@ GEM rack-protection (~> 1.3) tilt (~> 1.3, >= 1.3.3) six (0.2.0) - slim (1.3.6) - temple (~> 0.5.5) + slim (1.3.8) + temple (~> 0.6.3) tilt (~> 1.3.3) slop (3.4.4) - spinach (0.8.1) + spinach (0.8.2) colorize (= 0.5.8) - gherkin-ruby (~> 0.2.1) - spinach-rails (0.1.7) - capybara (>= 1.0) + gherkin-ruby (~> 0.3.0) + spinach-rails (0.2.1) + capybara (>= 2.0.0) railties (>= 3) spinach (>= 0.4) spork (1.0.0rc3) @@ -438,15 +454,14 @@ GEM rack (~> 1.0) tilt (~> 1.1, != 1.3.0) stamp (0.5.0) - state_machine (1.1.2) + state_machine (1.2.0) stringex (1.5.1) - temple (0.5.5) - terminal-table (1.4.5) - test_after_commit (0.0.1) + temple (0.6.4) + test_after_commit (0.2.0) therubyracer (0.11.4) libv8 (~> 3.11.8.12) ref - thin (1.5.0) + thin (1.5.1) daemons (>= 1.0.9) eventmachine (>= 0.12.6) rack (>= 1.0.0) @@ -456,8 +471,10 @@ GEM treetop (1.4.12) polyglot polyglot (>= 0.3.1) + turbolinks (1.1.1) + coffee-rails tzinfo (0.3.37) - uglifier (1.3.0) + uglifier (2.0.1) execjs (>= 0.3.0) multi_json (~> 1.0, >= 1.0.2) virtus (0.5.4) @@ -465,9 +482,9 @@ GEM descendants_tracker (~> 0.0.1) warden (1.2.1) rack (>= 1.0) - webmock (1.9.0) + webmock (1.11.0) addressable (>= 2.2.7) - crack (>= 0.1.7) + crack (>= 0.3.2) xpath (2.0.0) nokogiri (~> 1.3) yajl-ruby (1.1.0) @@ -476,7 +493,7 @@ PLATFORMS ruby DEPENDENCIES - acts-as-taggable-on (= 2.3.3) + acts-as-taggable-on annotate! awesome_print better_errors @@ -485,7 +502,7 @@ DEPENDENCIES capybara carrierwave chosen-rails (= 0.9.8) - coffee-rails (~> 3.2.2) + coffee-rails colored coveralls database_cleaner @@ -497,18 +514,18 @@ DEPENDENCIES font-awesome-sass-rails (~> 3.0.0) foreman gemoji (~> 1.2.1) - github-linguist (~> 2.3.4) + github-linguist github-markup (~> 0.7.4) gitlab-grack (~> 1.0.0) gitlab-pygments.rb (~> 0.3.2) + gitlab_git (~> 1.0.6) gitlab_meta (= 5.0) gitlab_omniauth-ldap (= 1.0.2) gollum-lib (~> 1.0.0) gon - grape (~> 0.3.1) - grape-entity (~> 0.2.0) + grape + grape-entity grit (~> 2.5.0)! - grit_ext (~> 0.8.1) growl guard-rspec guard-spinach @@ -516,6 +533,7 @@ DEPENDENCIES httparty jquery-atwho-rails (= 0.1.7) jquery-rails (= 2.1.3) + jquery-turbolinks jquery-ui-rails (= 2.0.2) kaminari (~> 0.14.1) launchy @@ -529,7 +547,7 @@ DEPENDENCIES pg poltergeist! pry - puma (~> 2.0.0.b7) + puma (~> 2.0.1) quiet_assets (~> 1.0.1) rack-mini-profiler rails (= 3.2.13) @@ -541,7 +559,7 @@ DEPENDENCIES redcarpet (~> 2.2.2) redis-rails rspec-rails - sass-rails (~> 3.2.5) + sass-rails sdoc seed-fu select2-rails @@ -559,5 +577,6 @@ DEPENDENCIES test_after_commit therubyracer thin - uglifier (~> 1.3.0) + turbolinks + uglifier webmock diff --git a/README.md b/README.md index fa9cf817469..f3af521a779 100644 --- a/README.md +++ b/README.md @@ -49,18 +49,14 @@ #### Official production installation -Follow the installation guide for production server. - -* [Installation guide for latest stable release (5.0)](https://github.com/gitlabhq/gitlabhq/blob/5-0-stable/doc/install/installation.md) - **Recommended** - -* [Installation guide for the current master branch (5.1)](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) +* [Installation guide for a production server](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) #### Official development installation If you want to contribute, please first read our [Contributing Guidelines](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) and then we suggest you to use the Vagrant virtual machine project to get an environment working with all dependencies. -* [Vagrant virtual machine](https://github.com/gitlabhq/gitlab-vagrant-vm) +* [Vagrant virtual machine for development](https://github.com/gitlabhq/gitlab-vagrant-vm) #### Unsupported production installation @@ -78,7 +74,7 @@ If you want to contribute, please first read our [Contributing Guidelines](https Each month on the 22th a new version is released together with an upgrade guide. -* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/wiki) +* [Upgrade guides](https://github.com/gitlabhq/gitlabhq/tree/master/doc/update) * [Changelog](https://github.com/gitlabhq/gitlabhq/blob/master/CHANGELOG) @@ -143,13 +139,13 @@ Start it with [Foreman](https://github.com/ddollar/foreman) * [Support forum](https://groups.google.com/forum/#!forum/gitlabhq) is the best place to ask questions. For example you can use it if you have questions about: permission denied errors, invisible repos, can't clone/pull/push or with web hooks that don't fire. Please search for similar issues before posting your own, there's a good chance somebody else had the same issue you have now and had it resolved. There are a lot of helpful GitLab users there who may be able to help you quickly. If your particular issue turns out to be a bug, it will find its way from there to a fix. -* [Feedback and suggestions forum](http://gitlab.uservoice.com/forums/176466-general) is the place to propose and discuss new features for GitLab. +* [Feedback and suggestions forum](http://feedback.gitlab.com) is the place to propose and discuss new features for GitLab. * [Support subscription](http://www.gitlab.com/subscription/) connect you to the knowledge of GitLab experts that will resolve your issues and answer your questions. -* [Consultancy](http://www.gitlab.com/consultancy/) allows you hire GitLab exports for installations, upgrades and customizations. +* [Consultancy](http://www.gitlab.com/consultancy/) allows you hire GitLab experts for installations, upgrades and customizations. -* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed without comment. +* [Contributing guide](https://github.com/gitlabhq/gitlabhq/blob/master/CONTRIBUTING.md) describes how to submit pull requests and issues. Pull requests and issues not in line with the guidelines in this document will be closed. ### Getting in touch @@ -1 +1 @@ -5.1.0pre +5.2.0.pre diff --git a/app/assets/images/monokai.png b/app/assets/images/monokai.png Binary files differnew file mode 100644 index 00000000000..9477941778e --- /dev/null +++ b/app/assets/images/monokai.png diff --git a/app/assets/javascripts/admin.js.coffee b/app/assets/javascripts/admin.js.coffee index 1dafdf4bd8b..c83b74a76a2 100644 --- a/app/assets/javascripts/admin.js.coffee +++ b/app/assets/javascripts/admin.js.coffee @@ -1,17 +1,30 @@ -$ -> - $('input#user_force_random_password').on 'change', (elem) -> - elems = $('#user_password, #user_password_confirmation') +class Admin + constructor: -> + $('input#user_force_random_password').on 'change', (elem) -> + elems = $('#user_password, #user_password_confirmation') - if $(@).attr 'checked' - elems.val('').attr 'disabled', true - else - elems.removeAttr 'disabled' + if $(@).attr 'checked' + elems.val('').attr 'disabled', true + else + elems.removeAttr 'disabled' - $('.log-tabs a').click (e) -> - e.preventDefault() - $(this).tab('show') + $('.log-tabs a').click (e) -> + e.preventDefault() + $(this).tab('show') - $('.log-bottom').click (e) -> - e.preventDefault() - visible_log = $(".file_content:visible") - visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast") + $('.log-bottom').click (e) -> + e.preventDefault() + visible_log = $(".file_content:visible") + visible_log.animate({ scrollTop: visible_log.find('ol').height() }, "fast") + + modal = $('.change-owner-holder') + + $('.change-owner-link').bind "click", -> + $(this).hide() + modal.show() + + $('.change-owner-cancel-link').bind "click", -> + modal.hide() + $('.change-owner-link').show() + +@Admin = Admin diff --git a/app/assets/javascripts/api.js.coffee b/app/assets/javascripts/api.js.coffee index ca721517867..7cac971f247 100644 --- a/app/assets/javascripts/api.js.coffee +++ b/app/assets/javascripts/api.js.coffee @@ -50,4 +50,5 @@ callback(users) buildUrl: (url) -> + url = gon.relative_url_root + url if gon.relative_url_root.present? return url.replace(':version', gon.api_version) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index adb4009fbc2..bbec12ad08c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -14,6 +14,8 @@ //= require jquery.waitforimages //= require jquery.atwho //= require jquery.scrollto +//= require turbolinks +//= require jquery.turbolinks //= require bootstrap //= require modernizr //= require chosen-jquery diff --git a/app/assets/javascripts/branch-graph.js.coffee b/app/assets/javascripts/branch-graph.js.coffee index 2a668de278a..c12e672d666 100644 --- a/app/assets/javascripts/branch-graph.js.coffee +++ b/app/assets/javascripts/branch-graph.js.coffee @@ -9,6 +9,7 @@ class BranchGraph @offsetY = 20 @unitTime = 30 @unitSpace = 10 + @prev_start = -1 @load() load: -> @@ -24,10 +25,18 @@ class BranchGraph prepareData: (@days, @commits) -> @collectParents() + @graphHeight = $(@element).height() + @graphWidth = $(@element).width() + ch = Math.max(@graphHeight, @offsetY + @unitTime * @mtime + 150) + cw = Math.max(@graphWidth, @offsetX + @unitSpace * @mspace + 300) + @r = Raphael(@element.get(0), cw, ch) + @top = @r.set() + @barHeight = Math.max(@graphHeight, @unitTime * @days.length + 320) for c in @commits c.isParent = true if c.id of @parents @preparedCommits[c.id] = c + @markCommit(c) @collectColors() @@ -49,18 +58,12 @@ class BranchGraph k++ buildGraph: -> - graphHeight = $(@element).height() - graphWidth = $(@element).width() - ch = Math.max(graphHeight, @offsetY + @unitTime * @mtime + 150) - cw = Math.max(graphWidth, @offsetX + @unitSpace * @mspace + 300) - @r = r = Raphael(@element.get(0), cw, ch) - top = r.set() + r = @r cuday = 0 cumonth = "" - barHeight = Math.max(graphHeight, @unitTime * @days.length + 320) - r.rect(0, 0, 26, barHeight).attr fill: "#222" - r.rect(26, 0, 20, barHeight).attr fill: "#444" + r.rect(0, 0, 26, @barHeight).attr fill: "#222" + r.rect(26, 0, 20, @barHeight).attr fill: "#444" for day, mm in @days if cuday isnt day[0] @@ -81,42 +84,50 @@ class BranchGraph ) cumonth = day[1] - for commit in @commits - x = @offsetX + @unitSpace * (@mspace - commit.space) - y = @offsetY + @unitTime * commit.time + @renderPartialGraph() + + @bindEvents() - @drawDot(x, y, commit) + renderPartialGraph: -> + start = Math.floor((@element.scrollTop() - @offsetY) / @unitTime) - 10 + start = 0 if start < 0 + end = start + 40 + end = @commits.length if @commits.length < end - @drawLines(x, y, commit) + if @prev_start == -1 or Math.abs(@prev_start - start) > 10 + i = start - @appendLabel(x, y, commit.refs) if commit.refs + @prev_start = start - @appendAnchor(top, commit, x, y) + while i < end + commit = @commits[i] + i += 1 - @markCommit(x, y, commit, graphHeight) + if commit.hasDrawn isnt true + x = @offsetX + @unitSpace * (@mspace - commit.space) + y = @offsetY + @unitTime * commit.time - top.toFront() - @bindEvents() + @drawDot(x, y, commit) + + @drawLines(x, y, commit) + + @appendLabel(x, y, commit) + + @appendAnchor(x, y, commit) + + commit.hasDrawn = true + + @top.toFront() bindEvents: -> drag = {} element = @element - dragger = (event) -> - element.scrollLeft drag.sl - (event.clientX - drag.x) - element.scrollTop drag.st - (event.clientY - drag.y) - - element.on mousedown: (event) -> - drag = - x: event.clientX - y: event.clientY - st: element.scrollTop() - sl: element.scrollLeft() - $(window).on "mousemove", dragger + + $(element).scroll (event) => + @renderPartialGraph() $(window).on - mouseup: -> - $(window).off "mousemove", dragger - keydown: (event) -> + keydown: (event) => # left element.scrollLeft element.scrollLeft() - 50 if event.keyCode is 37 # top @@ -125,17 +136,20 @@ class BranchGraph element.scrollLeft element.scrollLeft() + 50 if event.keyCode is 39 # bottom element.scrollTop element.scrollTop() + 50 if event.keyCode is 40 + @renderPartialGraph() + + appendLabel: (x, y, commit) -> + return unless commit.refs - appendLabel: (x, y, refs) -> r = @r - shortrefs = refs + shortrefs = commit.refs # Truncate if longer than 15 chars shortrefs = shortrefs.substr(0, 15) + "…" if shortrefs.length > 17 text = r.text(x + 4, y, shortrefs).attr( "text-anchor": "start" font: "10px Monaco, monospace" fill: "#FFF" - title: refs + title: commit.refs ) textbox = text.getBBox() # Create rectangle based on the size of the textbox @@ -156,8 +170,9 @@ class BranchGraph # Set text to front text.toFront() - appendAnchor: (top, commit, x, y) -> + appendAnchor: (x, y, commit) -> r = @r + top = @top options = @options anchor = r.circle(x, y, 10).attr( fill: "#000" @@ -240,16 +255,18 @@ class BranchGraph stroke: color "stroke-width": 2) - markCommit: (x, y, commit, graphHeight) -> + markCommit: (commit) -> if commit.id is @options.commit_id r = @r + x = @offsetX + @unitSpace * (@mspace - commit.space) + y = @offsetY + @unitTime * commit.time r.path(["M", x + 5, y, "L", x + 15, y + 4, "L", x + 15, y - 4, "Z"]).attr( fill: "#000" "fill-opacity": .5 stroke: "none" ) # Displayed in the center - @element.scrollTop(y - graphHeight / 2) + @element.scrollTop(y - @graphHeight / 2) Raphael::commitTooltip = (x, y, commit) -> boxWidth = 300 diff --git a/app/assets/javascripts/commit.js.coffee b/app/assets/javascripts/commit.js.coffee new file mode 100644 index 00000000000..9f55a1e6368 --- /dev/null +++ b/app/assets/javascripts/commit.js.coffee @@ -0,0 +1,6 @@ +class Commit + constructor: -> + $('.files .file').each -> + new CommitFile(this) + +@Commit = Commit diff --git a/app/assets/javascripts/dashboard.js.coffee b/app/assets/javascripts/dashboard.js.coffee index 4189c90bbfa..9beca261467 100644 --- a/app/assets/javascripts/dashboard.js.coffee +++ b/app/assets/javascripts/dashboard.js.coffee @@ -1,39 +1,44 @@ -window.dashboardPage = -> - Pager.init 20, true - initSidebarTab() - $(".event_filter_link").bind "click", (event) -> - event.preventDefault() - toggleFilter $(this) - reloadActivities() - -reloadActivities = -> - $(".content_list").html '' - Pager.init 20, true - -toggleFilter = (sender) -> - sender.parent().toggleClass "inactive" - event_filters = $.cookie("event_filter") - filter = sender.attr("id").split("_")[0] - if event_filters - event_filters = event_filters.split(",") - else - event_filters = new Array() - - index = event_filters.indexOf(filter) - if index is -1 - event_filters.push filter - else - event_filters.splice index, 1 - - $.cookie "event_filter", event_filters.join(",") - -initSidebarTab = -> - key = "dashboard_sidebar_filter" - - # store selection in cookie - $('.dash-sidebar-tabs a').on 'click', (e) -> - $.cookie(key, $(e.target).attr('id')) - - # show tab from cookie - sidebar_filter = $.cookie(key) - $("#" + sidebar_filter).tab('show') if sidebar_filter +class Dashboard + constructor: -> + Pager.init 20, true + @initSidebarTab() + + $(".event_filter_link").bind "click", (event) => + event.preventDefault() + @toggleFilter($(event.currentTarget)) + @reloadActivities() + + reloadActivities: -> + $(".content_list").html '' + Pager.init 20, true + + toggleFilter: (sender) -> + sender.parent().toggleClass "inactive" + event_filters = $.cookie("event_filter") + filter = sender.attr("id").split("_")[0] + if event_filters + event_filters = event_filters.split(",") + else + event_filters = new Array() + + index = event_filters.indexOf(filter) + if index is -1 + event_filters.push filter + else + event_filters.splice index, 1 + + $.cookie "event_filter", event_filters.join(",") + + initSidebarTab: -> + key = "dashboard_sidebar_filter" + + # store selection in cookie + $('.dash-sidebar-tabs a').on 'click', (e) -> + $.cookie(key, $(e.target).attr('id')) + + # show tab from cookie + sidebar_filter = $.cookie(key) + $("#" + sidebar_filter).tab('show') if sidebar_filter + + +@Dashboard = Dashboard diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee new file mode 100644 index 00000000000..6e2d1592e32 --- /dev/null +++ b/app/assets/javascripts/dispatcher.js.coffee @@ -0,0 +1,40 @@ +$ -> + new Dispatcher() + +class Dispatcher + constructor: () -> + @initSearch() + @initPageScripts() + + initPageScripts: -> + page = $('body').attr('data-page') + project_id = $('body').attr('data-project-id') + + console.log(page) + + unless page + return false + + path = page.split(':') + + switch page + when 'issues:index' + Issues.init() + when 'dashboard:show' + new Dashboard() + when 'commit:show' + new Commit() + when 'groups:show', 'teams:show', 'projects:show' + Pager.init(20, true) + when 'projects:new', 'projects:edit' + new Project() + when 'walls:show' + new Wall(project_id) + + switch path.first() + when 'admin' then new Admin() + when 'wikis' then new Wikis() + + initSearch: -> + autocomplete_json = $('.search-autocomplete-json').data('autocomplete-opts') + new SearchAutocomplete(autocomplete_json) diff --git a/app/assets/javascripts/gfm_auto_complete.js.coffee b/app/assets/javascripts/gfm_auto_complete.js.coffee index 1cc9d34dd80..9ef194fbd25 100644 --- a/app/assets/javascripts/gfm_auto_complete.js.coffee +++ b/app/assets/javascripts/gfm_auto_complete.js.coffee @@ -20,7 +20,7 @@ GitLab.GfmAutoComplete = input = $('.js-gfm-input') # Emoji - input.atWho ':', + input.atWho '(?:^|\\s):', data: @Emoji.data tpl: @Emoji.template diff --git a/app/assets/javascripts/main.js.coffee b/app/assets/javascripts/main.js.coffee index 39ec86e623f..fb51d379ebd 100644 --- a/app/assets/javascripts/main.js.coffee +++ b/app/assets/javascripts/main.js.coffee @@ -41,6 +41,14 @@ window.linkify = (str) -> exp = /(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig return str.replace(exp,"<a href='$1'>$1</a>") +window.startSpinner = -> + $('.turbolink-spinner').fadeIn() + +window.stopSpinner = -> + $('.turbolink-spinner').fadeOut() + +document.addEventListener("page:fetch", startSpinner) +document.addEventListener("page:receive", stopSpinner) $ -> # Click a .one_click_select field, select the contents diff --git a/app/assets/javascripts/merge_requests.js.coffee b/app/assets/javascripts/merge_requests.js.coffee index 9ab41f9ac1b..769a940959b 100644 --- a/app/assets/javascripts/merge_requests.js.coffee +++ b/app/assets/javascripts/merge_requests.js.coffee @@ -21,6 +21,13 @@ class MergeRequest this.initMergeWidget() this.$('.show-all-commits').on 'click', => this.showAllCommits() + + modal = $('#modal_merge_info').modal modal: true, show:false + + $('.how_to_merge_link').bind "click", -> + modal.show() + $('.modal-header .close').bind "click", -> + modal.hide() # Local jQuery finder $: (selector) -> diff --git a/app/assets/javascripts/project.js.coffee b/app/assets/javascripts/project.js.coffee new file mode 100644 index 00000000000..f926188d23f --- /dev/null +++ b/app/assets/javascripts/project.js.coffee @@ -0,0 +1,37 @@ +class Project + constructor: -> + $('.new_project, .edit_project').on 'ajax:before', -> + $('.project_new_holder, .project_edit_holder').hide() + $('.save-project-loader').show() + + $('form #project_default_branch').chosen() + disableButtonIfEmptyField '#project_name', '.project-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') + +@Project = Project + +$ -> + # Git clone panel switcher + scope = $ '.project_clone_holder' + if scope.length > 0 + $('a, button', scope).click -> + $('a, button', scope).removeClass 'active' + $(@).addClass 'active' + $('#project_clone', scope).val $(@).data 'clone' + + # Ref switcher + $('.project-refs-select').on 'change', -> + $(@).parents('form').submit() diff --git a/app/assets/javascripts/projects.js.coffee b/app/assets/javascripts/projects.js.coffee deleted file mode 100644 index 24106c61b75..00000000000 --- a/app/assets/javascripts/projects.js.coffee +++ /dev/null @@ -1,35 +0,0 @@ -window.Projects = -> - $('.new_project, .edit_project').on 'ajax:before', -> - $('.project_new_holder, .project_edit_holder').hide() - $('.save-project-loader').show() - - $('form #project_default_branch').chosen() - disableButtonIfEmptyField '#project_name', '.project-submit' - -$ -> - # Git clone panel switcher - scope = $ '.project_clone_holder' - if scope.length > 0 - $('a, button', scope).click -> - $('a, button', scope).removeClass 'active' - $(@).addClass 'active' - $('#project_clone', scope).val $(@).data 'clone' - - # 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/javascripts/search_autocomplete.js.coffee b/app/assets/javascripts/search_autocomplete.js.coffee new file mode 100644 index 00000000000..3418690e109 --- /dev/null +++ b/app/assets/javascripts/search_autocomplete.js.coffee @@ -0,0 +1,8 @@ +class SearchAutocomplete + constructor: (json) -> + $("#search").autocomplete + source: json + select: (event, ui) -> + location.href = ui.item.url + +@SearchAutocomplete = SearchAutocomplete diff --git a/app/assets/javascripts/tree.js.coffee b/app/assets/javascripts/tree.js.coffee index 10d0df700e1..fdc82ff6668 100644 --- a/app/assets/javascripts/tree.js.coffee +++ b/app/assets/javascripts/tree.js.coffee @@ -1,40 +1,13 @@ # Code browser tree slider +# Make the entire tree-item row clickable, but not if clicking another link (like a commit message) +$(".tree-content-holder .tree-item").live 'click', (e) -> + if (e.target.nodeName != "A") + path = $('.tree-item-file-name a', this).attr('href') + Turbolinks.visit(path) $ -> - if $('#tree-slider').length > 0 - # Show the "Loading commit data" for only the first element - $('span.log_loading:first').removeClass('hide') - - $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live "click", -> - $("#tree-content-holder").hide("slide", { direction: "left" }, 400) - - # Make the entire tree-item row clickable, but not if clicking another link (like a commit message) - $("#tree-slider .tree-item").live 'click', (e) -> - $('.tree-item-file-name a', this).trigger('click') if (e.target.nodeName != "A") - - # Maintain forward/back history while browsing the file tree - ((window) -> - History = window.History - $ = window.jQuery - document = window.document - - # Check to see if History.js is enabled for our Browser - unless History.enabled - return false - - $('#tree-slider .tree-item-file-name a, .breadcrumb li > a').live 'click', (e) -> - History.pushState(null, null, decodeURIComponent($(@).attr('href'))) - return false - - History.Adapter.bind window, 'statechange', -> - state = History.getState() - $.ajax({ - url: state.url, - dataType: 'script', - beforeSend: -> $('.tree_progress').addClass("loading"), - complete: -> $('.tree_progress').removeClass("loading") - }) - )(window) + # Show the "Loading commit data" for only the first element + $('span.log_loading:first').removeClass('hide') # See if there are lines selected # "#L12" and "#L34-56" supported diff --git a/app/assets/javascripts/wall.js.coffee b/app/assets/javascripts/wall.js.coffee index e2fca3ddee4..c8fc960e174 100644 --- a/app/assets/javascripts/wall.js.coffee +++ b/app/assets/javascripts/wall.js.coffee @@ -1,32 +1,32 @@ -@Wall = - note_ids: [] - project_id: null - - init: (project_id) -> - Wall.project_id = project_id - Wall.getContent() - Wall.initRefresh() - Wall.initForm() +class Wall + constructor: (project_id) -> + @project_id = project_id + @note_ids = [] + @getContent() + @initRefresh() + @initForm() # # Gets an initial set of notes. # getContent: -> - Api.notes Wall.project_id, (notes) -> - $.each notes, (i, note) -> + Api.notes @project_id, (notes) => + $.each notes, (i, note) => # render note if it not present in loaded list # or skip if rendered - if $.inArray(note.id, Wall.note_ids) == -1 - Wall.note_ids.push(note.id) - Wall.renderNote(note) - Wall.scrollDown() + if $.inArray(note.id, @note_ids) == -1 + @note_ids.push(note.id) + @renderNote(note) + @scrollDown() $("abbr.timeago").timeago() initRefresh: -> - setInterval("Wall.refresh()", 10000) + setInterval => + @refresh() + , 10000 refresh: -> - Wall.getContent() + @getContent() scrollDown: -> notes = $('ul.notes') @@ -36,8 +36,8 @@ form = $('.wall-note-form') form.find("#target_type").val('wall') - form.on 'ajax:success', -> - Wall.refresh() + form.on 'ajax:success', => + @refresh() form.find(".js-note-text").val("").trigger("input") form.on 'ajax:complete', -> @@ -58,7 +58,7 @@ form.show() renderNote: (note) -> - template = Wall.noteTemplate() + template = @noteTemplate() template = template.replace('{{author_name}}', note.author.name) template = template.replace('{{created_at}}', note.created_at) template = template.replace('{{text}}', linkify(sanitize(note.body))) @@ -81,3 +81,5 @@ </span> <abbr class="timeago" title="{{created_at}}">{{created_at}}</abbr> </li>' + +@Wall = Wall diff --git a/app/assets/javascripts/wikis.js.coffee b/app/assets/javascripts/wikis.js.coffee new file mode 100644 index 00000000000..f2867c8026e --- /dev/null +++ b/app/assets/javascripts/wikis.js.coffee @@ -0,0 +1,19 @@ +class Wikis + constructor: -> + modal = $('#modal-new-wiki').modal({modal: true, show:false}) + + $('.add-new-wiki').bind "click", -> + modal.show() + + $('.build-new-wiki').bind "click", -> + field = $('#new_wiki_path') + slug = field.val() + path = field.attr('data-wikis-path') + + if(slug.length > 0) + location.href = path + "/" + slug + + $('.modal-header .close').bind "click", -> + modal.hide() + +@Wikis = Wikis diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index 893cb2196d7..85e43ed0d35 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -41,6 +41,7 @@ @import "highlight/white.scss"; @import "highlight/dark.scss"; @import "highlight/solarized_dark.scss"; +@import "highlight/monokai.scss"; /** * UI themes: diff --git a/app/assets/stylesheets/common.scss b/app/assets/stylesheets/common.scss index c3cc601f16f..ccc6f7a9d2d 100644 --- a/app/assets/stylesheets/common.scss +++ b/app/assets/stylesheets/common.scss @@ -195,6 +195,11 @@ p.time { top: -5px; @include border-radius(4px); + &.success { + background: #4A4; + color: #FFF; + } + &.error { background: #DA4E49; color: #FFF; diff --git a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss index 842e7a08057..867920ad08f 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/blocks.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/blocks.scss @@ -13,6 +13,7 @@ background: #F9F9F9; margin-bottom: 25px; border: 1px solid #CCC; + word-wrap: break-word; @include solid-shade; &.ui-box-show { @@ -41,7 +42,6 @@ .ui-box-body, .ui-box-bottom { padding: 15px; - word-wrap: break-word; .clearfix { margin: 0; @@ -171,3 +171,8 @@ margin: 3px 3px 25px 3px; } } + +.light-well { + background: #f9f9f9; + padding: 15px; +} diff --git a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss index 03497e32d26..e9b85686fad 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/buttons.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/buttons.scss @@ -23,7 +23,7 @@ &.disabled { color: #fff; - background: #29B; + background: $primary_color; } } @@ -39,7 +39,7 @@ &.disabled { color: #fff; - background: #29B; + background: $primary_color; } } diff --git a/app/assets/stylesheets/gitlab_bootstrap/common.scss b/app/assets/stylesheets/gitlab_bootstrap/common.scss index 3ec03b96434..dd072b978d4 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/common.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/common.scss @@ -74,3 +74,9 @@ fieldset legend { font-size: 17px; } .tab-content { overflow: visible; } + +@media (max-width: 1200px) { + .only-wide { + display: none; + } +} diff --git a/app/assets/stylesheets/gitlab_bootstrap/lists.scss b/app/assets/stylesheets/gitlab_bootstrap/lists.scss index 0f893a553ee..e661e02623e 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/lists.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/lists.scss @@ -69,5 +69,14 @@ ul.bordered-list { display: block; margin: 0px; &:last-child { border:none } + + &.active { + background: #f9f9f9; + a { font-weight: bold; } + } + + &.light { + a { color: #777; } + } } } diff --git a/app/assets/stylesheets/gitlab_bootstrap/nav.scss b/app/assets/stylesheets/gitlab_bootstrap/nav.scss index 2eaef61ca33..0fc8b21de7b 100644 --- a/app/assets/stylesheets/gitlab_bootstrap/nav.scss +++ b/app/assets/stylesheets/gitlab_bootstrap/nav.scss @@ -16,7 +16,7 @@ padding: 12px; } > .active > a { - border-color: #29B; + border-color: $primary_color; border-radius: 0; background: #F1F1F1; color: $style_color; diff --git a/app/assets/stylesheets/highlight/monokai.scss b/app/assets/stylesheets/highlight/monokai.scss new file mode 100644 index 00000000000..c196cc1d61c --- /dev/null +++ b/app/assets/stylesheets/highlight/monokai.scss @@ -0,0 +1,86 @@ +$monokai-fg: #f8f8f2; +$monokai-comment: #75715e; +$monokai-pink: #f92672; +$monokai-blue: #66d9ef; +$monokai-green: #a6e22e; +$monokai-gold: #e6db74; +$monokai-dark: #3b3a32; +$monokai-purple: #ae81ff; + +.monokai .highlight { + pre { + background-color: #272822; + color: $monokai-fg; + } + + .hll { background-color: #ffffcc } + .c { color: $monokai-comment } /* Comment */ + .err { color: $monokai-fg } /* Error */ + .g { color: $monokai-fg } /* Generic */ + .k { color: $monokai-pink } /* Keyword */ + .l { color: $monokai-fg } /* Literal */ + .n { color: $monokai-blue } /* Name */ + .o { color: $monokai-fg } /* Operator */ + .x { color: $monokai-fg } /* Other */ + .p { color: $monokai-fg } /* Punctuation */ + .cm { color: $monokai-comment } /* Comment.Multiline */ + .cp { color: $monokai-comment } /* Comment.Preproc */ + .c1 { color: $monokai-comment } /* Comment.Single */ + .cs { color: $monokai-comment } /* Comment.Special */ + .gd { color: #8b0807 } /* Generic.Deleted */ + .ge { color: $monokai-fg; text-decoration: underline } /* Generic.Emph */ + .gr { color: $monokai-fg } /* Generic.Error */ + .gh { color: $monokai-fg; font-weight: bold } /* Generic.Heading */ + .gi { color: $monokai-fg; font-weight: bold; background-color: #46830c } /* Generic.Inserted */ + .go { color: $monokai-dark; background-color: #31322c } /* Generic.Output */ + .gp { color: $monokai-fg } /* Generic.Prompt */ + .gs { color: $monokai-fg } /* Generic.Strong */ + .gu { color: $monokai-fg; font-weight: bold } /* Generic.Subheading */ + .gt { color: #f8f8f0; background-color: $monokai-pink } /* Generic.Traceback */ + .kc { color: $monokai-purple } /* Keyword.Constant */ + .kd { color: $monokai-pink } /* Keyword.Declaration */ + .kn { color: $monokai-pink } /* Keyword.Namespace */ + .kp { color: $monokai-pink } /* Keyword.Pseudo */ + .kr { color: $monokai-pink } /* Keyword.Reserved */ + .kt { color: $monokai-fg } /* Keyword.Type */ + .ld { color: $monokai-fg } /* Literal.Date */ + .m { color: $monokai-purple } /* Literal.Number */ + .s { color: $monokai-gold } /* Literal.String */ + .na { color: $monokai-purple } /* Name.Attribute */ + .nb { color: $monokai-blue } /* Name.Builtin */ + .nc { color: $monokai-fg } /* Name.Class */ + .no { color: $monokai-fg } /* Name.Constant */ + .nd { color: $monokai-fg } /* Name.Decorator */ + .ni { color: $monokai-fg } /* Name.Entity */ + .ne { color: $monokai-fg } /* Name.Exception */ + .nf { color: $monokai-green } /* Name.Function */ + .nl { color: $monokai-gold } /* Name.Label */ + .nn { color: $monokai-fg } /* Name.Namespace */ + .nx { color: $monokai-fg } /* Name.Other */ + .nt { color: $monokai-pink } /* Name.Tag */ + .nv { color: $monokai-blue; font-style: italic } /* Name.Variable */ + .py { color: $monokai-fg } /* Name.Property */ + .ow { color: $monokai-pink } /* Operator.Word */ + .w { color: $monokai-fg } /* Text.Whitespace */ + .mf { color: $monokai-purple } /* Literal.Number.Float */ + .mh { color: $monokai-purple } /* Literal.Number.Hex */ + .mi { color: $monokai-purple } /* Literal.Number.Integer */ + .mo { color: $monokai-purple } /* Literal.Number.Oct */ + .sb { color: $monokai-gold } /* Literal.String.Backtick */ + .sc { color: $monokai-gold } /* Literal.String.Char */ + .sd { color: $monokai-gold } /* Literal.String.Doc */ + .s2 { color: $monokai-gold } /* Literal.String.Double */ + .se { color: $monokai-gold } /* Literal.String.Escape */ + .sh { color: $monokai-gold } /* Literal.String.Heredoc */ + .si { color: $monokai-gold } /* Literal.String.Interpol */ + .sx { color: $monokai-gold } /* Literal.String.Other */ + .sr { color: $monokai-gold } /* Literal.String.Regex */ + .s1 { color: $monokai-gold } /* Literal.String.Single */ + .ss { color: $monokai-gold } /* Literal.String.Symbol */ + .bp { color: $monokai-fg } /* Name.Builtin.Pseudo */ + .vc { color: $monokai-blue; font-style: italic } /* Name.Variable.Class */ + .vg { color: $monokai-blue; font-style: italic } /* Name.Variable.Global */ + .vi { color: $monokai-blue; font-style: italic } /* Name.Variable.Instance */ + .il { color: $monokai-purple } /* Literal.Number.Integer.Long */ +} + diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss index 51a307e4d4e..812587a2ee6 100644 --- a/app/assets/stylesheets/sections/commits.scss +++ b/app/assets/stylesheets/sections/commits.scss @@ -99,12 +99,24 @@ } } } + .line_holder { + &.old .old_line, + &.old .new_line { + background: #FCC; + border-color: #E7BABA; + } + &.new .old_line, + &.new .new_line { + background: #CFC; + border-color: #B9ECB9; + } + } .line_content { display: block; white-space: pre; height: 18px; margin: 0px; - padding: 0px; + padding: 0px 0.5em; border: none; &.new { background: #CFD; diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss index 4876af296d8..40f35b65da6 100644 --- a/app/assets/stylesheets/sections/events.scss +++ b/app/assets/stylesheets/sections/events.scss @@ -124,7 +124,7 @@ color: #777; padding: 10px; min-height: 22px; - border-left: 5px solid #5AB9C3; + border-left: 5px solid $primary_color; margin-bottom: 20px; background: #f9f9f9; @@ -133,10 +133,10 @@ } .btn-new-mr { - @extend .btn-info; + @extend .btn-primary; @extend .small; @extend .pull-right; - margin: -3px; + margin: -2px; } } @@ -152,7 +152,7 @@ .filter_icon { a { text-align:center; - border-left: 3px solid #29B; + border-left: 3px solid $primary_color; background: #f9f9f9; margin-bottom: 10px; float: left; diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss index 7da00719b33..58c2c203219 100644 --- a/app/assets/stylesheets/sections/graph.scss +++ b/app/assets/stylesheets/sections/graph.scss @@ -13,7 +13,8 @@ background: #f1f1f1; cursor: move; height: 500px; - overflow: hidden; + overflow-y: scroll; + overflow-x: hidden; } } diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index a8628fc58f2..a86384dc2ef 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -213,7 +213,17 @@ ul.notes { .reply-btn { @extend .btn-primary; } -.file .content tr.line_holder:hover > td { background: $hover !important; } +.file .content tr.line_holder:hover { + &> td.line_content { + background: $hover !important; + border-color: darken($hover, 10%) !important; + } + &> td.new_line, + &> td.old_line { + background: darken($hover, 4%) !important; + border-color: darken($hover, 10%) !important; + } +} .file .content tr.line_holder:hover > td .line_note_link { opacity: 1.0; filter: alpha(opacity=100); diff --git a/app/assets/stylesheets/sections/projects.scss b/app/assets/stylesheets/sections/projects.scss index 6c890d3420d..22618765eaa 100644 --- a/app/assets/stylesheets/sections/projects.scss +++ b/app/assets/stylesheets/sections/projects.scss @@ -33,14 +33,6 @@ } .project_clone_holder { - input[type="text"], - .btn { - font-size: 12px; - line-height: 18px; - margin: 0; - padding: 3px 10px; - } - input[type="text"] { @extend .monospace; border: 1px solid #BBB; diff --git a/app/assets/stylesheets/sections/tree.scss b/app/assets/stylesheets/sections/tree.scss index def440c7134..ffde6aa3fa6 100644 --- a/app/assets/stylesheets/sections/tree.scss +++ b/app/assets/stylesheets/sections/tree.scss @@ -97,7 +97,7 @@ .tree-btn-group { .btn { - margin-right:-3px; + margin-right: 0px; padding: 2px 10px; } } diff --git a/app/contexts/projects/create_context.rb b/app/contexts/projects/create_context.rb index 56c4e1c51da..2922564ba20 100644 --- a/app/contexts/projects/create_context.rb +++ b/app/contexts/projects/create_context.rb @@ -8,7 +8,18 @@ module Projects # get namespace id namespace_id = params.delete(:namespace_id) - @project = Project.new(params) + # Load default feature settings + default_features = Gitlab.config.gitlab.default_projects_features + + default_opts = { + issues_enabled: default_features.issues, + wiki_enabled: default_features.wiki, + wall_enabled: default_features.wall, + snippets_enabled: default_features.snippets, + merge_requests_enabled: default_features.merge_requests + } + + @project = Project.new(default_opts.merge(params)) # Parametrize path for project # @@ -32,10 +43,6 @@ module Projects @project.namespace_id = current_user.namespace_id end - # Disable less important features by default - @project.wall_enabled = false - @project.snippets_enabled = false - @project.creator = current_user # Import project from cloneable resource diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 32b1246601d..22fe5abacb3 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -155,5 +155,6 @@ class ApplicationController < ActionController::Base gon.api_version = Gitlab::API.version gon.api_token = current_user.private_token if current_user gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url + gon.relative_url_root = Gitlab.config.gitlab.relative_url_root end end diff --git a/app/controllers/dashboard_controller.rb b/app/controllers/dashboard_controller.rb index 91a67985710..f651b02c1e5 100644 --- a/app/controllers/dashboard_controller.rb +++ b/app/controllers/dashboard_controller.rb @@ -34,6 +34,7 @@ class DashboardController < ApplicationController @projects end + @projects = @projects.tagged_with(params[:label]) if params[:label].present? @projects = @projects.search(params[:search]) if params[:search].present? @projects = @projects.page(params[:page]).per(30) end diff --git a/app/controllers/edit_tree_controller.rb b/app/controllers/edit_tree_controller.rb index e3bd10ec758..9ed7a2143e4 100644 --- a/app/controllers/edit_tree_controller.rb +++ b/app/controllers/edit_tree_controller.rb @@ -25,7 +25,7 @@ class EditTreeController < ProjectResourceController redirect_to project_blob_path(@project, @id), notice: "Your changes have been successfully commited" else flash[:notice] = "Your changes could not be commited, because the file has been changed" - render :edit + render :show end end diff --git a/app/controllers/milestones_controller.rb b/app/controllers/milestones_controller.rb index 135281bd28d..25647f97576 100644 --- a/app/controllers/milestones_controller.rb +++ b/app/controllers/milestones_controller.rb @@ -14,7 +14,7 @@ class MilestonesController < ProjectResourceController @milestones = case params[:f] when 'all'; @project.milestones.order("state, due_date DESC") when 'closed'; @project.milestones.closed.order("due_date DESC") - else @project.milestones.active.order("due_date ASC") + else @project.milestones.active.order("due_date DESC") end @milestones = @milestones.includes(:project) @@ -32,7 +32,7 @@ class MilestonesController < ProjectResourceController def show @issues = @milestone.issues - @users = @milestone.participants + @users = @milestone.participants.uniq @merge_requests = @milestone.merge_requests respond_to do |format| diff --git a/app/controllers/refs_controller.rb b/app/controllers/refs_controller.rb index e116bc358c9..188feb73ec1 100644 --- a/app/controllers/refs_controller.rb +++ b/app/controllers/refs_controller.rb @@ -13,6 +13,8 @@ class RefsController < ProjectResourceController format.html do new_path = if params[:destination] == "tree" project_tree_path(@project, (@ref + "/" + params[:path])) + elsif params[:destination] == "blob" + project_blob_path(@project, (@ref + "/" + params[:path])) elsif params[:destination] == "graph" project_graph_path(@project, @ref) else diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 6fba2518306..a7d393af82b 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -27,7 +27,9 @@ class RepositoriesController < ProjectResourceController end - file_path = @repository.archive_repo(params[:ref]) + storage_path = Rails.root.join("tmp", "repositories") + + file_path = @repository.archive_repo(params[:ref], storage_path) if file_path # Send file to user diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 387172b5804..703c88975a3 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -37,7 +37,7 @@ module ApplicationHelper if !Gitlab.config.gravatar.enabled || user_email.blank? 'no_avatar.png' else - gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url + gravatar_url = request.ssl? || Gitlab.config.gitlab.https ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url user_email.strip! sprintf gravatar_url, hash: Digest::MD5.hexdigest(user_email.downcase), size: size end @@ -132,18 +132,27 @@ module ApplicationHelper when 1 then 'white' when 2 then 'black' when 3 then 'solarized-dark' + when 4 then 'monokai' else 'white' end end + # Define whenever show last push event + # with suggestion to create MR def show_last_push_widget?(event) - event && - event.last_push_to_non_root? && - !event.rm_ref? && - event.project && - event.project.repository && - event.project.merge_requests_enabled + # Skip if event is not about added or modified non-master branch + return false unless event && event.last_push_to_non_root? && !event.rm_ref? + + project = event.project + + # Skip if project repo is empty or MR disabled + return false unless project && !project.empty_repo? && project.merge_requests_enabled + + # Skip if user already created appropriate MR + return false if project.merge_requests.where(source_branch: event.branch_name).opened.any? + + true end def hexdigest(string) @@ -180,4 +189,11 @@ module ApplicationHelper css_class << " multiselect" if opts[:multiple] hidden_field_tag(id, '', class: css_class) end + + def body_data_page + path = controller.controller_path.split('/') + namespace = path.first if path.second + + [namespace, controller.controller_name, controller.action_name].compact.join(":") + end end diff --git a/app/helpers/graph_helper.rb b/app/helpers/graph_helper.rb index ca7d823a45a..71a07d6cad1 100644 --- a/app/helpers/graph_helper.rb +++ b/app/helpers/graph_helper.rb @@ -4,8 +4,7 @@ module GraphHelper refs += commit.refs.collect{|r|r.name}.join(" ") if commit.refs # append note count - notes = @project.notes.for_commit_id(commit.id) - refs += "[#{notes.count}]" if notes.any? + refs += "[#{@graph.notes[commit.id]}]" if @graph.notes[commit.id] > 0 refs end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index 1db8b7c689c..9e7c4ee245a 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -3,6 +3,10 @@ module ProjectsHelper "You are going to remove #{user.name} from #{project.name} project team. Are you sure?" end + def projects_labels + Project.tag_counts_on(:labels).map(&:name) + end + def link_to_project project link_to project do title = content_tag(:strong, project.name) diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb index e7002f60b8a..1f764ea1038 100644 --- a/app/helpers/tree_helper.rb +++ b/app/helpers/tree_helper.rb @@ -5,24 +5,18 @@ module TreeHelper # contents - A Grit::Tree object for the current tree def render_tree(tree) # Render Folders before Files/Submodules - folders, files = tree.trees, tree.blobs + folders, files, submodules = tree.trees, tree.blobs, tree.submodules tree = "" # Render folders if we have any tree += render partial: 'tree/tree_item', collection: folders, locals: {type: 'folder'} if folders.present? - files.each do |f| - html = if f.respond_to?(:url) - # Object is a Submodule - render partial: 'tree/submodule_item', object: f - else - # Object is a Blob - render partial: 'tree/blob_item', object: f, locals: {type: 'file'} - end + # Render files if we have any + tree += render partial: 'tree/blob_item', collection: files, locals: {type: 'file'} if files.present? - tree += html if html.present? - end + # Render submodules if we have any + tree += render partial: 'tree/submodule_item', collection: submodules if submodules.present? tree.html_safe end diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 105d9239cf6..c1b4d4e0760 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -24,8 +24,6 @@ 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 @@ -109,22 +107,18 @@ class MergeRequest < ActiveRecord::Base end def diffs - st_diffs || [] + load_diffs(st_diffs) || [] end def reloaded_diffs if opened? && unmerged_diffs.any? - self.st_diffs = unmerged_diffs + self.st_diffs = dump_diffs(unmerged_diffs) self.save end - - rescue Grit::Git::GitTimeout - self.st_diffs = [BROKEN_DIFF] - self.save end def broken_diffs? - diffs == [BROKEN_DIFF] + diffs == [Gitlab::Git::Diff::BROKEN_DIFF] end def valid_diffs? @@ -132,11 +126,7 @@ class MergeRequest < ActiveRecord::Base end def unmerged_diffs - # Only show what is new in the source branch compared to the target branch, not the other way around. - # The linex below with merge_base is equivalent to diff with three dots (git diff branch1...branch2) - # From the git documentation: "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B" - common_commit = project.repo.git.native(:merge_base, {}, [target_branch, source_branch]).strip - diffs = project.repo.diff(common_commit, source_branch) + project.repository.diffs_between(source_branch, target_branch) end def last_commit @@ -222,4 +212,12 @@ class MergeRequest < ActiveRecord::Base def load_commits(array) array.map { |hash| Commit.new(Gitlab::Git::Commit.new(hash)) } end + + def dump_diffs(diffs) + diffs.map(&:to_hash) + end + + def load_diffs(array) + array.map { |hash| Gitlab::Git::Diff.new(hash) } + end end diff --git a/app/models/network/graph.rb b/app/models/network/graph.rb index 0fe7765b9ea..27072836cbb 100644 --- a/app/models/network/graph.rb +++ b/app/models/network/graph.rb @@ -2,7 +2,7 @@ require "grit" module Network class Graph - attr_reader :days, :commits, :map + attr_reader :days, :commits, :map, :notes def self.max_count @max_count ||= 650 @@ -16,10 +16,19 @@ module Network @commits = collect_commits @days = index_commits + @notes = collect_notes end protected + def collect_notes + h = Hash.new(0) + @project.notes.where('noteable_type = ?' ,"Commit").group('notes.commit_id').select('notes.commit_id, count(notes.id) as note_count').each do |item| + h[item["commit_id"]] = item["note_count"] + end + h + end + # Get commits from repository # def collect_commits @@ -181,7 +190,7 @@ module Network l.spaces << space # Also add space to parent l.parents(@map).each do |parent| - if parent.space > 0 + if 0 < parent.space && parent.space < space parent.spaces << space end end diff --git a/app/models/note.rb b/app/models/note.rb index 8274b866568..7b7e6e99df4 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -68,8 +68,8 @@ class Note < ActiveRecord::Base def diff if noteable.diffs.present? noteable.diffs.select do |d| - if d.b_path - Digest::SHA1.hexdigest(d.b_path) == diff_file_index + if d.new_path + Digest::SHA1.hexdigest(d.new_path) == diff_file_index end end.first end @@ -80,7 +80,7 @@ class Note < ActiveRecord::Base end def diff_file_name - diff.b_path + diff.new_path end def diff_new_line diff --git a/app/models/project.rb b/app/models/project.rb index 1d1b7c1134c..291316f3088 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -28,12 +28,14 @@ class Project < ActiveRecord::Base include Gitlab::ShellAdapter extend Enumerize - attr_accessible :name, :path, :description, :default_branch, :issues_tracker, + attr_accessible :name, :path, :description, :default_branch, :issues_tracker, :label_list, :issues_enabled, :wall_enabled, :merge_requests_enabled, :snippets_enabled, :issues_tracker_id, :wiki_enabled, :public, :import_url, :last_activity_at, as: [:default, :admin] attr_accessible :namespace_id, :creator_id, as: :admin + acts_as_taggable_on :labels + attr_accessor :import_url # Relations diff --git a/app/models/repository.rb b/app/models/repository.rb index ed600e29232..d45ec9bd575 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -37,6 +37,22 @@ class Repository raw_repository.send(m, *args, &block) end + # Return repo size in megabytes + # Cached in redis + def size + Rails.cache.fetch(cache_key(:size)) do + raw_repository.size + end + end + + def expire_cache + Rails.cache.delete(cache_key(:size)) + end + + def cache_key(type) + "#{type}:#{path_with_namespace}" + end + def respond_to?(method) return true if raw_repository.respond_to?(method) diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 4b3c982c189..379d2c54629 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -13,7 +13,7 @@ class NotificationService # even if user disabled notifications def new_key(key) if key.user - Notify.delay.new_ssh_key_email(key.id) + mailer.new_ssh_key_email(key.id) end end @@ -84,14 +84,14 @@ class NotificationService recipients = recipients.concat(project_watchers(merge_request.project)).uniq recipients.each do |recipient| - Notify.delay.merged_merge_request_email(recipient.id, merge_request.id) + mailer.merged_merge_request_email(recipient.id, merge_request.id) end end # Notify new user with email after creation def new_user(user) # Dont email omniauth created users - Notify.delay.new_user_email(user.id, user.password) unless user.extern_uid? + mailer.new_user_email(user.id, user.password) unless user.extern_uid? end # Notify users on new note in system @@ -131,16 +131,16 @@ class NotificationService notify_method = "note_#{note.noteable_type.underscore}_email".to_sym recipients.each do |recipient| - Notify.delay.send(notify_method, recipient.id, note.id) + mailer.send(notify_method, recipient.id, note.id) end end def new_team_member(users_project) - Notify.delay.project_access_granted_email(users_project.id) + mailer.project_access_granted_email(users_project.id) end def update_team_member(users_project) - Notify.delay.project_access_granted_email(users_project.id) + mailer.project_access_granted_email(users_project.id) end protected @@ -186,7 +186,7 @@ class NotificationService recipients.delete(target.author) recipients.each do |recipient| - Notify.delay.send(method, recipient.id, target.id) + mailer.send(method, recipient.id, target.id) end end @@ -196,7 +196,7 @@ class NotificationService recipients.delete(current_user) recipients.each do |recipient| - Notify.delay.send(method, recipient.id, target.id, current_user.id) + mailer.send(method, recipient.id, target.id, current_user.id) end end @@ -213,7 +213,11 @@ class NotificationService recipients.delete(current_user) recipients.each do |recipient| - Notify.delay.send(method, recipient.id, target.id, target.assignee_id_was) + mailer.send(method, recipient.id, target.id, target.assignee_id_was) end end + + def mailer + Notify.delay + end end diff --git a/app/views/admin/groups/edit.html.haml b/app/views/admin/groups/edit.html.haml index bb1398f66cd..af87503128e 100644 --- a/app/views/admin/groups/edit.html.haml +++ b/app/views/admin/groups/edit.html.haml @@ -27,5 +27,5 @@ %li It will change the git path to repositories under this group. .form-actions - = f.submit 'Edit group', class: "btn btn-remove" + = f.submit 'Save changes', class: "btn btn-primary" = link_to 'Cancel', admin_groups_path, class: "btn btn-cancel" diff --git a/app/views/admin/groups/new.html.haml b/app/views/admin/groups/new.html.haml index 6f76ee648ae..2da654ec764 100644 --- a/app/views/admin/groups/new.html.haml +++ b/app/views/admin/groups/new.html.haml @@ -15,7 +15,7 @@ = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 .form-actions - = f.submit 'Create group', class: "btn btn-primary" + = f.submit 'Create group', class: "btn btn-create" %hr .padded diff --git a/app/views/admin/groups/show.html.haml b/app/views/admin/groups/show.html.haml index 63ea78fdd99..0e2e144d326 100644 --- a/app/views/admin/groups/show.html.haml +++ b/app/views/admin/groups/show.html.haml @@ -94,7 +94,7 @@ %td= select_tag :project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3"} %tr - %td= submit_tag 'Add user to projects in group', class: "btn btn-primary" + %td= submit_tag 'Add user to projects in group', class: "btn btn-create" %td Read more about project permissions %strong= link_to "here", help_permissions_path, class: "vlink" @@ -116,18 +116,5 @@ .input = select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name_with_namespace), multiple: true, data: {placeholder: 'Select projects'}, class: 'chosen span5' .form-actions - = submit_tag 'Add', class: "btn btn-primary" - -:javascript - $(function(){ - var modal = $('.change-owner-holder'); - $('.change-owner-link').bind("click", function(){ - $(this).hide(); - modal.show(); - }); - $('.change-owner-cancel-link').bind("click", function(){ - modal.hide(); - $('.change-owner-link').show(); - }) - }) + = submit_tag 'Move projects', class: "btn btn-create" diff --git a/app/views/admin/hooks/index.html.haml b/app/views/admin/hooks/index.html.haml index acbf7a108b8..316e8235cbe 100644 --- a/app/views/admin/hooks/index.html.haml +++ b/app/views/admin/hooks/index.html.haml @@ -15,7 +15,7 @@ .input = f.text_field :url, class: "text_field xxlarge" - = f.submit "Add System Hook", class: "btn btn-primary" + = f.submit "Add System Hook", class: "btn btn-create" %hr -if @hooks.any? diff --git a/app/views/admin/teams/index.html.haml b/app/views/admin/teams/index.html.haml index 225ad166774..cf24ed5398f 100644 --- a/app/views/admin/teams/index.html.haml +++ b/app/views/admin/teams/index.html.haml @@ -1,7 +1,7 @@ %h3.page_title Teams %small - simple Teams description + allow you to organize groups of people that have a common focus. Use teams to simplify the process of assigning roles to groups of people. = link_to 'New Team', new_admin_team_path, class: "btn btn-small pull-right" %br diff --git a/app/views/admin/teams/new.html.haml b/app/views/admin/teams/new.html.haml index 1c90cb20c10..8bccdacc351 100644 --- a/app/views/admin/teams/new.html.haml +++ b/app/views/admin/teams/new.html.haml @@ -16,7 +16,7 @@ = f.text_area :description, maxlength: 250, class: "xxlarge js-gfm-input", rows: 4 .form-actions - = f.submit 'Create team', class: "btn btn-primary" + = f.submit 'Create team', class: "btn btn-create" %hr .padded diff --git a/app/views/admin/teams/show.html.haml b/app/views/admin/teams/show.html.haml index abdfada8c5e..bd4d90b607f 100644 --- a/app/views/admin/teams/show.html.haml +++ b/app/views/admin/teams/show.html.haml @@ -91,17 +91,3 @@ = link_to 'Edit', edit_admin_team_project_path(@team, project), class: "btn btn-small" = link_to 'Relegate', admin_team_project_path(@team, project), confirm: 'Remove project from team. Are you sure?', method: :delete, class: "btn btn-remove small", id: "relegate_project_#{project.id}" - -:javascript - $(function(){ - var modal = $('.change-owner-holder'); - $('.change-owner-link').bind("click", function(){ - $(this).hide(); - modal.show(); - }); - $('.change-owner-cancel-link').bind("click", function(){ - modal.hide(); - $('.change-owner-link').show(); - }) - }) - diff --git a/app/views/admin/users/_form.html.haml b/app/views/admin/users/_form.html.haml index 1d1fe341c5b..9bde50f8947 100644 --- a/app/views/admin/users/_form.html.haml +++ b/app/views/admin/users/_form.html.haml @@ -80,8 +80,9 @@ .input= f.text_field :twitter .actions - = f.submit 'Save', class: "btn btn-save" - if @admin_user.new_record? + = f.submit 'Create user', class: "btn btn-create" = link_to 'Cancel', admin_users_path, class: "btn btn-cancel" - else + = f.submit 'Save changes', class: "btn btn-save" = link_to 'Cancel', admin_user_path(@admin_user), class: "btn btn-cancel" diff --git a/app/views/blob/_actions.html.haml b/app/views/blob/_actions.html.haml index 1da39e72c98..456c7432c94 100644 --- a/app/views/blob/_actions.html.haml +++ b/app/views/blob/_actions.html.haml @@ -8,5 +8,5 @@ - if current_page? project_blame_path(@project, @id) = link_to "normal view", project_blob_path(@project, @id), class: "btn btn-tiny" - else - = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" + = link_to "blame", project_blame_path(@project, @id), class: "btn btn-tiny" unless @blob.empty? = link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny" diff --git a/app/views/blob/show.html.haml b/app/views/blob/show.html.haml index d1ca0e05e83..d96595bc7f0 100644 --- a/app/views/blob/show.html.haml +++ b/app/views/blob/show.html.haml @@ -1,4 +1,4 @@ %div.tree-ref-holder - = render 'shared/ref_switcher', destination: 'tree', path: @path + = render 'shared/ref_switcher', destination: 'blob', path: @path %div#tree-holder.tree-holder = render 'blob', blob: @blob diff --git a/app/views/blob/show.js.haml b/app/views/blob/show.js.haml deleted file mode 100644 index 804107f42fa..00000000000 --- a/app/views/blob/show.js.haml +++ /dev/null @@ -1,10 +0,0 @@ -:plain - // Load Files list - $("#tree-holder").html("#{escape_javascript(render(partial: "blob", locals: {blob: @blob}))}"); - $("#tree-content-holder").show("slide", { direction: "right" }, 400); - $('.project-refs-form #path').val("#{@path}"); - - // Load last commit log for each file in tree - $('#tree-slider').waitForImages(function() { - ajaxGet('#{@logs_path}'); - }); diff --git a/app/views/commit/huge_commit.html.haml b/app/views/commit/huge_commit.html.haml index 7f0bcf38037..5d447d6cee5 100644 --- a/app/views/commit/huge_commit.html.haml +++ b/app/views/commit/huge_commit.html.haml @@ -1,3 +1,3 @@ -= render "commits/commit_box" += render "commit/commit_box" .alert.alert-error %h4 Commit diffs are too big to be displayed diff --git a/app/views/commit/show.html.haml b/app/views/commit/show.html.haml index 48fb44a99d5..6cb1a6905ca 100644 --- a/app/views/commit/show.html.haml +++ b/app/views/commit/show.html.haml @@ -9,10 +9,3 @@ = render "commits/diffs", diffs: @commit.diffs = render "notes/notes_with_form" - -:javascript - $(function(){ - $('.files .file').each(function(){ - new CommitFile(this); - }); - }); diff --git a/app/views/commits/_text_file.html.haml b/app/views/commits/_text_file.html.haml index 760fd07ed8b..8f737e43887 100644 --- a/app/views/commits/_text_file.html.haml +++ b/app/views/commits/_text_file.html.haml @@ -4,7 +4,7 @@ %table.text-file{class: "#{'hide' if too_big}"} - each_diff_line(diff, index) do |line, type, line_code, line_new, line_old| - %tr.line_holder{ id: line_code } + %tr.line_holder{ id: line_code, class: "#{type}" } - if type == "match" %td.old_line= "..." %td.new_line= "..." diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index 586b21dfa5d..cb9ef820d3e 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -11,7 +11,5 @@ - if @commits.count == @limit :javascript - $(function(){ - CommitsList.init("#{@ref}", #{@limit}); - }); + CommitsList.init("#{@ref}", #{@limit}); diff --git a/app/views/dashboard/_sidebar.html.haml b/app/views/dashboard/_sidebar.html.haml index 876a5b61297..748ff9810b5 100644 --- a/app/views/dashboard/_sidebar.html.haml +++ b/app/views/dashboard/_sidebar.html.haml @@ -22,7 +22,4 @@ News Feed %hr -.gitlab-promo - = link_to "Homepage", "http://gitlab.org" - = link_to "Blog", "http://blog.gitlab.org" - = link_to "@gitlabhq", "https://twitter.com/gitlabhq" += render 'shared/promo' diff --git a/app/views/dashboard/projects.html.haml b/app/views/dashboard/projects.html.haml index f81af59b38f..511366cf1ab 100644 --- a/app/views/dashboard/projects.html.haml +++ b/app/views/dashboard/projects.html.haml @@ -20,6 +20,15 @@ = nav_tab :scope, 'joined' do = link_to "Joined", projects_dashboard_path(scope: 'joined') + %p.light Filter by label: + %ul.bordered-list + - projects_labels.each do |label| + %li{ class: (label == params[:label]) ? 'active' : 'light' } + = link_to projects_dashboard_path(scope: params[:scope], label: label) do + %i.icon-tag + = label + + .span9 = form_tag projects_dashboard_path, method: 'get' do %fieldset.dashboard-search-filter @@ -49,6 +58,10 @@ .left - if project.description.present? %span.light= project.description + - project.labels.each do |label| + %span.label.label-info + %i.icon-tag + = label.name .pull-right.light %small.light diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml index ff2db0e3180..2305eae1f71 100644 --- a/app/views/dashboard/show.html.haml +++ b/app/views/dashboard/show.html.haml @@ -7,6 +7,3 @@ - else = render "zero_authorized_projects" - -:javascript - dashboardPage(); diff --git a/app/views/deploy_keys/index.html.haml b/app/views/deploy_keys/index.html.haml index 66a8d3b7b7b..8fa9d5f3bca 100644 --- a/app/views/deploy_keys/index.html.haml +++ b/app/views/deploy_keys/index.html.haml @@ -1,7 +1,7 @@ = render "projects/settings_nav" %p.slead - Deploy keys allow read-only access to repository. They can be used for for CI, staging or production servers. A deploy key can be added to only one project. If you need to add the same key to multiple projects you can create a deploy user and add that user to multiple projects. + Deploy keys allow read-only access to repository. They can be used for CI, staging or production servers. A deploy key can be added to only one project. If you need to add the same key to multiple projects you can create a deploy user and add that user to multiple projects. - if can? current_user, :admin_project, @project = link_to new_project_deploy_key_path(@project), class: "btn btn-small", title: "New Deploy Key" do diff --git a/app/views/devise/sessions/_new_ldap.html.haml b/app/views/devise/sessions/_new_ldap.html.haml index eb8c5194607..29ba9c1e99c 100644 --- a/app/views/devise/sessions/_new_ldap.html.haml +++ b/app/views/devise/sessions/_new_ldap.html.haml @@ -1,29 +1,29 @@ -= form_tag(user_omniauth_callback_path(:ldap), :class => "login-box", :id => 'new_ldap_user' ) do - = image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" - = text_field_tag :username, nil, {:class => "text top", :placeholder => "LDAP Login", :autofocus => "autofocus"} - = password_field_tag :password, nil, {:class => "text bottom", :placeholder => "Password"} += form_tag(user_omniauth_callback_path(:ldap), class: "login-box", id: 'new_ldap_user' ) do + = image_tag "login-logo.png", width: "304", height: "66", class: "login-logo", alt: "Login Logo" + = text_field_tag :username, nil, {class: "text top", placeholder: "LDAP Login", autofocus: "autofocus"} + = password_field_tag :password, nil, {class: "text bottom", placeholder: "Password"} %br/ - = submit_tag "LDAP Sign in", :class => "btn-primary btn" + = submit_tag "LDAP Sign in", class: "btn-primary btn" - if devise_mapping.omniauthable? - (resource_class.omniauth_providers - [:ldap]).each do |provider| %hr/ - = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn btn-primary" + = link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), class: "btn btn-primary" %br/ %hr/ - %a#other_form_toggle{:href => "#", :onclick => "javascript:$('#new_user').toggle();"} Other Sign in + %a#other_form_toggle{href: "#", onclick: "javascript:$('#new_user').toggle();"} Other Sign in :javascript $(function() { $('#new_user').toggle(); }); -= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| - = f.text_field :email, :class => "text top", :placeholder => "Email" - = f.password_field :password, :class => "text bottom", :placeholder => "Password" += form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: "login-box" }) do |f| + = f.text_field :login, class: "text top", placeholder: "Username or Email", autofocus: "autofocus" + = f.password_field :password, class: "text bottom", placeholder: "Password" - if devise_mapping.rememberable? .clearfix.inputs-list - %label.checkbox.remember_me{:for => "user_remember_me"} + %label.checkbox.remember_me{for: "user_remember_me"} = f.check_box :remember_me %span Remember me %br/ - = f.submit "Sign in", :class => "btn-primary btn" + = f.submit "Sign in", class: "btn-primary btn" .pull-right - = render :partial => "devise/shared/links" + = render partial: "devise/shared/links" diff --git a/app/views/graph/show.html.haml b/app/views/graph/show.html.haml index e45aca1ddcb..682d2798906 100644 --- a/app/views/graph/show.html.haml +++ b/app/views/graph/show.html.haml @@ -7,11 +7,10 @@ :javascript var branch_graph; - $(function(){ - branch_graph = new BranchGraph($("#holder"), { - url: '#{project_graph_path(@project, @ref, q: @q, format: :json)}', - commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}', - ref: '#{@ref}', - commit_id: '#{@commit.id}' - }); + + branch_graph = new BranchGraph($("#holder"), { + url: '#{project_graph_path(@project, @ref, q: @q, format: :json)}', + commit_url: '#{project_commit_path(@project, 'ae45ca32').gsub("ae45ca32", "%s")}', + ref: '#{@ref}', + commit_id: '#{@commit.id}' }); diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml index 62d640c8532..1ce008f7e85 100644 --- a/app/views/groups/show.html.haml +++ b/app/views/groups/show.html.haml @@ -23,10 +23,4 @@ News Feed %hr - .gitlab-promo - = link_to "Homepage", "http://gitlabhq.com" - = link_to "Blog", "http://blog.gitlabhq.com" - = link_to "@gitlabhq", "https://twitter.com/gitlabhq" - -:javascript - $(function(){ Pager.init(20, true); }); + = render 'shared/promo' diff --git a/app/views/issues/_form.html.haml b/app/views/issues/_form.html.haml index 6d7613a700d..ae386961948 100644 --- a/app/views/issues/_form.html.haml +++ b/app/views/issues/_form.html.haml @@ -19,7 +19,7 @@ = f.label :assignee_id do %i.icon-user Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) + .input= f.select(:assignee_id, @project.users.alphabetically.collect {|p| [ p.name, p.id ] }, { include_blank: "Select a user" }, {class: 'chosen'}) .issue_milestone.pull-left = f.label :milestone_id do %i.icon-time diff --git a/app/views/issues/index.html.haml b/app/views/issues/index.html.haml index 4edc1d9b912..bf33769349a 100644 --- a/app/views/issues/index.html.haml +++ b/app/views/issues/index.html.haml @@ -4,7 +4,7 @@ Issues %span (<span class=issue_counter>#{@issues.total_count}</span>) .pull-right - .span5 + .span6 - if can? current_user, :write_issue, @project = link_to new_project_issue_path(@project, issue: { assignee_id: params[:assignee_id], milestone_id: params[:milestone_id]}), class: "btn btn-primary pull-right", title: "New Issue", id: "new_issue_link" do %i.icon-plus @@ -23,8 +23,3 @@ = render 'filter', entity: 'issue' .span9.issues-holder = render "issues" - -:javascript - $(function(){ - Issues.init(); - }) diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml index 8f6873e1dfc..b43650459d8 100644 --- a/app/views/layouts/_head_panel.html.haml +++ b/app/views/layouts/_head_panel.html.haml @@ -9,6 +9,11 @@ %h1.project_name= title %ul.nav %li + %a + %div.hide.turbolink-spinner + %i.icon-refresh.icon-spin + Loading... + %li = render "layouts/search" %li = link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml index c484af04704..16f52270902 100644 --- a/app/views/layouts/_search.html.haml +++ b/app/views/layouts/_search.html.haml @@ -3,11 +3,4 @@ = text_field_tag "search", nil, placeholder: "Search", class: "search-input" = hidden_field_tag :group_id, @group.try(:id) = hidden_field_tag :project_id, @project.try(:id) - -:javascript - $(function(){ - $("#search").autocomplete({ - source: #{raw search_autocomplete_source}, - select: function(event, ui) { location.href = ui.item.url } - }); - }); + .search-autocomplete-json.hide{:'data-autocomplete-opts' => search_autocomplete_source } diff --git a/app/views/layouts/admin.html.haml b/app/views/layouts/admin.html.haml index abe3f2ea854..3a23cbdb376 100644 --- a/app/views/layouts/admin.html.haml +++ b/app/views/layouts/admin.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: "Admin area" - %body{class: "#{app_theme} admin"} + %body{class: "#{app_theme} admin", :'data-page' => body_data_page} = render "layouts/head_panel", title: "Admin area" = render "layouts/flash" %nav.main-nav diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 4e6831406e3..792fe5e4a28 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: "Dashboard" - %body{class: "#{app_theme} application"} + %body{class: "#{app_theme} application", :'data-page' => body_data_page } = render "layouts/head_panel", title: "Dashboard" = render "layouts/flash" %nav.main-nav diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml index 8296b8ae9a8..0e955d59ff8 100644 --- a/app/views/layouts/group.html.haml +++ b/app/views/layouts/group.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: "#{@group.name}" - %body{class: "#{app_theme} application"} + %body{class: "#{app_theme} application", :'data-page' => body_data_page} = render "layouts/head_panel", title: "group: #{@group.name}" = render "layouts/flash" %nav.main-nav diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml index 535f94c4ef6..30a0532bc2b 100644 --- a/app/views/layouts/profile.html.haml +++ b/app/views/layouts/profile.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: "Profile" - %body{class: "#{app_theme} profile"} + %body{class: "#{app_theme} profile", :'data-page' => body_data_page} = render "layouts/head_panel", title: "Profile" = render "layouts/flash" %nav.main-nav diff --git a/app/views/layouts/project_resource.html.haml b/app/views/layouts/project_resource.html.haml index 7b0d4789f8e..1fc36410668 100644 --- a/app/views/layouts/project_resource.html.haml +++ b/app/views/layouts/project_resource.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: @project.name_with_namespace - %body{class: "#{app_theme} project"} + %body{class: "#{app_theme} project", :'data-page' => body_data_page, :'data-project-id' => @project.id } = render "layouts/head_panel", title: project_title(@project) = render "layouts/flash" - if can?(current_user, :download_code, @project) diff --git a/app/views/layouts/user_team.html.haml b/app/views/layouts/user_team.html.haml index f2ead9d242a..e64e68d2446 100644 --- a/app/views/layouts/user_team.html.haml +++ b/app/views/layouts/user_team.html.haml @@ -1,7 +1,7 @@ !!! 5 %html{ lang: "en"} = render "layouts/head", title: "#{@team.name}" - %body{class: "#{app_theme} application"} + %body{class: "#{app_theme} application", :'data-page' => body_data_page} = render "layouts/head_panel", title: "team: #{@team.name}" = render "layouts/flash" %nav.main-nav diff --git a/app/views/merge_requests/_form.html.haml b/app/views/merge_requests/_form.html.haml index 6d64988c15a..1c3aca176ab 100644 --- a/app/views/merge_requests/_form.html.haml +++ b/app/views/merge_requests/_form.html.haml @@ -40,7 +40,7 @@ = f.label :assignee_id do %i.icon-user Assign to - .input= f.select(:assignee_id, @project.users.all.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) + .input= f.select(:assignee_id, @project.users.alphabetically.collect {|p| [ p.name, p.id ] }, { include_blank: "Select user" }, {class: 'chosen span3'}) .left = f.label :milestone_id do %i.icon-time diff --git a/app/views/merge_requests/_show.html.haml b/app/views/merge_requests/_show.html.haml index 08b80172645..d6e00ca9b8b 100644 --- a/app/views/merge_requests/_show.html.haml +++ b/app/views/merge_requests/_show.html.haml @@ -26,14 +26,12 @@ :javascript var merge_request; - $(function(){ - merge_request = new MergeRequest({ - url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", - 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.merge_status_name}", - action: "#{controller.action_name}" - }); - }); + merge_request = new MergeRequest({ + url_to_automerge_check: "#{automerge_check_project_merge_request_path(@project, @merge_request)}", + 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.merge_status_name}", + action: "#{controller.action_name}" + }); diff --git a/app/views/merge_requests/show/_how_to_merge.html.haml b/app/views/merge_requests/show/_how_to_merge.html.haml index 69881d4352f..7f1e33418de 100644 --- a/app/views/merge_requests/show/_how_to_merge.html.haml +++ b/app/views/merge_requests/show/_how_to_merge.html.haml @@ -3,22 +3,17 @@ %a.close{href: "#"} × %h3 How To Merge .modal-body + %p + %strong Step 1. + Checkout target branch and get recent objects from GitLab %pre.dark - = preserve do + :preserve git checkout #{@merge_request.target_branch} git fetch origin + %p + %strong Step 2. + Merge source branch into target branch and push changes to GitLab + %pre.dark + :preserve git merge origin/#{@merge_request.source_branch} git push origin #{@merge_request.target_branch} - - -:javascript - $(function(){ - var modal = $('#modal_merge_info').modal({modal: true, show:false}); - $('.how_to_merge_link').bind("click", function(){ - modal.show(); - }); - $('.modal-header .close').bind("click", function(){ - modal.hide(); - }) - }) - diff --git a/app/views/merge_requests/show/_mr_box.html.haml b/app/views/merge_requests/show/_mr_box.html.haml index 3b54f613f58..594f4061c23 100644 --- a/app/views/merge_requests/show/_mr_box.html.haml +++ b/app/views/merge_requests/show/_mr_box.html.haml @@ -1,13 +1,13 @@ .ui-box.ui-box-show .ui-box-head %h4.box-title + = gfm escape_once(@merge_request.title) - if @merge_request.merged? - .error.status_info + .success.status_info %i.icon-ok Merged - elsif @merge_request.closed? .error.status_info Closed - = gfm escape_once(@merge_request.title) .ui-box-body %div @@ -22,13 +22,15 @@ - if @merge_request.closed? - .ui-box-bottom + .ui-box-bottom.alert-error %span + %i.icon-remove Closed by #{link_to_member(@project, @merge_request.closed_event.author)} %small #{time_ago_in_words(@merge_request.closed_event.created_at)} ago. - if @merge_request.merged? - .ui-box-bottom + .ui-box-bottom.alert-success %span + %i.icon-ok Merged by #{link_to_member(@project, @merge_request.merge_event.author)} - %small #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. + #{time_ago_in_words(@merge_request.merge_event.created_at)} ago. diff --git a/app/views/merge_requests/show/_mr_ci.html.haml b/app/views/merge_requests/show/_mr_ci.html.haml index a8faa6ba617..9b15c4526e9 100644 --- a/app/views/merge_requests/show/_mr_ci.html.haml +++ b/app/views/merge_requests/show/_mr_ci.html.haml @@ -1,4 +1,4 @@ -- if @merge_request.opened? && @commits.any? +- if @commits.any? .ci_widget.ci-success{style: "display:none"} .alert.alert-success %i.icon-ok diff --git a/app/views/milestones/_milestone.html.haml b/app/views/milestones/_milestone.html.haml index 8a3727c6f6a..894fa6c1133 100644 --- a/app/views/milestones/_milestone.html.haml +++ b/app/views/milestones/_milestone.html.haml @@ -4,6 +4,8 @@ = link_to edit_project_milestone_path(milestone.project, milestone), class: "btn btn-small edit-milestone-link grouped" do %i.icon-edit Edit + - if milestone.can_be_closed? + = link_to 'Close', project_milestone_path(@project, milestone, milestone: {state_event: :close }), method: :put, remote: true, class: "btn btn-small btn-remove" %h4 = link_to_gfm truncate(milestone.title, length: 100), project_milestone_path(milestone.project, milestone) - if milestone.expired? and not milestone.closed? @@ -13,11 +15,8 @@ - if milestone.is_empty? %span.muted Empty - else - .row - .span4 - .progress.progress-info - .bar{style: "width: #{milestone.percent_complete}%;"} - .span6 + %div + %div = link_to project_issues_path(milestone.project, milestone_id: milestone.id) do = pluralize milestone.issues.count, 'Issue' @@ -25,3 +24,5 @@ = pluralize milestone.merge_requests.count, 'Merge Request' %span.light #{milestone.percent_complete}% complete + .progress.progress-info + .bar{style: "width: #{milestone.percent_complete}%;"} diff --git a/app/views/milestones/index.html.haml b/app/views/milestones/index.html.haml index b78f17053fd..89892cd23f1 100644 --- a/app/views/milestones/index.html.haml +++ b/app/views/milestones/index.html.haml @@ -3,11 +3,14 @@ %h3.page_title Milestones - if can? current_user, :admin_milestone, @project - = link_to "New Milestone", new_project_milestone_path(@project), class: "pull-right btn btn-small", title: "New Milestone" + = link_to new_project_milestone_path(@project), class: "pull-right btn btn-primary", title: "New Milestone" do + %i.icon-plus + New Milestone %br - %div.ui-box - .title - %ul.nav.nav-pills + + .row + .span3 + %ul.nav.nav-pills.nav-stacked %li{class: ("active" if (params[:f] == "active" || !params[:f]))} = link_to project_milestones_path(@project, f: "active") do Active @@ -17,12 +20,13 @@ %li{class: ("active" if params[:f] == "all")} = link_to project_milestones_path(@project, f: "all") do All + .span9 + %div.ui-box + %ul.well-list + = render @milestones - %ul.well-list - = render @milestones - - - if @milestones.present? - %li.bottom= paginate @milestones, theme: "gitlab" - - else - %li - %h3.nothing_here_message Nothing to show here + - if @milestones.present? + %li.bottom= paginate @milestones, theme: "gitlab" + - else + %li + %h3.nothing_here_message Nothing to show here diff --git a/app/views/milestones/show.html.haml b/app/views/milestones/show.html.haml index 30539af48d8..034c37852f1 100644 --- a/app/views/milestones/show.html.haml +++ b/app/views/milestones/show.html.haml @@ -1,3 +1,4 @@ += render "issues/head" .row .span6 %h3.page_title @@ -87,7 +88,6 @@ %h6 Participants: %div - @users.each do |user| - = link_to user do - = link_to_member(@project, user) + = link_to_member(@project, user) .clearfix diff --git a/app/views/milestones/update.js.haml b/app/views/milestones/update.js.haml new file mode 100644 index 00000000000..3ff84915e97 --- /dev/null +++ b/app/views/milestones/update.js.haml @@ -0,0 +1,2 @@ +:plain + $('##{dom_id(@milestone)}').fadeOut(); diff --git a/app/views/notes/_notes_with_form.html.haml b/app/views/notes/_notes_with_form.html.haml index 2566edd81ad..38d1a3c93c0 100644 --- a/app/views/notes/_notes_with_form.html.haml +++ b/app/views/notes/_notes_with_form.html.haml @@ -6,6 +6,4 @@ = render "notes/form" :javascript - $(function(){ - NoteList.init("#{@target_id}", "#{@target_type}", "#{project_notes_path(@project)}"); - }); + NoteList.init("#{@target_id}", "#{@target_type}", "#{project_notes_path(@project)}"); diff --git a/app/views/notifications/show.html.haml b/app/views/notifications/show.html.haml index 38e492f2d1b..b7f39306fd8 100644 --- a/app/views/notifications/show.html.haml +++ b/app/views/notifications/show.html.haml @@ -15,7 +15,7 @@ .row .span4 - %h5 Global + %h5 Global setting .span7 = form_tag profile_notifications_path, method: :put, remote: true, class: 'update-notifications' do = hidden_field_tag :notification_type, 'global' @@ -36,7 +36,7 @@ = link_to '#', class: 'js-toggle-visibility-link' do %h6.btn.btn-tiny %i.icon-chevron-down - %span Per project notifications settings + %span Per project notifications setting %ul.well-list.js-toggle-visibility-container.hide - @users_projects.each do |users_project| @@ -53,7 +53,7 @@ = label_tag do = radio_button_tag :notification_level, Notification::N_GLOBAL, notification.global?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' - %span Use global settings + %span Use global setting = label_tag do = radio_button_tag :notification_level, Notification::N_DISABLED, notification.disabled?, id: dom_id(users_project, 'notification_level'), class: 'trigger-submit' diff --git a/app/views/profiles/design.html.haml b/app/views/profiles/design.html.haml index 77068dabb32..878297fe49d 100644 --- a/app/views/profiles/design.html.haml +++ b/app/views/profiles/design.html.haml @@ -55,3 +55,8 @@ = image_tag "solarized_dark.png" = f.radio_button :color_scheme_id, 3 Solarized Dark + = label_tag do + .prev + = image_tag "monokai.png" + = f.radio_button :color_scheme_id, 4 + Monokai diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index f63729ffdf6..d4793da8987 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -51,7 +51,7 @@ %legend Tips: %ul %li - %p You can change your password on Account page + %p You can change your password on the Account page - if Gitlab.config.gravatar.enabled %li %p You can change your avatar at #{link_to "gravatar.com", "http://gravatar.com"} diff --git a/app/views/projects/_clone_panel.html.haml b/app/views/projects/_clone_panel.html.haml index 7b90f80985c..02b09ab73d9 100644 --- a/app/views/projects/_clone_panel.html.haml +++ b/app/views/projects/_clone_panel.html.haml @@ -1,20 +1,42 @@ .project_clone_panel .row - .span7 + .span8 .form-horizontal= render "shared/clone_panel" - .span4.pull-right + .span3.pull-right .pull-right - unless @project.empty_repo? - if can? current_user, :fork_project, @project = link_to fork_project_path(@project), title: "Fork", class: "btn small grouped", method: "POST" do Fork - if can? current_user, :download_code, @project - = link_to archive_project_repository_path(@project), class: "btn-small btn grouped" do + = link_to archive_project_repository_path(@project), class: "btn grouped" do %i.icon-download-alt Download - - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project) - = link_to new_project_merge_request_path(@project), title: "New Merge Request", class: "btn-small btn grouped" do - Merge Request - - if @project.issues_enabled && can?(current_user, :write_issue, @project) - = link_to url_for_new_issue, title: "New Issue", class: "btn-small btn grouped" do - Issue + + = link_to tags_project_repository_path(@project), class: "btn grouped only-wide", title: 'Git Tags' do + %i.icon-tags + + .dropdown.pull-right + %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"} + %i.icon-plus + Add new + %b.caret + %ul.dropdown-menu + - if @project.issues_enabled && can?(current_user, :write_issue, @project) + %li + = link_to url_for_new_issue, title: "New Issue" do + Issue + - if @project.merge_requests_enabled && can?(current_user, :write_merge_request, @project) + %li + = link_to new_project_merge_request_path(@project), title: "New Merge Request" do + Merge Request + - if @project.snippets_enabled && can?(current_user, :write_snippet, @project) + %li + = link_to new_project_snippet_path(@project), title: "New Snippet" do + Snippet + - if can?(current_user, :admin_team_member, @project) + %li.divider + %li + = link_to new_project_team_member_path(@project), title: "New Team member" do + Team member + diff --git a/app/views/projects/_form.html.haml b/app/views/projects/_form.html.haml index 4d51e10dc3e..4d635e3dc68 100644 --- a/app/views/projects/_form.html.haml +++ b/app/views/projects/_form.html.haml @@ -59,6 +59,15 @@ %fieldset.features %legend + Labels: + .control-group + = f.label :label_list, "Labels", class: 'control-label' + .controls + = f.text_field :label_list, maxlength: 2000, class: "span5" + %p.hint Separate with comma. + + %fieldset.features + %legend Features: .control-group = f.label :issues_enabled, "Issues", class: 'control-label' diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml index c050f9454a5..e215ad6fd73 100644 --- a/app/views/projects/edit.html.haml +++ b/app/views/projects/edit.html.haml @@ -8,6 +8,3 @@ %center = image_tag "ajax_loader.gif" %h3 Saving project. Please wait a moment, this page will automatically refresh when ready. - -:javascript - $(function(){ new Projects(); }); diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index eb4ef5979cf..8ff873aac65 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -7,6 +7,3 @@ %center = image_tag "ajax_loader.gif" %h3 Creating project & repository. Please wait a moment, this page will automatically refresh when ready. - -:javascript - $(function(){ new Projects(); }); diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index 824d4daf698..6edfd2ed401 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -1,32 +1,19 @@ = render 'clone_panel' -= render "events/event_last_push", event: @last_push .row .span9 + = render "events/event_last_push", event: @last_push .content_list= render @events .loading.hide .span3 - .ui-box.white - .padded - %h3.page_title - = @project.name - - if @project.description.present? - %p.light= @project.description + .light-well + %h3.page_title + = @project.name + - if @project.description.present? + %p.light= @project.description - %hr - %p - Access level: - - if @project.public - %span.cblue - %i.icon-share - Public - - else - %span.cgreen - %i.icon-lock - Private - - %p Repo Size: #{@project.repository.size} MB - %p Created at: #{@project.created_at.stamp('Aug 22, 2013')} - %p Owner: #{link_to @project.owner_name, @project.owner} -:javascript - $(function(){ Pager.init(20); }); + %hr + %p + %p Repo Size: #{@project.repository.size} MB + %p Created at: #{@project.created_at.stamp('Aug 22, 2013')} + %p Owner: #{link_to @project.owner_name, @project.owner} diff --git a/app/views/projects/tree.js.haml b/app/views/projects/tree.js.haml deleted file mode 100644 index ba5d53c16a2..00000000000 --- a/app/views/projects/tree.js.haml +++ /dev/null @@ -1,5 +0,0 @@ -:plain - $("#tree-holder table").hide("slide", { direction: "left" }, 150, function(){ - $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {repo: @repo, commit: @commit, tree: @tree}))}"); - $("#tree-holder table").show("slide", { direction: "right" }, 150); - }); diff --git a/app/views/repositories/stats.html.haml b/app/views/repositories/stats.html.haml index d448c669271..6d1fb4686ea 100644 --- a/app/views/repositories/stats.html.haml +++ b/app/views/repositories/stats.html.haml @@ -27,9 +27,7 @@ :javascript - $(function(){ - var labels = [#{@graph.labels.to_json}]; - var commits = [#{@graph.commits.join(', ')}]; - var title = "Commit activity for last #{@graph.weeks} weeks"; - Chart.init(labels, commits, title); - }) + var labels = [#{@graph.labels.to_json}]; + var commits = [#{@graph.commits.join(', ')}]; + var title = "Commit activity for last #{@graph.weeks} weeks"; + Chart.init(labels, commits, title); diff --git a/app/views/shared/_clone_panel.html.haml b/app/views/shared/_clone_panel.html.haml index bd9ca729352..9e5b8dade56 100644 --- a/app/views/shared/_clone_panel.html.haml +++ b/app/views/shared/_clone_panel.html.haml @@ -1,4 +1,13 @@ -.input-prepend.project_clone_holder +.input-prepend.input-append.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", readonly: true + = text_field_tag :project_clone, @project.url_to_repo, class: "one_click_select span7", readonly: true + %span.add-on + - if @project.public + .cblue + %i.icon-share + public + - else + .cgreen + %i.icon-lock + private diff --git a/app/views/shared/_promo.html.haml b/app/views/shared/_promo.html.haml new file mode 100644 index 00000000000..c97f8ba0f0e --- /dev/null +++ b/app/views/shared/_promo.html.haml @@ -0,0 +1,4 @@ +.gitlab-promo + = link_to "Homepage", "http://gitlab.org" + = link_to "Blog", "http://blog.gitlab.org" + = link_to "@gitlabhq", "https://twitter.com/gitlabhq" diff --git a/app/views/team_members/_team.html.haml b/app/views/team_members/_team.html.haml index 2ec8c1a8451..4b49b308edc 100644 --- a/app/views/team_members/_team.html.haml +++ b/app/views/team_members/_team.html.haml @@ -1,8 +1,9 @@ - team.each do |access, members| - .ui-box + - role = Project.access_options.key(access).pluralize + .ui-box{class: role.downcase} %h5.title - = Project.access_options.key(access).pluralize - %small= members.size + = role + %span.light (#{members.size}) %ul.well-list - members.sort_by(&:user_name).each do |team_member| = render 'team_members/team_member', member: team_member diff --git a/app/views/team_members/_team_member.html.haml b/app/views/team_members/_team_member.html.haml index 2b0709beb92..5fd8d2465d1 100644 --- a/app/views/team_members/_team_member.html.haml +++ b/app/views/team_members/_team_member.html.haml @@ -16,11 +16,11 @@ = f.select :project_access, options_for_select(UsersProject.access_roles, member.project_access), {}, class: "medium project-access-select span2 trigger-submit" .pull-right - if current_user == user - %span.label This is you! + %span.label.label-success This is you! - if @project.namespace_owner == user - %span.label Owner + %span.label.label-info Owner - elsif user.blocked? - %span.label Blocked + %span.label.label-error Blocked - elsif allow_admin = link_to project_team_member_path(@project, user), confirm: remove_from_project_team_message(@project, user), method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from team' do %i.icon-minus.icon-white diff --git a/app/views/team_members/create.js.haml b/app/views/team_members/create.js.haml deleted file mode 100644 index b7dff35a269..00000000000 --- a/app/views/team_members/create.js.haml +++ /dev/null @@ -1,13 +0,0 @@ -- if @user_project_relation.valid? - :plain - $("#new_team_member").hide("slide", { direction: "right" }, 150, function(){ - $("#team-table").show("slide", { direction: "left" }, 150, function() { - $("#new_team_member").remove(); - $("#team-table").replaceWith("#{escape_javascript(render('projects/team'))}"); - $(".add_new").show(); - }); - }); -- else - :plain - $("#new_team_member").replaceWith("#{escape_javascript(render('form'))}"); - $('select#team_member_user_id').chosen(); diff --git a/app/views/teams/members/_show.html.haml b/app/views/teams/members/_show.html.haml index 1a323043d09..dc32acb4693 100644 --- a/app/views/teams/members/_show.html.haml +++ b/app/views/teams/members/_show.html.haml @@ -2,7 +2,7 @@ - allow_admin = can? current_user, :manage_user_team, @team %li{id: dom_id(member), class: "team_member_row user_#{user.id}"} .row - .span5 + .span4 = link_to user_path(user.username), title: user.name, class: "dark" do = image_tag gravatar_icon(user.email, 40), class: "avatar s32" = link_to user_path(user.username), title: user.name, class: "dark" do @@ -10,21 +10,22 @@ %br %small.cgray= user.username - .span4 + .span7.pull-right - if allow_admin - = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| - = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit" - %br - = label_tag do - = f.check_box :group_admin, class: 'trigger-submit' - %span Admin access - .pull-right - - if current_user == user - %span.btn.disabled This is you! - - if @team.owner == user - %span.btn.disabled Owner - - elsif user.blocked? - %span.btn.disabled.blocked Blocked - - elsif allow_admin - = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do - %i.icon-minus.icon-white + .pull-left + = form_for(member, as: :team_member, url: team_member_path(@team, user)) do |f| + = label_tag do + = f.check_box :group_admin, class: 'trigger-submit' + %span Admin access + + = f.select :permission, options_for_select(UsersProject.access_roles, @team.default_projects_access(user)), {}, class: "medium trigger-submit" + .pull-right + - if current_user == user + %span.btn.disabled This is you! + - if @team.owner == user + %span.btn.disabled Owner + - elsif user.blocked? + %span.btn.disabled.blocked Blocked + - elsif allow_admin + = link_to team_member_path(@team, user), confirm: remove_from_user_team_message(@team, user), method: :delete, class: "btn-tiny btn btn-remove", title: "Remove from team" do + %i.icon-minus.icon-white diff --git a/app/views/teams/members/new.html.haml b/app/views/teams/members/new.html.haml index 9b9b3cef59b..99530ebb7f0 100644 --- a/app/views/teams/members/new.html.haml +++ b/app/views/teams/members/new.html.haml @@ -1,29 +1,25 @@ %h3.page_title Team: #{@team.name} -%fieldset - %legend Members (#{@team.members.count}) - = form_tag team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do - %table#members_list - %thead - %tr - %th User name - %th Default project access - %th Team access - %th - - @team.members.each do |member| - %tr.member - %td - = member.name - %small= "(#{member.username})" - %td= @team.human_default_projects_access(member) - %td= @team.admin?(member) ? "Admin" : "Member" - %td - %tr - %td - = users_select_tag(:user_ids, multiple: true) - %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } - %td - %span= check_box_tag :group_admin - %span Admin? - %td= submit_tag 'Add User', class: "btn btn-create", id: :add_members_to_team +%hr + += form_tag team_members_path(@team), id: "team_members", class: "bulk_import", method: :post do + %h6 1. Choose people you want in the team + .clearfix + = label_tag :user_ids, "People" + .input + = users_select_tag(:user_ids, multiple: true) + + %h6 2. Set access level for them + .clearfix + = label_tag :project_access, "Project Access" + .input= select_tag :default_project_access, options_for_select(Project.access_options), class: "project-access-select chosen" + + .clearfix + = label_tag :group_admin do + %span Team Admin? + .input= check_box_tag :group_admin + + .actions + = submit_tag 'Add users', class: "btn btn-create", id: :add_members_to_team + = link_to "Cancel", team_members_path(@team), class: "btn btn-cancel" diff --git a/app/views/teams/show.html.haml b/app/views/teams/show.html.haml index 88cffa011ed..2ad7f743010 100644 --- a/app/views/teams/show.html.haml +++ b/app/views/teams/show.html.haml @@ -22,10 +22,4 @@ News Feed %hr - .gitlab-promo - = link_to "Homepage", "http://gitlabhq.com" - = link_to "Blog", "http://blog.gitlabhq.com" - = link_to "@gitlabhq", "https://twitter.com/gitlabhq" - -:javascript - $(function(){ Pager.init(20, true); }); + = render 'shared/promo' diff --git a/app/views/tree/_tree.html.haml b/app/views/tree/_tree.html.haml index f77b8983726..cc45faa1459 100644 --- a/app/views/tree/_tree.html.haml +++ b/app/views/tree/_tree.html.haml @@ -17,7 +17,15 @@ %tr %th Name %th Last Update - %th Last Commit + %th + Last Commit + + %i.icon-angle-right + + %small.light + = link_to @commit.short_id, project_commit_path(@project, @commit) + – + = truncate(@commit.title, length: 50) %th= link_to "history", project_commits_path(@project, @id), class: "btn btn-tiny pull-right" - if tree.up_dir? @@ -38,6 +46,6 @@ :javascript // Load last commit log for each file in tree - $(window).load(function(){ + $('#tree-slider').waitForImages(function() { ajaxGet('#{@logs_path}'); }); diff --git a/app/views/tree/show.js.haml b/app/views/tree/show.js.haml deleted file mode 100644 index a01d49179b9..00000000000 --- a/app/views/tree/show.js.haml +++ /dev/null @@ -1,10 +0,0 @@ -:plain - // Load Files list - $("#tree-holder").html("#{escape_javascript(render(partial: "tree", locals: {tree: @tree}))}"); - $("#tree-content-holder").show("slide", { direction: "right" }, 400); - $('.project-refs-form #path').val("#{@path}"); - - // Load last commit log for each file in tree - $('#tree-slider').waitForImages(function() { - ajaxGet('#{@logs_path}'); - }); diff --git a/app/views/walls/show.html.haml b/app/views/walls/show.html.haml index 139e66f5dd0..88aecee0815 100644 --- a/app/views/walls/show.html.haml +++ b/app/views/walls/show.html.haml @@ -21,8 +21,3 @@ .hint.pull-right CTRL + Enter to send message .clearfix - -:javascript - $(function(){ - Wall.init(#{@project.id}); - }); diff --git a/app/views/wikis/_nav.html.haml b/app/views/wikis/_nav.html.haml index 0dffdd8fc14..09a1986e105 100644 --- a/app/views/wikis/_nav.html.haml +++ b/app/views/wikis/_nav.html.haml @@ -11,8 +11,8 @@ Git Access - if can?(current_user, :write_wiki, @project) - %li.pull-right - = link_to '#', class: "add-new-wiki" do + .pull-right + = link_to '#', class: "add-new-wiki btn btn-small btn-primary" do %i.icon-plus New Page diff --git a/app/views/wikis/_new.html.haml b/app/views/wikis/_new.html.haml index 50b40bff41c..ca8e7c1b4b4 100644 --- a/app/views/wikis/_new.html.haml +++ b/app/views/wikis/_new.html.haml @@ -1,25 +1,12 @@ %div#modal-new-wiki.modal.hide .modal-header %a.close{href: "#"} × - %h3 New Wiki Page + %h3.page_title New Wiki Page .modal-body = label_tag :new_wiki_path do %span Page slug - = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'input-xlarge' + = text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'input-xlarge', required: true, :'data-wikis-path' => project_wikis_path(@project) + %p.hint + Please dont use spaces and slashes .modal-footer = link_to 'Build', '#', class: 'build-new-wiki btn btn-create' - -:javascript - $(function(){ - var modal = $('#modal-new-wiki').modal({modal: true, show:false}); - $('.add-new-wiki').bind("click", function(){ - modal.show(); - }); - $('.build-new-wiki').bind("click", function(){ - location.href = "#{project_wikis_path(@project)}/" + $('#new_wiki_path').val(); - }); - $('.modal-header .close').bind("click", function(){ - modal.hide(); - }) - }) - diff --git a/app/workers/post_receive.rb b/app/workers/post_receive.rb index 132f1a6d7e9..6416aa608ec 100644 --- a/app/workers/post_receive.rb +++ b/app/workers/post_receive.rb @@ -1,5 +1,6 @@ class PostReceive include Sidekiq::Worker + include Gitlab::Identifier sidekiq_options queue: :post_receive @@ -8,7 +9,7 @@ class PostReceive if repo_path.start_with?(Gitlab.config.gitlab_shell.repos_path.to_s) repo_path.gsub!(Gitlab.config.gitlab_shell.repos_path.to_s, "") else - Gitlab::GitLogger.error("POST-RECEIVE: Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"") + log("Check gitlab.yml config for correct gitlab_shell.repos_path variable. \"#{Gitlab.config.gitlab_shell.repos_path}\" does not match \"#{repo_path}\"") end repo_path.gsub!(/.git$/, "") @@ -17,31 +18,21 @@ class PostReceive project = Project.find_with_namespace(repo_path) if project.nil? - Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing project with full path \"#{repo_path} \"") + log("Triggered hook for non-existing project with full path \"#{repo_path} \"") return false end - user = if identifier.blank? - # Local push from gitlab - email = project.repository.commit(newrev).author_email rescue nil - User.find_by_email(email) if email - - elsif identifier =~ /\Auser-\d+\Z/ - # git push over http - user_id = identifier.gsub("user-", "") - User.find_by_id(user_id) - - elsif identifier =~ /\Akey-\d+\Z/ - # git push over ssh - key_id = identifier.gsub("key-", "") - Key.find_by_id(key_id).try(:user) - end + user = identify(identifier, project, newrev) unless user - Gitlab::GitLogger.error("POST-RECEIVE: Triggered hook for non-existing user \"#{identifier} \"") + log("Triggered hook for non-existing user \"#{identifier} \"") return false end GitPushService.new.execute(project, user, oldrev, newrev, ref) end + + def log(message) + Gitlab::GitLogger.error("POST-RECEIVE: #{message}") + end end diff --git a/config/aws.yml.example b/config/aws.yml.example new file mode 100644 index 00000000000..29d029b078d --- /dev/null +++ b/config/aws.yml.example @@ -0,0 +1,19 @@ +# See https://github.com/jnicklas/carrierwave#using-amazon-s3 +# for more options +production: + access_key_id: AKIA1111111111111UA + secret_access_key: secret + bucket: mygitlab.production.us + region: us-east-1 + +development: + access_key_id: AKIA1111111111111UA + secret_access_key: secret + bucket: mygitlab.development.us + region: us-east-1 + +test: + access_key_id: AKIA1111111111111UA + secret_access_key: secret + bucket: mygitlab.test.us + region: us-east-1 diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 90d04b390c3..0ba8b5d211f 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -37,6 +37,13 @@ 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 + ## Default project features settings + default_projects_features: + issues: true + merge_requests: true + wiki: true + wall: false + snippets: false ## External issues trackers issues_tracker: @@ -159,7 +166,7 @@ test: redmine: project_url: "http://redmine/projects/:issues_tracker_id" issues_url: "http://redmine/:project_id/:issues_tracker_id/:id" - new_issue_url: "http://redmine/projects/:issues_tracker_id/insues/new" + new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new" staging: <<: *base diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index ac35eef4218..be5393b0483 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -60,6 +60,12 @@ Settings.gitlab['url'] ||= Settings.send(:build_gitlab_url) Settings.gitlab['user'] ||= 'git' Settings.gitlab['signup_enabled'] ||= false Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil? +Settings.gitlab['default_projects_features'] ||= {} +Settings.gitlab.default_projects_features['issues'] = true if Settings.gitlab.default_projects_features['issues'].nil? +Settings.gitlab.default_projects_features['merge_requests'] = true if Settings.gitlab.default_projects_features['merge_requests'].nil? +Settings.gitlab.default_projects_features['wiki'] = true if Settings.gitlab.default_projects_features['wiki'].nil? +Settings.gitlab.default_projects_features['wall'] = false if Settings.gitlab.default_projects_features['wall'].nil? +Settings.gitlab.default_projects_features['snippets'] = false if Settings.gitlab.default_projects_features['snippets'].nil? # # Gravatar diff --git a/config/initializers/3_grit_ext.rb b/config/initializers/3_grit_ext.rb index 097c301a06a..2728f51c3ea 100644 --- a/config/initializers/3_grit_ext.rb +++ b/config/initializers/3_grit_ext.rb @@ -3,7 +3,3 @@ require 'pygments' Grit::Git.git_timeout = Gitlab.config.git.timeout Grit::Git.git_max_size = Gitlab.config.git.max_size - -Grit::Blob.class_eval do - include Linguist::BlobHelper -end diff --git a/config/initializers/5_backend.rb b/config/initializers/5_backend.rb index 7c2e7f39000..e60d9559c94 100644 --- a/config/initializers/5_backend.rb +++ b/config/initializers/5_backend.rb @@ -6,3 +6,6 @@ require Rails.root.join("lib", "gitlab", "backend", "shell") # GitLab shell adapter require Rails.root.join("lib", "gitlab", "backend", "shell_adapter") + +# Gitlab Git repos path +Gitlab::Git::Repository.repos_path = Gitlab.config.gitlab_shell.repos_path diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb index 9bb62f6d55a..6659c1a1f7c 100644 --- a/config/initializers/carrierwave.rb +++ b/config/initializers/carrierwave.rb @@ -1 +1,17 @@ CarrierWave::SanitizedFile.sanitize_regexp = /[^[:word:]\.\-\+]/ + +aws_file = Rails.root.join('config', 'aws.yml') + +if File.exists?(aws_file) + AWS_CONFIG = YAML.load(File.read(aws_file))[Rails.env] + + config.fog_credentials = { + provider: 'AWS', # required + aws_access_key_id: AWS_CONFIG['access_key_id'], # required + aws_secret_access_key: AWS_CONFIG['secret_access_key'], # required + region: AWS_CONFIG['region'], # optional, defaults to 'us-east-1' + } + config.fog_directory = AWS_CONFIG['bucket'] # required + config.fog_public = false # optional, defaults to true + config.fog_attributes = {'Cache-Control'=>'max-age=315576000'} # optional, defaults to {} +end diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example deleted file mode 100644 index 75945182806..00000000000 --- a/config/unicorn.rb.example +++ /dev/null @@ -1,68 +0,0 @@ -# uncomment and customize to run in non-root path -# note that config/gitlab.yml web path should also be changed -# ENV['RAILS_RELATIVE_URL_ROOT'] = "/gitlab" - -app_dir = File.expand_path '../../', __FILE__ -worker_processes 2 -working_directory app_dir - -# Load app into the master before forking workers for super-fast -# worker spawn times -preload_app true - -# nuke workers after 30 seconds (60 is the default) -timeout 30 - -# listen on a Unix domain socket and/or a TCP port, - -#listen 8080 # listen to port 8080 on all TCP interfaces -#listen "127.0.0.1:8080" # listen to port 8080 on the loopback interface -listen "#{app_dir}/tmp/sockets/gitlab.socket" - -pid "#{app_dir}/tmp/pids/unicorn.pid" -stderr_path "#{app_dir}/log/unicorn.stderr.log" -stdout_path "#{app_dir}/log/unicorn.stdout.log" - -# http://www.rubyenterpriseedition.com/faq.html#adapt_apps_for_cow -if GC.respond_to?(:copy_on_write_friendly=) - GC.copy_on_write_friendly = true -end - - -before_fork do |server, worker| - # the following is highly recommended for Rails + "preload_app true" - # as there's no need for the master process to hold a connection - defined?(ActiveRecord::Base) and ActiveRecord::Base.connection.disconnect! - - ## - # When sent a USR2, Unicorn will suffix its pidfile with .oldbin and - # immediately start loading up a new version of itself (loaded with a new - # version of our app). When this new Unicorn is completely loaded - # it will begin spawning workers. The first worker spawned will check to - # see if an .oldbin pidfile exists. If so, this means we've just booted up - # a new Unicorn and need to tell the old one that it can now die. To do so - # we send it a QUIT. - # - # Using this method we get 0 downtime deploys. - - old_pid = "#{server.config[:pid]}.oldbin" - - if File.exists?(old_pid) && server.pid != old_pid - begin - sig = (worker.nr + 1) >= server.worker_processes ? :QUIT : :TTOU - Process.kill(sig, File.read(old_pid).to_i) - rescue Errno::ENOENT, Errno::ESRCH - # someone else did our job for us - end - end -end - -after_fork do |server, worker| - # Unicorn master loads the app then forks off workers - because of the way - # Unix forking works, we need to make sure we aren't using any of the parent's - # sockets, e.g. db connection - - defined?(ActiveRecord::Base) and ActiveRecord::Base.establish_connection - # Redis and Memcached would go here but their connections are established - # on demand, so the master never opens a socket -end diff --git a/db/fixtures/development/02_source_code.rb b/db/fixtures/development/02_source_code.rb index a0a46c9e927..5ce5bcf4aba 100644 --- a/db/fixtures/development/02_source_code.rb +++ b/db/fixtures/development/02_source_code.rb @@ -1,3 +1,4 @@ +gitlab_shell_path = File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") root = Gitlab.config.gitlab_shell.repos_path projects = [ @@ -17,8 +18,7 @@ projects.each do |project| print '-' next end - - if system("/home/git/gitlab-shell/bin/gitlab-projects import-project #{project[:path]} #{project[:git]}") + if system("#{gitlab_shell_path}/gitlab-shell/bin/gitlab-projects import-project #{project[:path]} #{project[:git]}") print '.' else print 'F' diff --git a/doc/api/projects.md b/doc/api/projects.md index d6a9a8854ca..d3d15ab4e02 100644 --- a/doc/api/projects.md +++ b/doc/api/projects.md @@ -313,7 +313,7 @@ Removes a hook from project. This is an idempotent method and can be called mult Either the hook is available or not. ``` -DELETE /projects/:id/hooks/ +DELETE /projects/:id/hooks/:hook_id ``` Parameters: diff --git a/doc/api/users.md b/doc/api/users.md index c05bcb3e539..ee5e98a016c 100644 --- a/doc/api/users.md +++ b/doc/api/users.md @@ -1,6 +1,7 @@ ## List users Get a list of users. +This function takes pagination parameters `page` and `per_page` to restrict the list of users. ``` GET /users diff --git a/doc/install/installation.md b/doc/install/installation.md index 41202b09b74..9734034bf84 100644 --- a/doc/install/installation.md +++ b/doc/install/installation.md @@ -42,7 +42,7 @@ edited by hand. But, you can use any editor you like instead. Install the required packages: - sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl git-core openssh-server redis-server postfix checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev + sudo apt-get install -y build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl git-core openssh-server redis-server checkinstall libxml2-dev libxslt-dev libcurl4-openssl-dev libicu-dev Make sure you have the right version of Python installed. @@ -61,6 +61,11 @@ Make sure you have the right version of Python installed. # If you get a "command not found" error create a link to the python binary sudo ln -s /usr/bin/python /usr/bin/python2 +**Note:** In order to receive mail notifications, make sure to install a +mail server. By default, Debian is shipped with exim4 whereas Ubuntu +does not ship with one. The recommended mail server is postfix and you can install it with: + + sudo apt-get install postfix # 2. Ruby @@ -99,6 +104,10 @@ GitLab Shell is a ssh access and repository management software developed specia git clone https://github.com/gitlabhq/gitlab-shell.git cd gitlab-shell + + # switch to right version + git checkout v1.3.0 + cp config.yml.example config.yml # Edit config and replace gitlab_url @@ -128,10 +137,10 @@ To setup the MySQL/PostgreSQL database and dependencies please see [`doc/install cd /home/git/gitlab # Checkout to stable release - sudo -u git -H git checkout 5-0-stable + sudo -u git -H git checkout 5-1-stable **Note:** -You can change `5-0-stable` to `master` if you want the *bleeding edge* version, but +You can change `5-1-stable` to `master` if you want the *bleeding edge* version, but do so with caution! ## Configure it @@ -154,12 +163,14 @@ do so with caution! # Create directory for satellites sudo -u git -H mkdir /home/git/gitlab-satellites - # Create directory for pids and make sure GitLab can write to it + # Create directories for sockets/pids and make sure GitLab can write to them sudo -u git -H mkdir tmp/pids/ + sudo -u git -H mkdir tmp/sockets/ sudo chmod -R u+rwX tmp/pids/ + sudo chmod -R u+rwX tmp/sockets/ - # Copy the example Unicorn config - sudo -u git -H cp config/unicorn.rb.example config/unicorn.rb + # Copy the example Puma config + sudo -u git -H cp config/puma.rb.example config/puma.rb **Important Note:** Make sure to edit both files to match your setup. @@ -196,7 +207,7 @@ Make sure to update username/password in config/database.yml. Download the init script (will be /etc/init.d/gitlab): - sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/init.d/gitlab + sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlabhq/master/lib/support/init.d/gitlab sudo chmod +x /etc/init.d/gitlab Make GitLab start on boot: @@ -237,7 +248,7 @@ If you can't or don't want to use Nginx as your web server, have a look at the Download an example site config: - sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/master/nginx/gitlab + sudo curl --output /etc/nginx/sites-available/gitlab https://raw.github.com/gitlabhq/gitlabhq/master/lib/support/nginx/gitlab sudo ln -s /etc/nginx/sites-available/gitlab /etc/nginx/sites-enabled/gitlab Make sure to edit the config file to match your setup: diff --git a/doc/install/requirements.md b/doc/install/requirements.md index 9209fad571b..6b7b4bdab0b 100644 --- a/doc/install/requirements.md +++ b/doc/install/requirements.md @@ -45,7 +45,10 @@ We recommend a processor with **4 cores**. At a minimum you need a processor wit ## Memory -We recommend you to run GitLab on a server with at least **1GB of RAM** memory. You can use it with 512MB of memory but you need to setup unicorn to use only 1 worker and you need at least 200MB of swap. The minimal requirement for an unmodified installation is 768MB. With 1.5GB of memory you should be able to support 1000+ users. +- 512MB is too little memory, GitLab will be very slow you will need 250MB of swap +- 768MB is the minimal memory size and supports up to 100 users +- **1GB** is the **recommended** memory size and supports up to 1,000 users +- 1.5GB supports up to 10,000 users ## Storage diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md index b551470545c..338e885851d 100644 --- a/doc/raketasks/maintenance.md +++ b/doc/raketasks/maintenance.md @@ -11,31 +11,30 @@ Example output: ``` System information -System: Debian 6.0.6 -Current User: gitlab -Using RVM: yes -RVM Version: 1.17.2 -Ruby Version: ruby-1.9.3-p392 -Gem Version: 1.8.24 -Bundler Version:1.2.3 -Rake Version: 10.0.1 +System: Debian 6.0.7 +Current User: git +Using RVM: no +Ruby Version: 1.9.3p392 +Gem Version: 1.8.23 +Bundler Version:1.3.5 +Rake Version: 10.0.4 GitLab information -Version: 3.1.0 -Resivion: fd5141d -Directory: /home/gitlab/gitlab -DB Adapter: mysql2 -URL: http://localhost:3000 -HTTP Clone URL: http://localhost:3000/some-project.git -SSH Clone URL: git@localhost:some-project.git -Using LDAP: no -Using Omniauth: no +Version: 5.1.0.beta2 +Revision: 4da8b37 +Directory: /home/git/gitlab +DB Adapter: mysql2 +URL: http://localhost +HTTP Clone URL: http://localhost/some-project.git +SSH Clone URL: git@localhost:some-project.git +Using LDAP: no +Using Omniauth: no GitLab Shell -Version: 1.0.4 -Repositories: /home/git/repositories/ -Hooks: /home/git/gitlab-shell/hooks/ -Git: /usr/bin/git +Version: 1.2.0 +Repositories: /home/git/repositories/ +Hooks: /home/git/gitlab-shell/hooks/ +Git: /usr/bin/git ``` @@ -61,60 +60,43 @@ Example output: ``` Checking Environment ... -gitlab user is in git group? ... yes -Has no "-e" in ~git/.profile ... yes -Git configured for gitlab user? ... yes +Git configured for git user? ... yes Has python2? ... yes python2 is supported version? ... yes Checking Environment ... Finished -Checking Gitolite ... +Checking Gitlab Shell ... -Using recommended version ... yes -Config directory exists? ... yes -Config directory owned by git:git? ... yes -Config directory access is drwxr-x---? ... yes +GitLab Shell version? ... OK (1.2.0) Repo base directory exists? ... yes +Repo base directory is a symlink? ... no Repo base owned by git:git? ... yes Repo base access is drwxrws---? ... yes -post-receive hook exists? ... yes post-receive hook up-to-date? ... yes -post-receive hooks in repos are links: ... -GitLab ... ok -Non-Ascii Files Test ... ok -Touch Commit Test ... ok -Without Master Test ... ok -Git config in repos: ... -GitLab ... ok -Non-Ascii Files Test ... ok -Touch Commit Test ... ok -Without Master Test ... ok +post-receive hooks in repos are links: ... yes -Checking Gitolite ... Finished +Checking Gitlab Shell ... Finished -Checking Resque ... +Checking Sidekiq ... Running? ... yes -Checking Resque ... Finished +Checking Sidekiq ... Finished Checking GitLab ... Database config exists? ... yes -Database is not SQLite ... yes +Database is SQLite ... no All migrations up? ... yes GitLab config exists? ... yes -GitLab config not outdated? ... yes +GitLab config outdated? ... no Log directory writable? ... yes Tmp directory writable? ... yes Init script exists? ... yes Init script up-to-date? ... yes -Projects have satellites? ... -GitLab ... yes -Non-Ascii Files Test ... yes -Touch Commit Test ... yes -Without Master Test ... yes +Projects have satellites? ... yes +Redis version >= 2.0.0? ... yes Checking GitLab ... Finished ``` diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md index 021ce35931f..8fa2ed1311c 100644 --- a/doc/raketasks/user_management.md +++ b/doc/raketasks/user_management.md @@ -1,4 +1,4 @@ -### Add user to as a developer to all projects +### Add user as a developer to all projects ``` bundle exec rake gitlab:import:user_to_projects[username@domain.tld] diff --git a/doc/update/2.6-to-3.0.md b/doc/update/2.6-to-3.0.md new file mode 100644 index 00000000000..d7047d8eb19 --- /dev/null +++ b/doc/update/2.6-to-3.0.md @@ -0,0 +1,63 @@ +# From 2.6 to 3.0 + +### 1. Stop server & resque + + sudo service gitlab stop + +### 2. Update code & db + + +```bash +# Get latest code +git fetch origin +git checkout v3.0.3 + + +# Install libs +sudo -u gitlab bundle install --without development test postgres + +# update db +sudo -u gitlab bundle exec rake db:migrate RAILS_ENV=production + +# !!! Config should be replaced with a new one. Check it after replace +cp config/gitlab.yml.example config/gitlab.yml + +# update gitolite hooks + +# GITOLITE v2: +sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive +sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive + +# GITOLITE v3: +sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive +sudo chown git:git /home/git/.gitolite/hooks/common/post-receive + +# set valid path to hooks in gitlab.yml in git_host section +# like this +git_host: + # gitolite 2 + hooks_path: /home/git/share/gitolite/hooks + # gitolite 3 + hooks_path: /home/git/.gitolite/hooks/ + + +# Make some changes to gitolite config +# For more information visit https://github.com/gitlabhq/gitlabhq/pull/1719 + +# gitolite v2 +sudo -u git -H sed -i 's/\(GL_GITCONFIG_KEYS\s*=>*\s*\).\{2\}/\\1"\.\*"/g' /home/git/.gitolite.rc + +# gitlite v3 +sudo -u git -H sed -i "s/\(GIT_CONFIG_KEYS\s*=>*\s*\).\{2\}/\\1'\.\*'/g" /home/git/.gitolite.rc + + +# Check app status +sudo -u gitlab bundle exec rake gitlab:app:status RAILS_ENV=production + + +``` + + +### 3. Start all + + sudo service gitlab start diff --git a/doc/update/2.9-to-3.0.md b/doc/update/2.9-to-3.0.md new file mode 100644 index 00000000000..af929e027a4 --- /dev/null +++ b/doc/update/2.9-to-3.0.md @@ -0,0 +1,37 @@ +# From 2.9 to 3.0 + +### 1. Stop server & resque + + sudo service gitlab stop + +### 2. Follow instructions + +```bash + +# Get latest code +sudo -u gitlab -H git fetch origin +sudo -u gitlab -H git checkout v3.0.3 + +# Install gems +sudo -u gitlab -H bundle install --without development test postgres + +# Migrate db +sudo -u gitlab -H bundle exec rake db:migrate RAILS_ENV=production + +# Make some changes to gitolite v3 config +# For more information visit https://github.com/gitlabhq/gitlabhq/pull/1719 + +# Gitolite version 3 +sudo -u git -H sed -i "s/\(GIT_CONFIG_KEYS\s*=>*\s*\).\{2\}/\\1'\.\*'/g" /home/git/.gitolite.rc + +# If you still use gitolite v2 +sudo -u git -H sed -i 's/\(GL_GITCONFIG_KEYS\s*=>*\s*\).\{2\}/\\1"\.\*"/g' /home/git/.gitolite.rc + +# Check APP Status +sudo -u gitlab -H bundle exec rake gitlab:app:status RAILS_ENV=production +``` + + +### 3. Start all + + sudo service gitlab start diff --git a/doc/update/3.0-to-3.1.md b/doc/update/3.0-to-3.1.md new file mode 100644 index 00000000000..5f06f818d10 --- /dev/null +++ b/doc/update/3.0-to-3.1.md @@ -0,0 +1,108 @@ +# From 3.0 to 3.1 + +__IMPORTANT!__ + +In this release __we moved Resque jobs under own gitlab namespace__. + +Despite a lot of advantages it requires from our users to __replace gitolite post-receive hook with new one__. + +Most of projects has post-receive file as symlink to gitolite `/home/git/.gitolite/hooks/post-receive`. +But some of them may have a real file. In this case you should rewrite it with symlink to gitolite hook. + +I wrote a bash script which will do it automatically for you. Just make sure all path inside is valid for you + +- - - + +### 1. Stop server & resque + + sudo service gitlab stop + +### 2. Update GitLab + +```bash + +# Get latest code +sudo -u gitlab -H git fetch +sudo -u gitlab -H git checkout v3.1.0 + +# Install new charlock_holmes +sudo gem install charlock_holmes --version '0.6.9' + +# Install gems for MySQL +sudo -u gitlab -H bundle install --without development test postgres sqlite + + +# Migrate db +sudo -u gitlab -H bundle exec rake db:migrate RAILS_ENV=production + + +``` + +### 3. Update post-receive hooks + +#### Gitolite 3 + +Step 1: Rewrite post-receive hook + +```bash +# Rewrite hook for gitolite 3 +sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive +sudo chown git:git /home/git/.gitolite/hooks/common/post-receive +``` + +Step 2: Rewrite hooks in all projects to symlink gitolite hook + +```bash +# 1. Check for valid path +sudo -u gitlab -H vim lib/support/rewrite-hooks.sh + +# 2. Run script +sudo -u git -H lib/support/rewrite-hooks.sh +``` + +#### Gitolite v2 + +Step 1: rewrite post-receive hook for gitolite 2 + +``` +sudo cp ./lib/hooks/post-receive /home/git/share/gitolite/hooks/common/post-receive +sudo chown git:git /home/git/share/gitolite/hooks/common/post-receive +``` + +Step 2: Replace symlinks in project to valid place + + + #!/bin/bash + src="/home/git/repositories" + for dir in `ls "$src/"` + do + if [ -d "$src/$dir" ]; then + + if [ "$dir" = "gitolite-admin.git" ] + then + continue + fi + + project_hook="$src/$dir/hooks/post-receive" + gitolite_hook="/home/git/share/gitolite/hooks/common/post-receive" + + ln -s -f $gitolite_hook $project_hook + fi + done + + +### 4. Check app status + +```bash + +# Check APP Status +sudo -u gitlab -H bundle exec rake gitlab:app:status RAILS_ENV=production + + + +``` + + +### 5. Start all + + sudo service gitlab start diff --git a/doc/update/3.1-to-4.0.md b/doc/update/3.1-to-4.0.md new file mode 100644 index 00000000000..c5ae3a40a76 --- /dev/null +++ b/doc/update/3.1-to-4.0.md @@ -0,0 +1,99 @@ +# From 3.1 to 4.0 + +## Important changes + +* Support for SQLite was dropped +* Support for gitolite 2 was dropped +* Projects are organized in namespaces +* The GitLab post-receive hook needs to be updated +* The configuration file needs to be updated +* Availability of `python2` executable + +Most of projects has post-receive file as symlink to gitolite `/home/git/.gitolite/hooks/post-receive`. +But some of them may have a real file. In this case you should rewrite it with symlink to gitolite hook. + +I wrote a bash script which will do it automatically for you. Just make sure all path inside is valid for you + +- - - + +### 1. Stop GitLab & Resque + + sudo service gitlab stop + +### 2. Update GitLab + +```bash + +# Get latest code +sudo -u gitlab -H git fetch +sudo -u gitlab -H git checkout 4-0-stable + +# Install gems for MySQL +sudo -u gitlab -H bundle install --without development test postgres + +# Update repos permissions +sudo chmod -R ug+rwXs /home/git/repositories/ +sudo chown -R git:git /home/git/repositories/ + +# Migrate db +sudo -u gitlab -H bundle exec rake db:migrate RAILS_ENV=production + +# Enable namespaces (**Warning!** All projects in groups will be moved to subdirectories) +sudo -u gitlab -H bundle exec rake gitlab:enable_namespaces RAILS_ENV=production + +``` + +### 3. Update post-receive hooks (Requires gitolite v3 ) + + +Step 1: Rewrite post-receive hook + +```bash +sudo cp ./lib/hooks/post-receive /home/git/.gitolite/hooks/common/post-receive +sudo chown git:git /home/git/.gitolite/hooks/common/post-receive +``` + +Step 2: Update project hooks to be symlinks to the Gitolite hook + +```bash +# 1. Check paths in script +sudo -u gitlab -H vim lib/support/rewrite-hooks.sh + +# 2. Run script +sudo -u git -H lib/support/rewrite-hooks.sh +``` + + +### 4. Replace config with new one + + + # backup old one + sudo -u gitlab -H cp config/gitlab.yml config/gitlab.yml.old + + # copy new one + sudo -u gitlab -H cp config/gitlab.yml.example config/gitlab.yml + + # edit it + sudo -u gitlab -H vim config/gitlab.yml + + +### 5. Disable ssh known_host check for own domain + + + echo "Host localhost + StrictHostKeyChecking no + UserKnownHostsFile=/dev/null" | sudo tee -a /etc/ssh/ssh_config + + echo "Host YOUR_DOMAIN_NAME + StrictHostKeyChecking no + UserKnownHostsFile=/dev/null" | sudo tee -a /etc/ssh/ssh_config + + +### 6. Check GitLab's status + + sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production + + +### 7. Start GitLab & Resque + + sudo service gitlab start diff --git a/doc/update/4.0-to-4.1.md b/doc/update/4.0-to-4.1.md new file mode 100644 index 00000000000..368351d0c91 --- /dev/null +++ b/doc/update/4.0-to-4.1.md @@ -0,0 +1,55 @@ +# From 4.0 to 4.1 + +## Important changes + +* Resque replaced with Sidekiq +* New options for configuration file added +* Init.d script should be updated +* __requires ruby1.9.3-p327__ + +- - - + +### 1. Stop GitLab & Resque + + sudo service gitlab stop + +### 2. Update GitLab + +```bash + +# Get latest code +sudo -u gitlab -H git fetch +sudo -u gitlab -H git checkout 4-1-stable + +# Install gems for MySQL +sudo -u gitlab -H bundle install --without development test postgres + +# Migrate db +sudo -u gitlab -H bundle exec rake db:migrate RAILS_ENV=production + +``` + +### 3. Replace init.d script with a new one + +``` +# backup old one +sudo mv /etc/init.d/gitlab /etc/init.d/gitlab.old + +# get new one usign sidekiq +sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/4-1-stable/init.d/gitlab +sudo chmod +x /etc/init.d/gitlab + +``` + +### 4. Check GitLab's status + + sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production + + +### 5. Start GitLab & Sidekiq + + sudo service gitlab start + +### 6. Remove old init.d script + + sudo rm /etc/init.d/gitlab.old diff --git a/doc/update/4.1-to-4.2.md b/doc/update/4.1-to-4.2.md new file mode 100644 index 00000000000..15fea593560 --- /dev/null +++ b/doc/update/4.1-to-4.2.md @@ -0,0 +1,34 @@ +# From 4.1 to 4.2 + +### 1. Stop server & resque + + sudo service gitlab stop + +### 2. Update code & db + +```bash +# Get latest code +sudo -u gitlab git fetch + +sudo -u gitlab git checkout 4-2-stable + +# Install libs +sudo -u gitlab bundle install --without development test postgres --deployment + +# update db +sudo -u gitlab bundle exec rake db:migrate RAILS_ENV=production + +``` + + +### 3. Check GitLab's status + +```bash +sudo -u gitlab -H bundle exec rake gitlab:check RAILS_ENV=production +``` + + + +### 4. Start all + + sudo service gitlab start diff --git a/doc/update/4.2-to-5.0.md b/doc/update/4.2-to-5.0.md new file mode 100644 index 00000000000..408e4ed3d0f --- /dev/null +++ b/doc/update/4.2-to-5.0.md @@ -0,0 +1,163 @@ +# From 4.2 to 5.0 + +## Important changes + +* We dont use `gitlab` user any more. Everything will be moved to `git` user +* __requires ruby1.9.3__ + + +__0. Stop gitlab__ + + sudo service gitlab stop + +__1. add bash to git user__ + +``` +sudo chsh -s /bin/bash git +``` + +__2. git clone gitlab-shell__ + +``` +sudo -u git -H git clone https://github.com/gitlabhq/gitlab-shell.git /home/git/gitlab-shell +``` + +__3. setup gitlab-shell__ + +```bash +# chmod all repos and files under git +sudo chown git:git -R /home/git/repositories/ + +# login as git +sudo su git +cd /home/git/gitlab-shell + +# copy config +cp config.yml.example config.yml + +# change url to gitlab instance +# ! make sure url end with '/' like 'https://gitlab.example/' +vim config.yml + +# rewrite hooks +./support/rewrite-hooks.sh + +# check ruby version for git user ( 1.9 required!! ) +# gitlab shell requires system ruby 1.9 +ruby -v + +# exit from git user +exit +``` + +__4. Copy gitlab instance to git user__ + +```bash +sudo cp -R /home/gitlab/gitlab /home/git/gitlab +sudo chown git:git -R /home/git/gitlab +sudo rm -rf /home/gitlab/gitlab-satellites + +# if exists +sudo rm /tmp/gitlab.socket +``` + +__5. Update gitlab to recent version__ + +```bash +cd /home/git/gitlab + +# backup current config +sudo -u git -H cp config/gitlab.yml config/gitlab.yml.old + +sudo -u git -H git fetch +sudo -u git -H git checkout 5-0-stable + +# replace config with recent one +sudo -u git -H cp config/gitlab.yml.example config/gitlab.yml + +# edit it +sudo -u git -H vim config/gitlab.yml + + +sudo -u git -H bundle install --without development test postgres --deployment +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production +sudo -u git -H bundle exec rake gitlab:shell:setup RAILS_ENV=production +sudo -u git -H bundle exec rake gitlab:shell:build_missing_projects RAILS_ENV=production + +sudo -u git -H mkdir /home/git/gitlab-satellites +sudo -u git -H bundle exec rake gitlab:satellites:create RAILS_ENV=production + +# migrate wiki to git +sudo -u git -H bundle exec rake gitlab:wiki:migrate RAILS_ENV=production + + +# check permissions for /home/git/.ssh/ +sudo -u git -H chmod 700 /home/git/.ssh +sudo -u git -H chmod 600 /home/git/.ssh/authorized_keys + +# check permissions for /home/git/gitlab/ +sudo chown -R git /home/git/gitlab/log/ +sudo chown -R git /home/git/gitlab/tmp/ +sudo chmod -R u+rwX /home/git/gitlab/log/ +sudo chmod -R u+rwX /home/git/gitlab/tmp/ +sudo -u git -H mkdir /home/git/gitlab/tmp/pids/ +sudo chmod -R u+rwX /home/git/gitlab/tmp/pids + +``` + +__6. Update init.d script and nginx config__ + +```bash +# init.d +sudo rm /etc/init.d/gitlab +sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/5-0-stable/init.d/gitlab +sudo chmod +x /etc/init.d/gitlab + +# unicorn +sudo -u git -H cp /home/git/gitlab/config/unicorn.rb /home/git/gitlab/config/unicorn.rb.old +sudo -u git -H cp /home/git/gitlab/config/unicorn.rb.example /home/git/gitlab/config/unicorn.rb + +#nginx +# Replace path from '/home/gitlab/' to '/home/git/' +sudo vim /etc/nginx/sites-enabled/gitlab +sudo service nginx restart + + +``` + +__7. Start gitlab instace__ + +``` + + +sudo service gitlab start + +# check if unicorn and sidekiq started +# If not try to logout, also check replaced path from '/home/gitlab/' to '/home/git/' +# in nginx, unicorn, init.d etc +ps aux | grep unicorn +ps aux | grep sidekiq + +``` + +__8. Check installation__ + + +```bash +# In 5-10 seconds lets check gitlab-shell +sudo -u git -H /home/git/gitlab-shell/bin/check + +# Example of success output +# Check GitLab API access: OK +# Check directories and files: +# /home/git/repositories: OK +# /home/git/.ssh/authorized_keys: OK + + +# Now check gitlab instance +sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production + +``` + + +__P.S. If everything works as expected you can remove gitlab user from system__ diff --git a/doc/update/5.0-to-5.1.md b/doc/update/5.0-to-5.1.md new file mode 100644 index 00000000000..25fe2f50e25 --- /dev/null +++ b/doc/update/5.0-to-5.1.md @@ -0,0 +1,61 @@ +# From 5.0 to 5.1 + +## Release notes: + +* `unicorn` replaced with `puma` +* merge request cached diff will be truncated + +### 1. Stop server + + sudo service gitlab stop + +### 2. Get latest code + +```bash +cd /home/git/gitlab +sudo -u git -H git fetch +sudo -u git -H git checkout 5-1-stable +``` + +### 3. Update gitlab-shell + +```bash +cd /home/git/gitlab-shell +sudo -u git -H git fetch +sudo -u git -H git checkout v1.3.0 +``` + +### 4. Install libs, migrations etc + +```bash +cd /home/git/gitlab +sudo rm tmp/sockets/gitlab.socket +sudo -u git -H cp config/puma.rb.example config/puma.rb + +sudo -u git -H bundle install --without development test postgres --deployment +sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production +sudo -u git -H bundle exec rake migrate_merge_requests RAILS_ENV=production +``` + +### 5. Update init.d script with a new one + +```bash +# init.d +sudo rm /etc/init.d/gitlab +sudo curl --output /etc/init.d/gitlab https://raw.github.com/gitlabhq/gitlab-recipes/5-1-stable/init.d/gitlab +sudo chmod +x /etc/init.d/gitlab +``` + +### 6. Mysql grant privileges + +Only if you are using mysql: + +```bash +mysql -u root -p +mysql> GRANT LOCK TABLES ON `gitlabhq_production`.* TO 'gitlab'@'localhost'; +mysql> \q +``` + +### 7. Start application + + sudo service gitlab start diff --git a/features/project/network.feature b/features/project/network.feature index a6cbd2c4781..538124a4c5f 100644 --- a/features/project/network.feature +++ b/features/project/network.feature @@ -11,14 +11,16 @@ Feature: Project Network Graph And page should have "master" on graph @javascript - Scenario: I should switch ref to "stable" + Scenario: I should switch "branch" and "tag" When I switch ref to "stable" - Then page should have network graph - And page should select "stable" in select box + Then page should select "stable" in select box And page should have "stable" on graph + When I switch ref to "v2.1.0" + Then page should select "v2.1.0" in select box + And page should have "v2.1.0" on graph @javascript - Scenario: I should looking for a commit by SHA of "v2.1.0" + Scenario: I should looking for a commit by SHA When I looking for a commit by SHA of "v2.1.0" Then page should have network graph And page should select "master" in select box diff --git a/features/project/team_management.feature b/features/project/team_management.feature index 04545a08e0a..fc353424e36 100644 --- a/features/project/team_management.feature +++ b/features/project/team_management.feature @@ -21,7 +21,6 @@ Feature: Project Team management Scenario: Update user access Given I should see "Sam" in team list as "Developer" And I change "Sam" role to "Reporter" - Then I visit project "Shop" team page And I should see "Sam" in team list as "Reporter" Scenario: Cancel team member diff --git a/features/steps/project/project_network_graph.rb b/features/steps/project/project_network_graph.rb index cf5fa751ccf..763b4de2abc 100644 --- a/features/steps/project/project_network_graph.rb +++ b/features/steps/project/project_network_graph.rb @@ -30,10 +30,19 @@ class ProjectNetworkGraph < Spinach::FeatureSteps sleep 2 end + When 'I switch ref to "v2.1.0"' do + page.select 'v2.1.0', :from => 'ref' + sleep 2 + end + And 'page should select "stable" in select box' do page.should have_selector '#ref_chzn span', :text => "stable" end + And 'page should select "v2.1.0" in select box' do + page.should have_selector '#ref_chzn span', :text => "v2.1.0" + end + And 'page should have "stable" on graph' do within '.graph' do page.should have_content 'stable' diff --git a/features/steps/project/project_team_management.rb b/features/steps/project/project_team_management.rb index 96bf0df2899..ffd2aa24676 100644 --- a/features/steps/project/project_team_management.rb +++ b/features/steps/project/project_team_management.rb @@ -30,15 +30,15 @@ class ProjectTeamManagement < Spinach::FeatureSteps end Then 'I should see "Mike" in team list as "Reporter"' do - user = User.find_by_name("Mike") - role_id = find(".user_#{user.id} #team_member_project_access").value - role_id.should == UsersProject.access_roles["Reporter"].to_s + within '.reporters' do + page.should have_content('Mike') + end end Given 'I should see "Sam" in team list as "Developer"' do - user = User.find_by_name("Sam") - role_id = find(".user_#{user.id} #team_member_project_access").value - role_id.should == UsersProject.access_roles["Developer"].to_s + within '.developers' do + page.should have_content('Sam') + end end And 'I change "Sam" role to "Reporter"' do @@ -49,9 +49,9 @@ class ProjectTeamManagement < Spinach::FeatureSteps end And 'I should see "Sam" in team list as "Reporter"' do - user = User.find_by_name("Sam") - role_id = find(".user_#{user.id} #team_member_project_access").value - role_id.should == UsersProject.access_roles["Reporter"].to_s + within '.reporters' do + page.should have_content('Sam') + end end And 'I click link "Remove from team"' do diff --git a/lib/api/internal.rb b/lib/api/internal.rb index 81451638090..affe1be54dd 100644 --- a/lib/api/internal.rb +++ b/lib/api/internal.rb @@ -22,6 +22,7 @@ module Gitlab key = Key.find(params[:key_id]) project = Project.find_with_namespace(project_path) git_cmd = params[:action] + return false unless project if key.is_deploy_key @@ -32,7 +33,7 @@ module Gitlab return false if user.blocked? action = case git_cmd - when 'git-upload-pack' + when 'git-upload-pack', 'git-upload-archive' then :download_code when 'git-receive-pack' then diff --git a/lib/api/users.rb b/lib/api/users.rb index 125a8624021..4198387d403 100644 --- a/lib/api/users.rb +++ b/lib/api/users.rb @@ -12,6 +12,7 @@ module Gitlab @users = User.scoped @users = @users.active if params[:active].present? @users = @users.search(params[:search]) if params[:search].present? + @users = paginate @users present @users, with: Entities::User end diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb index 009c5fcada9..1b7c698d0a8 100644 --- a/lib/extracts_path.rb +++ b/lib/extracts_path.rb @@ -98,9 +98,7 @@ module ExtractsPath @ref, @path = extract_ref(@id) - # It is used "@project.repository.commits(@ref, @path, 1, 0)", - # because "@project.repository.commit(@ref)" returns wrong commit when @ref is tag name. - @commit = @project.repository.commits(@ref, @path, 1, 0).first + @commit = @project.repository.commit(@ref) @tree = Tree.new(@project.repository, @commit.id, @ref, @path) diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb index abbee6132d3..6a411aabcc6 100644 --- a/lib/gitlab/backend/grack_auth.rb +++ b/lib/gitlab/backend/grack_auth.rb @@ -1,4 +1,5 @@ require_relative 'shell_env' +require 'omniauth-ldap' module Grack class Auth < Rack::Auth::Basic @@ -32,8 +33,18 @@ module Grack # Authentication with username and password login, password = @auth.credentials self.user = User.find_by_email(login) || User.find_by_username(login) - return false unless user.try(:valid_password?, password) + # If the provided login was not a known email or username + # then user is nil + if user.nil? + # Second chance - try LDAP authentication + return false unless Gitlab.config.ldap.enabled + ldap_auth(login,password) + return false unless !user.nil? + else + return false unless user.valid_password?(password) + end + Gitlab::ShellEnv.set_env(user) end @@ -47,14 +58,35 @@ module Grack end end + def ldap_auth(login, password) + # Check user against LDAP backend if user is not authenticated + # Only check with valid login and password to prevent anonymous bind results + gl = Gitlab.config + if gl.ldap.enabled && !login.blank? && !password.blank? + ldap = OmniAuth::LDAP::Adaptor.new(gl.ldap) + ldap_user = ldap.bind_as( + filter: Net::LDAP::Filter.eq(ldap.uid, login), + size: 1, + password: password + ) + if ldap_user + self.user = User.find_by_extern_uid_and_provider(ldap_user.dn, 'ldap') + end + end + end + def validate_get_request - project.public || can?(user, :download_code, project) + validate_request(@request.params['service']) end def validate_post_request - if @request.path_info.end_with?('git-upload-pack') + validate_request(File.basename(@request.path)) + end + + def validate_request(service) + if service == 'git-upload-pack' project.public || can?(user, :download_code, project) - elsif @request.path_info.end_with?('git-receive-pack') + elsif service == 'git-receive-pack' action = if project.protected_branch?(current_ref) :push_code_to_protected_branches else @@ -79,7 +111,7 @@ module Grack end # Need to reset seek point @request.body.rewind - /refs\/heads\/([\w\.-]+)/.match(input).to_a.last + /refs\/heads\/([\w\.-]+)/n.match(input.force_encoding('ascii-8bit')).to_a.last end def project diff --git a/lib/gitlab/git/blame.rb b/lib/gitlab/git/blame.rb deleted file mode 100644 index d6e988b6762..00000000000 --- a/lib/gitlab/git/blame.rb +++ /dev/null @@ -1,22 +0,0 @@ -module Gitlab - module Git - class Blame - - attr_accessor :repository, :sha, :path - - def initialize(repository, sha, path) - @repository, @sha, @path = repository, sha, path - - end - - def each - raw_blame = Grit::Blob.blame(repository.repo, sha, path) - - raw_blame.each do |commit, lines| - commit = Gitlab::Git::Commit.new(commit) - yield(commit, lines) - end - end - end - end -end diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb deleted file mode 100644 index 57b89912f2d..00000000000 --- a/lib/gitlab/git/blob.rb +++ /dev/null @@ -1,42 +0,0 @@ -module Gitlab - module Git - class Blob - include Linguist::BlobHelper - - attr_accessor :raw_blob - - delegate :name, to: :raw_blob - - def initialize(repository, sha, ref, path) - @repository, @sha, @ref = repository, sha, ref - - @commit = @repository.commit(sha) - @raw_blob = @repository.tree(@commit, path) - end - - def data - if raw_blob - raw_blob.data - else - nil - end - end - - def exists? - raw_blob - end - - def empty? - data.blank? - end - - def mode - raw_blob.mode - end - - def size - raw_blob.size - end - end - end -end diff --git a/lib/gitlab/git/commit.rb b/lib/gitlab/git/commit.rb deleted file mode 100644 index 27b866893f9..00000000000 --- a/lib/gitlab/git/commit.rb +++ /dev/null @@ -1,121 +0,0 @@ -# Gitlab::Git::Commit is a wrapper around native Grit::Commit object -# We dont want to use grit objects inside app/ -# It helps us easily migrate to rugged in future -module Gitlab - module Git - class Commit - attr_accessor :raw_commit, :head, :refs, - :id, :authored_date, :committed_date, :message, - :author_name, :author_email, :parent_ids, - :committer_name, :committer_email - - delegate :parents, :diffs, :tree, :stats, :to_patch, - to: :raw_commit - - def initialize(raw_commit, head = nil) - raise "Nil as raw commit passed" unless raw_commit - - if raw_commit.is_a?(Hash) - init_from_hash(raw_commit) - else - init_from_grit(raw_commit) - end - - @head = head - end - - def serialize_keys - %w(id authored_date committed_date author_name author_email committer_name committer_email message parent_ids) - end - - def sha - id - end - - def short_id(length = 10) - id.to_s[0..length] - end - - def safe_message - @safe_message ||= message - end - - def created_at - committed_date - end - - # Was this commit committed by a different person than the original author? - def different_committer? - author_name != committer_name || author_email != committer_email - end - - def parent_id - parent_ids.first - end - - # Shows the diff between the commit's parent and the commit. - # - # Cuts out the header and stats from #to_patch and returns only the diff. - def to_diff - # see Grit::Commit#show - patch = to_patch - - # discard lines before the diff - lines = patch.split("\n") - while !lines.first.start_with?("diff --git") do - lines.shift - end - lines.pop if lines.last =~ /^[\d.]+$/ # Git version - lines.pop if lines.last == "-- " # end of diff - lines.join("\n") - end - - def has_zero_stats? - stats.total.zero? - rescue - true - end - - def no_commit_message - "--no commit message" - end - - def to_hash - hash = {} - - keys = serialize_keys - - keys.each do |key| - hash[key] = send(key) - end - - hash - end - - def date - committed_date - end - - private - - def init_from_grit(grit) - @raw_commit = grit - @id = grit.id - @message = grit.message - @authored_date = grit.authored_date - @committed_date = grit.committed_date - @author_name = grit.author.name - @author_email = grit.author.email - @committer_name = grit.committer.name - @committer_email = grit.committer.email - @parent_ids = grit.parents.map(&:id) - end - - def init_from_hash(hash) - serialize_keys.each do |key| - send(:"#{key}=", hash[key]) - end - end - end - end -end diff --git a/lib/gitlab/git/compare.rb b/lib/gitlab/git/compare.rb deleted file mode 100644 index e34f204e8bd..00000000000 --- a/lib/gitlab/git/compare.rb +++ /dev/null @@ -1,35 +0,0 @@ -module Gitlab - module Git - class Compare - attr_accessor :commits, :commit, :diffs, :same - - def initialize(repository, from, to) - @commits, @diffs = [], [] - @commit = nil - @same = false - - return unless from && to - - first = repository.commit(to.try(:strip)) - last = repository.commit(from.try(:strip)) - - return unless first && last - - if first.id == last.id - @same = true - return - end - - @commit = first - @commits = repository.commits_between(last.id, first.id) - - @diffs = if @commits.size > 100 - [] - else - repository.repo.diff(last.id, first.id) rescue [] - end - end - end - end -end - diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb deleted file mode 100644 index 6d4e9e8491f..00000000000 --- a/lib/gitlab/git/repository.rb +++ /dev/null @@ -1,201 +0,0 @@ -# Gitlab::Git::Gitlab::Git::Commit is a wrapper around native Grit::Repository object -# We dont want to use grit objects inside app/ -# It helps us easily migrate to rugged in future -module Gitlab - module Git - class Repository - include Gitlab::Popen - - class NoRepository < StandardError; end - - # Repository directory name with namespace direcotry - # Examples: - # gitlab/gitolite - # diaspora - # - attr_accessor :path_with_namespace - - # Grit repo object - attr_accessor :repo - - # Default branch in the repository - attr_accessor :root_ref - - def initialize(path_with_namespace, root_ref = 'master') - @root_ref = root_ref || "master" - @path_with_namespace = path_with_namespace - - # Init grit repo object - repo - end - - def raw - repo - end - - def path_to_repo - @path_to_repo ||= File.join(repos_path, "#{path_with_namespace}.git") - end - - def repos_path - Gitlab.config.gitlab_shell.repos_path - end - - def repo - @repo ||= Grit::Repo.new(path_to_repo) - rescue Grit::NoSuchPathError - raise NoRepository.new('no repository for such path') - end - - def commit(commit_id = nil) - commit = if commit_id - repo.commit(commit_id) - else - repo.commits(root_ref).first - end - - decorate_commit(commit) if commit - end - - def commits_with_refs(n = 20) - commits = repo.branches.map { |ref| decorate_commit(ref.commit, ref) } - - commits.sort! do |x, y| - y.committed_date <=> x.committed_date - end - - commits[0..n] - end - - def commits(ref, path = nil, limit = nil, offset = nil) - if path - repo.log(ref, path, max_count: limit, skip: offset) - elsif limit && offset - repo.commits(ref, limit, offset) - else - repo.commits(ref) - end.map{ |c| decorate_commit(c) } - end - - def commits_between(from, to) - repo.commits_between(from, to).map { |c| decorate_commit(c) } - end - - def last_commit_for(ref, path = nil) - commits(ref, path, 1).first - end - - # Returns an Array of branch names - # sorted by name ASC - def branch_names - branches.map(&:name) - end - - # Returns an Array of Branches - def branches - repo.branches.sort_by(&:name) - end - - # Returns an Array of tag names - def tag_names - repo.tags.collect(&:name).sort.reverse - end - - # Returns an Array of Tags - def tags - repo.tags.sort_by(&:name).reverse - end - - # Returns an Array of branch and tag names - def ref_names - [branch_names + tag_names].flatten - end - - def heads - @heads ||= repo.heads - end - - def tree(fcommit, path = nil) - fcommit = commit if fcommit == :head - tree = fcommit.tree - path ? (tree / path) : tree - end - - def has_commits? - !!commit - rescue Grit::NoSuchPathError - false - end - - def empty? - !has_commits? - end - - # Discovers the default branch based on the repository's available branches - # - # - If no branches are present, returns nil - # - If one branch is present, returns its name - # - If two or more branches are present, returns the one that has a name - # matching root_ref (default_branch or 'master' if default_branch is nil) - def discover_default_branch - if branch_names.length == 0 - nil - elsif branch_names.length == 1 - branch_names.first - else - branch_names.select { |v| v == root_ref }.first - end - end - - # Archive Project to .tar.gz - # - # Already packed repo archives stored at - # app_root/tmp/repositories/project_name/project_name-commit-id.tag.gz - # - def archive_repo(ref) - ref = ref || self.root_ref - commit = self.commit(ref) - return nil unless commit - - # Build file path - file_name = self.path_with_namespace.gsub("/","_") + "-" + commit.id.to_s + ".tar.gz" - storage_path = Rails.root.join("tmp", "repositories") - file_path = File.join(storage_path, self.path_with_namespace, file_name) - - # Put files into a directory before archiving - prefix = File.basename(self.path_with_namespace) + "/" - - # Create file if not exists - unless File.exists?(file_path) - FileUtils.mkdir_p File.dirname(file_path) - file = self.repo.archive_to_file(ref, prefix, file_path) - end - - file_path - end - - # Return repo size in megabytes - # Cached in redis - def size - Rails.cache.fetch(cache_key(:size)) do - size = popen('du -s', path_to_repo).first.strip.to_i - (size.to_f / 1024).round(2) - end - end - - def expire_cache - Rails.cache.delete(cache_key(:size)) - end - - def cache_key(type) - "#{type}:#{path_with_namespace}" - end - - protected - - def decorate_commit(commit, ref = nil) - Gitlab::Git::Commit.new(commit, ref) - end - end - end -end diff --git a/lib/gitlab/git/stats.rb b/lib/gitlab/git/stats.rb deleted file mode 100644 index c925c653342..00000000000 --- a/lib/gitlab/git/stats.rb +++ /dev/null @@ -1,75 +0,0 @@ -module Gitlab - module Git - class Stats - attr_accessor :repo, :ref - - def initialize repo, ref - @repo, @ref = repo, ref - end - - def authors - @authors ||= collect_authors - end - - def commits_count - @commits_count ||= repo.commit_count(ref) - end - - def files_count - args = [ref, '-r', '--name-only' ] - repo.git.run(nil, 'ls-tree', nil, {}, args).split("\n").count - end - - def authors_count - authors.size - end - - def graph - @graph ||= build_graph - end - - protected - - def collect_authors - shortlog = repo.git.shortlog({e: true, s: true }, ref) - - authors = [] - - lines = shortlog.split("\n") - - lines.each do |line| - data = line.split("\t") - commits = data.first - author = Grit::Actor.from_string(data.last) - - authors << OpenStruct.new( - name: author.name, - email: author.email, - commits: commits.to_i - ) - end - - authors.sort_by(&:commits).reverse - end - - def build_graph n = 4 - from, to = (Date.today - n.weeks), Date.today - args = ['--all', "--since=#{from.to_s(:date)}", '--format=%ad' ] - rev_list = repo.git.run(nil, 'rev-list', nil, {}, args).split("\n") - - commits_dates = rev_list.values_at(* rev_list.each_index.select {|i| i.odd?}) - commits_dates = commits_dates.map { |date_str| Time.parse(date_str).to_date.to_s(:date) } - - commits_per_day = from.upto(to).map do |day| - commits_dates.count(day.to_date.to_s(:date)) - end - - OpenStruct.new( - labels: from.upto(to).map { |day| day.stamp('Aug 23') }, - commits: commits_per_day, - weeks: n - ) - end - end - end -end diff --git a/lib/gitlab/git/tree.rb b/lib/gitlab/git/tree.rb deleted file mode 100644 index e6b500ba18c..00000000000 --- a/lib/gitlab/git/tree.rb +++ /dev/null @@ -1,52 +0,0 @@ -module Gitlab - module Git - class Tree - attr_accessor :repository, :sha, :path, :ref, :raw_tree, :id - - def initialize(repository, sha, ref = nil, path = nil) - @repository, @sha, @ref, @path = repository, sha, ref, path - - @path = nil if @path.blank? - - # Load tree from repository - @commit = @repository.commit(@sha) - @raw_tree = @repository.tree(@commit, @path) - end - - def exists? - raw_tree - end - - def empty? - data.blank? - end - - def trees - entries.select { |t| t.is_a?(Grit::Tree) } - end - - def blobs - entries.select { |t| t.is_a?(Grit::Blob) } - end - - def is_blob? - raw_tree.is_a?(Grit::Blob) - end - - def up_dir? - path.present? - end - - def readme - @readme ||= blobs.find { |c| c.name =~ /^readme/i } - end - - protected - - def entries - raw_tree.contents - end - end - end -end - diff --git a/lib/gitlab/identifier.rb b/lib/gitlab/identifier.rb new file mode 100644 index 00000000000..a1ff248a77f --- /dev/null +++ b/lib/gitlab/identifier.rb @@ -0,0 +1,23 @@ +# Detect user based on identifier like +# key-13 or user-36 or last commit +module Gitlab + module Identifier + def identify(identifier, project, newrev) + if identifier.blank? + # Local push from gitlab + email = project.repository.commit(newrev).author_email rescue nil + User.find_by_email(email) if email + + elsif identifier =~ /\Auser-\d+\Z/ + # git push over http + user_id = identifier.gsub("user-", "") + User.find_by_id(user_id) + + elsif identifier =~ /\Akey-\d+\Z/ + # git push over ssh + key_id = identifier.gsub("key-", "") + Key.find_by_id(key_id).try(:user) + end + end + end +end diff --git a/lib/support/init.d/gitlab b/lib/support/init.d/gitlab new file mode 100644 index 00000000000..93321d6440f --- /dev/null +++ b/lib/support/init.d/gitlab @@ -0,0 +1,131 @@ +#! /bin/bash + +# GITLAB +# Maintainer: @randx +# App Version: 5.1 + +### BEGIN INIT INFO +# Provides: gitlab +# Required-Start: $local_fs $remote_fs $network $syslog redis-server +# Required-Stop: $local_fs $remote_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: GitLab git repository management +# Description: GitLab git repository management +### END INIT INFO + + +APP_ROOT="/home/git/gitlab" +DAEMON_OPTS="-C $APP_ROOT/config/puma.rb -e production" +PID_PATH="$APP_ROOT/tmp/pids" +WEB_SERVER_PID="$PID_PATH/puma.pid" +SIDEKIQ_PID="$PID_PATH/sidekiq.pid" +STOP_SIDEKIQ="RAILS_ENV=production bundle exec rake sidekiq:stop" +START_SIDEKIQ="RAILS_ENV=production bundle exec rake sidekiq:start" +NAME="gitlab" +DESC="Gitlab service" + +check_pid(){ + if [ -f $WEB_SERVER_PID ]; then + PID=`cat $WEB_SERVER_PID` + SPID=`cat $SIDEKIQ_PID` + STATUS=`ps aux | grep $PID | grep -v grep | wc -l` + else + STATUS=0 + PID=0 + fi +} + +start() { + cd $APP_ROOT + check_pid + if [ "$PID" -ne 0 -a "$STATUS" -ne 0 ]; then + # Program is running, exit with error code 1. + echo "Error! $DESC $NAME is currently running!" + exit 1 + else + if [ `whoami` = root ]; then + sudo -u git -H bash -l -c "RAILS_ENV=production bundle exec puma $DAEMON_OPTS" + sudo -u git -H bash -l -c "mkdir -p $PID_PATH && $START_SIDEKIQ > /dev/null 2>&1 &" + echo "$DESC started" + fi + fi +} + +stop() { + cd $APP_ROOT + check_pid + if [ "$PID" -ne 0 -a "$STATUS" -ne 0 ]; then + ## Program is running, stop it. + kill -QUIT `cat $WEB_SERVER_PID` + sudo -u git -H bash -l -c "mkdir -p $PID_PATH && $STOP_SIDEKIQ > /dev/null 2>&1 &" + rm "$WEB_SERVER_PID" >> /dev/null + echo "$DESC stopped" + else + ## Program is not running, exit with error. + echo "Error! $DESC not started!" + exit 1 + fi +} + +restart() { + cd $APP_ROOT + check_pid + if [ "$PID" -ne 0 -a "$STATUS" -ne 0 ]; then + echo "Restarting $DESC..." + kill -USR2 `cat $WEB_SERVER_PID` + sudo -u git -H bash -l -c "mkdir -p $PID_PATH && $STOP_SIDEKIQ > /dev/null 2>&1 &" + if [ `whoami` = root ]; then + sudo -u git -H bash -l -c "mkdir -p $PID_PATH && $START_SIDEKIQ > /dev/null 2>&1 &" + fi + echo "$DESC restarted." + else + echo "Error, $NAME not running!" + exit 1 + fi +} + +status() { + cd $APP_ROOT + check_pid + if [ "$PID" -ne 0 -a "$STATUS" -ne 0 ]; then + echo "$DESC / Unicorn with PID $PID is running." + echo "$DESC / Sidekiq with PID $SPID is running." + else + echo "$DESC is not running." + exit 1 + fi +} + +## Check to see if we are running as root first. +## Found at http://www.cyberciti.biz/tips/shell-root-user-check-script.html +if [ "$(id -u)" != "0" ]; then + echo "This script must be run as root" + exit 1 +fi + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + restart + ;; + reload|force-reload) + echo -n "Reloading $NAME configuration: " + kill -HUP `cat $PID` + echo "done." + ;; + status) + status + ;; + *) + echo "Usage: sudo service gitlab {start|stop|restart|reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab new file mode 100644 index 00000000000..7428393e664 --- /dev/null +++ b/lib/support/nginx/gitlab @@ -0,0 +1,38 @@ +# GITLAB +# Maintainer: @randx +# App Version: 5.0 + +upstream gitlab { + server unix:/home/git/gitlab/tmp/sockets/gitlab.socket; +} + +server { + listen YOUR_SERVER_IP:80 default_server; # e.g., listen 192.168.1.1:80; + server_name YOUR_SERVER_FQDN; # e.g., server_name source.example.com; + root /home/git/gitlab/public; + + # individual nginx logs for this gitlab vhost + access_log /var/log/nginx/gitlab_access.log; + error_log /var/log/nginx/gitlab_error.log; + + location / { + # serve static files from defined root folder;. + # @gitlab is a named location for the upstream fallback, see below + try_files $uri $uri/index.html $uri.html @gitlab; + } + + # if a file, which is not found in the root folder is requested, + # then the proxy pass the request to the upsteam (gitlab unicorn) + location @gitlab { + proxy_read_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694 + proxy_connect_timeout 300; # https://github.com/gitlabhq/gitlabhq/issues/694 + proxy_redirect off; + + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + + proxy_pass http://gitlab; + } +} + diff --git a/lib/tasks/gitlab/backup.rake b/lib/tasks/gitlab/backup.rake index ad6ba43049c..9f28de593e9 100644 --- a/lib/tasks/gitlab/backup.rake +++ b/lib/tasks/gitlab/backup.rake @@ -11,8 +11,6 @@ namespace :gitlab do Rake::Task["gitlab:backup:repo:create"].invoke Rake::Task["gitlab:backup:uploads:create"].invoke - Dir.chdir(Gitlab.config.backup.path) - # saving additional informations s = {} s[:db_version] = "#{ActiveRecord::Migrator.current_version}" @@ -20,6 +18,8 @@ namespace :gitlab do s[:gitlab_version] = %x{git rev-parse HEAD}.gsub(/\n/,"") s[:tar_version] = %x{tar --version | head -1}.gsub(/\n/,"") + Dir.chdir(Gitlab.config.backup.path) + File.open("#{Gitlab.config.backup.path}/backup_information.yml", "w+") do |file| file << s.to_yaml.gsub(/^---\n/,'') end @@ -101,6 +101,7 @@ namespace :gitlab do Rake::Task["gitlab:backup:db:restore"].invoke Rake::Task["gitlab:backup:repo:restore"].invoke Rake::Task["gitlab:backup:uploads:restore"].invoke + Rake::Task["gitlab:shell:setup"].invoke # cleanup: remove tmp files print "Deleting tmp directories ... " diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake index c8d8d531836..773e496ee41 100644 --- a/lib/tasks/gitlab/check.rake +++ b/lib/tasks/gitlab/check.rake @@ -23,6 +23,7 @@ namespace :gitlab do check_init_script_exists check_init_script_up_to_date check_satellites_exist + check_redis_version finished_checking "GitLab" end @@ -245,6 +246,23 @@ namespace :gitlab do fix_and_rerun end end + + def check_redis_version + print "Redis version >= 2.0.0? ... " + + if run_and_match("redis-cli --version", /redis-cli 2.\d.\d/) + puts "yes".green + else + puts "no".red + try_fixing_it( + "Update your redis server to a version >= 2.0.0" + ) + for_more_information( + "gitlab-public-wiki/wiki/Trouble-Shooting-Guide in section sidekiq" + ) + fix_and_rerun + end + end end @@ -636,11 +654,13 @@ namespace :gitlab do end def check_gitlab_shell + required_version = '1.4.0' + print "GitLab Shell version? ... " - if gitlab_shell_version.strip == '1.2.0' - puts 'OK (1.2.0)'.green + if gitlab_shell_version.strip == required_version + puts "OK (#{required_version})".green else - puts 'FAIL. Please update gitlab-shell to v1.2.0'.red + puts "FAIL. Please update gitlab-shell to v#{required_version}".red end end end diff --git a/lib/tasks/gitlab/task_helpers.rake b/lib/tasks/gitlab/task_helpers.rake index cfab3670fb2..34a4a322c11 100644 --- a/lib/tasks/gitlab/task_helpers.rake +++ b/lib/tasks/gitlab/task_helpers.rake @@ -16,7 +16,7 @@ namespace :gitlab do # Check which OS is running # # It will primarily use lsb_relase to determine the OS. - # It has fallbacks to Debian, SuSE and OS X. + # It has fallbacks to Debian, SuSE, OS X and systems running systemd. def os_name os_name = run("lsb_release -irs") os_name ||= if File.readable?('/etc/system-release') @@ -32,6 +32,9 @@ namespace :gitlab do os_name ||= if os_x_version = run("sw_vers -productVersion") "Mac OS X #{os_x_version}" end + os_name ||= if File.readable?('/etc/os-release') + File.read('/etc/os-release').match(/PRETTY_NAME=\"(.+)\"/)[1] + end os_name.try(:squish!) end diff --git a/lib/tasks/migrate/migrate_milestones.rake b/lib/tasks/migrate/migrate_milestones.rake new file mode 100644 index 00000000000..14c70a3d1c7 --- /dev/null +++ b/lib/tasks/migrate/migrate_milestones.rake @@ -0,0 +1,4 @@ +desc "GITLAB | Migrate Milestones" +task migrate_milestones: :environment do + Milestone.where(state: nil).update_all(state: 'active') +end diff --git a/lib/tasks/migrate/migrate_mr.rake b/lib/tasks/migrate/migrate_mr.rake index 6c2312b053c..74b1db03442 100644 --- a/lib/tasks/migrate/migrate_mr.rake +++ b/lib/tasks/migrate/migrate_mr.rake @@ -1,6 +1,13 @@ # This taks will reload commits/diff for all merge requests desc "GITLAB | Migrate Merge Requests" task migrate_merge_requests: :environment do + puts "Since 5.1 old merge request serialization logic was replaced with a better one." + puts "It makes old merge request diff invalid for GitLab 5.1+" + puts "* * *" + puts "This will rebuild commits/diffs info for existing merge requests." + puts "You will lose merge request diff if its already merged." + ask_to_continue + MergeRequest.find_each(batch_size: 20) do |mr| mr.st_commits = [] mr.save diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb index 22d1ee91480..a6cf5299791 100644 --- a/spec/features/admin/admin_users_spec.rb +++ b/spec/features/admin/admin_users_spec.rb @@ -30,11 +30,11 @@ describe "Admin::Users" do end it "should create new user" do - expect { click_button "Save" }.to change {User.count}.by(1) + expect { click_button "Create user" }.to change {User.count}.by(1) end it "should create user with valid data" do - click_button "Save" + click_button "Create user" user = User.last user.name.should == "Big Bang" user.email.should == "bigbang@mail.com" @@ -44,14 +44,14 @@ describe "Admin::Users" do Notify.should_receive(:new_user_email) User.observers.enable :user_observer do - click_button "Save" + click_button "Create user" end end it "should send valid email to user with email & password" do Gitlab.config.gitlab.stub(:signup_enabled).and_return(false) User.observers.enable :user_observer do - click_button "Save" + click_button "Create user" user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") @@ -63,7 +63,7 @@ describe "Admin::Users" do it "should send valid email to user with email without password when signup is enabled" do Gitlab.config.gitlab.stub(:signup_enabled).and_return(true) User.observers.enable :user_observer do - click_button "Save" + click_button "Create user" user = User.last email = ActionMailer::Base.deliveries.last email.subject.should have_content("Account was created") @@ -102,7 +102,7 @@ describe "Admin::Users" do fill_in "user_name", with: "Big Bang" fill_in "user_email", with: "bigbang@mail.com" check "user_admin" - click_button "Save" + click_button "Save changes" end it "should show page with new data" do diff --git a/spec/lib/gitlab/git/commit_spec.rb b/spec/lib/gitlab/git/commit_spec.rb deleted file mode 100644 index bf2cd98eba1..00000000000 --- a/spec/lib/gitlab/git/commit_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require "spec_helper" - -describe Gitlab::Git::Commit do - let(:commit) { create(:project_with_code).repository.commit } - - describe "Commit info" do - before do - @committer = double( - email: 'mike@smith.com', - name: 'Mike Smith' - ) - - @author = double( - email: 'john@smith.com', - name: 'John Smith' - ) - - @raw_commit = double( - id: "bcf03b5de6abcf03b5de6c", - author: @author, - committer: @committer, - committed_date: Date.yesterday, - authored_date: Date.yesterday, - parents: [], - message: 'Refactoring specs' - ) - - @commit = Gitlab::Git::Commit.new(@raw_commit) - end - - it { @commit.short_id.should == "bcf03b5de6a" } - it { @commit.safe_message.should == @raw_commit.message } - it { @commit.created_at.should == @raw_commit.committed_date } - it { @commit.author_email.should == @author.email } - it { @commit.author_name.should == @author.name } - it { @commit.committer_name.should == @committer.name } - it { @commit.committer_email.should == @committer.email } - it { @commit.different_committer?.should be_true } - end -end diff --git a/spec/lib/gitlab/git/repository_spec.rb b/spec/lib/gitlab/git/repository_spec.rb deleted file mode 100644 index 2b0550aa72a..00000000000 --- a/spec/lib/gitlab/git/repository_spec.rb +++ /dev/null @@ -1,123 +0,0 @@ -require "spec_helper" - -describe Gitlab::Git::Repository do - let(:repository) { Gitlab::Git::Repository.new('gitlabhq', 'master') } - - describe "Respond to" do - subject { repository } - - it { should respond_to(:repo) } - it { should respond_to(:tree) } - it { should respond_to(:root_ref) } - it { should respond_to(:tags) } - it { should respond_to(:commit) } - it { should respond_to(:commits) } - it { should respond_to(:commits_between) } - it { should respond_to(:commits_with_refs) } - end - - - describe "#discover_default_branch" do - let(:master) { 'master' } - let(:stable) { 'stable' } - - it "returns 'master' when master exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - repository.discover_default_branch.should == 'master' - end - - it "returns non-master when master exists but default branch is set to something else" do - repository.root_ref = 'stable' - repository.should_receive(:branch_names).at_least(:once).and_return([stable, master]) - repository.discover_default_branch.should == 'stable' - end - - it "returns a non-master branch when only one exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([stable]) - repository.discover_default_branch.should == 'stable' - end - - it "returns nil when no branch exists" do - repository.should_receive(:branch_names).at_least(:once).and_return([]) - repository.discover_default_branch.should be_nil - end - end - - describe :commit do - it "should return first head commit if without params" do - repository.commit.id.should == repository.repo.commits.first.id - end - - it "should return valid commit" do - repository.commit(ValidCommit::ID).should be_valid_commit - end - - it "should return nil" do - repository.commit("+123_4532530XYZ").should be_nil - end - end - - describe :tree do - before do - @commit = repository.commit(ValidCommit::ID) - end - - it "should raise error w/o arguments" do - lambda { repository.tree }.should raise_error - end - - it "should return root tree for commit" do - tree = repository.tree(@commit) - tree.contents.size.should == ValidCommit::FILES_COUNT - tree.contents.map(&:name).should == ValidCommit::FILES - end - - it "should return root tree for commit with correct path" do - tree = repository.tree(@commit, ValidCommit::C_FILE_PATH) - tree.contents.map(&:name).should == ValidCommit::C_FILES - end - - it "should return root tree for commit with incorrect path" do - repository.tree(@commit, "invalid_path").should be_nil - end - end - - describe "commits" do - subject do - commits = repository.commits('master', 'app', 3, 1) - commits.map { |c| c.id } - end - - it { should have(3).elements } - it { should include("8716fc78f3c65bbf7bcf7b574febd583bc5d2812") } - it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } - end - - describe "commits_between" do - subject do - commits = repository.commits_between("3a4b4fb4cde7809f033822a171b9feae19d41fff", - "8470d70da67355c9c009e4401746b1d5410af2e3") - commits.map { |c| c.id } - end - - it { should have(3).elements } - it { should include("f0f14c8eaba69ebddd766498a9d0b0e79becd633") } - it { should_not include("bcf03b5de6c33f3869ef70d68cf06e679d1d7f9a") } - end - - describe "branch names" do - subject { repository.branch_names } - - it { should have(32).elements } - it { should include("master") } - it { should_not include("branch-from-space") } - end - - describe "tag names" do - subject { repository.tag_names } - - it { should have(16).elements } - it { should include("v1.2.0") } - it { should_not include("v5.0.0") } - end -end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 4e276deaabe..380bbe7351f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -120,7 +120,7 @@ describe User do end it { @user.several_namespaces?.should be_true } - it { @user.namespaces.should == [@user.namespace, @group] } + it { @user.namespaces.should include(@user.namespace, @group) } it { @user.authorized_groups.should == [@group] } it { @user.owned_groups.should == [@group] } end @@ -155,8 +155,8 @@ describe User do it { User.filter("admins").should == [@admin] } it { User.filter("blocked").should == [@blocked] } - it { User.filter("wop").should == [@user, @admin, @blocked] } - it { User.filter(nil).should == [@user, @admin] } + it { User.filter("wop").should include(@user, @admin, @blocked) } + it { User.filter(nil).should include(@user, @admin) } end describe :not_in_project do @@ -166,7 +166,7 @@ describe User do @project = create :project end - it { User.not_in_project(@project).should == [@user, @project.owner] } + it { User.not_in_project(@project).should include(@user, @project.owner) } end describe 'normal user' do diff --git a/spec/observers/merge_request_observer_spec.rb b/spec/observers/merge_request_observer_spec.rb index 24a05646cb5..82c3fbc8a30 100644 --- a/spec/observers/merge_request_observer_spec.rb +++ b/spec/observers/merge_request_observer_spec.rb @@ -12,6 +12,8 @@ describe MergeRequestObserver do before { subject.stub(:current_user).and_return(some_user) } before { subject.stub(notification: mock('NotificationService').as_null_object) } + before(:each) { enable_observers } + subject { MergeRequestObserver.instance } diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index 362c116b64b..1a93148139e 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -249,7 +249,7 @@ describe Gitlab::API do response.status.should == 200 json_response.should be_an Array json_response.count.should == 2 - json_response.first['email'].should == user.email + json_response.map { |u| u['email'] }.should include user.email end it "finds team members with query string" do diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb index 175698ac9c9..efc629e6478 100644 --- a/spec/support/test_env.rb +++ b/spec/support/test_env.rb @@ -1,3 +1,5 @@ +require 'rspec/mocks' + module TestEnv extend self @@ -13,6 +15,8 @@ module TestEnv # - remove_key # def init(opts = {}) + RSpec::Mocks::setup(self) + # Disable observers to improve test speed # # You can enable it in whole test case where needed by next string: @@ -28,6 +32,7 @@ module TestEnv # Use tmp dir for FS manipulations repos_path = Rails.root.join('tmp', 'test-git-base-path') Gitlab.config.gitlab_shell.stub(repos_path: repos_path) + Gitlab::Git::Repository.stub(repos_path: repos_path) GollumWiki.any_instance.stub(:init_repo) do |path| create_temp_repo(File.join(repos_path, "#{path}.git")) @@ -82,6 +87,6 @@ module TestEnv end def disable_mailer - ActionMailer::Base.perform_deliveries = false + NotificationService.any_instance.stub(mailer: double.as_null_object) end end |
