summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.pkgr.yml19
-rw-r--r--CHANGELOG17
-rw-r--r--CONTRIBUTING.md13
-rw-r--r--Gemfile12
-rw-r--r--Gemfile.lock86
-rw-r--r--README.md4
-rw-r--r--VERSION2
-rw-r--r--app/assets/images/ui-icons_222222_256x240.pngbin4193 -> 0 bytes
-rw-r--r--app/assets/images/ui-icons_454545_256x240.pngbin4193 -> 0 bytes
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee4
-rw-r--r--app/assets/javascripts/notes.js.coffee24
-rw-r--r--app/assets/javascripts/project_users_select.js.coffee2
-rw-r--r--app/assets/stylesheets/application.scss55
-rw-r--r--app/assets/stylesheets/generic/files.scss4
-rw-r--r--app/assets/stylesheets/generic/issue_box.scss20
-rw-r--r--app/assets/stylesheets/generic/jquery.scss39
-rw-r--r--app/assets/stylesheets/generic/typography.scss2
-rw-r--r--app/assets/stylesheets/main/mixins.scss25
-rw-r--r--app/assets/stylesheets/sections/diff.scss28
-rw-r--r--app/assets/stylesheets/sections/graph.scss7
-rw-r--r--app/assets/stylesheets/sections/issues.scss41
-rw-r--r--app/assets/stylesheets/sections/merge_requests.scss1
-rw-r--r--app/assets/stylesheets/sections/notes.scss1
-rw-r--r--app/assets/stylesheets/sections/votes.scss6
-rw-r--r--app/controllers/admin/projects_controller.rb1
-rw-r--r--app/controllers/projects/edit_tree_controller.rb12
-rw-r--r--app/controllers/projects/merge_requests_controller.rb24
-rw-r--r--app/controllers/projects/notes_controller.rb3
-rw-r--r--app/controllers/projects/wikis_controller.rb13
-rw-r--r--app/finders/notes_finder.rb11
-rw-r--r--app/helpers/application_helper.rb2
-rw-r--r--app/helpers/commits_helper.rb9
-rw-r--r--app/helpers/issues_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/helpers/selects_helper.rb4
-rw-r--r--app/helpers/tree_helper.rb8
-rw-r--r--app/mailers/emails/merge_requests.rb8
-rw-r--r--app/mailers/emails/notes.rb2
-rw-r--r--app/models/merge_request.rb8
-rw-r--r--app/models/merge_request_diff.rb16
-rw-r--r--app/models/milestone.rb1
-rw-r--r--app/models/note.rb7
-rw-r--r--app/models/project.rb5
-rw-r--r--app/models/project_wiki.rb9
-rw-r--r--app/models/wiki_page.rb16
-rw-r--r--app/services/git_push_service.rb1
-rw-r--r--app/services/system_hooks_service.rb6
-rw-r--r--app/views/admin/broadcast_messages/index.html.haml4
-rw-r--r--app/views/admin/projects/index.html.haml23
-rw-r--r--app/views/layouts/_head_panel.html.haml6
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/notify/closed_merge_request_email.html.haml2
-rw-r--r--app/views/notify/closed_merge_request_email.text.haml2
-rw-r--r--app/views/notify/merged_merge_request_email.html.haml2
-rw-r--r--app/views/notify/merged_merge_request_email.text.haml2
-rw-r--r--app/views/notify/repository_push_email.text.haml2
-rw-r--r--app/views/projects/commits/_parallel_view.html.haml83
-rw-r--r--app/views/projects/edit_tree/_diff.html.haml13
-rw-r--r--app/views/projects/edit_tree/preview.html.haml26
-rw-r--r--app/views/projects/edit_tree/show.html.haml33
-rw-r--r--app/views/projects/issues/_issue_context.html.haml40
-rw-r--r--app/views/projects/issues/show.html.haml31
-rw-r--r--app/views/projects/merge_requests/_form.html.haml63
-rw-r--r--app/views/projects/merge_requests/_merge_request.html.haml10
-rw-r--r--app/views/projects/merge_requests/_new_compare.html.haml84
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml82
-rw-r--r--app/views/projects/merge_requests/branch_from.js.haml5
-rw-r--r--app/views/projects/merge_requests/new.html.haml7
-rw-r--r--app/views/projects/merge_requests/show/_context.html.haml40
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml6
-rw-r--r--app/views/projects/merge_requests/show/_mr_ci.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml4
-rw-r--r--app/views/projects/merge_requests/show/_state_widget.html.haml17
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml21
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/wikis/_new.html.haml2
-rwxr-xr-xbin/pkgr_before_precompile.sh23
-rw-r--r--config/environments/production.rb2
-rw-r--r--config/gitlab.yml.example8
-rw-r--r--config/initializers/1_settings.rb5
-rw-r--r--config/initializers/carrierwave.rb12
-rw-r--r--config/initializers/devise.rb3
-rw-r--r--config/initializers/secret_token.rb4
-rw-r--r--config/initializers/session_store.rb2
-rw-r--r--config/routes.rb6
-rw-r--r--db/fixtures/development/04_project.rb3
-rw-r--r--db/fixtures/development/10_merge_requests.rb70
-rw-r--r--db/migrate/20140415124820_limits_to_mysql.rb1
-rw-r--r--db/migrate/20140416074002_add_index_on_iid.rb32
-rw-r--r--db/migrate/20140416185734_index_on_current_sign_in_at.rb5
-rw-r--r--db/migrate/20140428105831_add_notes_index_updated_at.rb5
-rw-r--r--db/migrate/20140502115131_add_repo_size_to_db.rb5
-rw-r--r--db/migrate/20140502125220_migrate_repo_size.rb21
-rw-r--r--db/migrate/limits_to_mysql.rb10
-rw-r--r--db/schema.rb10
-rw-r--r--doc/README.md2
-rw-r--r--doc/api/README.md4
-rw-r--r--doc/api/issues.md4
-rw-r--r--doc/api/merge_requests.md13
-rw-r--r--doc/api/notes.md2
-rw-r--r--doc/api/users.md27
-rw-r--r--doc/development/README.md7
-rw-r--r--doc/development/rake_tasks.md25
-rw-r--r--doc/install/installation.md56
-rw-r--r--doc/install/requirements.md29
-rw-r--r--doc/integration/README.md1
-rw-r--r--doc/integration/omniauth.md2
-rw-r--r--doc/permissions/permissions.md2
-rw-r--r--doc/public_access/public_access.md2
-rw-r--r--doc/raketasks/README.md3
-rw-r--r--doc/raketasks/import.md28
-rw-r--r--doc/raketasks/maintenance.md29
-rw-r--r--doc/release/monthly.md138
-rw-r--r--doc/system_hooks/system_hooks.md36
-rw-r--r--doc/update/6.0-to-6.8.md (renamed from doc/update/6.0-to-6.7.md)15
-rw-r--r--doc/update/6.7-to-6.8.md24
-rw-r--r--doc/update/README.md4
-rw-r--r--doc/update/mysql_to_postgresql.md61
-rw-r--r--doc/update/ruby.md4
-rw-r--r--doc/update/upgrader.md6
-rw-r--r--doc/web_hooks/web_hooks.md10
-rw-r--r--doc/workflow/authorization_for_merge_requests.md32
-rw-r--r--features/project/forked_merge_requests.feature3
-rw-r--r--features/project/source/browse_files.feature10
-rw-r--r--features/project/wiki.feature17
-rw-r--r--features/steps/dashboard/dashboard.rb1
-rw-r--r--features/steps/project/browse_files.rb12
-rw-r--r--features/steps/project/forked_merge_requests.rb15
-rw-r--r--features/steps/project/merge_requests.rb3
-rw-r--r--features/steps/project/wiki.rb41
-rw-r--r--lib/api/branches.rb10
-rw-r--r--lib/api/users.rb39
-rw-r--r--lib/backup/manager.rb2
-rw-r--r--lib/backup/repository.rb9
-rw-r--r--lib/gitlab/diff_parser.rb20
-rw-r--r--lib/gitlab/ldap/adapter.rb3
-rw-r--r--lib/gitlab/oauth/user.rb10
-rw-r--r--lib/gitlab/satellite/compare_action.rb53
-rw-r--r--lib/gitlab/satellite/satellite.rb1
-rw-r--r--lib/tasks/gitlab/check.rake2
-rw-r--r--lib/tasks/gitlab/setup.rake9
-rw-r--r--lib/tasks/gitlab/shell.rake59
-rw-r--r--lib/tasks/gitlab/test.rake4
-rw-r--r--lib/tasks/migrate/add_limits_mysql.rake11
-rw-r--r--lib/tasks/setup.rake4
-rw-r--r--public/apple-touch-icon-precomposed.pngbin0 -> 11979 bytes
-rw-r--r--public/static.css1
-rw-r--r--spec/finders/notes_finder_spec.rb38
-rw-r--r--spec/helpers/application_helper_spec.rb4
-rw-r--r--spec/mailers/notify_spec.rb8
-rw-r--r--spec/requests/api/users_spec.rb61
-rw-r--r--spec/services/system_hooks_service_spec.rb8
153 files changed, 1758 insertions, 693 deletions
diff --git a/.pkgr.yml b/.pkgr.yml
new file mode 100644
index 00000000000..09cb83783dc
--- /dev/null
+++ b/.pkgr.yml
@@ -0,0 +1,19 @@
+user: git
+group: git
+before_precompile: ./bin/pkgr_before_precompile.sh
+targets:
+ debian-7: &wheezy
+ build_dependencies:
+ - libicu-dev
+ dependencies:
+ - libicu48
+ - libpcre3
+ - git
+ ubuntu-12.04: *wheezy
+ ubuntu-14.04:
+ build_dependencies:
+ - libicu-dev
+ dependencies:
+ - libicu52
+ - libpcre3
+ - git
diff --git a/CHANGELOG b/CHANGELOG
index 3ef46f4484e..72bd6984869 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,20 @@
+v 6.9.0
+ - Store Rails cache data in the Redis `cache:gitlab` namespace
+ - Adjust MySQL limits for existing installations
+ - Add db index on project_id+iid column. This prevents duplicate on iid (During migration duplicates will be removed)
+ - Markdown preview or diff during editing via web editor (Evgeniy Sokovikov)
+ - Give the Rails cache its own Redis namespace
+ - Add ability to set different ssh host, if different from http/https
+ - Fix syntax highlighting for code comments blocks
+ - Improve comments loading logic
+ - Stop refreshing comments when the tab is hidden
+ - Improve issue and merge request mobile UI (Drew Blessing)
+ - Document how to convert a backup to PostgreSQL
+ - Fix locale bug in backup manager
+ - Fix wiki backup skip bug
+ - Two Step MR creation process
+ - Remove unwanted files from satellite working directory with git clean -fdx
+
v 6.8.0
- Ability to at mention users that are participating in issue and merge req. discussion
- Enabled GZip Compression for assets in example Nginx, make sure that Nginx is compiled with --with-http_gzip_static_module flag (this is default in Ubuntu)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 290804e6187..780db547f82 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -107,9 +107,10 @@ For examples of feedback on merge requests please look at already [closed merge
## Style guides
1. [Ruby](https://github.com/bbatsov/ruby-style-guide)
-2. [Rails](https://github.com/bbatsov/rails-style-guide)
-3. [Formatting](https://github.com/thoughtbot/guides/tree/master/style#formatting)
-4. [Naming](https://github.com/thoughtbot/guides/tree/master/style#naming)
-8. [Testing](https://github.com/thoughtbot/guides/tree/master/style#testing)
-7. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
-9. [Shell commands](doc/development/shell_commands.md)
+1. [Rails](https://github.com/bbatsov/rails-style-guide)
+1. [Formatting](https://github.com/thoughtbot/guides/tree/master/style#formatting)
+1. [Naming](https://github.com/thoughtbot/guides/tree/master/style#naming)
+1. [Testing](https://github.com/thoughtbot/guides/tree/master/style#testing)
+1. [CoffeeScript](https://github.com/thoughtbot/guides/tree/master/style#coffeescript)
+1. [Shell commands](doc/development/shell_commands.md)
+1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
diff --git a/Gemfile b/Gemfile
index 4ab1ab50eb9..7ff7515143c 100644
--- a/Gemfile
+++ b/Gemfile
@@ -71,6 +71,7 @@ gem "carrierwave"
# for aws storage
gem "fog", "~> 1.14", group: :aws
+gem "unf", group: :aws
# Authorization
gem "six"
@@ -82,6 +83,9 @@ gem "seed-fu"
gem "redcarpet", "~> 2.2.2"
gem "github-markup"
+# Diffs
+gem 'diffy', '~> 3.0.3'
+
# Asciidoc to HTML
gem "asciidoctor"
@@ -148,7 +152,7 @@ gem "rack-attack"
# Ace editor
gem 'ace-rails-ap'
-gem "sass-rails"
+gem "sass-rails", '~> 4.0.2'
gem "coffee-rails"
gem "uglifier"
gem "therubyracer"
@@ -157,8 +161,8 @@ gem 'jquery-turbolinks'
gem 'select2-rails'
gem 'jquery-atwho-rails', "~> 0.3.3"
-gem "jquery-rails", "2.1.3"
-gem "jquery-ui-rails", "2.0.2"
+gem "jquery-rails"
+gem "jquery-ui-rails"
gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 3.2'
@@ -232,4 +236,4 @@ end
group :production do
gem "gitlab_meta", '6.0'
-end \ No newline at end of file
+end
diff --git a/Gemfile.lock b/Gemfile.lock
index 155e03e5456..c022868bc2e 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -2,26 +2,26 @@ GEM
remote: https://rubygems.org/
specs:
ace-rails-ap (2.0.1)
- actionmailer (4.0.3)
- actionpack (= 4.0.3)
+ actionmailer (4.0.5)
+ actionpack (= 4.0.5)
mail (~> 2.5.4)
- actionpack (4.0.3)
- activesupport (= 4.0.3)
+ actionpack (4.0.5)
+ activesupport (= 4.0.5)
builder (~> 3.1.0)
erubis (~> 2.7.0)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
- activemodel (4.0.3)
- activesupport (= 4.0.3)
+ activemodel (4.0.5)
+ activesupport (= 4.0.5)
builder (~> 3.1.0)
- activerecord (4.0.3)
- activemodel (= 4.0.3)
+ activerecord (4.0.5)
+ activemodel (= 4.0.5)
activerecord-deprecated_finders (~> 1.0.2)
- activesupport (= 4.0.3)
+ activesupport (= 4.0.5)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
- activesupport (4.0.3)
- i18n (~> 0.6, >= 0.6.4)
+ activesupport (4.0.5)
+ i18n (~> 0.6, >= 0.6.9)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
@@ -34,7 +34,6 @@ GEM
rake (>= 0.8.7)
arel (4.0.2)
asciidoctor (0.1.4)
- atomic (1.1.16)
awesome_print (1.2.0)
axiom-types (0.0.5)
descendants_tracker (~> 0.0.1)
@@ -101,6 +100,7 @@ GEM
devise-async (0.8.0)
devise (>= 2.2, < 3.2)
diff-lcs (1.2.5)
+ diffy (3.0.3)
docile (1.1.1)
dotenv (0.9.0)
email_spec (1.5.0)
@@ -162,7 +162,7 @@ GEM
multi_json
gitlab-grack (2.0.0.pre)
rack (~> 1.5.1)
- gitlab-grit (2.6.5)
+ gitlab-grit (2.6.6)
charlock_holmes (~> 0.6)
diff-lcs (~> 1.1)
mime-types (~> 1.15)
@@ -247,15 +247,14 @@ GEM
rake
jasmine-core (2.0.0.rc5)
jquery-atwho-rails (0.3.3)
- jquery-rails (2.1.3)
- railties (>= 3.1.0, < 5.0)
- thor (~> 0.14)
+ jquery-rails (3.1.0)
+ railties (>= 3.0, < 5.0)
+ thor (>= 0.14, < 2.0)
jquery-turbolinks (2.0.1)
railties (>= 3.1.0)
turbolinks
- jquery-ui-rails (2.0.2)
- jquery-rails
- railties (>= 3.1.0)
+ jquery-ui-rails (4.2.1)
+ railties (>= 3.2.16)
json (1.8.1)
jwt (0.1.8)
multi_json (>= 1.5)
@@ -280,7 +279,7 @@ GEM
mime-types (1.25.1)
mini_portile (0.5.3)
minitest (4.7.5)
- multi_json (1.9.2)
+ multi_json (1.10.0)
multi_xml (0.5.5)
multipart-post (1.2.0)
mysql2 (0.3.11)
@@ -350,13 +349,13 @@ GEM
rack
rack-test (0.6.2)
rack (>= 1.0)
- rails (4.0.3)
- actionmailer (= 4.0.3)
- actionpack (= 4.0.3)
- activerecord (= 4.0.3)
- activesupport (= 4.0.3)
+ rails (4.0.5)
+ actionmailer (= 4.0.5)
+ actionpack (= 4.0.5)
+ activerecord (= 4.0.5)
+ activesupport (= 4.0.5)
bundler (>= 1.3.0, < 2.0)
- railties (= 4.0.3)
+ railties (= 4.0.5)
sprockets-rails (~> 2.0.0)
rails-observers (0.1.2)
activemodel (~> 4.0)
@@ -369,13 +368,13 @@ GEM
i18n
require_all
ruby-progressbar
- railties (4.0.3)
- actionpack (= 4.0.3)
- activesupport (= 4.0.3)
+ railties (4.0.5)
+ actionpack (= 4.0.5)
+ activesupport (= 4.0.5)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
raindrops (0.12.0)
- rake (10.1.1)
+ rake (10.3.1)
raphael-rails (2.1.2)
rb-fsevent (0.9.3)
rb-inotify (0.9.2)
@@ -428,11 +427,12 @@ GEM
safe_yaml (0.9.7)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
- sass (3.2.12)
- sass-rails (4.0.1)
+ sass (3.2.19)
+ sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0)
- sass (>= 3.1.10)
- sprockets-rails (~> 2.0.0)
+ sass (~> 3.2.0)
+ sprockets (~> 2.8, <= 2.11.0)
+ sprockets-rails (~> 2.0)
sdoc (0.3.20)
json (>= 1.1.3)
rdoc (~> 3.10)
@@ -479,7 +479,7 @@ GEM
spring (>= 0.9.1)
spring-commands-spinach (1.0.0)
spring (>= 0.9.1)
- sprockets (2.10.1)
+ sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
@@ -502,9 +502,8 @@ GEM
daemons (>= 1.0.9)
eventmachine (>= 1.0.0)
rack (>= 1.0.0)
- thor (0.18.1)
- thread_safe (0.3.1)
- atomic (>= 1.1.7, < 2)
+ thor (0.19.1)
+ thread_safe (0.3.3)
tilt (1.4.1)
timers (1.1.0)
tinder (1.9.3)
@@ -531,6 +530,9 @@ GEM
execjs (>= 0.3.0)
json (>= 1.8.0)
underscore-rails (1.4.4)
+ unf (0.1.4)
+ unf_ext
+ unf_ext (0.0.6)
unicorn (4.6.3)
kgio (~> 2.6)
rack
@@ -574,6 +576,7 @@ DEPENDENCIES
default_value_for (~> 3.0.0)
devise (= 3.0.4)
devise-async (= 0.8.0)
+ diffy (~> 3.0.3)
email_spec
email_validator (~> 1.4.0)
enumerize
@@ -603,9 +606,9 @@ DEPENDENCIES
httparty
jasmine (= 2.0.0.rc5)
jquery-atwho-rails (~> 0.3.3)
- jquery-rails (= 2.1.3)
+ jquery-rails
jquery-turbolinks
- jquery-ui-rails (= 2.0.2)
+ jquery-ui-rails
kaminari (~> 0.15.1)
launchy
letter_opener
@@ -634,7 +637,7 @@ DEPENDENCIES
redis-rails
rspec-rails
sanitize (~> 2.0)
- sass-rails
+ sass-rails (~> 4.0.2)
sdoc
seed-fu
select2-rails
@@ -659,6 +662,7 @@ DEPENDENCIES
turbolinks
uglifier
underscore-rails (~> 1.4.4)
+ unf
unicorn (~> 4.6.3)
unicorn-worker-killer
version_sorter
diff --git a/README.md b/README.md
index 3f3453a267a..ca7bec3b6d6 100644
--- a/README.md
+++ b/README.md
@@ -29,11 +29,11 @@
* [GitLab.com](https://www.gitlab.com/) includes information about [subscriptions](https://www.gitlab.com/subscription/), [consultancy](https://www.gitlab.com/consultancy/), the [community](https://www.gitlab.com/community/) and the [hosted GitLab Cloud](https://www.gitlab.com/cloud/).
-* [GitLab Enterprise Edition](https://www.gitlab.com/gitlab-ce/) offers additional features that are useful for larger organizations (100+ users).
+* [GitLab Enterprise Edition](https://www.gitlab.com/gitlab-ee/) offers additional features aimed at larger organizations.
* [GitLab CI](https://www.gitlab.com/gitlab-ci/) is a continuous integration (CI) server that is easy to integrate with GitLab.
-* Unofficial third-party [iPhone app](http://gitlabcontrol.com/) and [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) for GitLab
+* Unofficial third-party [iPhone app](http://gitlabcontrol.com/), [Android app](https://play.google.com/store/apps/details?id=com.bd.gitlab&hl=en) and [command line client](https://github.com/drewblessing/gitlab-cli) and [Ruby API wrapper](https://github.com/NARKOZ/gitlab) for GitLab.
### Requirements
diff --git a/VERSION b/VERSION
index 5a92de67b0c..c0ad52beda3 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-6.8.0.rc1
+6.9.0.pre
diff --git a/app/assets/images/ui-icons_222222_256x240.png b/app/assets/images/ui-icons_222222_256x240.png
deleted file mode 100644
index 8bc06cbf03b..00000000000
--- a/app/assets/images/ui-icons_222222_256x240.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/images/ui-icons_454545_256x240.png b/app/assets/images/ui-icons_454545_256x240.png
deleted file mode 100644
index cfd1eaffaae..00000000000
--- a/app/assets/images/ui-icons_454545_256x240.png
+++ /dev/null
Binary files differ
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 46d6db0f05c..b61d9875e03 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -59,7 +59,7 @@ class Dispatcher
initHighlight: ->
$('.highlight pre code').each (i, e) ->
- hljs.highlightBlock(e)
$(e).html($.map($(e).html().split("\n"), (line, i) ->
- "<div class='line' id='LC" + (i + 1) + "'>" + line + "</div>"
+ "<span class='line' id='LC" + (i + 1) + "'>" + line + "</span>"
).join("\n"))
+ hljs.highlightBlock(e)
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index d200d962cae..47989010d1a 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -1,10 +1,11 @@
class Notes
@interval: null
- constructor: (notes_url, note_ids) ->
+ constructor: (notes_url, note_ids, last_fetched_at) ->
@notes_url = notes_url
@notes_url = gon.relative_url_root + @notes_url if gon.relative_url_root?
@note_ids = note_ids
+ @last_fetched_at = last_fetched_at
@initRefresh()
@setupMainTargetNoteForm()
@cleanBinding()
@@ -49,6 +50,15 @@ class Notes
# hide diff note form
$(document).on "click", ".js-close-discussion-note-form", @cancelDiscussionForm
+ # fetch notes when tab becomes visible
+ $(document).on "visibilitychange", @visibilityChange
+
+ @notes_forms = '.js-main-target-form textarea, .js-discussion-note-form textarea'
+ $(document).on('keypress', @notes_forms, (e)->
+ if event.keyCode == 10 || (event.ctrlKey && event.keyCode == 13)
+ $(@).parents('form').submit()
+ )
+
cleanBinding: ->
$(document).off "ajax:success", ".js-main-target-form"
$(document).off "ajax:success", ".js-discussion-note-form"
@@ -62,6 +72,8 @@ class Notes
$(document).off "click", ".js-choose-note-attachment-button"
$(document).off "click", ".js-discussion-reply-button"
$(document).off "click", ".js-add-diff-note-button"
+ $(document).off "visibilitychange"
+ $(document).off "keypress", @notes_forms
initRefresh: ->
@@ -71,14 +83,16 @@ class Notes
, 15000
refresh: ->
- @getContent()
+ @getContent() unless document.hidden
getContent: ->
$.ajax
url: @notes_url
+ data: "last_fetched_at=" + @last_fetched_at
dataType: "json"
success: (data) =>
notes = data.notes
+ @last_fetched_at = data.last_fetched_at
$.each notes, (i, note) =>
@renderNote(note)
@@ -450,4 +464,10 @@ class Notes
filename = $(this).val().replace(/^.*[\\\/]/, "")
form.find(".js-attachment-filename").text filename
+ ###
+ Called when the tab visibility changes
+ ###
+ visibilityChange: =>
+ @refresh()
+
@Notes = Notes
diff --git a/app/assets/javascripts/project_users_select.js.coffee b/app/assets/javascripts/project_users_select.js.coffee
index 03fad41c490..b0e39610feb 100644
--- a/app/assets/javascripts/project_users_select.js.coffee
+++ b/app/assets/javascripts/project_users_select.js.coffee
@@ -1,7 +1,7 @@
@projectUsersSelect =
init: ->
$('.ajax-project-users-select').each (i, select) ->
- project_id = $('body').data('project-id')
+ project_id = $(select).data('project-id') || $('body').data('project-id')
$(select).select2
placeholder: $(select).data('placeholder') || "Search for a user"
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index ce36c1132ea..c53873f95a2 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -12,10 +12,7 @@
*= require nprogress-bootstrap
*/
-@import "main/variables.scss";
-@import "main/mixins.scss";
-@import "main/fonts.scss";
-@import "main/layout.scss";
+@import "main/*";
/**
* Customized Twitter bootstrap
@@ -31,64 +28,22 @@
/**
* Generic css (forms, nav etc):
*/
-@import "generic/avatar.scss";
-@import "generic/common.scss";
-@import "generic/typography.scss";
-@import "generic/buttons.scss";
-@import "generic/blocks.scss";
-@import "generic/ui_box.scss";
-@import "generic/issue_box.scss";
-@import "generic/files.scss";
-@import "generic/lists.scss";
-@import "generic/flash.scss";
-@import "generic/forms.scss";
-@import "generic/selects.scss";
-@import "generic/highlight.scss";
-@import "generic/jquery.scss";
+@import "generic/*";
/**
* Page specific styles (issues, projects etc):
*/
-@import "sections/header.scss";
-@import "sections/nav.scss";
-@import "sections/commits.scss";
-@import "sections/diff.scss";
-@import "sections/issues.scss";
-@import "sections/projects.scss";
-@import "sections/snippets.scss";
-@import "sections/votes.scss";
-@import "sections/merge_requests.scss";
-@import "sections/graph.scss";
-@import "sections/events.scss";
-@import "sections/themes.scss";
-@import "sections/tree.scss";
-@import "sections/notes.scss";
-@import "sections/profile.scss";
-@import "sections/login.scss";
-@import "sections/editor.scss";
-@import "sections/admin.scss";
-@import "sections/wiki.scss";
-@import "sections/wall.scss";
-@import "sections/dashboard.scss";
-@import "sections/stat_graph.scss";
-@import "sections/groups.scss";
+@import "sections/*";
/**
* Code highlight
*/
-@import "highlight/white.scss";
-@import "highlight/dark.scss";
-@import "highlight/solarized_dark.scss";
-@import "highlight/monokai.scss";
+@import "highlight/*";
/**
* UI themes:
*/
-@import "themes/ui_basic.scss";
-@import "themes/ui_mars.scss";
-@import "themes/ui_modern.scss";
-@import "themes/ui_gray.scss";
-@import "themes/ui_color.scss";
+@import "themes/*";
/**
* Styles for JS behaviors.
diff --git a/app/assets/stylesheets/generic/files.scss b/app/assets/stylesheets/generic/files.scss
index 12559f76051..6418f24d97f 100644
--- a/app/assets/stylesheets/generic/files.scss
+++ b/app/assets/stylesheets/generic/files.scss
@@ -26,6 +26,10 @@
margin-top: -5px;
}
+ .left-options {
+ margin-top: -3px;
+ }
+
.file_name {
color: $style_color;
font-size: 14px;
diff --git a/app/assets/stylesheets/generic/issue_box.scss b/app/assets/stylesheets/generic/issue_box.scss
index 3db4d908d9c..d4d3361bc72 100644
--- a/app/assets/stylesheets/generic/issue_box.scss
+++ b/app/assets/stylesheets/generic/issue_box.scss
@@ -12,6 +12,7 @@
margin:20px 0;
background: #FFF;
border: 1px solid #EEE;
+ @include box-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
&.issue-box-closed {
border-color: #DA4E49;
@@ -70,7 +71,6 @@
}
.state {
- height: 34px;
border-bottom: 1px solid #DDD;
line-height: 32px;
}
@@ -89,6 +89,18 @@
border: none;
border-top: 1px solid #eee;
padding: 15px 25px;
+
+ // Reset text align for children
+ .text-right > * { text-align: left; }
+
+ @media (max-width: $screen-xs-max) {
+ // Don't right align on mobile
+ .text-right { text-align: left; }
+
+ .row .col-md-6 {
+ padding-top: 5px;
+ }
+ }
}
.description {
@@ -106,7 +118,11 @@
padding: 1px 25px;
text-align: center;
text-shadow: none;
- margin-right: 20px;
display: inline-block;
+ line-height: 34px;
+ }
+
+ .creator {
+ padding: 2px 15px;
}
}
diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/generic/jquery.scss
index 4a9341e8f53..6b29accb315 100644
--- a/app/assets/stylesheets/generic/jquery.scss
+++ b/app/assets/stylesheets/generic/jquery.scss
@@ -8,7 +8,7 @@
width: 270px;
.ui-datepicker-header {
- background: #EEE;
+ background: #FFF;
border-color: #DDD;
}
@@ -19,20 +19,37 @@
}
&.ui-autocomplete {
- @include border-radius(0px);
border-color: #DDD;
padding: 0;
+ margin-top: 2px;
+ z-index: 1001;
.ui-menu-item a {
- color: #777;
-
- &:hover {
- background: $hover;
- border-color: $primary_color;
- @include border-radius(0px);
- color: #333;
- }
+ padding: 4px 10px;
}
}
-}
+ .ui-state-default {
+ border: 1px solid #FFF;
+ background: #FFF;
+ color: #777;
+ }
+
+ .ui-state-highlight {
+ border: 1px solid #EEE;
+ background: #EEE;
+ }
+
+ .ui-state-active {
+ border: 1px solid $bg_style_color;
+ background: $bg_style_color;
+ color: #FFF;
+ }
+
+ .ui-state-hover,
+ .ui-state-focus {
+ border: 1px solid $hover;
+ background: $hover;
+ color: #333;
+ }
+}
diff --git a/app/assets/stylesheets/generic/typography.scss b/app/assets/stylesheets/generic/typography.scss
index a4419551738..8cc72d7f07a 100644
--- a/app/assets/stylesheets/generic/typography.scss
+++ b/app/assets/stylesheets/generic/typography.scss
@@ -47,7 +47,7 @@ a {
text-decoration: underline;
}
- &.dark {
+ &.darken {
color: $style_color;
}
diff --git a/app/assets/stylesheets/main/mixins.scss b/app/assets/stylesheets/main/mixins.scss
index fcc7374d0d9..147c759ecb8 100644
--- a/app/assets/stylesheets/main/mixins.scss
+++ b/app/assets/stylesheets/main/mixins.scss
@@ -41,31 +41,6 @@
* Prefilled mixins
* Mixins with fixed values
*/
-@mixin bg-light-gray-gradient {
- background: #f1f1f1;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #f5f5f5), to(#e1e1e1));
- background-image: -webkit-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
- background-image: -moz-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
- background-image: -ms-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
- background-image: -o-linear-gradient(#f5f5f5 6.6%, #e1e1e1);
-}
-
-@mixin bg-gray-gradient {
- background: #eee;
- background-image: -webkit-gradient(linear, 0 0, 0 30, color-stop(0.066, #eee), to(#dfdfdf));
- background-image: -webkit-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -moz-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -ms-linear-gradient(#eee 6.6%, #dfdfdf);
- background-image: -o-linear-gradient(#eee 6.6%, #dfdfdf);
-}
-
-@mixin bg-dark-gray-gradient {
- background: #eee;
- background-image: -webkit-linear-gradient(#e9e9e9, #d7d7d7);
- background-image: -moz-linear-gradient(#e9e9e9, #d7d7d7);
- background-image: -ms-linear-gradient(#e9e9e9, #d7d7d7);
- background-image: -o-linear-gradient(#e9e9e9, #d7d7d7);
-}
@mixin shade {
@include box-shadow(0 0 3px #ddd);
diff --git a/app/assets/stylesheets/sections/diff.scss b/app/assets/stylesheets/sections/diff.scss
index eb272f20f40..64e669ac2b3 100644
--- a/app/assets/stylesheets/sections/diff.scss
+++ b/app/assets/stylesheets/sections/diff.scss
@@ -63,26 +63,14 @@
}
}
- .text-file-parallel div {
- display: inline-block;
- padding-bottom: 16px;
- }
- .diff-side {
- overflow-x: scroll;
- width: 508px;
- height: 700px;
- }
- .diff-side.diff-side-left{
- overflow-y:hidden;
- }
- .diff-side table, td.diff-middle table {
- height: 700px;
- }
- .diff-middle {
- width: 114px;
- vertical-align: top;
- height: 700px;
- overflow: hidden
+ tr.line_holder.parallel{
+ .old_line, .new_line, .diff_line {
+ min-width: 50px;
+ }
+
+ td.line_content.parallel{
+ width: 50%;
+ }
}
.old_line, .new_line, .diff_line {
diff --git a/app/assets/stylesheets/sections/graph.scss b/app/assets/stylesheets/sections/graph.scss
index 1e22d161bfc..8a337a5e206 100644
--- a/app/assets/stylesheets/sections/graph.scss
+++ b/app/assets/stylesheets/sections/graph.scss
@@ -1,17 +1,16 @@
.project-network {
- border: 1px solid #aaa;
- padding: 1px;
+ border: 1px solid #CCC;
.tip {
color: #888;
font-size: 14px;
padding: 10px;
border-bottom: 1px solid #bbb;
- @include bg-gray-gradient;
+ background: #EEE;
}
.network-graph {
- background: #f1f1f1;
+ background: #FFF;
height: 500px;
overflow-y: scroll;
overflow-x: hidden;
diff --git a/app/assets/stylesheets/sections/issues.scss b/app/assets/stylesheets/sections/issues.scss
index d4f8c8108ab..02c9123178f 100644
--- a/app/assets/stylesheets/sections/issues.scss
+++ b/app/assets/stylesheets/sections/issues.scss
@@ -45,14 +45,6 @@
padding: 6px 10px;
border: 1px solid #ccc;
@include border-radius(4px);
-
-
- input.check_all_issues {
- padding: 0;
- margin: 0;
- position: relative;
- top: 3px;
- }
}
.issues_content {
@@ -143,3 +135,36 @@ form.edit-issue {
border-color: #E5E5E5;
}
}
+
+@media (max-width: $screen-xs-max) {
+ .issue-btn-group {
+ width: 100%;
+ margin-top: 5px;
+
+ .btn-group {
+ width: 100%;
+
+ ul {
+ width: 100%;
+ text-align: center;
+ }
+ }
+
+ .btn {
+ width: 100%;
+ margin-top: -1px;
+
+ &:first-child:not(:last-child) {
+ border-radius: 4px 4px 0 0;
+ }
+
+ &:not(:first-child):not(:last-child) {
+ border-radius: 0;
+ }
+
+ &:last-child:not(:first-child) {
+ border-radius: 0 0 4px 4px;
+ }
+ }
+ }
+}
diff --git a/app/assets/stylesheets/sections/merge_requests.scss b/app/assets/stylesheets/sections/merge_requests.scss
index 790496a1a5a..5dcfc449b42 100644
--- a/app/assets/stylesheets/sections/merge_requests.scss
+++ b/app/assets/stylesheets/sections/merge_requests.scss
@@ -31,7 +31,6 @@
.mr_source_commit,
.mr_target_commit {
- margin-top: 10px;
.commit {
margin: 0;
padding: 2px 0;
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index c9c7b6ecced..7e56781f56a 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -139,6 +139,7 @@ ul.notes {
background-color: #fff;
border-width: 1px 0;
padding-top: 0;
+ vertical-align: top;
li {
padding: 5px;
diff --git a/app/assets/stylesheets/sections/votes.scss b/app/assets/stylesheets/sections/votes.scss
index 13f811e01a1..d683e33e1f0 100644
--- a/app/assets/stylesheets/sections/votes.scss
+++ b/app/assets/stylesheets/sections/votes.scss
@@ -40,4 +40,10 @@
.votes-holder {
float: right;
width: 250px;
+
+ @media (max-width: $screen-xs-max) {
+ width: 100%;
+ margin-top: 5px;
+ margin-bottom: 10px;
+ }
}
diff --git a/app/controllers/admin/projects_controller.rb b/app/controllers/admin/projects_controller.rb
index 13a7bdcf34a..92ef5963373 100644
--- a/app/controllers/admin/projects_controller.rb
+++ b/app/controllers/admin/projects_controller.rb
@@ -12,6 +12,7 @@ class Admin::ProjectsController < Admin::ApplicationController
@projects = @projects.with_push if params[:with_push].present?
@projects = @projects.abandoned if params[:abandoned].present?
@projects = @projects.search(params[:name]) if params[:name].present?
+ @projects = @projects.sort(@sort = params[:sort])
@projects = @projects.includes(:namespace).order("namespaces.path, projects.name ASC").page(params[:page]).per(20)
end
diff --git a/app/controllers/projects/edit_tree_controller.rb b/app/controllers/projects/edit_tree_controller.rb
index ff5206b6fa1..be611892bb0 100644
--- a/app/controllers/projects/edit_tree_controller.rb
+++ b/app/controllers/projects/edit_tree_controller.rb
@@ -26,6 +26,18 @@ class Projects::EditTreeController < Projects::BaseTreeController
end
end
+ def preview
+ @content = params[:content]
+ #FIXME workaround https://github.com/gitlabhq/gitlabhq/issues/5936
+ @content += "\n" if @blob.data.end_with?("\n")
+
+ diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
+ include_diff_info: true)
+ @diff = Gitlab::DiffParser.new(diffy.diff.scan(/.*\n/))
+
+ render layout: false
+ end
+
private
def blob
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 745da9c49e4..d8551db7b01 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -62,11 +62,27 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request.source_project = @project unless @merge_request.source_project
@merge_request.target_project ||= (@project.forked_from_project || @project)
@target_branches = @merge_request.target_project.nil? ? [] : @merge_request.target_project.repository.branch_names
-
@merge_request.target_branch ||= @merge_request.target_project.default_branch
-
@source_project = @merge_request.source_project
- @merge_request
+
+ if @merge_request.target_branch && @merge_request.source_branch
+ compare_action = Gitlab::Satellite::CompareAction.new(
+ current_user,
+ @merge_request.target_project,
+ @merge_request.target_branch,
+ @merge_request.source_project,
+ @merge_request.source_branch
+ )
+
+ @commits = compare_action.commits
+ @commits.map! { |commit| Commit.new(commit) }
+ @commit = @commits.first
+
+ @diffs = compare_action.diffs
+ @merge_request.title = @merge_request.source_branch.titleize.humanize
+ @target_project = @merge_request.target_project
+ @target_repo = @target_project.repository
+ end
end
def edit
@@ -80,7 +96,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@merge_request = MergeRequests::CreateService.new(project, current_user, params[:merge_request]).execute
if @merge_request.valid?
- redirect_to [@merge_request.target_project, @merge_request], notice: 'Merge request was successfully created.'
+ redirect_to project_merge_request_path(@merge_request.target_project, @merge_request), notice: 'Merge request was successfully created.'
else
@source_project = @merge_request.source_project
@target_project = @merge_request.target_project
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index 85d042a89b5..b5b0446b43f 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -5,9 +5,10 @@ class Projects::NotesController < Projects::ApplicationController
before_filter :authorize_admin_note!, only: [:update, :destroy]
def index
+ current_fetched_at = Time.now.to_i
@notes = NotesFinder.new.execute(project, current_user, params)
- notes_json = { notes: [] }
+ notes_json = { notes: [], last_fetched_at: current_fetched_at }
@notes.each do |note|
notes_json[:notes] << {
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index bcd9e0d5219..496064c9a65 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -12,9 +12,22 @@ class Projects::WikisController < Projects::ApplicationController
def show
@page = @project_wiki.find_page(params[:id], params[:version_id])
+ gollum_wiki = @project_wiki.wiki
+ file = gollum_wiki.file(params[:id], gollum_wiki.ref, true)
if @page
render 'show'
+ elsif file
+ if file.on_disk?
+ send_file file.on_disk_path, disposition: 'inline'
+ else
+ send_data(
+ file.raw_data,
+ type: file.mime_type,
+ disposition: 'inline',
+ filename: file.name
+ )
+ end
else
return render('empty') unless can?(current_user, :write_wiki, @project)
@page = WikiPage.new(@project_wiki)
diff --git a/app/finders/notes_finder.rb b/app/finders/notes_finder.rb
index 384316e14b7..ea055694cd7 100644
--- a/app/finders/notes_finder.rb
+++ b/app/finders/notes_finder.rb
@@ -1,9 +1,13 @@
class NotesFinder
+ FETCH_OVERLAP = 5.seconds
+
def execute(project, current_user, params)
target_type = params[:target_type]
target_id = params[:target_id]
+ # Default to 0 to remain compatible with old clients
+ last_fetched_at = Time.at(params.fetch(:last_fetched_at, 0).to_i)
- case target_type
+ notes = case target_type
when "commit"
project.notes.for_commit_id(target_id).not_inline.fresh
when "issue"
@@ -12,6 +16,11 @@ class NotesFinder
project.merge_requests.find(target_id).mr_and_commit_notes.inc_author.fresh
when "snippet"
project.snippets.find(target_id).notes.fresh
+ else
+ raise 'invalid target_type'
end
+
+ # Use overlapping intervals to avoid worrying about race conditions
+ notes.where('updated_at > ?', last_fetched_at - FETCH_OVERLAP)
end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index faecde299c1..5f07cdf448c 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -75,7 +75,7 @@ module ApplicationHelper
else
gravatar_url = request.ssl? || gitlab_config.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
+ sprintf gravatar_url, hash: Digest::MD5.hexdigest(user_email.downcase), size: size, email: user_email
end
end
diff --git a/app/helpers/commits_helper.rb b/app/helpers/commits_helper.rb
index c6e4f574b67..c4abdbdabc7 100644
--- a/app/helpers/commits_helper.rb
+++ b/app/helpers/commits_helper.rb
@@ -16,9 +16,10 @@ module CommitsHelper
end
def each_diff_line(diff, index)
- Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
- yield(full_line, type, line_code, line_new, line_old)
- end
+ Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
+ .each do |full_line, type, line_code, line_new, line_old|
+ yield(full_line, type, line_code, line_new, line_old)
+ end
end
def each_diff_line_near(diff, index, expected_line_code)
@@ -116,7 +117,7 @@ module CommitsHelper
added_lines[line_new] = { line_code: line_code, type: type, line: line }
end
end
- max_length = old_file ? old_file.sloc + added_lines.length : file.sloc
+ max_length = old_file ? [old_file.loc, file.loc].max : file.loc
offset1 = 0
offset2 = 0
diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb
index 95f0eff58b1..7c58908165c 100644
--- a/app/helpers/issues_helper.rb
+++ b/app/helpers/issues_helper.rb
@@ -82,7 +82,7 @@ module IssuesHelper
end
def milestone_options object
- options_from_collection_for_select(@project.milestones.active, 'id', 'title', object.milestone_id)
+ options_from_collection_for_select(object.project.milestones.active, 'id', 'title', object.milestone_id)
end
def issue_box_class(item)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index 9bb3efc41d8..ef0460f8728 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -163,7 +163,7 @@ module ProjectsHelper
end
def repository_size(project = nil)
- "#{(project || @project).repository.size} MB"
+ "#{(project || @project).repository_size} MB"
rescue
# In order to prevent 500 error
# when application cannot allocate memory
diff --git a/app/helpers/selects_helper.rb b/app/helpers/selects_helper.rb
index a1fe4488ae9..ab24367c455 100644
--- a/app/helpers/selects_helper.rb
+++ b/app/helpers/selects_helper.rb
@@ -14,7 +14,7 @@ module SelectsHelper
css_class << (opts[:class] || '')
value = opts[:selected] || ''
placeholder = opts[:placeholder] || 'Select user'
-
- hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder)
+ project_id = opts[:project_id] || @project.id
+ hidden_field_tag(id, value, class: css_class, 'data-placeholder' => placeholder, 'data-project-id' => project_id)
end
end
diff --git a/app/helpers/tree_helper.rb b/app/helpers/tree_helper.rb
index 50501dffefb..f39d0081dce 100644
--- a/app/helpers/tree_helper.rb
+++ b/app/helpers/tree_helper.rb
@@ -91,4 +91,12 @@ module TreeHelper
def leave_edit_message
"Leave edit mode?\nAll unsaved changes will be lost."
end
+
+ def editing_preview_title(filename)
+ if gitlab_markdown?(filename) || markup?(filename)
+ 'Preview'
+ else
+ 'Diff'
+ end
+ end
end
diff --git a/app/mailers/emails/merge_requests.rb b/app/mailers/emails/merge_requests.rb
index a97d55f1b50..1130969a26d 100644
--- a/app/mailers/emails/merge_requests.rb
+++ b/app/mailers/emails/merge_requests.rb
@@ -6,7 +6,7 @@ module Emails
@target_url = project_merge_request_url(@project, @merge_request)
mail(from: sender(@merge_request.author_id),
to: recipient(recipient_id),
- subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
+ subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def reassigned_merge_request_email(recipient_id, merge_request_id, previous_assignee_id, updated_by_user_id)
@@ -16,7 +16,7 @@ module Emails
@target_url = project_merge_request_url(@project, @merge_request)
mail(from: sender(updated_by_user_id),
to: recipient(recipient_id),
- subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
+ subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def closed_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@@ -26,7 +26,7 @@ module Emails
@target_url = project_merge_request_url(@project, @merge_request)
mail(from: sender(updated_by_user_id),
to: recipient(recipient_id),
- subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
+ subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def merged_merge_request_email(recipient_id, merge_request_id, updated_by_user_id)
@@ -35,7 +35,7 @@ module Emails
@target_url = project_merge_request_url(@project, @merge_request)
mail(from: sender(updated_by_user_id),
to: recipient(recipient_id),
- subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
+ subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
end
diff --git a/app/mailers/emails/notes.rb b/app/mailers/emails/notes.rb
index ccbdadf010f..2a877bc1593 100644
--- a/app/mailers/emails/notes.rb
+++ b/app/mailers/emails/notes.rb
@@ -27,7 +27,7 @@ module Emails
@target_url = project_merge_request_url(@project, @merge_request, anchor: "note_#{@note.id}")
mail(from: sender(@note.author_id),
to: recipient(recipient_id),
- subject: subject("#{@merge_request.title} (!#{@merge_request.iid})"))
+ subject: subject("#{@merge_request.title} (##{@merge_request.iid})"))
end
def note_wall_email(recipient_id, note_id)
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 8c885b70a48..134a8c8dd40 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -253,6 +253,14 @@ class MergeRequest < ActiveRecord::Base
end
end
+ def target_project_namespace
+ if target_project && target_project.namespace
+ target_project.namespace.path
+ else
+ "(removed)"
+ end
+ end
+
def source_branch_exists?
return false unless self.source_project
diff --git a/app/models/merge_request_diff.rb b/app/models/merge_request_diff.rb
index 0684461add7..7dce71a677b 100644
--- a/app/models/merge_request_diff.rb
+++ b/app/models/merge_request_diff.rb
@@ -86,7 +86,7 @@ class MergeRequestDiff < ActiveRecord::Base
# between target and source branches
def unmerged_commits
commits = if merge_request.for_fork?
- Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).commits_between
+ compare_action.commits
else
repository.commits_between(target_branch, source_branch)
end
@@ -150,7 +150,7 @@ class MergeRequestDiff < ActiveRecord::Base
# between target and source branches
def unmerged_diffs
diffs = if merge_request.for_fork?
- Gitlab::Satellite::MergeAction.new(merge_request.author, merge_request).diffs_between_satellite
+ compare_action.diffs
else
Gitlab::Git::Diff.between(repository, source_branch, target_branch)
end
@@ -165,4 +165,16 @@ class MergeRequestDiff < ActiveRecord::Base
def repository
merge_request.target_project.repository
end
+
+ private
+
+ def compare_action
+ Gitlab::Satellite::CompareAction.new(
+ merge_request.author,
+ merge_request.target_project,
+ merge_request.target_branch,
+ merge_request.source_project,
+ merge_request.source_branch
+ )
+ end
end
diff --git a/app/models/milestone.rb b/app/models/milestone.rb
index 6a2ca767030..39ab0b536a3 100644
--- a/app/models/milestone.rb
+++ b/app/models/milestone.rb
@@ -25,6 +25,7 @@ class Milestone < ActiveRecord::Base
scope :active, -> { with_state(:active) }
scope :closed, -> { with_state(:closed) }
+ scope :of_projects, ->(ids) { where(project_id: ids) }
validates :title, presence: true
validates :project, presence: true
diff --git a/app/models/note.rb b/app/models/note.rb
index 6f7afcd1f9f..cee10ec90d2 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -184,9 +184,10 @@ class Note < ActiveRecord::Base
return @diff_line if @diff_line
if diff
- Gitlab::DiffParser.new(diff).each do |full_line, type, line_code, line_new, line_old|
- @diff_line = full_line if line_code == self.line_code
- end
+ Gitlab::DiffParser.new(diff.diff.lines.to_a, diff.new_path)
+ .each do |full_line, type, line_code, line_new, line_old|
+ @diff_line = full_line if line_code == self.line_code
+ end
end
@diff_line
diff --git a/app/models/project.rb b/app/models/project.rb
index 3ae47c18136..7ddcc73cf2a 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -203,6 +203,7 @@ class Project < ActiveRecord::Base
when 'oldest' then reorder('projects.created_at ASC')
when 'recently_updated' then reorder('projects.updated_at DESC')
when 'last_updated' then reorder('projects.updated_at ASC')
+ when 'largest_repository' then reorder('projects.repository_size DESC')
else reorder("namespaces.path, projects.name ASC")
end
end
@@ -562,4 +563,8 @@ class Project < ActiveRecord::Base
def forked_from?(project)
forked? && project == forked_from_project
end
+
+ def update_repository_size
+ update_attribute(:repository_size, repository.size)
+ end
end
diff --git a/app/models/project_wiki.rb b/app/models/project_wiki.rb
index 163302a18f7..08a52782475 100644
--- a/app/models/project_wiki.rb
+++ b/app/models/project_wiki.rb
@@ -64,7 +64,8 @@ class ProjectWiki
#
# Returns an initialized WikiPage instance or nil
def find_page(title, version = nil)
- if page = wiki.page(title, version)
+ page_title, page_dir = page_title_and_dir(title)
+ if page = wiki.page(page_title, version, page_dir)
WikiPage.new(self, page, true)
else
nil
@@ -90,6 +91,12 @@ class ProjectWiki
wiki.delete_page(page, commit_details(:deleted, message, page.title))
end
+ def page_title_and_dir(title)
+ title_array = title.split("/")
+ title = title_array.pop
+ [title.gsub(/\.[^.]*$/, ""), title_array.join("/")]
+ end
+
private
def create_repo!
diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb
index 76f311ed0b4..b8a0a9eb58b 100644
--- a/app/models/wiki_page.rb
+++ b/app/models/wiki_page.rb
@@ -175,14 +175,24 @@ class WikiPage
end
def save(method, *args)
- if valid? && wiki.send(method, *args)
- @page = wiki.wiki.paged(title)
+ project_wiki = wiki
+ if valid? && project_wiki.send(method, *args)
+
+ page_details = if method == :update_page
+ @page.path
+ else
+ title
+ end
+
+ page_title, page_dir = project_wiki.page_title_and_dir(page_details)
+ gollum_wiki = project_wiki.wiki
+ @page = gollum_wiki.paged(page_title, page_dir)
set_attributes
@persisted = true
else
- errors.add(:base, wiki.error_message) if wiki.error_message
+ errors.add(:base, project_wiki.error_message) if project_wiki.error_message
@persisted = false
end
@persisted
diff --git a/app/services/git_push_service.rb b/app/services/git_push_service.rb
index 351b446457d..715b5690751 100644
--- a/app/services/git_push_service.rb
+++ b/app/services/git_push_service.rb
@@ -25,6 +25,7 @@ class GitPushService
project.ensure_satellite_exists
project.repository.expire_cache
+ project.update_repository_size
if push_to_existing_branch?(ref, oldrev)
project.update_merge_requests(oldrev, newrev, ref, @user)
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 4969198b8c2..41014f199d5 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -31,7 +31,8 @@ class SystemHooksService
path_with_namespace: model.path_with_namespace,
project_id: model.id,
owner_name: owner.name,
- owner_email: owner.respond_to?(:email) ? owner.email : nil
+ owner_email: owner.respond_to?(:email) ? owner.email : nil,
+ project_visibility: Project.visibility_levels.key(model.visibility_level_field).downcase
})
when User
data.merge!({
@@ -46,7 +47,8 @@ class SystemHooksService
project_id: model.project_id,
user_name: model.user.name,
user_email: model.user.email,
- project_access: model.human_access
+ project_access: model.human_access,
+ project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase
})
end
end
diff --git a/app/views/admin/broadcast_messages/index.html.haml b/app/views/admin/broadcast_messages/index.html.haml
index f28dadfb659..c58ca2c9a33 100644
--- a/app/views/admin/broadcast_messages/index.html.haml
+++ b/app/views/admin/broadcast_messages/index.html.haml
@@ -22,12 +22,12 @@
= f.label :color, "Background Color", class: 'control-label'
.col-sm-10
= f.text_field :color, placeholder: "#AA33EE", class: "form-control"
- .light Hex values as 3 double digit numbers, starting with a # sign.
+ .light 6 character hex values starting with a # sign.
.form-group.js-toggle-colors-container.hide
= f.label :font, "Font Color", class: 'control-label'
.col-sm-10
= f.text_field :font, placeholder: "#224466", class: "form-control"
- .light Hex values as 3 double digit numbers, starting with a # sign.
+ .light 6 character hex values starting with a # sign.
.form-group
= f.label :starts_at, class: 'control-label'
.col-sm-10.datetime-controls
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 296094ab29c..51ad702154f 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -32,6 +32,7 @@
= visibility_level_icon(level)
= label
.form-actions
+ = hidden_field_tag :sort, params[:sort]
= submit_tag "Search", class: "btn submit btn-primary"
= link_to "Reset", admin_projects_path, class: "btn"
@@ -40,6 +41,28 @@
.title
Projects (#{@projects.total_count})
.pull-right
+ .dropdown.inline
+ %a.dropdown-toggle.btn{href: '#', "data-toggle" => "dropdown"}
+ %span.light sort:
+ - if @sort.present?
+ = @sort.humanize
+ - else
+ Name
+ %b.caret
+ %ul.dropdown-menu
+ %li
+ = link_to admin_projects_path(sort: nil) do
+ Name
+ = link_to admin_projects_path(sort: 'newest') do
+ Newest
+ = link_to admin_projects_path(sort: 'oldest') do
+ Oldest
+ = link_to admin_projects_path(sort: 'recently_updated') do
+ Recently updated
+ = link_to admin_projects_path(sort: 'last_updated') do
+ Last updated
+ = link_to admin_projects_path(sort: 'largest_repository') do
+ Largest repository
= link_to 'New Project', new_project_path, class: "btn btn-new"
%ul.well-list
- @projects.each do |project|
diff --git a/app/views/layouts/_head_panel.html.haml b/app/views/layouts/_head_panel.html.haml
index d8001fd76d7..fba56b5dc3b 100644
--- a/app/views/layouts/_head_panel.html.haml
+++ b/app/views/layouts/_head_panel.html.haml
@@ -20,6 +20,10 @@
= link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
%i.icon-search
%li
+ = link_to help_path, title: 'Help', class: 'has_bottom_tooltip',
+ 'data-original-title' => 'Help' do
+ %i.icon-question-sign
+ %li
= link_to public_root_path, title: "Public area", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
%i.icon-globe
%li
@@ -39,6 +43,6 @@
%li
= link_to destroy_user_session_path, class: "logout", method: :delete, title: "Logout", class: 'has_bottom_tooltip', 'data-original-title' => 'Logout' do
%i.icon-signout
- %li
+ %li.hidden-xs
= link_to current_user, class: "profile-pic", id: 'profile-pic' do
= image_tag avatar_icon(current_user.email, 26), alt: 'User activity'
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index c5041dd71b8..5d93ffa50ad 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -10,7 +10,7 @@
%p.light
GitLab is open source software to collaborate on code.
%br
- #{link_to "Sign in", new_user_session_path} or browse for #{link_to "public projects", public_projects_path}.
+ Sign in or browse for #{link_to "public projects", public_projects_path}.
%hr
.container
.content
diff --git a/app/views/notify/closed_merge_request_email.html.haml b/app/views/notify/closed_merge_request_email.html.haml
index 809d46f31be..574e8bfef24 100644
--- a/app/views/notify/closed_merge_request_email.html.haml
+++ b/app/views/notify/closed_merge_request_email.html.haml
@@ -1,2 +1,2 @@
%p
- = "Merge Request !#{@merge_request.iid} was closed by #{@updated_by.name}"
+ = "Merge Request ##{@merge_request.iid} was closed by #{@updated_by.name}"
diff --git a/app/views/notify/closed_merge_request_email.text.haml b/app/views/notify/closed_merge_request_email.text.haml
index ee434ec8cb2..d6b76e906c5 100644
--- a/app/views/notify/closed_merge_request_email.text.haml
+++ b/app/views/notify/closed_merge_request_email.text.haml
@@ -1,4 +1,4 @@
-= "Merge Request #{@merge_request.iid} was closed by #{@updated_by.name}"
+= "Merge Request ##{@merge_request.iid} was closed by #{@updated_by.name}"
Merge Request url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
diff --git a/app/views/notify/merged_merge_request_email.html.haml b/app/views/notify/merged_merge_request_email.html.haml
index 0c62d439aed..6762fae7f64 100644
--- a/app/views/notify/merged_merge_request_email.html.haml
+++ b/app/views/notify/merged_merge_request_email.html.haml
@@ -1,2 +1,2 @@
%p
- = "Merge Request !#{@merge_request.iid} was merged"
+ = "Merge Request ##{@merge_request.iid} was merged"
diff --git a/app/views/notify/merged_merge_request_email.text.haml b/app/views/notify/merged_merge_request_email.text.haml
index 550f677fed4..360da60bc3f 100644
--- a/app/views/notify/merged_merge_request_email.text.haml
+++ b/app/views/notify/merged_merge_request_email.text.haml
@@ -1,4 +1,4 @@
-= "Merge Request #{@merge_request.iid} was merged"
+= "Merge Request ##{@merge_request.iid} was merged"
Merge Request Url: #{project_merge_request_url(@merge_request.target_project, @merge_request)}
diff --git a/app/views/notify/repository_push_email.text.haml b/app/views/notify/repository_push_email.text.haml
index b8d7fbeb046..a15b8efe1f7 100644
--- a/app/views/notify/repository_push_email.text.haml
+++ b/app/views/notify/repository_push_email.text.haml
@@ -17,7 +17,7 @@ Changes:
- else
= diff.new_path || diff.old_path
\=====================================
- = diff.diff
+ != diff.diff
\
- if @compare.timeout
Huge diff. To prevent performance issues it was hidden
diff --git a/app/views/projects/commits/_parallel_view.html.haml b/app/views/projects/commits/_parallel_view.html.haml
index 5b60ab80ba4..80f5be98f2f 100644
--- a/app/views/projects/commits/_parallel_view.html.haml
+++ b/app/views/projects/commits/_parallel_view.html.haml
@@ -2,54 +2,37 @@
- old_lines, new_lines = parallel_diff_lines(project, @commit, diff, file)
- num_lines = old_lines.length
-%div.text-file-parallel
- %div.diff-side.diff-side-left
- %table
- - old_lines.each do |line|
+%div.text-file
+ %table
+ - num_lines.times do |index|
+ - new_line = new_lines[index]
+ - old_line = old_lines[index]
+ %tr.line_holder.parallel
+ -# For old line
+ - if old_line.type == :file_created
+ %td.old_line= old_line.num
+ %td.line_content.parallel= "File was created"
+ - elsif old_line.type == :deleted
+ %td.old_line.old= old_line.num
+ %td.line_content{class: "parallel noteable_line old #{old_line.code}", "line_code" => old_line.code}= old_line.content
+ - else old_line.type == :no_change
+ %td.old_line= old_line.num
+ %td.line_content.parallel= old_line.content
+
+ -# For new line
+ - if new_line.type == :file_deleted
+ %td.new_line= new_line.num
+ %td.line_content.parallel= "File was deleted"
+ - elsif new_line.type == :added
+ %td.new_line.new= new_line.num
+ %td.line_content{class: "parallel noteable_line new #{new_line.code}", "line_code" => new_line.code}= new_line.content
+ - else new_line.type == :no_change
+ %td.new_line= new_line.num
+ %td.line_content.parallel= new_line.content
+
+ - if @reply_allowed
+ - comments1 = @line_notes.select { |n| n.line_code == old_line.code }.sort_by(&:created_at)
+ - comments2 = @line_notes.select { |n| n.line_code == new_line.code }.sort_by(&:created_at)
+ - unless comments1.empty? and comments2.empty?
+ = render "projects/notes/diff_notes_with_reply_parallel", notes1: comments1, notes2: comments2
- %tr.line_holder.parallel
- - if line.type == :file_created
- %td.line_content.parallel= "File was created"
- - elsif line.type == :deleted
- %td.line_content{class: "parallel noteable_line old #{line.code}", "line_code" => line.code }= line.content
- - else line.type == :no_change
- %td.line_content.parallel= line.content
-
- %div.diff-middle
- %table
- - num_lines.times do |index|
- %tr
- - if old_lines[index].type == :deleted
- %td.old_line.old= old_lines[index].num
- - else
- %td.old_line= old_lines[index].num
-
- %td.diff_line=""
-
- - if new_lines[index].type == :added
- %td.new_line.new= new_lines[index].num
- - else
- %td.new_line= new_lines[index].num
-
- %div.diff-side.diff-side-right
- %table
- - new_lines.each do |line|
-
- %tr.line_holder.parallel
- - if line.type == :file_deleted
- %td.line_content.parallel= "File was deleted"
- - elsif line.type == :added
- %td.line_content{class: "parallel noteable_line new #{line.code}", "line_code" => line.code }= line.content
- - else line.type == :no_change
- %td.line_content.parallel= line.content
-
-:javascript
- $('.diff-side-right').on('scroll', function(){
- $('.diff-side-left, .diff-middle').scrollTop($(this).scrollTop());
- $('.diff-side-left').scrollLeft($(this).scrollLeft());
- });
-
- $('.diff-side-left').on('scroll', function(){
- $('.diff-side-right, .diff-middle').scrollTop($(this).scrollTop()); // might never be relevant
- $('.diff-side-right').scrollLeft($(this).scrollLeft());
- });
diff --git a/app/views/projects/edit_tree/_diff.html.haml b/app/views/projects/edit_tree/_diff.html.haml
new file mode 100644
index 00000000000..cf044feb9a4
--- /dev/null
+++ b/app/views/projects/edit_tree/_diff.html.haml
@@ -0,0 +1,13 @@
+%table.text-file
+ - each_diff_line(diff, 1) do |line, type, line_code, line_new, line_old, raw_line|
+ %tr.line_holder{ id: line_code, class: "#{type}" }
+ - if type == "match"
+ %td.old_line= "..."
+ %td.new_line= "..."
+ %td.line_content.matched= line
+ - else
+ %td.old_line
+ = link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
+ %td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
+ %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
+
diff --git a/app/views/projects/edit_tree/preview.html.haml b/app/views/projects/edit_tree/preview.html.haml
new file mode 100644
index 00000000000..fc6d3bfbc24
--- /dev/null
+++ b/app/views/projects/edit_tree/preview.html.haml
@@ -0,0 +1,26 @@
+.diff-file
+ .diff-content
+ - if gitlab_markdown?(@blob.name)
+ .file-content.wiki
+ = preserve do
+ = markdown(@content)
+ - elsif markup?(@blob.name)
+ .file-content.wiki
+ = raw GitHub::Markup.render(@blob.name, @content)
+ - else
+ .file-content.code
+ - unless @diff.empty?
+ %table.text-file
+ - @diff.each do |line, type, line_code, line_new, line_old, raw_line|
+ %tr.line_holder{ id: line_code, class: "#{type}" }
+ - if type == "match"
+ %td.old_line= "..."
+ %td.new_line= "..."
+ %td.line_content.matched= line
+ - else
+ %td.old_line
+ = link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
+ %td.new_line= link_to raw(type == "old" ? "&nbsp;" : line_new) , "##{line_code}", id: line_code
+ %td.line_content{class: "noteable_line #{type} #{line_code}", "line_code" => line_code}= raw diff_line_content(line)
+ - else
+ %p.nothing_here_message No changes.
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 3f2e98f3a7f..48babb43aaf 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -1,8 +1,11 @@
%h3.page-title Edit mode
.file-editor
= form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
- .file-holder
+ .file-holder.file
.file-title
+ .btn-group.js-edit-mode.left-options
+ = link_to 'Edit', '#editor', class: 'active hover btn btn-tiny'
+ = link_to editing_preview_title(@blob.name), '#preview', class: 'btn btn-tiny', 'data-preview-url' => preview_project_edit_tree_path(@project, @id)
%i.icon-file
%span.file_name
= @path
@@ -13,7 +16,8 @@
.btn-group.tree-btn-group
= link_to "Cancel", @after_edit_path, class: "btn btn-tiny btn-cancel", data: { confirm: leave_edit_message }
.file-content.code
- %pre#editor= @blob.data
+ %pre.js-edit-mode-pane#editor= @blob.data
+ .js-edit-mode-pane#preview.hide
.form-group.commit_message-group
= label_tag 'commit_message', class: "control-label" do
@@ -45,3 +49,28 @@
$("#file-content").val(editor.getValue());
$(".file-editor form").submit();
});
+
+ var editModePanes = $('.js-edit-mode-pane'),
+ editModeLinks = $('.js-edit-mode a');
+
+ editModeLinks.click(function(event) {
+ event.preventDefault();
+
+ var currentLink = $(this),
+ paneId = currentLink.attr('href'),
+ currentPane = editModePanes.filter(paneId);
+
+ editModeLinks.removeClass('active hover');
+ currentLink.addClass('active hover');
+ editModePanes.hide();
+
+ if (paneId == '#preview') {
+ $.post(currentLink.data('preview-url'), { content: editor.getValue() }, function(response) {
+ currentPane.empty().append(response);
+ currentPane.fadeIn(200);
+ })
+ } else {
+ currentPane.fadeIn(200);
+ editor.focus()
+ }
+ })
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
index aae101cf40f..425dcb45ddf 100644
--- a/app/views/projects/issues/_issue_context.html.haml
+++ b/app/views/projects/issues/_issue_context.html.haml
@@ -1,22 +1,24 @@
= form_for [@project, @issue], remote: true, html: {class: 'edit-issue inline-update'} do |f|
- %strong.append-right-10
- Assignee:
+ .row
+ .col-md-6
+ %strong.append-right-10
+ Assignee:
- - if can?(current_user, :modify_issue, @issue)
- = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id)
- - elsif issue.assignee
- = link_to_member(@project, @issue.assignee)
- - else
- None
+ - if can?(current_user, :modify_issue, @issue)
+ = project_users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @issue.assignee_id)
+ - elsif issue.assignee
+ = link_to_member(@project, @issue.assignee)
+ - else
+ None
- .pull-right
- %strong.append-right-10
- Milestone:
- - if can?(current_user, :modify_issue, @issue)
- = f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
- = hidden_field_tag :issue_context
- = f.submit class: 'btn'
- - elsif issue.milestone
- = link_to issue.milestone.title, project_milestone_path
- - else
- None
+ .col-md-6.text-right
+ %strong.append-right-10
+ Milestone:
+ - if can?(current_user, :modify_issue, @issue)
+ = f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact'})
+ = hidden_field_tag :issue_context
+ = f.submit class: 'btn'
+ - elsif issue.milestone
+ = link_to issue.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 124eb53571d..b6d3a8edf4d 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
Issue ##{@issue.iid}
- %span.pull-right
+ %span.pull-right.issue-btn-group
- if can?(current_user, :write_issue, @project)
= link_to new_project_issue_path(@project), class: "btn btn-grouped", title: "New Issue", id: "new_issue_link" do
%i.icon-plus
@@ -16,28 +16,29 @@
%i.icon-edit
Edit
-.votes-holder
- #votes= render 'votes/votes_block', votable: @issue
+.clearfix
+ .votes-holder
+ #votes= render 'votes/votes_block', votable: @issue
-.back-link
- = link_to project_issues_path(@project) do
- &larr; To issues list
- %span.milestone-nav-link
- - if @issue.milestone
- |
- %span.light Milestone
- = link_to project_milestone_path(@project, @issue.milestone) do
- = @issue.milestone.title
+ .back-link
+ = link_to project_issues_path(@project) do
+ &larr; To issues list
+ %span.milestone-nav-link
+ - if @issue.milestone
+ |
+ %span.light Milestone
+ = link_to project_milestone_path(@project, @issue.milestone) do
+ = @issue.milestone.title
.issue-box{ class: issue_box_class(@issue) }
- .state
- %span.state-label
+ .state.clearfix
+ .state-label.col-sm-2.col-xs-12
- if @issue.closed?
Closed
- else
Open
- %span.creator
+ %span.creator.col-sm-9.col-xs-12
Created by #{link_to_member(@project, @issue.author)} #{time_ago_with_tooltip(@issue.created_at)}
%h4.title
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index 0fe2d1d9801..ddff3dbead8 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -14,33 +14,6 @@
- @merge_request.errors.full_messages.each do |msg|
%div= msg
- .merge-request-branches
- .form-group
- = label_tag nil, class: 'control-label' do
- From
- .col-sm-10
- .clearfix
- .pull-left
- = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted? })
- .pull-left
- &nbsp;
- = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
- .mr_source_commit
- %br
- .form-group
- = label_tag nil, class: 'control-label' do
- To
- .col-sm-10
- .clearfix
- .pull-left
- - projects = @project.forked_from_project.nil? ? [@project] : [@project, @project.forked_from_project]
- = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace', f.object.target_project_id), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted? })
- .pull-left
- &nbsp;
- = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
- .mr_target_commit
-
- %hr
.merge-request-form-info
.form-group
= f.label :title, class: 'control-label' do
@@ -51,6 +24,23 @@
.col-sm-10
= f.text_area :description, class: "form-control js-gfm-input", rows: 14
%p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ %hr
+ .form-group
+ .issue-assignee
+ = f.label :assignee_id, class: 'control-label' do
+ %i.icon-user
+ Assign to
+ .col-sm-10
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id)
+ &nbsp;
+ = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
+ .form-group
+ .issue-milestone
+ = f.label :milestone_id, class: 'control-label' do
+ %i.icon-time
+ Milestone
+ .col-sm-10= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
+
.form-actions
- if @merge_request.new_record?
@@ -66,20 +56,7 @@
:javascript
disableButtonIfEmptyField("#merge_request_title", ".btn-save");
-
- var source_branch = $("#merge_request_source_branch")
- , target_branch = $("#merge_request_target_branch")
- , target_project = $("#merge_request_target_project_id");
-
- $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: source_branch.val() });
- $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() });
-
- target_project.on("change", function() {
- $.get("#{update_branches_project_merge_requests_path(@source_project)}", {target_project_id: $(this).val() });
- });
- source_branch.on("change", function() {
- $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: $(this).val() });
- });
- target_branch.on("change", function() {
- $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
+ $('.assign-to-me-link').on('click', function(e){
+ $('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
+ e.preventDefault();
});
diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml
index 980ac126742..d1cab89a35c 100644
--- a/app/views/projects/merge_requests/_merge_request.html.haml
+++ b/app/views/projects/merge_requests/_merge_request.html.haml
@@ -11,13 +11,9 @@
- if merge_request.for_fork?
%span.light
#{merge_request.source_project_namespace}:
- = merge_request.source_branch
- %i.icon-angle-right.light
- = merge_request.target_branch
- - else
- = merge_request.source_branch
- %i.icon-angle-right.light
- = merge_request.target_branch
+ = truncate merge_request.source_branch, length: 25
+ %i.icon-angle-right.light
+ = merge_request.target_branch
.merge-request-info
- if merge_request.author
authored by #{link_to_member(merge_request.source_project, merge_request.author)}
diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
new file mode 100644
index 00000000000..a8b774a3cd1
--- /dev/null
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -0,0 +1,84 @@
+%h3.page-title Compare branches for new Merge Request
+%hr
+
+= form_for [@project, @merge_request], url: new_project_merge_request_path(@project), method: :get, html: { class: "merge-request-form form-inline" } do |f|
+ .hide.alert.alert-danger.mr-compare-errors
+ .merge-request-branches.row
+ .col-md-6
+ .panel.panel-default
+ .panel-heading
+ %strong Source branch
+ .panel-body
+ = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted? })
+ &nbsp;
+ = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
+ .panel-footer
+ .mr_source_commit
+
+ .col-md-6
+ .panel.panel-default
+ .panel-heading
+ %strong Target branch
+ .panel-body
+ - projects = @project.forked_from_project.nil? ? [@project] : [@project, @project.forked_from_project]
+ = f.select(:target_project_id, options_from_collection_for_select(projects, 'id', 'path_with_namespace', f.object.target_project_id), {}, { class: 'target_project select2 span3', disabled: @merge_request.persisted? })
+ &nbsp;
+ = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
+ .panel-footer
+ .mr_target_commit
+
+ -if @merge_request.errors.any?
+ .alert.alert-danger
+ - @merge_request.errors.full_messages.each do |msg|
+ %div= msg
+
+ - if @merge_request.source_branch.present? && @merge_request.target_branch.present?
+ .light-well
+ %center
+ %h4
+ There isn't anything to merge.
+ %p.slead
+ - if @merge_request.source_branch == @merge_request.target_branch
+ You'll need to use different branch names to get a valid comparison.
+ - else
+ %span.label-branch #{@merge_request.source_branch}
+ and
+ %span.label-branch #{@merge_request.target_branch}
+ are the same.
+
+
+ %hr
+ = f.submit 'Compare branches', class: "btn btn-primary mr-compare-btn"
+
+:javascript
+ var source_branch = $("#merge_request_source_branch")
+ , target_branch = $("#merge_request_target_branch")
+ , target_project = $("#merge_request_target_project_id");
+
+ $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: source_branch.val() });
+ $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: target_branch.val() });
+
+ target_project.on("change", function() {
+ $.get("#{update_branches_project_merge_requests_path(@source_project)}", {target_project_id: $(this).val() });
+ });
+ source_branch.on("change", function() {
+ $.get("#{branch_from_project_merge_requests_path(@source_project)}", {ref: $(this).val() });
+ $(".mr-compare-errors").fadeOut();
+ $(".mr-compare-btn").enable();
+ });
+ target_branch.on("change", function() {
+ $.get("#{branch_to_project_merge_requests_path(@source_project)}", {target_project_id: target_project.val(),ref: $(this).val() });
+ $(".mr-compare-errors").fadeOut();
+ $(".mr-compare-btn").enable();
+ });
+
+
+:coffeescript
+
+ $(".merge-request-form").on 'submit', ->
+ if $("#merge_request_source_branch").val() is "" or $('#merge_request_target_branch').val() is ""
+ $(".mr-compare-errors").html("You must select source and target branch to proceed")
+ $(".mr-compare-errors").fadeIn()
+ event.preventDefault()
+ return
+
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
new file mode 100644
index 00000000000..b5479be708b
--- /dev/null
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -0,0 +1,82 @@
+%h3.page-title
+ New merge request
+%p.slead
+ From
+ %strong.monospace
+ #{@merge_request.source_project_namespace}:#{@merge_request.source_branch}
+ into
+ %strong.monospace
+ #{@merge_request.target_project_namespace}:#{@merge_request.target_branch}
+
+ %span.pull-right
+ = link_to 'Change branches', new_project_merge_request_path(@project)
+
+= form_for [@project, @merge_request], html: { class: "merge-request-form" } do |f|
+ .panel.panel-default
+
+ .panel-body
+ .form-group
+ .light
+ = f.label :title do
+ = "Title *"
+ = f.text_field :title, class: "form-control input-lg js-gfm-input", maxlength: 255, rows: 5, required: true
+ .form-group
+ .light
+ = f.label :description, "Description"
+ = f.text_area :description, class: "form-control js-gfm-input", rows: 10
+ %p.hint Description is parsed with #{link_to "GitLab Flavored Markdown", help_markdown_path, target: '_blank'}.
+ .form-group
+ .issue-assignee
+ = f.label :assignee_id do
+ %i.icon-user
+ Assign to
+ %div
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select a user', class: 'custom-form-control', selected: @merge_request.assignee_id, project_id: @merge_request.target_project_id)
+ &nbsp;
+ = link_to 'Assign to me', '#', class: 'btn btn-small assign-to-me-link'
+ .form-group
+ .issue-milestone
+ = f.label :milestone_id do
+ %i.icon-time
+ Milestone
+ %div= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2'})
+ .panel-footer
+ - if @target_repo.contribution_guide
+ - contribution_guide_url = project_blob_path(@target_project, tree_join(@target_repo.root_ref, @target_repo.contribution_guide.name))
+ %p
+ Please review the
+ %strong #{link_to "guidelines for contribution", contribution_guide_url}
+ to this repository.
+ = f.hidden_field :source_project_id
+ = f.hidden_field :target_project_id
+ = f.hidden_field :target_branch
+ = f.hidden_field :source_branch
+ = f.submit 'Submit merge request', class: "btn btn-create"
+
+.mr-compare
+ %div.ui-box
+ .title
+ Commits (#{@commits.count})
+ - if @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ %ul.well-list
+ - Commit.decorate(@commits.first(MergeRequestDiff::COMMITS_SAFE_SIZE)).each do |commit|
+ = render "projects/commits/inline_commit", commit: commit, project: @project
+ %li.warning-row.unstyled
+ other #{@commits.size - MergeRequestDiff::COMMITS_SAFE_SIZE} commits hidden to prevent performance issues.
+ - else
+ %ul.well-list= render Commit.decorate(@commits), project: @project
+
+ %h4 Changes
+ - if @diffs.present?
+ = render "projects/commits/diffs", diffs: @diffs, project: @project
+ - elsif @commits.size > MergeRequestDiff::COMMITS_SAFE_SIZE
+ .bs-callout.bs-callout-danger
+ %h4 This comparison includes more than #{MergeRequestDiff::COMMITS_SAFE_SIZE} commits.
+ %p To preserve performance the line changes are not shown.
+
+
+:javascript
+ $('.assign-to-me-link').on('click', function(e){
+ $('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
+ e.preventDefault();
+ });
diff --git a/app/views/projects/merge_requests/branch_from.js.haml b/app/views/projects/merge_requests/branch_from.js.haml
index 693c2057a0f..8372afa61b5 100644
--- a/app/views/projects/merge_requests/branch_from.js.haml
+++ b/app/views/projects/merge_requests/branch_from.js.haml
@@ -1,7 +1,2 @@
:plain
$(".mr_source_commit").html("#{commit_to_html(@commit, @source_project, false)}");
- var mrTitle = $('#merge_request_title');
-
- if(mrTitle.val().length == 0) {
- mrTitle.val("#{params[:ref].titleize.humanize}");
- }
diff --git a/app/views/projects/merge_requests/new.html.haml b/app/views/projects/merge_requests/new.html.haml
index 8ee0e1a8d46..c24e5916721 100644
--- a/app/views/projects/merge_requests/new.html.haml
+++ b/app/views/projects/merge_requests/new.html.haml
@@ -1,3 +1,4 @@
-%h3.page-title New Merge Request
-%hr
-= render 'form'
+- if @commits.present?
+ = render 'new_submit'
+- else
+ = render 'new_compare'
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
index 2bd850426a9..5c6734fd24b 100644
--- a/app/views/projects/merge_requests/show/_context.html.haml
+++ b/app/views/projects/merge_requests/show/_context.html.haml
@@ -1,22 +1,24 @@
= form_for [@project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update'} do |f|
- %strong.append-right-10
- Assignee:
+ .row
+ .col-md-6
+ %strong.append-right-10
+ Assignee:
- - if can?(current_user, :modify_merge_request, @merge_request)
- = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id)
- - elsif merge_request.assignee
- = link_to_member(@project, @merge_request.assignee)
- - else
- None
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = project_users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control', selected: @merge_request.assignee_id)
+ - elsif merge_request.assignee
+ = link_to_member(@project, @merge_request.assignee)
+ - else
+ None
- .pull-right
- %strong.append-right-10
- Milestone:
- - if can?(current_user, :modify_merge_request, @merge_request)
- = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone (none):" }, {class: 'select2 select2-compact'})
- = hidden_field_tag :merge_request_context
- = f.submit class: 'btn'
- - elsif merge_request.milestone
- = link_to merge_request.milestone.title, project_milestone_path
- - else
- None
+ .col-md-6.text-right
+ %strong.append-right-10
+ Milestone:
+ - if can?(current_user, :modify_merge_request, @merge_request)
+ = f.select(:milestone_id, milestone_options(@merge_request), { include_blank: "Select milestone" }, {class: 'select2 select2-compact'})
+ = hidden_field_tag :merge_request_context
+ = f.submit class: 'btn'
+ - elsif merge_request.milestone
+ = link_to merge_request.milestone.title, project_milestone_path
+ - else
+ None
diff --git a/app/views/projects/merge_requests/show/_mr_box.html.haml b/app/views/projects/merge_requests/show/_mr_box.html.haml
index 8855982a2e7..435e916c6dc 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -1,6 +1,6 @@
.issue-box{ class: issue_box_class(@merge_request) }
- .state
- %span.state-label
+ .state.clearfix
+ %span.state-label.col-sm-2.col-xs-12
- if @merge_request.merged?
Merged
- elsif @merge_request.closed?
@@ -8,7 +8,7 @@
- else
Open
- %span.creator
+ %span.creator.col-sm-9.col-xs-12
Created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
%h4.title
diff --git a/app/views/projects/merge_requests/show/_mr_ci.html.haml b/app/views/projects/merge_requests/show/_mr_ci.html.haml
index c175d2f6b40..507a9e507f1 100644
--- a/app/views/projects/merge_requests/show/_mr_ci.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_ci.html.haml
@@ -26,4 +26,4 @@
.ci_widget.ci-error{style: "display:none"}
%i.icon-remove
- %strong Cannot connect to CI server. Please check your setting
+ %strong Cannot connect to the CI server. Please check your settings and try again.
diff --git a/app/views/projects/merge_requests/show/_mr_title.html.haml b/app/views/projects/merge_requests/show/_mr_title.html.haml
index 7676fc137c7..2c905413bc3 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -1,7 +1,7 @@
%h3.page-title
= "Merge Request ##{@merge_request.iid}"
- %span.pull-right
+ %span.pull-right.issue-btn-group
- if can?(current_user, :modify_merge_request, @merge_request)
- if @merge_request.open?
.btn-group.pull-left
@@ -39,4 +39,4 @@
- else
%span= @merge_request.source_branch
&rarr;
- %spanh= @merge_request.target_branch
+ %span= @merge_request.target_branch
diff --git a/app/views/projects/merge_requests/show/_state_widget.html.haml b/app/views/projects/merge_requests/show/_state_widget.html.haml
index c9ecbceaf54..80fe540489b 100644
--- a/app/views/projects/merge_requests/show/_state_widget.html.haml
+++ b/app/views/projects/merge_requests/show/_state_widget.html.haml
@@ -21,14 +21,6 @@
#{time_ago_with_tooltip(@merge_request.merge_event.created_at)}
= render "projects/merge_requests/show/remove_source_branch"
- - if !@closes_issues.empty? && @merge_request.open?
- .alert.alert-info.alert-info
- %span
- %i.icon-ok
- Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
- = succeed '.' do
- != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
-
- unless @commits.any?
%h4 Nothing to merge
%p
@@ -38,3 +30,12 @@
%span.label-branch #{@merge_request.target_branch}
%br
Try to use different branches or push new code.
+
+ - if !@closes_issues.empty? && @merge_request.open?
+ .panel-footer
+ %span
+ %i.icon-ok
+ Accepting this merge request will close #{@closes_issues.size == 1 ? 'issue' : 'issues'}
+ = succeed '.' do
+ != gfm(@closes_issues.map { |i| "##{i.iid}" }.to_sentence)
+
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 06cf9946784..5c5df46d33d 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -100,7 +100,7 @@
%ul.bordered-list
- @users.each do |user|
%li
- = link_to user, title: user.name, class: "dark" do
+ = link_to user, title: user.name, class: "darken" do
= image_tag avatar_icon(user.email, 32), class: "avatar s32"
%strong= truncate(user.name, lenght: 40)
%br
diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
index 2012aa021b9..399ce30d1a9 100644
--- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
@@ -1,34 +1,33 @@
- note1 = notes1.first # example note
- note2 = notes2.first # example note
+-# Check if line want not changed since comment was left
+/- if !defined?(line) || line == note.diff_line
%tr.notes_holder.js-toggle-content
- -# Check if line want not changed since comment was left
- /- if !defined?(line1) || line1 == note1.diff_line
- if note1
+ %td.notes_line
+ %span.btn.disabled
+ %i.icon-comment
+ = notes1.count
%td.notes_content
%ul.notes{ rel: note1.discussion_id }
= render notes1
+
= render "projects/notes/discussion_reply_button", note: note1
- %td.notes_line2
- %span.btn.disabled.parallel-comment
- %i.icon-comment
- = notes1.count
- else
%td= ""
%td= ""
- %td= ""
-
- -# Check if line want not changed since comment was left
- /- if !defined?(line2) || line2 == note2.diff_line
- if note2
%td.notes_line
- %span.btn.disabled.parallel-comment
+ %span.btn.disabled
%i.icon-comment
= notes2.count
%td.notes_content
%ul.notes{ rel: note2.discussion_id }
= render notes2
+
= render "projects/notes/discussion_reply_button", note: note2
- else
%td= ""
%td= ""
+
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index 3bd592e3982..052661962e4 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -7,4 +7,4 @@
= render "projects/notes/form"
:javascript
- new Notes("#{project_notes_path(target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json})
+ new Notes("#{project_notes_path(target_id: @noteable.id, target_type: @noteable.class.name.underscore)}", #{@notes.map(&:id).to_json}, #{Time.now.to_i})
diff --git a/app/views/projects/wikis/_new.html.haml b/app/views/projects/wikis/_new.html.haml
index 8cb7fa8aa0b..1ce292a02df 100644
--- a/app/views/projects/wikis/_new.html.haml
+++ b/app/views/projects/wikis/_new.html.haml
@@ -9,6 +9,6 @@
%span Page slug
= text_field_tag :new_wiki_path, nil, placeholder: 'how-to-setup', class: 'form-control', required: true, :'data-wikis-path' => project_wikis_path(@project)
%p.hint
- Please don't use spaces and slashes
+ Please don't use spaces.
.modal-footer
= link_to 'Build', '#', class: 'build-new-wiki btn btn-create'
diff --git a/bin/pkgr_before_precompile.sh b/bin/pkgr_before_precompile.sh
new file mode 100755
index 00000000000..283abb6a0cd
--- /dev/null
+++ b/bin/pkgr_before_precompile.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+set -e
+
+for file in config/*.yml.example; do
+ cp ${file} config/$(basename ${file} .example)
+done
+
+# Allow to override the Gitlab URL from an environment variable, as this will avoid having to change the configuration file for simple deployments.
+config=$(echo '<% gitlab_url = URI(ENV["GITLAB_URL"] || "http://localhost:80") %>' | cat - config/gitlab.yml)
+echo "$config" > config/gitlab.yml
+sed -i "s/host: localhost/host: <%= gitlab_url.host %>/" config/gitlab.yml
+sed -i "s/port: 80/port: <%= gitlab_url.port %>/" config/gitlab.yml
+sed -i "s/https: false/https: <%= gitlab_url.scheme == 'https' %>/" config/gitlab.yml
+
+# No need for config file. Will be taken care of by REDIS_URL env variable
+rm config/resque.yml
+
+# Set default unicorn.rb file
+echo "" > config/unicorn.rb
+
+# Required for assets precompilation
+sudo service postgresql start
diff --git a/config/environments/production.rb b/config/environments/production.rb
index ad3c03d8fc9..47f7e17aeb6 100644
--- a/config/environments/production.rb
+++ b/config/environments/production.rb
@@ -53,7 +53,7 @@ Gitlab::Application.configure do
else
"redis://localhost:6379"
end
- config.cache_store = :redis_store, resque_url
+ config.cache_store = :redis_store, resque_url, {namespace: 'cache:gitlab'}
# Enable serving of images, stylesheets, and JavaScripts from an asset server
# config.action_controller.asset_host = "http://assets.example.com"
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index 64fc02fe8c2..3774910cf96 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -19,6 +19,11 @@ production: &base
port: 80
https: false
+ # Uncommment this line below if your ssh host is different from HTTP/HTTPS one
+ # (you'd obviously need to replace ssh.host_example.com with your own host).
+ # Otherwise, ssh host will be set to the `host:` value above
+ # ssh_host: ssh.host_example.com
+
# Uncomment and customize the last line to run in a non-root path
# WARNING: We recommend creating a FQDN to host GitLab in a root path instead of this.
# Note that four settings need to be changed for this to work.
@@ -102,7 +107,7 @@ production: &base
# ## :id - Issue id (from commit messages)
# issues_url: "http://redmine.sample/issues/:id"
#
- # ## If not nil, linkis to creating new issues will be replaced with this
+ # ## If not nil, links to creating new issues will be replaced with this
# ## Use placeholders:
# ## :project_id - GitLab project identifier
# ## :issues_tracker_id - Project Name or Id in external issue tracker
@@ -117,6 +122,7 @@ production: &base
## Gravatar
gravatar:
enabled: true # Use user avatar image from Gravatar.com (default: true)
+ # gravatar urls: possible placeholders: %{hash} %{size} %{email}
# plain_url: "http://..." # default: http://www.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
# ssl_url: "https://..." # default: https://secure.gravatar.com/avatar/%{hash}?s=%{size}&d=mm
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 59564d9ea33..97f29546404 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -1,5 +1,5 @@
class Settings < Settingslogic
- source "#{Rails.root}/config/gitlab.yml"
+ source ENV.fetch('GITLAB_CONFIG') { "#{Rails.root}/config/gitlab.yml" }
namespace Rails.env
class << self
@@ -73,6 +73,7 @@ Settings.gitlab['default_projects_limit'] ||= 10
Settings.gitlab['default_can_create_group'] = true if Settings.gitlab['default_can_create_group'].nil?
Settings.gitlab['default_theme'] = Gitlab::Theme::MARS if Settings.gitlab['default_theme'].nil?
Settings.gitlab['host'] ||= 'localhost'
+Settings.gitlab['ssh_host'] ||= Settings.gitlab.host
Settings.gitlab['https'] = false if Settings.gitlab['https'].nil?
Settings.gitlab['port'] ||= Settings.gitlab.https ? 443 : 80
Settings.gitlab['relative_url_root'] ||= ENV['RAILS_RELATIVE_URL_ROOT'] || ''
@@ -117,7 +118,7 @@ Settings.gitlab_shell['hooks_path'] ||= Settings.gitlab['user_home'] + '/gitla
Settings.gitlab_shell['receive_pack'] = true if Settings.gitlab_shell['receive_pack'].nil?
Settings.gitlab_shell['upload_pack'] = true if Settings.gitlab_shell['upload_pack'].nil?
Settings.gitlab_shell['repos_path'] ||= Settings.gitlab['user_home'] + '/repositories/'
-Settings.gitlab_shell['ssh_host'] ||= (Settings.gitlab.host || 'localhost')
+Settings.gitlab_shell['ssh_host'] ||= Settings.gitlab.ssh_host
Settings.gitlab_shell['ssh_port'] ||= 22
Settings.gitlab_shell['ssh_user'] ||= Settings.gitlab.user
Settings.gitlab_shell['owner_group'] ||= Settings.gitlab.user
diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb
index 6875fa74edd..d0065b63e54 100644
--- a/config/initializers/carrierwave.rb
+++ b/config/initializers/carrierwave.rb
@@ -18,4 +18,16 @@ if File.exists?(aws_file)
config.fog_authenticated_url_expiration = 1 << 29 # optional time (in seconds) that authenticated urls will be valid.
# when fog_public is false and provider is AWS or Google, defaults to 600
end
+
+ # Mocking Fog requests, based on: https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Test-Fog-based-uploaders
+ if Rails.env.test?
+ Fog.mock!
+ connection = ::Fog::Storage.new(
+ :aws_access_key_id => AWS_CONFIG['access_key_id'],
+ :aws_secret_access_key => AWS_CONFIG['secret_access_key'],
+ :provider => 'AWS',
+ :region => AWS_CONFIG['region']
+ )
+ connection.directories.create(:key => AWS_CONFIG['bucket'])
+ end
end
diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb
index 50669ece7a8..d5cb110e881 100644
--- a/config/initializers/devise.rb
+++ b/config/initializers/devise.rb
@@ -223,6 +223,7 @@ Devise.setup do |config|
method: Gitlab.config.ldap['method'],
bind_dn: Gitlab.config.ldap['bind_dn'],
password: Gitlab.config.ldap['password'],
+ filter: Gitlab.config.ldap['user_filter'],
name_proc: email_stripping_proc
end
@@ -244,4 +245,4 @@ Devise.setup do |config|
config.omniauth provider['name'].to_sym, *provider_arguments
end
-end
+end \ No newline at end of file
diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb
index 98400290113..62a54bc8c63 100644
--- a/config/initializers/secret_token.rb
+++ b/config/initializers/secret_token.rb
@@ -9,7 +9,9 @@ require 'securerandom'
def find_secure_token
token_file = Rails.root.join('.secret')
- if File.exist? token_file
+ if ENV.key?('SECRET_KEY_BASE')
+ ENV['SECRET_KEY_BASE']
+ elsif File.exist? token_file
# Use the existing token.
File.read(token_file).chomp
else
diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb
index f80b67a554b..5fe5270236b 100644
--- a/config/initializers/session_store.rb
+++ b/config/initializers/session_store.rb
@@ -2,7 +2,7 @@
Gitlab::Application.config.session_store(
:redis_store, # Using the cookie_store would enable session replay attacks.
- servers: Gitlab::Application.config.cache_store.last, # re-use the Redis config from the Rails cache store
+ servers: Gitlab::Application.config.cache_store[1], # re-use the Redis config from the Rails cache store
key: '_gitlab_session',
secure: Gitlab.config.gitlab.https,
httponly: true,
diff --git a/config/routes.rb b/config/routes.rb
index f23542cc893..7a33686b810 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -187,7 +187,9 @@ Gitlab::Application.routes.draw do
resources :blob, only: [:show, :destroy], constraints: {id: /.+/}
resources :raw, only: [:show], constraints: {id: /.+/}
resources :tree, only: [:show], constraints: {id: /.+/, format: /(html|js)/ }
- resources :edit_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'edit'
+ resources :edit_tree, only: [:show, :update], constraints: { id: /.+/ }, path: 'edit' do
+ post :preview, on: :member
+ end
resources :new_tree, only: [:show, :update], constraints: {id: /.+/}, path: 'new'
resources :commit, only: [:show], constraints: {id: /[[:alnum:]]{6,40}/}
resources :commits, only: [:show], constraints: {id: /(?:[^.]|\.(?!atom$))+/, format: /atom/}
@@ -204,7 +206,7 @@ Gitlab::Application.routes.draw do
end
end
- resources :wikis, only: [:show, :edit, :destroy, :create], constraints: {id: /[a-zA-Z.0-9_\-]+/} do
+ resources :wikis, only: [:show, :edit, :destroy, :create], constraints: {id: /[a-zA-Z.0-9_\-\/]+/} do
collection do
get :pages
put ':id' => 'wikis#update'
diff --git a/db/fixtures/development/04_project.rb b/db/fixtures/development/04_project.rb
index 9303ab93300..164bb637809 100644
--- a/db/fixtures/development/04_project.rb
+++ b/db/fixtures/development/04_project.rb
@@ -40,7 +40,8 @@ Gitlab::Seeder.quiet do
import_url: url,
namespace_id: group.id,
name: project_path.titleize,
- description: Faker::Lorem.sentence
+ description: Faker::Lorem.sentence,
+ visibility_level: Gitlab::VisibilityLevel.values.sample
}
project = Projects::CreateService.new(User.first, params).execute
diff --git a/db/fixtures/development/10_merge_requests.rb b/db/fixtures/development/10_merge_requests.rb
index cb08a7c2537..62fd0d84ea3 100644
--- a/db/fixtures/development/10_merge_requests.rb
+++ b/db/fixtures/development/10_merge_requests.rb
@@ -1,45 +1,33 @@
Gitlab::Seeder.quiet do
- (1..100).each do |i|
- # Random Project
- project = Project.all.sample
-
- # Random user
- user = project.team.users.sample
-
- next unless user
-
- next if project.empty_repo?
-
- branches = project.repository.branch_names.sample(2)
-
- next if branches.uniq.size < 2
-
- user_id = user.id
-
- Gitlab::Seeder.by_user(user) do
- MergeRequest.seed(:id, [{
- id: i,
- source_branch: branches.first,
- target_branch: branches.last,
- source_project_id: project.id,
- target_project_id: project.id,
- author_id: user_id,
- assignee_id: user_id,
- milestone: project.milestones.sample,
- title: Faker::Lorem.sentence(6)
- }])
+ Project.all.reject(&:empty_repo?).each do |project|
+ branches = project.repository.branch_names
+
+ branches.each do |branch_name|
+ break if branches.size < 2
+ source_branch = branches.pop
+ target_branch = branches.pop
+
+ # Random user
+ user = project.team.users.sample
+ next unless user
+
+ params = {
+ source_branch: source_branch,
+ target_branch: target_branch,
+ title: Faker::Lorem.sentence(6),
+ description: Faker::Lorem.sentences(3).join(" ")
+ }
+
+ merge_request = MergeRequests::CreateService.new(project, user, params).execute
+
+ if merge_request.valid?
+ merge_request.assignee = user
+ merge_request.milestone = project.milestones.sample
+ merge_request.save
+ print '.'
+ else
+ print 'F'
+ end
end
- print('.')
end
end
-
-MergeRequest.all.map do |mr|
- mr.set_iid
- mr.save
-end
-
-puts 'Load diffs for Merge Requests (it will take some time)...'
-MergeRequest.all.each do |mr|
- mr.reload_code
- print '.'
-end
diff --git a/db/migrate/20140415124820_limits_to_mysql.rb b/db/migrate/20140415124820_limits_to_mysql.rb
new file mode 100644
index 00000000000..3f6e62617c5
--- /dev/null
+++ b/db/migrate/20140415124820_limits_to_mysql.rb
@@ -0,0 +1 @@
+require_relative 'limits_to_mysql'
diff --git a/db/migrate/20140416074002_add_index_on_iid.rb b/db/migrate/20140416074002_add_index_on_iid.rb
new file mode 100644
index 00000000000..85269e2a03b
--- /dev/null
+++ b/db/migrate/20140416074002_add_index_on_iid.rb
@@ -0,0 +1,32 @@
+class AddIndexOnIid < ActiveRecord::Migration
+ def change
+ RemoveDuplicateIid.clean(Issue)
+ RemoveDuplicateIid.clean(MergeRequest, 'target_project_id')
+ RemoveDuplicateIid.clean(Milestone)
+
+ add_index :issues, [:project_id, :iid], unique: true
+ add_index :merge_requests, [:target_project_id, :iid], unique: true
+ add_index :milestones, [:project_id, :iid], unique: true
+ end
+end
+
+class RemoveDuplicateIid
+ def self.clean(klass, project_field = 'project_id')
+ duplicates = klass.find_by_sql("SELECT iid, #{project_field} FROM #{klass.table_name} GROUP BY #{project_field}, iid HAVING COUNT(*) > 1")
+
+ duplicates.each do |duplicate|
+ project_id = duplicate.send(project_field)
+ iid = duplicate.iid
+ items = klass.of_projects(project_id).where(iid: iid)
+
+ if items.size > 1
+ puts "Remove #{klass.name} duplicates for iid: #{iid} and project_id: #{project_id}"
+ items.shift
+ items.each do |item|
+ item.destroy
+ puts '.'
+ end
+ end
+ end
+ end
+end
diff --git a/db/migrate/20140416185734_index_on_current_sign_in_at.rb b/db/migrate/20140416185734_index_on_current_sign_in_at.rb
new file mode 100644
index 00000000000..0bf80ce154a
--- /dev/null
+++ b/db/migrate/20140416185734_index_on_current_sign_in_at.rb
@@ -0,0 +1,5 @@
+class IndexOnCurrentSignInAt < ActiveRecord::Migration
+ def change
+ add_index :users, :current_sign_in_at
+ end
+end
diff --git a/db/migrate/20140428105831_add_notes_index_updated_at.rb b/db/migrate/20140428105831_add_notes_index_updated_at.rb
new file mode 100644
index 00000000000..6c25570f128
--- /dev/null
+++ b/db/migrate/20140428105831_add_notes_index_updated_at.rb
@@ -0,0 +1,5 @@
+class AddNotesIndexUpdatedAt < ActiveRecord::Migration
+ def change
+ add_index :notes, :updated_at
+ end
+end
diff --git a/db/migrate/20140502115131_add_repo_size_to_db.rb b/db/migrate/20140502115131_add_repo_size_to_db.rb
new file mode 100644
index 00000000000..7361d1a9440
--- /dev/null
+++ b/db/migrate/20140502115131_add_repo_size_to_db.rb
@@ -0,0 +1,5 @@
+class AddRepoSizeToDb < ActiveRecord::Migration
+ def change
+ add_column :projects, :repository_size, :float, default: 0
+ end
+end
diff --git a/db/migrate/20140502125220_migrate_repo_size.rb b/db/migrate/20140502125220_migrate_repo_size.rb
new file mode 100644
index 00000000000..eed6d366814
--- /dev/null
+++ b/db/migrate/20140502125220_migrate_repo_size.rb
@@ -0,0 +1,21 @@
+class MigrateRepoSize < ActiveRecord::Migration
+ def up
+ Project.reset_column_information
+ Project.find_each(batch_size: 500) do |project|
+ begin
+ if project.empty_repo?
+ print '-'
+ else
+ project.update_repository_size
+ print '.'
+ end
+ rescue
+ print 'F'
+ end
+ end
+ puts 'Done'
+ end
+
+ def down
+ end
+end
diff --git a/db/migrate/limits_to_mysql.rb b/db/migrate/limits_to_mysql.rb
new file mode 100644
index 00000000000..2b7afae6d7c
--- /dev/null
+++ b/db/migrate/limits_to_mysql.rb
@@ -0,0 +1,10 @@
+class LimitsToMysql < ActiveRecord::Migration
+ def up
+ return unless ActiveRecord::Base.configurations[Rails.env]['adapter'] =~ /^mysql/
+
+ change_column :merge_request_diffs, :st_commits, :text, limit: 2147483647
+ change_column :merge_request_diffs, :st_diffs, :text, limit: 2147483647
+ change_column :snippets, :content, :text, limit: 2147483647
+ change_column :notes, :st_diff, :text, limit: 2147483647
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 265d556bd27..93837337afc 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20140414131055) do
+ActiveRecord::Schema.define(version: 20140502125220) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@@ -93,6 +93,7 @@ ActiveRecord::Schema.define(version: 20140414131055) do
add_index "issues", ["author_id"], name: "index_issues_on_author_id", using: :btree
add_index "issues", ["created_at"], name: "index_issues_on_created_at", using: :btree
add_index "issues", ["milestone_id"], name: "index_issues_on_milestone_id", using: :btree
+ add_index "issues", ["project_id", "iid"], name: "index_issues_on_project_id_and_iid", unique: true, using: :btree
add_index "issues", ["project_id"], name: "index_issues_on_project_id", using: :btree
add_index "issues", ["title"], name: "index_issues_on_title", using: :btree
@@ -143,6 +144,7 @@ ActiveRecord::Schema.define(version: 20140414131055) do
add_index "merge_requests", ["source_branch"], name: "index_merge_requests_on_source_branch", using: :btree
add_index "merge_requests", ["source_project_id"], name: "index_merge_requests_on_source_project_id", using: :btree
add_index "merge_requests", ["target_branch"], name: "index_merge_requests_on_target_branch", using: :btree
+ add_index "merge_requests", ["target_project_id", "iid"], name: "index_merge_requests_on_target_project_id_and_iid", unique: true, using: :btree
add_index "merge_requests", ["title"], name: "index_merge_requests_on_title", using: :btree
create_table "milestones", force: true do |t|
@@ -157,6 +159,7 @@ ActiveRecord::Schema.define(version: 20140414131055) do
end
add_index "milestones", ["due_date"], name: "index_milestones_on_due_date", using: :btree
+ add_index "milestones", ["project_id", "iid"], name: "index_milestones_on_project_id_and_iid", unique: true, using: :btree
add_index "milestones", ["project_id"], name: "index_milestones_on_project_id", using: :btree
create_table "namespaces", force: true do |t|
@@ -197,6 +200,7 @@ ActiveRecord::Schema.define(version: 20140414131055) do
add_index "notes", ["noteable_type"], name: "index_notes_on_noteable_type", using: :btree
add_index "notes", ["project_id", "noteable_type"], name: "index_notes_on_project_id_and_noteable_type", using: :btree
add_index "notes", ["project_id"], name: "index_notes_on_project_id", using: :btree
+ add_index "notes", ["updated_at"], name: "index_notes_on_updated_at", using: :btree
create_table "projects", force: true do |t|
t.string "name"
@@ -218,6 +222,7 @@ ActiveRecord::Schema.define(version: 20140414131055) do
t.integer "visibility_level", default: 0, null: false
t.boolean "archived", default: false, null: false
t.string "import_status"
+ t.float "repository_size", default: 0.0
end
add_index "projects", ["creator_id"], name: "index_projects_on_creator_id", using: :btree
@@ -319,7 +324,6 @@ ActiveRecord::Schema.define(version: 20140414131055) do
t.integer "notification_level", default: 1, null: false
t.datetime "password_expires_at"
t.integer "created_by_id"
- t.datetime "last_credential_check_at"
t.string "avatar"
t.string "confirmation_token"
t.datetime "confirmed_at"
@@ -327,11 +331,13 @@ ActiveRecord::Schema.define(version: 20140414131055) do
t.string "unconfirmed_email"
t.boolean "hide_no_ssh_key", default: false
t.string "website_url", default: "", null: false
+ t.datetime "last_credential_check_at"
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
+ add_index "users", ["current_sign_in_at"], name: "index_users_on_current_sign_in_at", using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["extern_uid", "provider"], name: "index_users_on_extern_uid_and_provider", unique: true, using: :btree
add_index "users", ["name"], name: "index_users_on_name", using: :btree
diff --git a/doc/README.md b/doc/README.md
index 6c8fe3a96ce..b73d7bb38e1 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -6,7 +6,7 @@
+ [Public access](public_access/public_access.md) Learn how you can allow public and internal access to a project.
+ [SSH](ssh/README.md) Setup your ssh keys and deploy keys for secure access to your projects.
+ [Web hooks](web_hooks/web_hooks.md) Let GitLab notify you when new code has been pushed to your project.
-+ [Workflow](workflow/workflow.md) Learn how to use Git and GitLab together.
++ [Workflow](workflow/README.md) Learn how to use Git and GitLab together.
**Administrator documentation**
diff --git a/doc/api/README.md b/doc/api/README.md
index b1740f35792..4c40589fd4f 100644
--- a/doc/api/README.md
+++ b/doc/api/README.md
@@ -13,7 +13,7 @@
+ [Merge Requests](merge_requests.md)
+ [Issues](issues.md)
+ [Milestones](milestones.md)
-+ [Notes](notes.md)
++ [Notes](notes.md) (comments)
+ [Deploy Keys](deploy_keys.md)
+ [System Hooks](system_hooks.md)
+ [Groups](groups.md)
@@ -21,9 +21,11 @@
## Clients
+ [php-gitlab-api](https://github.com/m4tthumphrey/php-gitlab-api) - PHP
++ [Laravel API Wrapper for GitLab CE](https://github.com/adamgoose/gitlab) - PHP / [Laravel](http://laravel.com)
+ [Ruby Wrapper](https://github.com/NARKOZ/gitlab) - Ruby
+ [python-gitlab](https://github.com/Itxaka/python-gitlab) - Python
+ [java-gitlab-api](https://github.com/timols/java-gitlab-api) - Java
++ [node-gitlab](https://github.com/moul/node-gitlab) - Node.js
## Introduction
diff --git a/doc/api/issues.md b/doc/api/issues.md
index 823b72f5b0c..d18506f9ce6 100644
--- a/doc/api/issues.md
+++ b/doc/api/issues.md
@@ -193,3 +193,7 @@ Parameters:
+ `id` (required) - The project ID
+ `issue_id` (required) - The ID of the issue
+
+## Comments on issues
+
+Comments are done via the notes resource.
diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md
index 4e864ae1078..d5b106729c9 100644
--- a/doc/api/merge_requests.md
+++ b/doc/api/merge_requests.md
@@ -105,10 +105,11 @@ POST /projects/:id/merge_requests
Parameters:
+ `id` (required) - The ID of a project
-+ `source_branch` (required) - The source branch
-+ `target_branch` (required) - The target branch
-+ `assignee_id` (optional) - Assignee user ID
-+ `title` (required) - Title of MR
++ `source_branch` (required) - The source branch
++ `target_branch` (required) - The target branch
++ `assignee_id` (optional) - Assignee user ID
++ `title` (required) - Title of MR
++ `target_project_id` (optional) - The target project (numeric id)
```json
{
@@ -257,3 +258,7 @@ Parameters:
}
]
```
+
+## Comments on issues
+
+Comments are done via the notes resource.
diff --git a/doc/api/notes.md b/doc/api/notes.md
index b15ebdd2bac..e9ad6e00c73 100644
--- a/doc/api/notes.md
+++ b/doc/api/notes.md
@@ -1,3 +1,5 @@
+Notes can be wall notes or comments on snippets, issues or merge requests.
+
## Wall
### List project wall notes
diff --git a/doc/api/users.md b/doc/api/users.md
index 2d5dedb3a39..2b927c30777 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -220,6 +220,18 @@ Parameters:
+ **none**
+## List SSH keys for user
+
+Get a list of a specified user's SSH keys. Available only for admin
+
+```
+GET /users/:uid/keys
+```
+
+Parameters:
+
++ `uid` (required) - id of specified user
+
## Single SSH key
@@ -286,3 +298,18 @@ Parameters:
+ `id` (required) - SSH key ID
+## Delete SSH key
+
+Deletes key owned by a specified user. Available only for admin.
+
+```
+DELETE /users/:uid/keys/:id
+```
+
+Parameters:
+
++ `uid` (required) - id of specified user
++ `id` (required) - SSH key ID
+
+Will return `200 Ok` on success, or `404 Not found` if either user or key cannot be found.
+
diff --git a/doc/development/README.md b/doc/development/README.md
index aa59eb2c3e1..eb88b6c860f 100644
--- a/doc/development/README.md
+++ b/doc/development/README.md
@@ -1,2 +1,5 @@
-+ [Architecture](architecture.md)
-+ [Shell commands](shell_commands.md)
+## Development
+
++ [Architecture](architecture.md) of GitLab
++ [Shell commands](shell_commands.md) in the GitLab codebase
++ [Rake tasks](rake_tasks.md) for development
diff --git a/doc/development/rake_tasks.md b/doc/development/rake_tasks.md
new file mode 100644
index 00000000000..9e75b3a6275
--- /dev/null
+++ b/doc/development/rake_tasks.md
@@ -0,0 +1,25 @@
+# Rake tasks for developers
+
+## Setup db with developer seeds:
+
+Note that if your db user does not have advanced privilegies you must create db manually before run this command
+
+```
+bundle exec rake setup
+```
+
+## Run tests
+
+This runs all test suite present in GitLab
+
+```
+bundle exec rake test
+```
+
+## Generate searchable docs for source code
+
+You can find results under `doc/code` directory
+
+```
+bundle exec rake gitlab:generate_docs
+```
diff --git a/doc/install/installation.md b/doc/install/installation.md
index fb3faa536f0..eea5c763fcd 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -1,10 +1,10 @@
# Select Version to Install
-Make sure you view this installation guide from the branch (version) of GitLab you would like to install. In most cases
+Make sure you view [this installation guide](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md) from the branch (version) of GitLab you would like to install. In most cases
this should be the highest numbered stable branch (example shown below).
![capture](http://i.imgur.com/d2AlIVj.png)
-If this is unclear check the [GitLab Blog](https://www.gitlab.com/blog/) for installation guide links by version.
+If the highest number stable branch is unclear please check the [GitLab Blog](https://www.gitlab.com/blog/) for installation guide links by version.
# Important notes
@@ -27,10 +27,9 @@ The GitLab installation consists of setting up the following components:
1. Packages / Dependencies
2. Ruby
3. System Users
-4. GitLab shell
-5. Database
-6. GitLab
-7. Nginx
+4. Database
+5. GitLab
+6. Nginx
# 1. Packages / Dependencies
@@ -119,32 +118,10 @@ Create a `git` user for Gitlab:
sudo adduser --disabled-login --gecos 'GitLab' git
-
-# 4. GitLab shell
-
-GitLab Shell is an ssh access and repository management software developed specially for GitLab.
-
- # Go to home directory
- cd /home/git
-
- # Clone gitlab shell
- sudo -u git -H git clone https://gitlab.com/gitlab-org/gitlab-shell.git -b v1.9.1
-
- cd gitlab-shell
-
- sudo -u git -H cp config.yml.example config.yml
-
- # Edit config and replace gitlab_url
- # with something like 'http://domain.com/'
- sudo -u git -H editor config.yml
-
- # Do setup
- sudo -u git -H ./bin/install
-
-
-# 5. Database
+# 4. Database
We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](database_mysql.md).
+NOTE: because we need to make use of extensions you need at least pgsql 9.1.
# Install the database packages
sudo apt-get install -y postgresql-9.1 postgresql-client libpq-dev
@@ -153,7 +130,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
sudo -u postgres psql -d template1
# Create a user for GitLab.
- template1=# CREATE USER git;
+ template1=# CREATE USER git CREATEDB;
# Create the GitLab production database & grant all privileges on database
template1=# CREATE DATABASE gitlabhq_production OWNER git;
@@ -165,7 +142,7 @@ We recommend using a PostgreSQL database. For MySQL check [MySQL setup guide](da
sudo -u git -H psql -d gitlabhq_production
-# 6. GitLab
+# 5. GitLab
# We'll install GitLab into home directory of the user "git"
cd /home/git
@@ -276,6 +253,18 @@ that were [fixed](https://github.com/bundler/bundler/pull/2817) in 1.5.2.
# When done you see 'Administrator account created:'
+## Install GitLab shell
+
+GitLab Shell is an ssh access and repository management software developed specially for GitLab.
+
+ # Go to the Gitlab installation folder:
+ cd /home/git/gitlab
+
+ # Run the installation task for gitlab-shell (replace `REDIS_URL` if needed):
+ sudo -u git -H bundle exec rake gitlab:shell:install[v1.9.3] REDIS_URL=redis://localhost:6379 RAILS_ENV=production
+
+ # By default, the gitlab-shell config is generated from your main gitlab config. You can review (and modify) it as follows:
+ sudo -u git -H editor /home/git/gitlab-shell/config.yml
## Install Init Script
@@ -313,7 +302,8 @@ Check if GitLab and its environment are configured correctly:
# or
sudo /etc/init.d/gitlab restart
-# 7. Nginx
+
+# 6. Nginx
**Note:**
Nginx is the officially supported web server for GitLab. If you cannot or do not want to use Nginx as your web server, have a look at the
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index 56a2a5efeb0..dc21a7e55ab 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -43,18 +43,24 @@ We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) but GitLab
## CPU
-- 1 core works for under 100 users but the responsiveness might suffer
-- **2 cores** is the **recommended** number of cores and supports up to 100 users
-- 4 cores supports up to 1,000 users
-- 8 cores supports up to 10,000 users
+- 1 core works supports up to 100 users but the application will not be responsive
+- **2 cores** is the **recommended** number of cores and supports up to 500 users
+- 4 cores supports up to 2,000 users
+- 8 cores supports up to 5,000 users
+- 16 cores supports up to 10,0000 users
+- 32 cores supports up to 20,0000 users
+- 64 cores supports up to 40,0000 users
## Memory
-- 512MB is too little memory, GitLab will be very slow and you will need 250MB of swap
-- 768MB is the minimal memory size but we advise against this
+- 512MB is the abolute minimum, you need 256MB of swap, you can configure only one slow unicorn worker, only ssh access will work, we do not recommend this
- 1GB supports up to 100 users (with individual repositories under 250MB, otherwise git memory usage necessitates using swap space)
-- **2GB** is the **recommended** memory size and supports up to 1,000 users
-- 4GB supports up to 10,000 users
+- **2GB** is the **recommended** memory size and supports up to 500 users
+- 4GB supports up to 2,000 users
+- 8GB supports up to 5,000 users
+- 16GB supports up to 10,000 users
+- 32GB supports up to 20,000 users
+- 64GB supports up to 40,000 users
## Storage
@@ -68,11 +74,14 @@ Apart from a local hard drive you can also mount a volume that supports the netw
If you have enough RAM memory and a recent CPU the speed of GitLab is mainly limited by hard drive seek times. Having a fast drive (7200 RPM and up) or a solid state drive (SSD) will improve the responsiveness of GitLab.
+## Database
+
+If you want to run the database separately, the **recommended** database size is **1 MB per user**
# Supported webbrowsers
- Chrome (Latest stable version)
- Firefox (Latest released version)
-- Safari 7+ (Know problem: required fields in html5 do not work)
+- Safari 7+ (known problem: required fields in html5 do not work)
- Opera (Latest released version)
-- IE 10+
+- IE 10+ \ No newline at end of file
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 3e8d329d558..8318113ce92 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -6,3 +6,4 @@ See the documentation below for details on how to configure these services.
+ [External issue tracker](external-issue-tracker.md) Redmine, JIRA, etc.
+ [LDAP](ldap.md) Set up sign in via LDAP
+ [OmniAuth](omniauth.md) Sign in via Twitter, GitHub, and Google via OAuth.
++ [Slack](slack.md) Integrate with the Slack chat service
diff --git a/doc/integration/omniauth.md b/doc/integration/omniauth.md
index a4491432caf..84a5a8e8c28 100644
--- a/doc/integration/omniauth.md
+++ b/doc/integration/omniauth.md
@@ -21,6 +21,7 @@ Before configuring individual OmniAuth providers there are a few global settings
```
2. Find the section dealing with OmniAuth. The section will look similar to the following.<br />
+
```
## OmniAuth settings
omniauth:
@@ -50,6 +51,7 @@ Before configuring individual OmniAuth providers there are a few global settings
# app_secret: 'YOUR APP SECRET',
# args: { scope: 'user:email' } }
```
+
3. Change `enabled` to `true`.
4. Consider the next two configuration options: `allow_single_sign_on` and `block_auto_created_users`.
* `allow_single_sign_on` defaults to `false`. If `false` users must be created manually or they will not be able to
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index ac4bdefddd5..9be6423f667 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -27,7 +27,7 @@ If a user is a GitLab administrator they receive all permissions.
|Remove protected branches| |||✓|✓|
|Edit project| |||✓|✓|
|Add Deploy Keys to project| |||✓|✓|
-|Confiure Project Hooks| |||✓|✓|
+|Configure Project Hooks| |||✓|✓|
|Switch visibility level| ||||✓|
|Transfer project to another namespace| ||||✓|
|Remove project| ||||✓|
diff --git a/doc/public_access/public_access.md b/doc/public_access/public_access.md
index bf9d2784aff..76d83e6f3b6 100644
--- a/doc/public_access/public_access.md
+++ b/doc/public_access/public_access.md
@@ -4,7 +4,7 @@ Internal projects will only be available to authenticated users.
#### Public projects
Public projects can be cloned **without any** authentication.
-It will also be listen on the [public access directory](/public).
+It will also be listed on the [public access directory](/public).
**Any logged in user** will have [Guest](/help/permissions) permissions on the repository.
#### Internal projects
diff --git a/doc/raketasks/README.md b/doc/raketasks/README.md
index 9aa80af12cc..6be24f0102a 100644
--- a/doc/raketasks/README.md
+++ b/doc/raketasks/README.md
@@ -1,6 +1,7 @@
+ [Backup restore](backup_restore.md)
+ [Cleanup](cleanup.md)
+ [Features](features.md)
-+ [Maintenance](maintenance.md)
++ [Maintenance](maintenance.md) and self-checks
+ [User management](user_management.md)
+ [Web hooks](web_hooks.md)
++ [Import](import.md) of git repositories in bulk
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
new file mode 100644
index 00000000000..e11328dc5ce
--- /dev/null
+++ b/doc/raketasks/import.md
@@ -0,0 +1,28 @@
+### Import bare repositories into GitLab project instance
+
+Notes:
+
+* project owner will be a first admin
+* groups will be created as needed
+* group owner will be the first admin
+* existing projects will be skipped
+
+How to use:
+
+1. copy your bare repos under git repos_path (see `config/gitlab.yml` gitlab_shell -> repos_path)
+2. run the command below
+
+```
+bundle exec rake gitlab:import:repos RAILS_ENV=production
+```
+
+Example output:
+
+```
+Processing abcd.git
+ * Created abcd (abcd.git)
+Processing group/xyz.git
+ * Created Group group (2)
+ * Created xyz (group/xyz.git)
+[...]
+```
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
index 3033d8c46b4..2783c4153c5 100644
--- a/doc/raketasks/maintenance.md
+++ b/doc/raketasks/maintenance.md
@@ -110,32 +110,3 @@ If necessary, remove the `tmp/repo_satellites` directory and rerun the command b
```
bundle exec rake gitlab:satellites:create RAILS_ENV=production
```
-
-### Import bare repositories into GitLab project instance
-
-Notes:
-
-* project owner will be a first admin
-* groups will be created as needed
-* group owner will be the first admin
-* existing projects will be skipped
-
-How to use:
-
-1. copy your bare repos under git repos_path (see `config/gitlab.yml` gitlab_shell -> repos_path)
-2. run the command below
-
-```
-bundle exec rake gitlab:import:repos RAILS_ENV=production
-```
-
-Example output:
-
-```
-Processing abcd.git
- * Created abcd (abcd.git)
-Processing group/xyz.git
- * Created Group group (2)
- * Created xyz (group/xyz.git)
-[...]
-```
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 9dbe62f1210..514d73517b2 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -1,15 +1,36 @@
-# Things to do when creating new monthly minor or major release
-NOTE: This is a guide for GitLab developers. If you are trying to install GitLab see the latest stable [installation guide](install/installation.md) and if you are trying to upgrade, see the [upgrade guides](update).
+# Monthly Release
+NOTE: This is a guide for GitLab developers.
-## Install guide up to date?
+# **15th - Code Freeze & Release Manager**
-* References correct GitLab branch `x-x-stable` and correct GitLab shell tag?
+### **1. Stop merging in code, except for important bugfixes**
-## Make upgrade guide
+### **2. Release Manager**
-### From x.x to x.x
+A release manager is selected that coordinates the entire release of this version. The release manager has to make sure all the steps below are done and delegated where necessary. This person should also make sure this document is kept up to date and issues are created and updated.
-#### 0. Any major changes? Database updates? Web server change? File structure changes?
+# **18th - Releasing RC1**
+
+The RC1 release comes with the task to update the installation and upgrade docs. Be mindful that there might already be merge requests for this on GitLab or GitHub.
+
+### **1. Create an issue for RC1 release**
+
+### **2. Update the installation guide**
+
+1. Check if it references the correct branch `x-x-stable` (doesn't exist yet, but that is okay)
+2. Check the [GitLab Shell version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L782)
+3. Check the [Git version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L794)
+4. There might be other changes. Ask around.
+
+### **3. Create an update guide**
+
+It's best to copy paste the previous guide and make changes where necessary. The typical steps are listed below with any points you should specifically look at.
+
+#### 0. Any major changes?
+List any major changes here, so the user is aware of them before starting to upgrade. For instance:
+- Database updates
+- Web server changes
+- File structure changes
#### 1. Make backup
@@ -17,9 +38,9 @@ NOTE: This is a guide for GitLab developers. If you are trying to install GitLab
#### 3. Do users need to update dependencies like `git`?
-- Check the [GitLab Shell version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L782)
+- Check if the [GitLab Shell version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L782) changed since the last release.
-- Check the [Git version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L794)
+- Check if the [Git version](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/lib/tasks/gitlab/check.rake#L794) changed since the last release.
#### 4. Get latest code
@@ -29,7 +50,7 @@ NOTE: This is a guide for GitLab developers. If you are trying to install GitLab
#### 7. Any config files updated since last release?
-Check if any of these changed since last release (~22nd of last month depending on when last release branch was created):
+Check if any of these changed since last release:
* https://gitlab.com/gitlab-org/gitlab-ce/commits/master/lib/support/nginx/gitlab
* https://gitlab.com/gitlab-org/gitlab-shell/commits/master/config.yml.example
@@ -40,13 +61,14 @@ Check if any of these changed since last release (~22nd of last month depending
#### 8. Need to update init script?
-Check if changed since last release (~22nd of last month depending on when last release branch was created): https://gitlab.com/gitlab-org/gitlab-ce/commits/master/lib/support/init.d/gitlab
+Check if the init.d/gitlab script changed since last release: https://gitlab.com/gitlab-org/gitlab-ce/commits/master/lib/support/init.d/gitlab
#### 9. Start application
#### 10. Check application status
-## Make sure the code quality indicatiors are good
+### **4. Code quality indicatiors**
+Make sure the code quality indicators are green / good.
* [![build status](http://ci.gitlab.org/projects/1/status.png?ref=master)](http://ci.gitlab.org/projects/1?ref=master) on ci.gitlab.org (master branch)
@@ -58,32 +80,88 @@ Check if changed since last release (~22nd of last month depending on when last
* [![Coverage Status](https://coveralls.io/repos/gitlabhq/gitlabhq/badge.png?branch=master)](https://coveralls.io/r/gitlabhq/gitlabhq)
-## Make a release branch
+### **5. Set VERSION**
-After making the release branch new commits are cherry-picked from master. When the release gets closer we get more selective what is cherry-picked. The days of the month are approximately as follows:
+Set VERSION tot x.x.0.rc1
-* 1-7th: official merge window (see contributing guide)
-* 8-14th: work on bugfixes, sponsored features and GitLab EE
-* 15th: code freeze (stop merging into master except essential bugfixes)
-* 18th: release candidate 1 (VERSION x.x.0.rc1, annotated tag and tweet about x.x.0.rc1, release on GitLab Cloud)
-* 20st: optional release candidate 2 (x.x.0.rc2, only if rc1 had problems)
-* 22nd: release (VERSION x.x.0, create x-x-stable branch, annotated tag tag, blog and tweet)
-* 23nd: optional patch releases (x.x.1, x.x.2, etc., only if there are serious problems)
-* 24-end of month: release GitLab EE and GitLab CI
-# Write a blog post
+### **6. Tag**
-* Mention what GitLab is on the second line: GitLab is open source software to collaborate on code.
-* Select and thank the the Most Valuable Person (MVP) of this release.
-* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
+Create an annotated tag that points to the version change commit.
+```
+git tag -a vx.x.0.rc1 -m 'Version x.x.0.rc1'
+```
+
+### **7. Tweet**
+
+Tweet about the RC release:
+
+> GitLab x.x.x.rc1 is out. This is a release candidate intended for testing only. Please let us know if you find regressions.
+
+### **8. Update Cloud**
+
+Merge the RC1 code into Cloud. Once the build is green, deploy in the morning.
+
+It is important to do this as soon as possible, so we can catch any errors before we release the full version.
+
+
+# **22nd - Release CE and EE**
-# Tweet
+For GitLab EE, append -ee to the branches and tags.
-Send out a tweet to share the good news with the world. For a major/minor release, list the features in short and link to the blog post.
+`x-x-stable-ee`
-For a RC, make sure to explain what a RC is.
+`v.x.x.0-ee`
+
+### **1. Create x-x-stable branch and push to the repositories**
+
+```
+git checkout master
+git pull
+git checkout -b x-x-stable
+git push <remote> x-x-stable
+```
+
+### **2. Build the Omnibus packages**
+[Follow this guide](https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/doc/release.md)
+
+### **3. QA**
+Use the omnibus packages to test using [this guide](https://dev.gitlab.org/gitlab/gitlab-ee/blob/master/doc/release/manual_testing.md)
+
+
+### **4. Fix anything coming out of the QA**
+
+### **5. Set VERSION to x.x.0**
+
+### **6. Create annotated tag vx.x.0**
+```
+git tag -a vx.x.0 -m 'Version x.x.0'
+```
+
+### **7. Push VERSION + Tag to master, merge into x-x-stable**
+```
+git push origin master
+```
+
+Next, merge the VERSION into the x-x-stable branch.
+
+### **8. Push to remotes**
+
+For GitLab CE, push to dev, GitLab.com and GitHub.
+
+For GitLab EE, push to the subscribers repo.
+
+NOTE: You might not have the rights to push to master on dev. Ask Dmitriy.
+
+### **9. Publish blog for new release**
+* Mention what GitLab is on the second line: GitLab is open source software to collaborate on code.
+* Select and thank the the Most Valuable Person (MVP) of this release.
+* Add a note if there are security fixes: This release fixes an important security issue and we advise everyone to upgrade as soon as possible.
-A patch release tweet should specify the fixes it brings and link to the corresponding blog post.
+### **10. Tweet to blog**
+Send out a tweet to share the good news with the world. List the features in short and link to the blog post.
+# **23rd - Optional Patch Release**
+# **25th - Release GitLab CI**
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 76ca2a59911..5c8daf466ab 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -16,6 +16,7 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
"path": "stormcloud",
"path_with_namespace": "jsmith/stormcloud",
"project_id": 74,
+ "project_visibility": "private",
}
```
@@ -31,6 +32,7 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
"path": "underscore",
"path_with_namespace": "jsmith/underscore",
"project_id": 73,
+ "project_visibility": "internal",
}
```
@@ -38,14 +40,15 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
```json
{
- "created_at": "2012-07-21T07:30:56Z",
- "event_name": "user_add_to_team",
- "project_access": "Master",
- "project_id": 74,
- "project_name": "StoreCloud",
- "project_path": "storecloud",
- "user_email": "johnsmith@gmail.com",
- "user_name": "John Smith",
+ "created_at": "2012-07-21T07:30:56Z",
+ "event_name": "user_add_to_team",
+ "project_access": "Master",
+ "project_id": 74,
+ "project_name": "StoreCloud",
+ "project_path": "storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ "project_visibility": "private",
}
```
@@ -53,14 +56,15 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
```json
{
- "created_at": "2012-07-21T07:30:56Z",
- "event_name": "user_remove_from_team",
- "project_access": "Master",
- "project_id": 74,
- "project_name": "StoreCloud",
- "project_path": "storecloud",
- "user_email": "johnsmith@gmail.com",
- "user_name": "John Smith",
+ "created_at": "2012-07-21T07:30:56Z",
+ "event_name": "user_remove_from_team",
+ "project_access": "Master",
+ "project_id": 74,
+ "project_name": "StoreCloud",
+ "project_path": "storecloud",
+ "user_email": "johnsmith@gmail.com",
+ "user_name": "John Smith",
+ "project_visibility": "private",
}
```
diff --git a/doc/update/6.0-to-6.7.md b/doc/update/6.0-to-6.8.md
index aa1b388fa9a..5c71e99aa52 100644
--- a/doc/update/6.0-to-6.7.md
+++ b/doc/update/6.0-to-6.8.md
@@ -1,4 +1,4 @@
-# From 6.0 to 6.7
+# From 6.0 to 6.8
# In 6.1 we remove a lot of deprecated code.
# You should update to 6.0 before installing 6.1 or higher so all the necessary conversions are run.
@@ -33,7 +33,7 @@ sudo -u git -H git fetch --all
For Gitlab Community Edition:
```bash
-sudo -u git -H git checkout 6-7-stable
+sudo -u git -H git checkout 6-8-stable
```
OR
@@ -41,7 +41,7 @@ OR
For GitLab Enterprise Edition:
```bash
-sudo -u git -H git checkout 6-7-stable-ee
+sudo -u git -H git checkout 6-8-stable-ee
```
@@ -57,7 +57,7 @@ sudo apt-get install logrotate
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.9.1 # Addresses multiple critical security vulnerabilities
+sudo -u git -H git checkout v1.9.3 # Addresses multiple critical security vulnerabilities
```
### 5. Install libs, migrations, etc.
@@ -90,11 +90,12 @@ sudo chmod u+rwx,g+rx,o-rwx /home/git/gitlab-satellites
TIP: to see what changed in gitlab.yml.example in this release use next command:
```
-git diff 6-0-stable:config/gitlab.yml.example 6-7-stable:config/gitlab.yml.example
+git diff 6-0-stable:config/gitlab.yml.example 6-8-stable:config/gitlab.yml.example
```
-* Make `/home/git/gitlab/config/gitlab.yml` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-7-stable/config/gitlab.yml.example but with your settings.
-* Make `/home/git/gitlab/config/unicorn.rb` same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-7-stable/config/unicorn.rb.example but with your settings.
+* Make `/home/git/gitlab/config/gitlab.yml` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-8-stable/config/gitlab.yml.example but with your settings.
+* Make `/home/git/gitlab/config/unicorn.rb` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-8-stable/config/unicorn.rb.example but with your settings.
+* Make `/etc/nginx/sites-available/nginx` the same as https://gitlab.com/gitlab-org/gitlab-ce/blob/6-8-stable/lib/support/nginx/gitlab but with your settings.
* Copy rack attack middleware config
```bash
diff --git a/doc/update/6.7-to-6.8.md b/doc/update/6.7-to-6.8.md
index 57918bca82d..457433c6482 100644
--- a/doc/update/6.7-to-6.8.md
+++ b/doc/update/6.7-to-6.8.md
@@ -1,4 +1,4 @@
-# From 6.6 to 6.7
+# From 6.7 to 6.8
### 0. Backup
@@ -9,7 +9,9 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
### 1. Stop server
- sudo service gitlab stop
+```bash
+sudo service gitlab stop
+```
### 2. Get latest code
@@ -37,7 +39,7 @@ sudo -u git -H git checkout 6-8-stable-ee
```bash
cd /home/git/gitlab-shell
sudo -u git -H git fetch
-sudo -u git -H git checkout v1.9.1
+sudo -u git -H git checkout v1.9.3
```
### 4. Install libs, migrations, etc.
@@ -60,6 +62,7 @@ sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS
# Update init.d script
sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+sudo chmod +x /etc/init.d/gitlab
# Update the logrotate configuration (keep logs for 90 days instead of 52 weeks)
sudo cp lib/support/logrotate/gitlab /etc/logrotate.d/gitlab
@@ -90,19 +93,12 @@ If you are using HTTPS, disable gzip as in [this commit](https://gitlab.com/gitl
To improve performance, enable gzip asset compression as seen [in this commit](https://gitlab.com/gitlab-org/gitlab-ce/commit/8af94ed75505f0253823b9b2d44320fecea5b5fb).
-### 6. Update Init script
-
-```bash
-sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
-sudo chmod +x /etc/init.d/gitlab
-```
-
-### 7. Start application
+### 6. Start application
sudo service gitlab start
sudo service nginx restart
-### 8. Check application status
+### 7. Check application status
Check if GitLab and its environment are configured correctly:
@@ -114,10 +110,10 @@ To make sure you didn't miss anything run a more thorough check with:
If all items are green, then congratulations upgrade is complete!
-## Things went south? Revert to previous version (6.6)
+## Things went south? Revert to previous version (6.7)
### 1. Revert the code to the previous version
-Follow the [`upgrade guide from 6.5 to 6.6`](6.5-to-6.6.md), except for the database migration
+Follow the [`upgrade guide from 6.6 to 6.7`](6.6-to-6.7.md), except for the database migration
(The backup is already migrated to the previous version)
### 2. Restore from the backup:
diff --git a/doc/update/README.md b/doc/update/README.md
index 06e3764616f..9ce48a019e8 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -1,5 +1,5 @@
-+ [The indivual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update)
-+ [Uprader](upgrader.md)
++ [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update)
++ [Upgrader](upgrader.md)
+ [Ruby](ruby.md)
+ [Patch versions](patch_versions.md)
+ [MySQL to PostgreSQL](mysql_to_postgresql.md)
diff --git a/doc/update/mysql_to_postgresql.md b/doc/update/mysql_to_postgresql.md
index 9a324545eb0..5b9209d7df4 100644
--- a/doc/update/mysql_to_postgresql.md
+++ b/doc/update/mysql_to_postgresql.md
@@ -1,9 +1,68 @@
-# Use the shell commands below to convert a MySQL GitLab database to a PostgreSQL one.
+# Migrating GitLab from MySQL to Postgres
+
+If you are replacing MySQL with Postgres while keeping GitLab on the same
+server all you need to do is to export from MySQL and import into Postgres as
+described below. If you are also moving GitLab to another server, or if you are
+switching to omnibus-gitlab, you may want to use a GitLab backup file. The
+second part of this documents explains the procedure to do this.
+
+## Export from MySQL and import into Postgres
+
+Use this if you are keeping GitLab on the same server.
```
+sudo service gitlab stop
+
+# Update /home/git/gitlab/config/database.yml
+
git clone https://github.com/lanyrd/mysql-postgresql-converter.git
cd mysql-postgresql-converter
mysqldump --compatible=postgresql --default-character-set=utf8 -r databasename.mysql -u root gitlabhq_production
python db_converter.py databasename.mysql databasename.psql
psql -f databasename.psql -d gitlabhq_production
+
+sudo service gitlab start
+```
+
+## Converting a GitLab backup file from MySQL to Postgres
+
+GitLab backup files (<timestamp>_gitlab_backup.tar) contain a SQL dump. Using
+the lanyrd database converter we can replace a MySQL database dump inside the
+tar file with a Postgres database dump. This can be useful if you are moving to
+another server.
+
+```
+# Stop GitLab
+sudo service gitlab stop
+
+# Create the backup
+cd /home/git/gitlab
+sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
+
+# Note the filename of the backup that was created. We will call it
+# TIMESTAMP_gitlab_backup.tar below.
+
+# Move the backup file we will convert to its own directory
+sudo -u git -H mkdir -p tmp/backups/postgresql
+sudo -u git -H mv tmp/backups/TIMESTAMP_gitlab_backup.tar tmp/backups/postgresql/
+
+# Create a separate database dump with PostgreSQL compatibility
+cd tmp/backups/postgresql
+sudo -u git -H mysqldump --compatible=postgresql --default-character-set=utf8 -r gitlabhq_production.mysql -u root gitlabhq_production
+
+# Clone the database converter
+sudo -u git -H git clone https://github.com/lanyrd/mysql-postgresql-converter.git
+
+# Convert gitlabhq_production.mysql
+sudo -u git -H mkdir db
+sudo -u git -H python mysql-postgresql-converter/db_converter.py gitlabhq_production.mysql db/database.sql
+
+# Replace the MySQL dump in TIMESTAMP_gitlab_backup.tar.
+
+# Warning: if you forget to replace TIMESTAMP below, tar will create a new file
+# 'TIMESTAMP_gitlab_backup.tar' without giving an error.
+
+sudo -u git -H tar rf TIMESTAMP_gitlab_backup.tar db/database.sql
+
+# Done! TIMESTAMP_gitlab_backup.tar can now be restored into a Postgres GitLab installation.
```
diff --git a/doc/update/ruby.md b/doc/update/ruby.md
index 9d0cafb3f05..e98167f6b66 100644
--- a/doc/update/ruby.md
+++ b/doc/update/ruby.md
@@ -1,6 +1,6 @@
# Updating Ruby from source
-This guide explains how to update Ruby in case you installed it from source according to the instructions in https://gitlab.com/gitlab-org/gitlab-ce/blob/masterdoc/install/installation.md#2-ruby .
+This guide explains how to update Ruby in case you installed it from source according to the [instructions](../install/installation.md#2-ruby).
### 1. Look for Ruby versions
This guide will only update `/usr/local/bin/ruby`. You can see which Ruby binaries are installed on your system by running:
@@ -36,7 +36,7 @@ sudo gem install bundler
```
### 5. Reinstall GitLab gem bundle
-Just to be sure we will reinstall the gems used by GitLab. Note that the `bundle install` command [depends on your choice of database](https://gitlab.com/gitlab-org/gitlab-ce/blob/masterdoc/install/installation.md#install-gems).
+Just to be sure we will reinstall the gems used by GitLab. Note that the `bundle install` command [depends on your choice of database](../install/installation.md#install-gems).
```bash
cd /home/git/gitlab
diff --git a/doc/update/upgrader.md b/doc/update/upgrader.md
index fd45154ac82..72a94f67b3c 100644
--- a/doc/update/upgrader.md
+++ b/doc/update/upgrader.md
@@ -46,4 +46,8 @@ If all items are green, then congratulations upgrade is complete!
You've read through the entire guide, and probably did all the steps manually. Here is a one liner for convenience, the next time you upgrade:
- cd /home/git/gitlab; sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; sudo service gitlab stop; sudo -u git -H ruby script/upgrade.rb -y; sudo service gitlab start; sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```bash
+cd /home/git/gitlab; sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production; \
+ sudo service gitlab stop; sudo -u git -H ruby script/upgrade.rb -y; sudo service gitlab start; \
+ sudo service nginx restart; sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production
+```
diff --git a/doc/web_hooks/web_hooks.md b/doc/web_hooks/web_hooks.md
index f80891e264d..5ad0c8a138f 100644
--- a/doc/web_hooks/web_hooks.md
+++ b/doc/web_hooks/web_hooks.md
@@ -2,16 +2,16 @@ Project web hooks allow you to trigger an URL if new code is pushed or a new iss
---
-You can configure web hook to listen for specific events like pushes, issues, merge requests.
-GitLab will send POST request with data to web hook URL.
-Web Hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
+You can configure web hooks to listen for specific events like pushes, issues or merge requests.
+GitLab will send a POST request with data to the web hook URL.
+Web hooks can be used to update an external issue tracker, trigger CI builds, update a backup mirror, or even deploy to your production server.
If you send a web hook to an SSL endpoint [the certificate will not be verified](https://gitlab.com/gitlab-org/gitlab-ce/blob/ccd617e58ea71c42b6b073e692447d0fe3c00be6/app/models/web_hook.rb#L35) since many people use self-signed certificates.
---
#### Push events
-Triggered when you push to the repository except pushing tags.
+Triggered when you push to the repository except when pushing tags.
**Request body:**
@@ -84,7 +84,7 @@ Triggered when a new issue is created or an existing issue was updated/closed/re
#### Merge request events
-Triggered when a new merge request is created or an existing merge request was updated/merges/closed.
+Triggered when a new merge request is created or an existing merge request was updated/merged/closed.
**Request body:**
diff --git a/doc/workflow/authorization_for_merge_requests.md b/doc/workflow/authorization_for_merge_requests.md
new file mode 100644
index 00000000000..4e07d7c04c5
--- /dev/null
+++ b/doc/workflow/authorization_for_merge_requests.md
@@ -0,0 +1,32 @@
+There are two main ways to have a merge request flow with GitLab: working with protected branches in a single repository, or working with forks of an authoritative project.
+
+## Protected branch flow
+
+With the protected branch flow everybody works within the same GitLab project.
+The project maintainers get Master access and the regular developers get Developer access.
+The maintainers mark the authoritative branches as 'Protected'.
+The developers push feature branches to the project and create merge requests to have their feature branches reviewed and merged into one of the protected branches.
+Only users with Master access can merge changes into a protected branch.
+
+### Advantages
+
+- fewer projects means less clutter
+- developers need to consider only one remote repository
+
+### Disadvantages
+
+- manual setup of protected branch required for each new project
+
+## Forking workflow
+
+With the forking workflow the maintainers get Master access and the regular developers get Reporter access to the authoritative repository, which prohibits them from pushing any changes to it.
+Developers create forks of the authoritative project and push their feature branches to their own forks.
+To get their changes into master they need to create a merge request across forks.
+
+### Advantages
+
+- in an appropriately configured GitLab group, new projects automatically get the required access restrictions for regular developers: fewer manual steps to configure authorization for new projects
+
+### Disadvantages
+
+- the project need to keep their forks up to date, which requires more advanced Git skills (managing multiple remotes)
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index 2d94b98c90b..5832b729deb 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -30,11 +30,10 @@ Feature: Project Forked Merge Requests
Given I visit project "Forked Shop" merge requests page
And I click link "New Merge Request"
And I fill out an invalid "Merge Request On Forked Project" merge request
- And I submit the merge request
Then I should see validation errors
@javascript
Scenario: Merge request should target fork repository by default
Given I visit project "Forked Shop" merge requests page
And I click link "New Merge Request"
- Then the target repository should be the original repository \ No newline at end of file
+ Then the target repository should be the original repository
diff --git a/features/project/source/browse_files.feature b/features/project/source/browse_files.feature
index fd9a2f01a28..a204c3e10c7 100644
--- a/features/project/source/browse_files.feature
+++ b/features/project/source/browse_files.feature
@@ -29,3 +29,13 @@ Feature: Project Browse files
Given I click on "Gemfile.lock" file in repo
And I click button "edit"
Then I can edit code
+
+ @javascript
+ Scenario: I can see editing preview
+ Given I click on "Gemfile.lock" file in repo
+ And I click button "edit"
+ And I edit code
+ And I click link "Diff"
+ Then I see diff
+
+
diff --git a/features/project/wiki.feature b/features/project/wiki.feature
index 90eb2b79c66..4a8c771ddac 100644
--- a/features/project/wiki.feature
+++ b/features/project/wiki.feature
@@ -45,3 +45,20 @@ Feature: Project Wiki
And I browse to that Wiki page
And I click on the "Pages" button
Then I should see the existing page in the pages list
+
+ Scenario: File exists in wiki repo
+ Given I have an existing Wiki page with images linked on page
+ And I browse to wiki page with images
+ And I click on existing image link
+ Then I should see the image from wiki repo
+
+ Scenario: Image in wiki repo shown on the page
+ Given I have an existing Wiki page with images linked on page
+ And I browse to wiki page with images
+ Then Image should be shown on the page
+
+ Scenario: File does not exist in wiki repo
+ Given I have an existing Wiki page with images linked on page
+ And I browse to wiki page with images
+ And I click on image link
+ Then I should see the new wiki page form
diff --git a/features/steps/dashboard/dashboard.rb b/features/steps/dashboard/dashboard.rb
index 394acd3fe8f..706c9babcee 100644
--- a/features/steps/dashboard/dashboard.rb
+++ b/features/steps/dashboard/dashboard.rb
@@ -25,7 +25,6 @@ class Dashboard < Spinach::FeatureSteps
find("#merge_request_target_project_id").value.should == @project.id.to_s
find("#merge_request_source_branch").value.should == "new_design"
find("#merge_request_target_branch").value.should == "master"
- find("#merge_request_title").value.should == "New design"
end
Given 'user with name "John Doe" joined project "Shop"' do
diff --git a/features/steps/project/browse_files.rb b/features/steps/project/browse_files.rb
index 069086d5eac..7cdd1101ac5 100644
--- a/features/steps/project/browse_files.rb
+++ b/features/steps/project/browse_files.rb
@@ -41,6 +41,18 @@ class ProjectBrowseFiles < Spinach::FeatureSteps
page.evaluate_script('editor.getValue()').should == "GitlabFileEditor"
end
+ step 'I edit code' do
+ page.execute_script('editor.setValue("GitlabFileEditor")')
+ end
+
+ step 'I click link "Diff"' do
+ click_link 'Diff'
+ end
+
+ step 'I see diff' do
+ page.should have_css '.line_holder.new'
+ end
+
step 'I click on "new file" link in repo' do
click_link 'new-file-link'
end
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index df69cb75437..3c497638d9c 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -53,6 +53,7 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps
find(:select, "merge_request_source_branch", {}).value.should == 'master'
find(:select, "merge_request_target_branch", {}).value.should == 'stable'
+ click_button "Compare branches"
fill_in "merge_request_title", with: "Merge Request On Forked Project"
end
@@ -148,29 +149,19 @@ class ProjectForkedMergeRequests < Spinach::FeatureSteps
current_path.should == edit_project_merge_request_path(@project, @merge_request)
page.should have_content "Edit merge request ##{@merge_request.id}"
find("#merge_request_title").value.should == "Merge Request On Forked Project"
- find("#merge_request_source_project_id").value.should == @forked_project.id.to_s
- find("#merge_request_target_project_id").value.should == @project.id.to_s
- find("#merge_request_source_branch").value.should have_content "master"
- verify_commit_link(".mr_source_commit",@forked_project)
- find("#merge_request_target_branch").value.should have_content "stable"
- verify_commit_link(".mr_target_commit",@project)
end
step 'I fill out an invalid "Merge Request On Forked Project" merge request' do
- #If this isn't filled in the rest of the validations won't be triggered
- fill_in "merge_request_title", with: "Merge Request On Forked Project"
-
select "Select branch", from: "merge_request_target_branch"
-
find(:select, "merge_request_source_project_id", {}).value.should == @forked_project.id.to_s
find(:select, "merge_request_target_project_id", {}).value.should == project.id.to_s
find(:select, "merge_request_source_branch", {}).value.should == ""
find(:select, "merge_request_target_branch", {}).value.should == ""
+ click_button "Compare branches"
end
step 'I should see validation errors' do
- page.should have_content "Source branch can't be blank"
- page.should have_content "Target branch can't be blank"
+ page.should have_content "You must select source and target branch"
end
step 'the target repository should be the original repository' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index f42eb6377ce..e0aec699a56 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -61,9 +61,10 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I submit new merge request "Wiki Feature"' do
- fill_in "merge_request_title", with: "Wiki Feature"
select "master", from: "merge_request_source_branch"
select "notes_refactoring", from: "merge_request_target_branch"
+ click_button "Compare branches"
+ fill_in "merge_request_title", with: "Wiki Feature"
click_button "Submit merge request"
end
diff --git a/features/steps/project/wiki.rb b/features/steps/project/wiki.rb
index a819ee37d7f..96f2505d24c 100644
--- a/features/steps/project/wiki.rb
+++ b/features/steps/project/wiki.rb
@@ -86,6 +86,47 @@ class Spinach::Features::ProjectWiki < Spinach::FeatureSteps
page.should have_content @page.title
end
+ Given 'I have an existing Wiki page with images linked on page' do
+ wiki.create_page("pictures", "Look at this [image](image.jpg)\n\n ![image](image.jpg)", :markdown, "first commit")
+ @wiki_page = wiki.find_page("pictures")
+ end
+
+ And 'I browse to wiki page with images' do
+ visit project_wiki_path(project, @wiki_page)
+ end
+
+ And 'I click on existing image link' do
+ file = Gollum::File.new(wiki.wiki)
+ Gollum::Wiki.any_instance.stub(:file).with("image.jpg", "master", true).and_return(file)
+ Gollum::File.any_instance.stub(:mime_type).and_return("image/jpeg")
+ page.should have_link('image', href: "image.jpg")
+ click_on "image"
+ end
+
+ Then 'I should see the image from wiki repo' do
+ url = URI.parse(current_url)
+ url.path.should match("wikis/image.jpg")
+ page.should_not have_xpath('/html') # Page should render the image which means there is no html involved
+ Gollum::Wiki.any_instance.unstub(:file)
+ Gollum::File.any_instance.unstub(:mime_type)
+ end
+
+ Then 'Image should be shown on the page' do
+ page.should have_xpath("//img[@src=\"image.jpg\"]")
+ end
+
+ And 'I click on image link' do
+ page.should have_link('image', href: "image.jpg")
+ click_on "image"
+ end
+
+ Then 'I should see the new wiki page form' do
+ url = URI.parse(current_url)
+ url.path.should match("wikis/image.jpg")
+ page.should have_content('New Wiki Page')
+ page.should have_content('Editing - image.jpg')
+ end
+
def wiki
@project_wiki = ProjectWiki.new(project, current_user)
end
diff --git a/lib/api/branches.rb b/lib/api/branches.rb
index 953c6100f8b..d54f9371fbe 100644
--- a/lib/api/branches.rb
+++ b/lib/api/branches.rb
@@ -24,7 +24,7 @@ module API
# branch (required) - The name of the branch
# Example Request:
# GET /projects/:id/repository/branches/:branch
- get ":id/repository/branches/:branch" do
+ get ':id/repository/branches/:branch', requirements: { branch: /.*/ } do
@branch = user_project.repo.heads.find { |item| item.name == params[:branch] }
not_found!("Branch does not exist") if @branch.nil?
present @branch, with: Entities::RepoObject, project: user_project
@@ -37,7 +37,9 @@ module API
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/protect
- put ":id/repository/branches/:branch/protect" do
+ put ':id/repository/branches/:branch/protect',
+ requirements: { branch: /.*/ } do
+
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
@@ -55,7 +57,9 @@ module API
# branch (required) - The name of the branch
# Example Request:
# PUT /projects/:id/repository/branches/:branch/unprotect
- put ":id/repository/branches/:branch/unprotect" do
+ put ':id/repository/branches/:branch/unprotect',
+ requirements: { branch: /.*/ } do
+
authorize_admin_project
@branch = user_project.repository.find_branch(params[:branch])
diff --git a/lib/api/users.rb b/lib/api/users.rb
index ae808b6272b..6ed2740c333 100644
--- a/lib/api/users.rb
+++ b/lib/api/users.rb
@@ -113,6 +113,45 @@ module API
end
end
+ # Get ssh keys of a specified user. Only available to admin users.
+ #
+ # Parameters:
+ # uid (required) - The ID of a user
+ # Example Request:
+ # GET /users/:uid/keys
+ get ':uid/keys' do
+ authenticated_as_admin!
+ user = User.find_by(id: params[:uid])
+ if user
+ present user.keys, with: Entities::SSHKey
+ else
+ not_found!
+ end
+ end
+
+ # Delete existing ssh key of a specified user. Only available to admin
+ # users.
+ #
+ # Parameters:
+ # uid (required) - The ID of a user
+ # id (required) - SSH Key ID
+ # Example Request:
+ # DELETE /users/:uid/keys/:id
+ delete ':uid/keys/:id' do
+ authenticated_as_admin!
+ user = User.find_by(id: params[:uid])
+ if user
+ begin
+ key = user.keys.find params[:id]
+ key.destroy
+ rescue ActiveRecord::RecordNotFound
+ not_found!
+ end
+ else
+ not_found!
+ end
+ end
+
# Delete user. Available only for admin
#
# Example Request:
diff --git a/lib/backup/manager.rb b/lib/backup/manager.rb
index 05814fc78f6..28e323fe30d 100644
--- a/lib/backup/manager.rb
+++ b/lib/backup/manager.rb
@@ -101,7 +101,7 @@ module Backup
def tar_version
tar_version, _ = Gitlab::Popen.popen(%W(tar --version))
- tar_version.split("\n").first
+ tar_version.force_encoding('locale').split("\n").first
end
end
end
diff --git a/lib/backup/repository.rb b/lib/backup/repository.rb
index 214d9824ee1..6f7c4f7c909 100644
--- a/lib/backup/repository.rb
+++ b/lib/backup/repository.rb
@@ -10,15 +10,12 @@ module Backup
Project.find_each(batch_size: 1000) do |project|
print " * #{project.path_with_namespace} ... "
- if project.empty_repo?
- puts "[SKIPPED]".cyan
- next
- end
-
# Create namespace dir if missing
FileUtils.mkdir_p(File.join(backup_repos_path, project.namespace.path)) if project.namespace
- if system(*%W(git --git-dir=#{path_to_repo(project)} bundle create #{path_to_bundle(project)} --all), silent)
+ if project.empty_repo?
+ puts "[SKIPPED]".cyan
+ elsif system(*%W(git --git-dir=#{path_to_repo(project)} bundle create #{path_to_bundle(project)} --all), silent)
puts "[DONE]".green
else
puts "[FAILED]".red
diff --git a/lib/gitlab/diff_parser.rb b/lib/gitlab/diff_parser.rb
index fb27280c4a4..14bbb328637 100644
--- a/lib/gitlab/diff_parser.rb
+++ b/lib/gitlab/diff_parser.rb
@@ -4,9 +4,9 @@ module Gitlab
attr_reader :lines, :new_path
- def initialize(diff)
- @lines = diff.diff.lines.to_a
- @new_path = diff.new_path
+ def initialize(lines, new_path = '')
+ @lines = lines
+ @new_path = new_path
end
def each
@@ -18,10 +18,7 @@ module Gitlab
lines_arr.each do |line|
raw_line = line.dup
- next if line.match(/^\-\-\- \/dev\/null/)
- next if line.match(/^\+\+\+ \/dev\/null/)
- next if line.match(/^\-\-\- a/)
- next if line.match(/^\+\+\+ b/)
+ next if filename?(line)
full_line = html_escape(line.gsub(/\n/, ''))
full_line = ::Gitlab::InlineDiff.replace_markers full_line
@@ -53,8 +50,17 @@ module Gitlab
end
end
+ def empty?
+ @lines.empty?
+ end
+
private
+ def filename?(line)
+ line.start_with?('--- /dev/null', '+++ /dev/null', '--- a', '+++ b',
+ '--- /tmp/diffy', '+++ /tmp/diffy')
+ end
+
def identification_type(line)
if line[0] == "+"
"new"
diff --git a/lib/gitlab/ldap/adapter.rb b/lib/gitlab/ldap/adapter.rb
index 983a2956a35..0777558d643 100644
--- a/lib/gitlab/ldap/adapter.rb
+++ b/lib/gitlab/ldap/adapter.rb
@@ -44,7 +44,8 @@ module Gitlab
def users(field, value)
if field.to_sym == :dn
options = {
- base: value
+ base: value,
+ scope: Net::LDAP::SearchScope_BaseObject
}
else
options = {
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index 1bac93378ef..d154bd8600b 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -34,9 +34,11 @@ module Gitlab
# In this case we generate temporary email and force user to fill it later
if user.email.blank?
user.generate_tmp_oauth_email
- else
+ elsif provider != "ldap"
# Google oauth returns email but dont return nickname
# So we use part of email as username for new user
+ # For LDAP, username is already set to the user's
+ # uid/userid/sAMAccountName.
user.username = email.match(/^[^@]*/)[0]
end
@@ -65,7 +67,11 @@ module Gitlab
end
def name
- auth.info.name.to_s.force_encoding("utf-8")
+ if auth.info.name.nil?
+ "#{auth.info.first_name} #{auth.info.last_name}".force_encoding('utf-8')
+ else
+ auth.info.name.to_s.force_encoding('utf-8')
+ end
end
def username
diff --git a/lib/gitlab/satellite/compare_action.rb b/lib/gitlab/satellite/compare_action.rb
new file mode 100644
index 00000000000..c923bb9c0f0
--- /dev/null
+++ b/lib/gitlab/satellite/compare_action.rb
@@ -0,0 +1,53 @@
+module Gitlab
+ module Satellite
+ class CompareAction < Action
+ def initialize(user, target_project, target_branch, source_project, source_branch)
+ super user, target_project
+
+ @target_project, @target_branch = target_project, target_branch
+ @source_project, @source_branch = source_project, source_branch
+ end
+
+ # Only show what is new in the source branch compared to the target branch, not the other way around.
+ # The line 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"
+ def diffs
+ in_locked_and_timed_satellite do |target_repo|
+ prepare_satellite!(target_repo)
+ update_satellite_source_and_target!(target_repo)
+ common_commit = target_repo.git.native(:merge_base, default_options, ["origin/#{@target_branch}", "source/#{@source_branch}"]).strip
+ #this method doesn't take default options
+ diffs = target_repo.diff(common_commit, "source/#{@source_branch}")
+ diffs = diffs.map { |diff| Gitlab::Git::Diff.new(diff) }
+ diffs
+ end
+ rescue Grit::Git::CommandFailed => ex
+ handle_exception(ex)
+ end
+
+ # Retrieve an array of commits between the source and the target
+ def commits
+ in_locked_and_timed_satellite do |target_repo|
+ prepare_satellite!(target_repo)
+ update_satellite_source_and_target!(target_repo)
+ commits = target_repo.commits_between("origin/#{@target_branch}", "source/#{@source_branch}")
+ commits = commits.map { |commit| Gitlab::Git::Commit.new(commit, nil) }
+ commits
+ end
+ rescue Grit::Git::CommandFailed => ex
+ handle_exception(ex)
+ end
+
+ private
+
+ # Assumes a satellite exists that is a fresh clone of the projects repo, prepares satellite for diffs
+ def update_satellite_source_and_target!(target_repo)
+ target_repo.remote_add('source', @source_project.repository.path_to_repo)
+ target_repo.remote_fetch('source')
+ target_repo.git.checkout(default_options({b: true}), @target_branch, "origin/#{@target_branch}")
+ rescue Grit::Git::CommandFailed => ex
+ handle_exception(ex)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/satellite/satellite.rb b/lib/gitlab/satellite/satellite.rb
index c6e4d3351cf..05123ad9c41 100644
--- a/lib/gitlab/satellite/satellite.rb
+++ b/lib/gitlab/satellite/satellite.rb
@@ -84,6 +84,7 @@ module Gitlab
# Clear the working directory
def clear_working_dir!
repo.git.reset(hard: true)
+ repo.git.clean(f: true, d: true, x: true)
end
# Deletes all branches except the parking branch
diff --git a/lib/tasks/gitlab/check.rake b/lib/tasks/gitlab/check.rake
index e9258cc626b..bf015a1fe16 100644
--- a/lib/tasks/gitlab/check.rake
+++ b/lib/tasks/gitlab/check.rake
@@ -779,7 +779,7 @@ namespace :gitlab do
end
def check_gitlab_shell
- required_version = Gitlab::VersionInfo.new(1, 9, 1)
+ required_version = Gitlab::VersionInfo.new(1, 9, 3)
current_version = Gitlab::VersionInfo.parse(gitlab_shell_version)
print "GitLab Shell version >= #{required_version} ? ... "
diff --git a/lib/tasks/gitlab/setup.rake b/lib/tasks/gitlab/setup.rake
index 853994dd67d..8b4ccdfc3fe 100644
--- a/lib/tasks/gitlab/setup.rake
+++ b/lib/tasks/gitlab/setup.rake
@@ -15,14 +15,7 @@ namespace :gitlab do
end
Rake::Task["db:setup"].invoke
-
- config = YAML.load_file(File.join(Rails.root,'config','database.yml'))[Rails.env]
- success = case config["adapter"]
- when /^mysql/ then
- Rake::Task["add_limits_mysql"].invoke
- when "postgresql" then
- end
-
+ Rake::Task["add_limits_mysql"].invoke
Rake::Task["db:seed_fu"].invoke
rescue Gitlab::TaskAbortedByUserError
puts "Quitting...".red
diff --git a/lib/tasks/gitlab/shell.rake b/lib/tasks/gitlab/shell.rake
index 08de0f2dd5d..dfc90bb3339 100644
--- a/lib/tasks/gitlab/shell.rake
+++ b/lib/tasks/gitlab/shell.rake
@@ -1,5 +1,64 @@
namespace :gitlab do
namespace :shell do
+ desc "GITLAB | Install or upgrade gitlab-shell"
+ task :install, [:tag, :repo] => :environment do |t, args|
+ warn_user_is_not_gitlab
+
+ args.with_defaults(tag: "v1.9.3", repo: "https://gitlab.com/gitlab-org/gitlab-shell.git")
+
+ user = Settings.gitlab.user
+ home_dir = Settings.gitlab.user_home
+ gitlab_url = Settings.gitlab.url
+ # gitlab-shell requires a / at the end of the url
+ gitlab_url += "/" unless gitlab_url.match(/\/$/)
+ repos_path = Gitlab.config.gitlab_shell.repos_path
+ target_dir = Gitlab.config.gitlab_shell.path
+
+ # Clone if needed
+ unless File.directory?(target_dir)
+ sh "git clone '#{args.repo}' '#{target_dir}'"
+ end
+
+ # Make sure we're on the right tag
+ Dir.chdir(target_dir) do
+ sh "git fetch origin && git reset --hard $(git describe #{args.tag} || git describe origin/#{args.tag})"
+
+ redis_url = URI.parse(ENV['REDIS_URL'] || "redis://localhost:6379")
+
+ config = {
+ user: user,
+ gitlab_url: gitlab_url,
+ http_settings: {self_signed_cert: false}.stringify_keys,
+ repos_path: repos_path,
+ auth_file: File.join(home_dir, ".ssh", "authorized_keys"),
+ redis: {
+ bin: %x{which redis-cli}.chomp,
+ host: redis_url.host,
+ port: redis_url.port,
+ namespace: "resque:gitlab"
+ }.stringify_keys,
+ log_level: "INFO",
+ audit_usernames: false
+ }.stringify_keys
+
+ # Generate config.yml based on existing gitlab settings
+ File.open("config.yml", "w+") {|f| f.puts config.to_yaml}
+
+ # Launch installation process
+ sh "bin/install"
+ end
+
+ # Required for debian packaging with PKGR: Setup .ssh/environment with
+ # the current PATH, so that the correct ruby version gets loaded
+ # Requires to set "PermitUserEnvironment yes" in sshd config (should not
+ # be an issue since it is more than likely that there are no "normal"
+ # user accounts on a gitlab server). The alternative is for the admin to
+ # install a ruby (1.9.3+) in the global path.
+ File.open(File.join(home_dir, ".ssh", "environment"), "w+") do |f|
+ f.puts "PATH=#{ENV['PATH']}"
+ end
+ end
+
desc "GITLAB | Setup gitlab-shell"
task setup: :environment do
setup
diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake
index 2c9b9978933..9516210e205 100644
--- a/lib/tasks/gitlab/test.rake
+++ b/lib/tasks/gitlab/test.rake
@@ -8,9 +8,9 @@ namespace :gitlab do
]
cmds.each do |cmd|
- system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
+ result = system({'RAILS_ENV' => 'test', 'force' => 'yes'}, *cmd)
- raise "#{cmd} failed!" unless $?.exitstatus.zero?
+ raise "#{cmd} failed!" unless result
end
end
end
diff --git a/lib/tasks/migrate/add_limits_mysql.rake b/lib/tasks/migrate/add_limits_mysql.rake
index 46b6451752b..a1972a682d8 100644
--- a/lib/tasks/migrate/add_limits_mysql.rake
+++ b/lib/tasks/migrate/add_limits_mysql.rake
@@ -1,14 +1,7 @@
+require Rails.root.join('db/migrate/limits_to_mysql')
+
desc "GITLAB | Add limits to strings in mysql database"
task add_limits_mysql: :environment do
puts "Adding limits to schema.rb for mysql"
LimitsToMysql.new.up
end
-
-class LimitsToMysql < ActiveRecord::Migration
- def up
- change_column :merge_request_diffs, :st_commits, :text, limit: 2147483647
- change_column :merge_request_diffs, :st_diffs, :text, limit: 2147483647
- change_column :snippets, :content, :text, limit: 2147483647
- change_column :notes, :st_diff, :text, limit: 2147483647
- end
-end
diff --git a/lib/tasks/setup.rake b/lib/tasks/setup.rake
new file mode 100644
index 00000000000..93701de8f63
--- /dev/null
+++ b/lib/tasks/setup.rake
@@ -0,0 +1,4 @@
+desc "GITLAB | Setup gitlab db"
+task :setup do
+ Rake::Task["gitlab:setup"].invoke
+end
diff --git a/public/apple-touch-icon-precomposed.png b/public/apple-touch-icon-precomposed.png
new file mode 100644
index 00000000000..6f2e0dd090f
--- /dev/null
+++ b/public/apple-touch-icon-precomposed.png
Binary files differ
diff --git a/public/static.css b/public/static.css
index aa834553a1c..c6f92ac01d9 100644
--- a/public/static.css
+++ b/public/static.css
@@ -2,7 +2,6 @@ body {
color: #666;
text-align: center;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- sans-serif;
margin:0;
width: 800px;
margin: auto;
diff --git a/spec/finders/notes_finder_spec.rb b/spec/finders/notes_finder_spec.rb
new file mode 100644
index 00000000000..4f8a5f909df
--- /dev/null
+++ b/spec/finders/notes_finder_spec.rb
@@ -0,0 +1,38 @@
+require 'spec_helper'
+
+describe NotesFinder do
+ let(:user) { create :user }
+ let(:project) { create :project }
+ let(:note1) { create :note_on_commit, project: project }
+ let(:note2) { create :note_on_commit, project: project }
+ let(:commit) { note1.noteable }
+
+ before do
+ project.team << [user, :master]
+ end
+
+ describe :execute do
+ let(:params) { { target_id: commit.id, target_type: 'commit', last_fetched_at: 1.hour.ago.to_i } }
+
+ before do
+ note1
+ note2
+ end
+
+ it 'should find all notes' do
+ notes = NotesFinder.new.execute(project, user, params)
+ notes.size.should eq(2)
+ end
+
+ it 'should raise an exception for an invalid target_type' do
+ params.merge!(target_type: 'invalid')
+ expect { NotesFinder.new.execute(project, user, params) }.to raise_error('invalid target_type')
+ end
+
+ it 'filters out old notes' do
+ note2.update_attribute(:updated_at, 2.hours.ago)
+ notes = NotesFinder.new.execute(project, user, params)
+ notes.should eq([note1])
+ end
+ end
+end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 61c561335e5..0376e0aadf0 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -46,7 +46,7 @@ describe ApplicationHelper do
group = create(:group)
group.avatar = File.open(avatar_file_path)
group.save!
- group_icon(group.path).to_s.should == "/uploads/group/avatar/#{ group.id }/gitlab_logo.png"
+ group_icon(group.path).to_s.should match("/uploads/group/avatar/#{ group.id }/gitlab_logo.png")
end
it "should give default avatar_icon when no avatar is present" do
@@ -63,7 +63,7 @@ describe ApplicationHelper do
user = create(:user)
user.avatar = File.open(avatar_file_path)
user.save!
- avatar_icon(user.email).to_s.should == "/uploads/user/avatar/#{ user.id }/gitlab_logo.png"
+ avatar_icon(user.email).to_s.should match("/uploads/user/avatar/#{ user.id }/gitlab_logo.png")
end
it "should call gravatar_icon when no avatar is present" do
diff --git a/spec/mailers/notify_spec.rb b/spec/mailers/notify_spec.rb
index e86a60a42b5..3b075044955 100644
--- a/spec/mailers/notify_spec.rb
+++ b/spec/mailers/notify_spec.rb
@@ -239,7 +239,7 @@ describe Notify do
it_behaves_like 'an assignee email'
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/
+ should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains a link to the new merge request' do
@@ -275,7 +275,7 @@ describe Notify do
end
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/
+ should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains the name of the previous assignee' do
@@ -303,7 +303,7 @@ describe Notify do
end
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/
+ should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains the new status' do
@@ -426,7 +426,7 @@ describe Notify do
it_behaves_like 'a note email'
it 'has the correct subject' do
- should have_subject /#{merge_request.title} \(!#{merge_request.iid}\)/
+ should have_subject /#{merge_request.title} \(##{merge_request.iid}\)/
end
it 'contains a link to the merge request note' do
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index 86610c47513..a6d300b099b 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -242,6 +242,67 @@ describe API::API, api: true do
end
end
+ describe 'GET /user/:uid/keys' do
+ before { admin }
+
+ context 'when unauthenticated' do
+ it 'should return authentication error' do
+ get api("/users/#{user.id}/keys")
+ response.status.should == 401
+ end
+ end
+
+ context 'when authenticated' do
+ it 'should return 404 for non-existing user' do
+ get api('/users/999999/keys', admin)
+ response.status.should == 404
+ end
+
+ it 'should return array of ssh keys' do
+ user.keys << key
+ user.save
+ get api("/users/#{user.id}/keys", admin)
+ response.status.should == 200
+ json_response.should be_an Array
+ json_response.first['title'].should == key.title
+ end
+ end
+ end
+
+ describe 'DELETE /user/:uid/keys/:id' do
+ before { admin }
+
+ context 'when unauthenticated' do
+ it 'should return authentication error' do
+ delete api("/users/#{user.id}/keys/42")
+ response.status.should == 401
+ end
+ end
+
+ context 'when authenticated' do
+ it 'should delete existing key' do
+ user.keys << key
+ user.save
+ expect {
+ delete api("/users/#{user.id}/keys/#{key.id}", admin)
+ }.to change { user.keys.count }.by(-1)
+ response.status.should == 200
+ end
+
+ it 'should return 404 error if user not found' do
+ user.keys << key
+ user.save
+ delete api("/users/999999/keys/#{key.id}", admin)
+ response.status.should == 404
+ end
+
+ it 'should return 404 error if key not foud' do
+ delete api("/users/#{user.id}/keys/42", admin)
+ response.status.should == 404
+ end
+ end
+ end
+
describe "DELETE /users/:id" do
before { admin }
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index f1df7e55dd0..3c2eec6cfd9 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -8,10 +8,10 @@ describe SystemHooksService do
context 'event data' do
it { event_data(user, :create).should include(:event_name, :name, :created_at, :email, :user_id) }
it { event_data(user, :destroy).should include(:event_name, :name, :created_at, :email, :user_id) }
- it { event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email) }
- it { event_data(project, :destroy).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email) }
- it { event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access) }
- it { event_data(users_project, :destroy).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access) }
+ it { event_data(project, :create).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
+ it { event_data(project, :destroy).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
+ it { event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access, :project_visibility) }
+ it { event_data(users_project, :destroy).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access, :project_visibility) }
end
context 'event names' do