summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab-ci.yml4
-rw-r--r--.rspec1
-rw-r--r--CHANGELOG23
-rw-r--r--Gemfile7
-rw-r--r--Gemfile.lock19
-rw-r--r--README.md2
-rw-r--r--app/assets/javascripts/behaviors/requires_input.js.coffee39
-rw-r--r--app/assets/javascripts/blob/edit_blob.js.coffee1
-rw-r--r--app/assets/javascripts/blob/new_blob.js.coffee1
-rw-r--r--app/assets/javascripts/dispatcher.js.coffee19
-rw-r--r--app/assets/javascripts/issuable_context.js.coffee22
-rw-r--r--app/assets/javascripts/issuable_form.js.coffee4
-rw-r--r--app/assets/javascripts/issue.js.coffee19
-rw-r--r--app/assets/javascripts/labels.js.coffee5
-rw-r--r--app/assets/javascripts/merge_request.js.coffee21
-rw-r--r--app/assets/javascripts/merge_request_tabs.js.coffee16
-rw-r--r--app/assets/javascripts/merge_request_widget.js.coffee4
-rw-r--r--app/assets/javascripts/project_new.js.coffee6
-rw-r--r--app/assets/stylesheets/generic/common.scss9
-rw-r--r--app/assets/stylesheets/generic/header.scss5
-rw-r--r--app/assets/stylesheets/generic/sidebar.scss82
-rw-r--r--app/assets/stylesheets/generic/zen.scss27
-rw-r--r--app/assets/stylesheets/pages/issues.scss6
-rw-r--r--app/assets/stylesheets/themes/gitlab-theme.scss2
-rw-r--r--app/controllers/groups_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb9
-rw-r--r--app/controllers/projects/merge_requests_controller.rb10
-rw-r--r--app/controllers/projects/notes_controller.rb2
-rw-r--r--app/controllers/projects/snippets_controller.rb8
-rw-r--r--app/controllers/projects/wikis_controller.rb6
-rw-r--r--app/controllers/snippets_controller.rb6
-rw-r--r--app/helpers/gitlab_markdown_helper.rb23
-rw-r--r--app/helpers/gitlab_routing_helper.rb8
-rw-r--r--app/helpers/groups_helper.rb8
-rw-r--r--app/helpers/oauth_helper.rb2
-rw-r--r--app/helpers/submodule_helper.rb2
-rw-r--r--app/models/ability.rb84
-rw-r--r--app/models/commit.rb4
-rw-r--r--app/models/concerns/participable.rb8
-rw-r--r--app/models/merge_request.rb9
-rw-r--r--app/models/project_services/gitlab_ci_service.rb1
-rw-r--r--app/models/repository.rb19
-rw-r--r--app/models/user.rb16
-rw-r--r--app/services/issuable_base_service.rb8
-rw-r--r--app/services/issues/bulk_update_service.rb2
-rw-r--r--app/services/issues/create_service.rb1
-rw-r--r--app/services/issues/update_service.rb1
-rw-r--r--app/services/merge_requests/auto_merge_service.rb45
-rw-r--r--app/services/merge_requests/create_service.rb1
-rw-r--r--app/services/merge_requests/update_service.rb1
-rw-r--r--app/services/update_snippet_service.rb4
-rw-r--r--app/views/admin/application_settings/_form.html.haml108
-rw-r--r--app/views/admin/application_settings/show.html.haml2
-rw-r--r--app/views/admin/identities/_form.html.haml2
-rw-r--r--app/views/dashboard/issues.html.haml2
-rw-r--r--app/views/dashboard/merge_requests.html.haml2
-rw-r--r--app/views/events/_event.html.haml21
-rw-r--r--app/views/groups/edit.html.haml1
-rw-r--r--app/views/groups/group_members/_group_member.html.haml2
-rw-r--r--app/views/groups/issues.html.haml2
-rw-r--r--app/views/groups/merge_requests.html.haml2
-rw-r--r--app/views/layouts/group.html.haml2
-rw-r--r--app/views/layouts/group_settings.html.haml4
-rw-r--r--app/views/layouts/nav/_group.html.haml20
-rw-r--r--app/views/layouts/nav/_group_settings.html.haml20
-rw-r--r--app/views/layouts/nav/_project.html.haml4
-rw-r--r--app/views/layouts/nav/_project_settings.html.haml8
-rw-r--r--app/views/projects/_aside.html.haml6
-rw-r--r--app/views/projects/_zen.html.haml2
-rw-r--r--app/views/projects/blob/_remove.html.haml5
-rw-r--r--app/views/projects/blob/edit.html.haml8
-rw-r--r--app/views/projects/blob/new.html.haml2
-rw-r--r--app/views/projects/branches/new.html.haml3
-rw-r--r--app/views/projects/commits/_commit.html.haml57
-rw-r--r--app/views/projects/commits/show.html.haml3
-rw-r--r--app/views/projects/compare/_form.html.haml8
-rw-r--r--app/views/projects/diffs/_parallel_view.html.haml4
-rw-r--r--app/views/projects/diffs/_text_file.html.haml2
-rw-r--r--app/views/projects/issues/_discussion.html.haml8
-rw-r--r--app/views/projects/issues/_form.html.haml2
-rw-r--r--app/views/projects/issues/_issue.html.haml77
-rw-r--r--app/views/projects/issues/_issue_context.html.haml46
-rw-r--r--app/views/projects/issues/index.html.haml6
-rw-r--r--app/views/projects/issues/show.html.haml8
-rw-r--r--app/views/projects/issues/update.js.haml18
-rw-r--r--app/views/projects/labels/_form.html.haml2
-rw-r--r--app/views/projects/merge_requests/_discussion.html.haml4
-rw-r--r--app/views/projects/merge_requests/_form.html.haml5
-rw-r--r--app/views/projects/merge_requests/_new_compare.html.haml10
-rw-r--r--app/views/projects/merge_requests/_new_submit.html.haml4
-rw-r--r--app/views/projects/merge_requests/_show.html.haml2
-rw-r--r--app/views/projects/merge_requests/index.html.haml6
-rw-r--r--app/views/projects/merge_requests/show/_context.html.haml48
-rw-r--r--app/views/projects/merge_requests/show/_mr_box.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_mr_title.html.haml2
-rw-r--r--app/views/projects/merge_requests/show/_participants.html.haml4
-rw-r--r--app/views/projects/merge_requests/update.js.haml11
-rw-r--r--app/views/projects/merge_requests/widget/_heading.html.haml6
-rw-r--r--app/views/projects/merge_requests/widget/open/_accept.html.haml4
-rw-r--r--app/views/projects/milestones/_form.html.haml5
-rw-r--r--app/views/projects/milestones/show.html.haml2
-rw-r--r--app/views/projects/network/show.html.haml6
-rw-r--r--app/views/projects/new.html.haml4
-rw-r--r--app/views/projects/notes/_note.html.haml9
-rw-r--r--app/views/projects/notes/_notes_with_form.html.haml2
-rw-r--r--app/views/projects/snippets/index.html.haml2
-rw-r--r--app/views/projects/snippets/show.html.haml2
-rw-r--r--app/views/projects/wikis/_main_links.html.haml2
-rw-r--r--app/views/projects/wikis/_nav.html.haml2
-rw-r--r--app/views/shared/issuable/_context.html.haml50
-rw-r--r--app/views/shared/issuable/_filter.html.haml (renamed from app/views/shared/_issuable_filter.html.haml)7
-rw-r--r--app/views/shared/issuable/_form.html.haml (renamed from app/views/projects/_issuable_form.html.haml)75
-rw-r--r--app/views/shared/issuable/_search_form.html.haml (renamed from app/views/shared/_issuable_search_form.html.haml)0
-rw-r--r--app/views/snippets/show.html.haml2
-rw-r--r--app/views/users/show.html.haml2
-rw-r--r--config/initializers/6_rack_profiler.rb2
-rw-r--r--db/fixtures/development/01_admin.rb2
-rw-r--r--db/fixtures/production/001_admin.rb2
-rw-r--r--doc/README.md1
-rw-r--r--doc/api/users.md6
-rw-r--r--doc/gitlab-basics/README.md11
-rw-r--r--doc/gitlab-basics/basic-git-commands.md59
-rw-r--r--doc/gitlab-basics/basicsimages/add_new_merge_request.png (renamed from doc/gitlab_basics/basicsimages/add_new_merge_request.png)bin9467 -> 9467 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/add_sshkey.png (renamed from doc/gitlab_basics/basicsimages/add_sshkey.png)bin1463 -> 1463 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/branch_info.png (renamed from doc/gitlab_basics/basicsimages/branch_info.png)bin7978 -> 7978 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/branch_name.png (renamed from doc/gitlab_basics/basicsimages/branch_name.png)bin2199 -> 2199 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/branches.png (renamed from doc/gitlab_basics/basicsimages/branches.png)bin3653 -> 3653 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/commit_changes.png (renamed from doc/gitlab_basics/basicsimages/commit_changes.png)bin5567 -> 5567 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/commit_message.png (renamed from doc/gitlab_basics/basicsimages/commit_message.png)bin5707 -> 5707 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/commits.png (renamed from doc/gitlab_basics/basicsimages/commits.png)bin4258 -> 4258 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/compare_braches.png (renamed from doc/gitlab_basics/basicsimages/compare_braches.png)bin1624 -> 1624 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/create_file.png (renamed from doc/gitlab_basics/basicsimages/create_file.png)bin2524 -> 2524 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/create_group.png (renamed from doc/gitlab_basics/basicsimages/create_group.png)bin3224 -> 3224 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/edit_file.png (renamed from doc/gitlab_basics/basicsimages/edit_file.png)bin2259 -> 2259 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/file_located.png (renamed from doc/gitlab_basics/basicsimages/file_located.png)bin3156 -> 3156 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/file_name.png (renamed from doc/gitlab_basics/basicsimages/file_name.png)bin2544 -> 2544 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/find_file.png (renamed from doc/gitlab_basics/basicsimages/find_file.png)bin8840 -> 8840 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/find_group.png (renamed from doc/gitlab_basics/basicsimages/find_group.png)bin6159 -> 6159 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/fork.png (renamed from doc/gitlab_basics/basicsimages/fork.png)bin1046 -> 1046 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/group_info.png (renamed from doc/gitlab_basics/basicsimages/group_info.png)bin16217 -> 16217 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/groups.png (renamed from doc/gitlab_basics/basicsimages/groups.png)bin4857 -> 4857 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/https.png (renamed from doc/gitlab_basics/basicsimages/https.png)bin2887 -> 2887 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/image_file.png (renamed from doc/gitlab_basics/basicsimages/image_file.png)bin2939 -> 2939 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/issue_title.png (renamed from doc/gitlab_basics/basicsimages/issue_title.png)bin9059 -> 9059 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/issues.png (renamed from doc/gitlab_basics/basicsimages/issues.png)bin4332 -> 4332 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/key.png (renamed from doc/gitlab_basics/basicsimages/key.png)bin1264 -> 1264 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/merge_requests.png (renamed from doc/gitlab_basics/basicsimages/merge_requests.png)bin4381 -> 4381 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/new_issue.png (renamed from doc/gitlab_basics/basicsimages/new_issue.png)bin2974 -> 2974 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/new_merge_request.png (renamed from doc/gitlab_basics/basicsimages/new_merge_request.png)bin3227 -> 3227 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/new_project.png (renamed from doc/gitlab_basics/basicsimages/new_project.png)bin2319 -> 2319 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/newbranch.png (renamed from doc/gitlab_basics/basicsimages/newbranch.png)bin1314 -> 1314 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/paste_sshkey.png (renamed from doc/gitlab_basics/basicsimages/paste_sshkey.png)bin8620 -> 8620 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/profile_settings.png (renamed from doc/gitlab_basics/basicsimages/profile_settings.png)bin1194 -> 1194 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/project_info.png (renamed from doc/gitlab_basics/basicsimages/project_info.png)bin21862 -> 21862 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/public_file_link.png (renamed from doc/gitlab_basics/basicsimages/public_file_link.png)bin3038 -> 3038 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/select_branch.png (renamed from doc/gitlab_basics/basicsimages/select_branch.png)bin12213 -> 12213 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/select_project.png (renamed from doc/gitlab_basics/basicsimages/select_project.png)bin16832 -> 16832 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/settings.png (renamed from doc/gitlab_basics/basicsimages/settings.png)bin4321 -> 4321 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/shh_keys.png (renamed from doc/gitlab_basics/basicsimages/shh_keys.png)bin4981 -> 4981 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/submit_new_issue.png (renamed from doc/gitlab_basics/basicsimages/submit_new_issue.png)bin9083 -> 9083 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/title_description_mr.png (renamed from doc/gitlab_basics/basicsimages/title_description_mr.png)bin12749 -> 12749 bytes
-rw-r--r--doc/gitlab-basics/basicsimages/white_space.png (renamed from doc/gitlab_basics/basicsimages/white_space.png)bin3707 -> 3707 bytes
-rw-r--r--doc/gitlab-basics/command-line-commands.md72
-rw-r--r--doc/gitlab-basics/create-your-ssh-keys.md37
-rw-r--r--doc/gitlab-basics/start-using-git.md (renamed from doc/gitlab_basics/start_using_git.md)6
-rw-r--r--doc/gitlab_basics/README.md7
-rw-r--r--doc/install/installation.md2
-rw-r--r--doc/integration/README.md1
-rw-r--r--doc/permissions/permissions.md4
-rw-r--r--doc/raketasks/backup_restore.md27
-rw-r--r--doc/workflow/importing/import_projects_from_github.md4
-rw-r--r--doc_styleguide.md35
-rw-r--r--docker/README.md4
-rw-r--r--features/project/forked_merge_requests.feature1
-rw-r--r--features/project/issues/issues.feature12
-rw-r--r--features/project/merge_requests.feature16
-rw-r--r--features/steps/project/active_tab.rb4
-rw-r--r--features/steps/project/issues/issues.rb23
-rw-r--r--features/steps/project/merge_requests.rb22
-rw-r--r--lib/api/entities.rb1
-rw-r--r--lib/api/issues.rb4
-rw-r--r--lib/api/merge_requests.rb4
-rw-r--r--lib/api/project_snippets.rb6
-rw-r--r--lib/extracts_path.rb8
-rw-r--r--lib/gitlab/git_access_wiki.rb2
-rw-r--r--lib/gitlab/github_import/importer.rb4
-rw-r--r--lib/gitlab/markdown.rb4
-rw-r--r--lib/tasks/jasmine.rake12
-rwxr-xr-xscripts/prepare_build.sh2
-rw-r--r--spec/features/issues_spec.rb4
-rw-r--r--spec/features/notes_on_merge_requests_spec.rb5
-rw-r--r--spec/features/security/project/internal_access_spec.rb12
-rw-r--r--spec/features/security/project/private_access_spec.rb12
-rw-r--r--spec/features/security/project/public_access_spec.rb12
-rw-r--r--spec/features/task_lists_spec.rb6
-rw-r--r--spec/helpers/application_helper_spec.rb225
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb7
-rw-r--r--spec/helpers/submodule_helper_spec.rb2
-rw-r--r--spec/javascripts/behaviors/requires_input_spec.js.coffee49
-rw-r--r--spec/javascripts/fixtures/behaviors/requires_input.html.haml18
-rw-r--r--spec/javascripts/fixtures/issues_show.html.haml2
-rw-r--r--spec/javascripts/fixtures/merge_requests_show.html.haml2
-rw-r--r--spec/javascripts/merge_request_spec.js.coffee2
-rw-r--r--spec/lib/extracts_path_spec.rb11
-rw-r--r--spec/models/members/project_member_spec.rb2
-rw-r--r--spec/models/note_spec.rb6
-rw-r--r--spec/models/repository_spec.rb22
-rw-r--r--spec/models/user_spec.rb14
-rw-r--r--spec/requests/api/users_spec.rb1
-rw-r--r--spec/spec_helper.rb8
-rw-r--r--spec/support/factory_girl.rb3
-rw-r--r--spec/support/stub_configuration.rb14
212 files changed, 1339 insertions, 890 deletions
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5524c9a7fcb..ddf4e31204a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -45,9 +45,9 @@ spinach:other:
- ruby
- mysql
-jasmine:ci:
+teaspoon:
script:
- - RAILS_ENV=test SIMPLECOV=true bundle exec rake jasmine:ci
+ - RAILS_ENV=test bundle exec teaspoon
tags:
- ruby
- mysql
diff --git a/.rspec b/.rspec
index 4e1e0d2f722..35f4d7441e0 100644
--- a/.rspec
+++ b/.rspec
@@ -1 +1,2 @@
--color
+--format Fuubar
diff --git a/CHANGELOG b/CHANGELOG
index f353a444fba..252b084dd20 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,9 +1,16 @@
Please view this file on the master branch, on stable branches it's out of date.
v 7.13.0 (unreleased)
+ - Fix order of issues imported form GitHub (Hiroyuki Sato)
+ - Bump rugments to 1.0.0beta8 to fix C prototype function highlighting (Jonathon Reinhart)
+ - Fix Merge Request webhook to properly fire "merge" action when accepted from the web UI
+ - Add `two_factor_enabled` field to admin user API (Stan Hu)
- Fix invalid timestamps in RSS feeds (Rowan Wookey)
- Fix error when deleting a user who has projects (Stan Hu)
- Fix downloading of patches on public merge requests when user logged out (Stan Hu)
+ - The password for the default administrator (root) account has been changed from "5iveL!fe" to "password".
+ - Fix Error 500 when relative submodule resolves to a namespace that has a different name from its path (Stan Hu)
+ - Extract the longest-matching ref from a commit path when multiple matches occur (Stan Hu)
- Update maintenance documentation to explain no need to recompile asssets for omnibus installations (Stan Hu)
- Support commenting on diffs in side-by-side mode (Stan Hu)
- Fix JavaScript error when clicking on the comment button on a diff line that has a comment already (Stan Hu)
@@ -16,8 +23,22 @@ v 7.13.0 (unreleased)
- API request /projects/:project_id/merge_requests?state=closed will return only closed merge requests without merged one. If you need ones that were merged - use state=merged.
- Allow Administrators to filter the user list by those with or without Two-factor Authentication enabled.
- Show a user's Two-factor Authentication status in the administration area.
+ - Explicit error when commit not found in the CI
+ - Improve performance for issue and merge request pages
+ - Users with guest access level can not set assignee, labels or milestones for issue and merge request
+ - Reporter role can manage issue tracker now: edit any issue, set assignee or milestone and manage labels
+ - Better performance for pages with events list, issues list and commits list
-v 7.12.0 (unreleased)
+v 7.12.1
+ - Fix error when deleting a user who has projects (Stan Hu)
+ - Fix post-receive errors on a push when an external issue tracker is configured (Stan Hu)
+ - Add SAML to list of social_provider (Matt Firtion)
+ - Fix merge requests API scope to keep compatibility in 7.12.x patch release (Dmitriy Zaporozhets)
+ - Fix closed merge request scope at milestone page (Dmitriy Zaporozhets)
+ - Revert merge request states renaming
+ - Fix hooks for web based events with external issue references (Daniel Gerhardt)
+
+v 7.12.0
- Fix Error 500 when one user attempts to access a personal, internal snippet (Stan Hu)
- Disable changing of target branch in new merge request page when a branch has already been specified (Stan Hu)
- Fix post-receive errors on a push when an external issue tracker is configured (Stan Hu)
diff --git a/Gemfile b/Gemfile
index bda2fac1eec..ec63c7eef84 100644
--- a/Gemfile
+++ b/Gemfile
@@ -9,7 +9,7 @@ gem "default_value_for", "~> 3.0.0"
gem "mysql2", group: :mysql
gem "pg", group: :postgres
-# Auth
+# Authentication libraries
gem "devise", '3.2.4'
gem "devise-async", '0.9.0'
gem 'omniauth', "~> 1.2.2"
@@ -94,7 +94,7 @@ gem "seed-fu"
gem 'html-pipeline', '~> 1.11.0'
gem 'task_list', '1.0.2', require: 'task_list/railtie'
gem 'github-markup'
-gem 'redcarpet', '~> 3.3.0'
+gem 'redcarpet', '~> 3.3.2'
gem 'RedCloth'
gem 'rdoc', '~>3.6'
gem 'org-ruby', '= 0.9.12'
@@ -224,6 +224,7 @@ end
group :development, :test do
gem 'awesome_print'
gem 'byebug'
+ gem 'fuubar', '~> 2.0.0'
gem 'pry-rails'
gem 'coveralls', require: false
@@ -267,4 +268,4 @@ end
gem "newrelic_rpm"
gem 'octokit', '3.7.0'
-gem "rugments", "~> 1.0.0.beta7"
+gem "rugments", "~> 1.0.0.beta8"
diff --git a/Gemfile.lock b/Gemfile.lock
index b719dd4ab06..718236ec39c 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -242,6 +242,9 @@ GEM
dotenv (>= 0.7)
thor (>= 0.13.6)
formatador (0.2.5)
+ fuubar (2.0.0)
+ rspec (~> 3.0)
+ ruby-progressbar (~> 1.4)
gemnasium-gitlab-service (0.2.6)
rugged (~> 0.21)
gemojione (2.0.0)
@@ -499,7 +502,7 @@ GEM
trollop
rdoc (3.12.2)
json (~> 1.4)
- redcarpet (3.3.1)
+ redcarpet (3.3.2)
redis (3.1.0)
redis-actionpack (4.0.0)
actionpack (~> 4)
@@ -530,6 +533,10 @@ GEM
rqrcode (0.4.2)
rqrcode-rails3 (0.1.7)
rqrcode (>= 0.4.2)
+ rspec (3.3.0)
+ rspec-core (~> 3.3.0)
+ rspec-expectations (~> 3.3.0)
+ rspec-mocks (~> 3.3.0)
rspec-core (3.3.1)
rspec-support (~> 3.3.0)
rspec-expectations (3.3.0)
@@ -565,7 +572,7 @@ GEM
rubyntlm (0.5.0)
rubypants (0.2.0)
rugged (0.22.2)
- rugments (1.0.0.beta7)
+ rugments (1.0.0.beta8)
safe_yaml (1.0.4)
sanitize (2.1.0)
nokogiri (>= 1.4.4)
@@ -763,6 +770,7 @@ DEPENDENCIES
fog (~> 1.25.0)
font-awesome-rails (~> 4.2)
foreman
+ fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2)
github-markup
gitlab-flowdock-git-hook (~> 0.4.2)
@@ -814,14 +822,14 @@ DEPENDENCIES
rails (= 4.1.11)
raphael-rails (~> 2.1.2)
rdoc (~> 3.6)
- redcarpet (~> 3.3.0)
+ redcarpet (~> 3.3.2)
redis-rails
request_store
rerun (~> 0.10.0)
rqrcode-rails3
rspec-rails (~> 3.3.0)
rubocop (= 0.28.0)
- rugments (~> 1.0.0.beta7)
+ rugments (~> 1.0.0.beta8)
sanitize (~> 2.0)
sass-rails (~> 4.0.2)
sdoc
@@ -859,3 +867,6 @@ DEPENDENCIES
virtus
webmock (~> 1.21.0)
wikicloth (= 0.8.1)
+
+BUNDLED WITH
+ 1.10.4
diff --git a/README.md b/README.md
index 52a483aa532..37badd448c1 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,7 @@ The recommended way to install GitLab is using the provided [Omnibus packages](h
There are various other options to install GitLab, please refer to the [installation page on the GitLab website](https://about.gitlab.com/installation/) for more information.
-You can access a new installation with the login **`root`** and password **`5iveL!fe`**, after login you are required to set a unique password.
+You can access a new installation with the login **`root`** and password **`password`**, after login you are required to set a unique password.
## Third-party applications
diff --git a/app/assets/javascripts/behaviors/requires_input.js.coffee b/app/assets/javascripts/behaviors/requires_input.js.coffee
new file mode 100644
index 00000000000..8318fe435b3
--- /dev/null
+++ b/app/assets/javascripts/behaviors/requires_input.js.coffee
@@ -0,0 +1,39 @@
+# Requires Input behavior
+#
+# When called on a form with input fields with the `required` attribute, the
+# form's submit button will be disabled until all required fields have values.
+#
+#= require extensions/jquery
+#
+# ### Example Markup
+#
+# <form class="js-requires-input">
+# <input type="text" required="required">
+# <input type="submit" value="Submit">
+# </form>
+#
+$.fn.requiresInput = ->
+ $form = $(this)
+ $button = $('button[type=submit], input[type=submit]', $form)
+
+ required = '[required=required]'
+ fieldSelector = "input#{required}, select#{required}, textarea#{required}"
+
+ requireInput = ->
+ # Collect the input values of *all* required fields
+ values = _.map $(fieldSelector, $form), (field) -> field.value
+
+ # Disable the button if any required fields are empty
+ if values.length && _.any(values, _.isEmpty)
+ $button.disable()
+ else
+ $button.enable()
+
+ # Set initial button state
+ requireInput()
+
+ $form.on 'change input', fieldSelector, requireInput
+
+# Triggered on standard document `ready` and on Turbolinks `page:load` events
+$(document).on 'ready page:load', ->
+ $('form.js-requires-input').requiresInput()
diff --git a/app/assets/javascripts/blob/edit_blob.js.coffee b/app/assets/javascripts/blob/edit_blob.js.coffee
index 2e91a06daa8..050888f9c15 100644
--- a/app/assets/javascripts/blob/edit_blob.js.coffee
+++ b/app/assets/javascripts/blob/edit_blob.js.coffee
@@ -11,7 +11,6 @@ class @EditBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- disableButtonIfEmptyField "#commit_message", ".js-commit-button"
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
diff --git a/app/assets/javascripts/blob/new_blob.js.coffee b/app/assets/javascripts/blob/new_blob.js.coffee
index ab8f98715e8..1f36a53f191 100644
--- a/app/assets/javascripts/blob/new_blob.js.coffee
+++ b/app/assets/javascripts/blob/new_blob.js.coffee
@@ -11,7 +11,6 @@ class @NewBlob
if ace_mode
editor.getSession().setMode "ace/mode/" + ace_mode
- disableButtonIfEmptyField "#commit_message", ".js-commit-button"
$(".js-commit-button").click ->
$("#file-content").val editor.getValue()
$(".file-editor form").submit()
diff --git a/app/assets/javascripts/dispatcher.js.coffee b/app/assets/javascripts/dispatcher.js.coffee
index 84873e389ea..a8ec0abc264 100644
--- a/app/assets/javascripts/dispatcher.js.coffee
+++ b/app/assets/javascripts/dispatcher.js.coffee
@@ -31,20 +31,14 @@ class Dispatcher
when 'projects:compare:show'
new Diff()
when 'projects:issues:new','projects:issues:edit'
- GitLab.GfmAutoComplete.setup()
shortcut_handler = new ShortcutsNavigation()
- new ZenMode()
new DropzoneInput($('.issue-form'))
- if page == 'projects:issues:new'
- new IssuableForm($('.issue-form'))
+ new IssuableForm($('.issue-form'))
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
- GitLab.GfmAutoComplete.setup()
new Diff()
shortcut_handler = new ShortcutsNavigation()
- new ZenMode()
new DropzoneInput($('.merge-request-form'))
- if page == 'projects:merge_requests:new'
- new IssuableForm($('.merge-request-form'))
+ new IssuableForm($('.merge-request-form'))
when 'projects:merge_requests:show'
new Diff()
shortcut_handler = new ShortcutsIssuable()
@@ -113,13 +107,6 @@ class Dispatcher
new NamespaceSelect()
when 'dashboard'
shortcut_handler = new ShortcutsDashboardNavigation()
- switch path[1]
- when 'issues', 'merge_requests'
- new UsersSelect()
- when 'groups'
- switch path[1]
- when 'issues', 'merge_requests'
- new UsersSelect()
when 'profiles'
new Profile()
when 'projects'
@@ -135,8 +122,6 @@ class Dispatcher
new ProjectNew()
when 'show'
new ProjectShow()
- when 'issues', 'merge_requests'
- new UsersSelect()
when 'wikis'
new Wikis()
shortcut_handler = new ShortcutsNavigation()
diff --git a/app/assets/javascripts/issuable_context.js.coffee b/app/assets/javascripts/issuable_context.js.coffee
new file mode 100644
index 00000000000..176d9cabefa
--- /dev/null
+++ b/app/assets/javascripts/issuable_context.js.coffee
@@ -0,0 +1,22 @@
+#= require jquery.waitforimages
+
+class @IssuableContext
+ constructor: ->
+ new UsersSelect()
+ $('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
+
+ $(".context .inline-update").on "change", "select", ->
+ $(this).submit()
+ $(".context .inline-update").on "change", ".js-assignee", ->
+ $(this).submit()
+
+ $('.issuable-details').waitForImages ->
+ $('.issuable-affix').affix offset:
+ top: ->
+ @top = ($('.issuable-affix').offset().top - 70)
+ bottom: ->
+ @bottom = $('.footer').outerHeight(true)
+ $('.issuable-affix').on 'affix.bs.affix', ->
+ $(@).width($(@).outerWidth())
+ .on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
+ $(@).width('')
diff --git a/app/assets/javascripts/issuable_form.js.coffee b/app/assets/javascripts/issuable_form.js.coffee
index abd58bcf978..48c249943f2 100644
--- a/app/assets/javascripts/issuable_form.js.coffee
+++ b/app/assets/javascripts/issuable_form.js.coffee
@@ -1,5 +1,9 @@
class @IssuableForm
constructor: (@form) ->
+ GitLab.GfmAutoComplete.setup()
+ new UsersSelect()
+ new ZenMode()
+
@titleField = @form.find("input[name*='[title]']")
@descriptionField = @form.find("textarea[name*='[description]']")
diff --git a/app/assets/javascripts/issue.js.coffee b/app/assets/javascripts/issue.js.coffee
index 74d6b80be5e..603a16da1ce 100644
--- a/app/assets/javascripts/issue.js.coffee
+++ b/app/assets/javascripts/issue.js.coffee
@@ -3,29 +3,12 @@
class @Issue
constructor: ->
- $('.edit-issue.inline-update input[type="submit"]').hide()
- $(".context .inline-update").on "change", "select", ->
- $(this).submit()
- $(".context .inline-update").on "change", "#issue_assignee_id", ->
- $(this).submit()
-
# Prevent duplicate event bindings
@disableTaskList()
if $("a.btn-close").length
@initTaskList()
- $('.issue-details').waitForImages ->
- $('.issuable-affix').affix offset:
- top: ->
- @top = ($('.issuable-affix').offset().top - 70)
- bottom: ->
- @bottom = $('.footer').outerHeight(true)
- $('.issuable-affix').on 'affix.bs.affix', ->
- $(@).width($(@).outerWidth())
- .on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
- $(@).width('')
-
initTaskList: ->
$('.issue-details .js-task-list-container').taskList('enable')
$(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList
@@ -42,5 +25,5 @@ class @Issue
$.ajax
type: 'PATCH'
- url: $('form.js-issue-update').attr('action')
+ url: $('form.js-issuable-update').attr('action')
data: patchData
diff --git a/app/assets/javascripts/labels.js.coffee b/app/assets/javascripts/labels.js.coffee
index 1bc8840f9ac..d05bacd7494 100644
--- a/app/assets/javascripts/labels.js.coffee
+++ b/app/assets/javascripts/labels.js.coffee
@@ -1,7 +1,6 @@
class @Labels
constructor: ->
form = $('.label-form')
- @setupLabelForm(form)
@cleanBinding()
@addBinding()
@updateColorPreview()
@@ -14,10 +13,6 @@ class @Labels
$(document).off 'click', '.suggest-colors a'
$(document).off 'input', 'input#label_color'
- # Initializes the form to disable the save button if no color or title is entered
- setupLabelForm: (form) ->
- disableButtonIfAnyEmptyField form, '.form-control', form.find('.js-save-button')
-
# Updates the the preview color with the hex-color input
updateColorPreview: =>
previewColor = $('input#label_color').val()
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index 5c0bc686111..7462975bd3d 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -10,7 +10,6 @@ class @MergeRequest
# action - String, current controller action
#
constructor: (@opts) ->
- @initContextWidget()
this.$el = $('.merge-request')
this.$('.show-all-commits').on 'click', =>
@@ -26,28 +25,10 @@ class @MergeRequest
if $("a.btn-close").length
@initTaskList()
- $('.merge-request-details').waitForImages ->
- $('.issuable-affix').affix offset:
- top: ->
- @top = ($('.issuable-affix').offset().top - 70)
- bottom: ->
- @bottom = $('.footer').outerHeight(true)
- $('.issuable-affix').on 'affix.bs.affix', ->
- $(@).width($(@).outerWidth())
- .on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
- $(@).width('')
-
# Local jQuery finder
$: (selector) ->
this.$el.find(selector)
- initContextWidget: ->
- $('.edit-merge_request.inline-update input[type="submit"]').hide()
- $(".context .inline-update").on "change", "select", ->
- $(this).submit()
- $(".context .inline-update").on "change", "#merge_request_assignee_id", ->
- $(this).submit()
-
showAllCommits: ->
this.$('.first-commits').remove()
this.$('.all-commits').removeClass 'hide'
@@ -68,5 +49,5 @@ class @MergeRequest
$.ajax
type: 'PATCH'
- url: $('form.js-merge-request-update').attr('action')
+ url: $('form.js-issuable-update').attr('action')
data: patchData
diff --git a/app/assets/javascripts/merge_request_tabs.js.coffee b/app/assets/javascripts/merge_request_tabs.js.coffee
index de9a4c2cc2f..5dc441f64b5 100644
--- a/app/assets/javascripts/merge_request_tabs.js.coffee
+++ b/app/assets/javascripts/merge_request_tabs.js.coffee
@@ -49,13 +49,15 @@ class @MergeRequestTabs
# Store the `location` object, allowing for easier stubbing in tests
@_location = location
+ switch @opts.action
+ when 'commits'
+ @commitsLoaded = true
+ when 'diffs'
+ @diffsLoaded = true
+
@bindEvents()
@activateTab(@opts.action)
- switch @opts.action
- when 'commits' then @commitsLoaded = true
- when 'diffs' then @diffsLoaded = true
-
bindEvents: ->
$(document).on 'shown.bs.tab', '.merge-request-tabs a[data-toggle="tab"]', @tabShown
@@ -67,6 +69,7 @@ class @MergeRequestTabs
@loadCommits($target.attr('href'))
else if action == 'diffs'
@loadDiff($target.attr('href'))
+ @stickyDiffHeaders()
@setCurrentAction(action)
@@ -134,12 +137,15 @@ class @MergeRequestTabs
url: "#{source}.json"
success: (data) =>
document.getElementById('diffs').innerHTML = data.html
- $('.diff-header').trigger('sticky_kit:recalc')
+ @stickyDiffHeaders()
@diffsLoaded = true
toggleLoading: ->
$('.mr-loading-status .loading').toggle()
+ stickyDiffHeaders: ->
+ $('.diff-header').trigger('sticky_kit:recalc')
+
_get: (options) ->
defaults = {
beforeSend: @toggleLoading
diff --git a/app/assets/javascripts/merge_request_widget.js.coffee b/app/assets/javascripts/merge_request_widget.js.coffee
index ca769e06a4e..e4d815bb4e4 100644
--- a/app/assets/javascripts/merge_request_widget.js.coffee
+++ b/app/assets/javascripts/merge_request_widget.js.coffee
@@ -36,11 +36,11 @@ class @MergeRequestWidget
showCiState: (state) ->
$('.ci_widget').hide()
- allowed_states = ["failed", "canceled", "running", "pending", "success"]
+ allowed_states = ["failed", "canceled", "running", "pending", "success", "not_found"]
if state in allowed_states
$('.ci_widget.ci-' + state).show()
switch state
- when "failed", "canceled"
+ when "failed", "canceled", "not_found"
@setMergeButtonClass('btn-danger')
when "running", "pending"
@setMergeButtonClass('btn-warning')
diff --git a/app/assets/javascripts/project_new.js.coffee b/app/assets/javascripts/project_new.js.coffee
index 836269c44f9..fecdb9fc2e7 100644
--- a/app/assets/javascripts/project_new.js.coffee
+++ b/app/assets/javascripts/project_new.js.coffee
@@ -3,9 +3,3 @@ class @ProjectNew
$('.project-edit-container').on 'ajax:before', =>
$('.project-edit-container').hide()
$('.save-project-loader').show()
-
- @initEvents()
-
-
- initEvents: ->
- disableButtonIfEmptyField '#project_name', '.project-submit'
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index 1419a9cded9..961ac793de2 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -364,3 +364,12 @@ table {
margin-top: 8px;
}
}
+
+.profiler-results {
+ top: 50px !important;
+
+ .profiler-button,
+ .profiler-controls {
+ border-color: #EEE !important;
+ }
+}
diff --git a/app/assets/stylesheets/generic/header.scss b/app/assets/stylesheets/generic/header.scss
index 8faae893a51..31e2ad86691 100644
--- a/app/assets/stylesheets/generic/header.scss
+++ b/app/assets/stylesheets/generic/header.scss
@@ -69,6 +69,7 @@ header {
float: left;
height: $header-height;
width: $sidebar_width;
+ overflow: hidden;
transition-duration: .3s;
a {
@@ -169,10 +170,6 @@ header {
@mixin collapsed-header {
.header-logo {
width: $sidebar_collapsed_width;
-
- h3 {
- display: none;
- }
}
.header-content {
diff --git a/app/assets/stylesheets/generic/sidebar.scss b/app/assets/stylesheets/generic/sidebar.scss
index add0d1b04ad..00e0534b81e 100644
--- a/app/assets/stylesheets/generic/sidebar.scss
+++ b/app/assets/stylesheets/generic/sidebar.scss
@@ -16,7 +16,7 @@
.content-wrapper {
width: 100%;
- padding: 15px;
+ padding: 20px;
background: #FFF;
}
@@ -29,42 +29,44 @@
&.navbar-collapse {
padding: 0px !important;
}
-}
-
-.nav-sidebar li a .count {
- float: right;
- background: #eee;
- padding: 0px 8px;
- @include border-radius(6px);
-}
-.nav-sidebar li {
- &.separate-item {
- padding-top: 10px;
- margin-top: 10px;
- }
-
- a {
- color: $gray;
- display: block;
- text-decoration: none;
- padding: 8px 15px;
- font-size: 14px;
- line-height: 20px;
- padding-left: 16px;
+ li {
+ width: $sidebar_width;
- &:hover {
- text-decoration: none;
+ &.separate-item {
+ padding-top: 10px;
+ margin-top: 10px;
}
- &:active, &:focus {
+ a {
+ color: $gray;
+ display: block;
text-decoration: none;
- }
+ padding: 8px 15px;
+ font-size: 14px;
+ line-height: 20px;
+ padding-left: 16px;
+
+ &:hover {
+ text-decoration: none;
+ }
+
+ &:active, &:focus {
+ text-decoration: none;
+ }
+
+ i {
+ width: 20px;
+ color: $gray-light;
+ margin-right: 23px;
+ }
- i {
- width: 20px;
- color: $gray-light;
- margin-right: 23px;
+ .count {
+ float: right;
+ background: #eee;
+ padding: 0px 8px;
+ @include border-radius(6px);
+ }
}
}
}
@@ -96,10 +98,6 @@
width: 230px;
}
}
-
- .content-wrapper {
- padding: 20px;
- }
}
@mixin folded-sidebar {
@@ -120,11 +118,6 @@
padding: 8px 15px;
text-align: left;
padding-left: 16px;
-
-
- & > span {
- display: none;
- }
}
}
@@ -134,9 +127,7 @@
}
.sidebar-user {
- .username {
- display: none;
- }
+ width: $sidebar_collapsed_width;
}
}
}
@@ -186,12 +177,13 @@
.sidebar-user {
position: absolute;
bottom: 0;
- width: 100%;
+ width: $sidebar_width;
padding: 10px;
overflow: hidden;
+ transition-duration: .3s;
.username {
margin-top: 5px;
- width: 230px;
+ width: $sidebar_width - 2 * 10px;
}
}
diff --git a/app/assets/stylesheets/generic/zen.scss b/app/assets/stylesheets/generic/zen.scss
index 7ab01187a02..7e86a0fe4b9 100644
--- a/app/assets/stylesheets/generic/zen.scss
+++ b/app/assets/stylesheets/generic/zen.scss
@@ -63,43 +63,24 @@
}
}
- // Make the placeholder text in the standard textarea the same color as the
- // background, effectively hiding it
-
- .zen-backdrop textarea::-webkit-input-placeholder {
- color: white;
- }
-
- .zen-backdrop textarea:-moz-placeholder {
- color: white;
- }
-
- .zen-backdrop textarea::-moz-placeholder {
- color: white;
- }
-
- .zen-backdrop textarea:-ms-input-placeholder {
- color: white;
- }
-
// Make the color of the placeholder text in the Zenned-out textarea darker,
// so it becomes visible
input:checked ~ .zen-backdrop textarea::-webkit-input-placeholder {
- color: #999;
+ color: #A8A8A8;
}
input:checked ~ .zen-backdrop textarea:-moz-placeholder {
- color: #999;
+ color: #A8A8A8;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea::-moz-placeholder {
- color: #999;
+ color: #A8A8A8;
opacity: 1;
}
input:checked ~ .zen-backdrop textarea:-ms-input-placeholder {
- color: #999;
+ color: #A8A8A8;
}
}
diff --git a/app/assets/stylesheets/pages/issues.scss b/app/assets/stylesheets/pages/issues.scss
index ed938f86b35..3572f33e91f 100644
--- a/app/assets/stylesheets/pages/issues.scss
+++ b/app/assets/stylesheets/pages/issues.scss
@@ -145,9 +145,3 @@ h2.issue-title {
.issue-form .select2-container {
width: 250px !important;
}
-
-.issues-holder {
- .issue-info {
- margin-left: 20px;
- }
-}
diff --git a/app/assets/stylesheets/themes/gitlab-theme.scss b/app/assets/stylesheets/themes/gitlab-theme.scss
index 7cabeaefb93..dc47b108100 100644
--- a/app/assets/stylesheets/themes/gitlab-theme.scss
+++ b/app/assets/stylesheets/themes/gitlab-theme.scss
@@ -72,7 +72,7 @@
&.active a {
color: #FFF;
- font-weight: bold;
+ background: $color-dark;
&.no-highlight {
border: none;
diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb
index 2e381822e42..901c1cdddcb 100644
--- a/app/controllers/groups_controller.rb
+++ b/app/controllers/groups_controller.rb
@@ -121,6 +121,8 @@ class GroupsController < Groups::ApplicationController
def determine_layout
if [:new, :create].include?(action_name.to_sym)
'application'
+ elsif [:edit, :update, :projects].include?(action_name.to_sym)
+ 'group_settings'
else
'group'
end
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index 7d168aa827b..bfafdeeb1fb 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -6,10 +6,10 @@ class Projects::IssuesController < Projects::ApplicationController
before_action :authorize_read_issue!
# Allow write(create) issue
- before_action :authorize_write_issue!, only: [:new, :create]
+ before_action :authorize_create_issue!, only: [:new, :create]
# Allow modify issue
- before_action :authorize_modify_issue!, only: [:edit, :update]
+ before_action :authorize_update_issue!, only: [:edit, :update]
# Allow issues bulk update
before_action :authorize_admin_issues!, only: [:bulk_update]
@@ -55,6 +55,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def show
+ @participants = @issue.participants(current_user, @project)
@note = @project.notes.new(noteable: @issue)
@notes = @issue.notes.inc_author.fresh
@noteable = @issue
@@ -121,8 +122,8 @@ class Projects::IssuesController < Projects::ApplicationController
end
end
- def authorize_modify_issue!
- return render_404 unless can?(current_user, :modify_issue, @issue)
+ def authorize_update_issue!
+ return render_404 unless can?(current_user, :update_issue, @issue)
end
def authorize_admin_issues!
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 51ecbfd561a..d1265198318 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -14,10 +14,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :authorize_read_merge_request!
# Allow write(create) merge_request
- before_action :authorize_write_merge_request!, only: [:new, :create]
+ before_action :authorize_create_merge_request!, only: [:new, :create]
# Allow modify merge_request
- before_action :authorize_modify_merge_request!, only: [:close, :edit, :update, :sort]
+ before_action :authorize_update_merge_request!, only: [:close, :edit, :update, :sort]
def index
terms = params['issue_search']
@@ -218,8 +218,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@closes_issues ||= @merge_request.closes_issues
end
- def authorize_modify_merge_request!
- return render_404 unless can?(current_user, :modify_merge_request, @merge_request)
+ def authorize_update_merge_request!
+ return render_404 unless can?(current_user, :update_merge_request, @merge_request)
end
def authorize_admin_merge_request!
@@ -246,6 +246,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def define_show_vars
+ @participants = @merge_request.participants(current_user, @project)
+
# Build a note object for comment form
@note = @project.notes.new(noteable: @merge_request)
@notes = @merge_request.mr_and_commit_notes.inc_author.fresh
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index f3e521adb69..c4a87e9dbd8 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -1,7 +1,7 @@
class Projects::NotesController < Projects::ApplicationController
# Authorize
before_action :authorize_read_note!
- before_action :authorize_write_note!, only: [:create]
+ before_action :authorize_create_note!, only: [:create]
before_action :authorize_admin_note!, only: [:update, :destroy]
before_action :find_current_user_notes, except: [:destroy, :delete_attachment]
diff --git a/app/controllers/projects/snippets_controller.rb b/app/controllers/projects/snippets_controller.rb
index 3d75abcc29d..64306637423 100644
--- a/app/controllers/projects/snippets_controller.rb
+++ b/app/controllers/projects/snippets_controller.rb
@@ -6,10 +6,10 @@ class Projects::SnippetsController < Projects::ApplicationController
before_action :authorize_read_project_snippet!
# Allow write(create) snippet
- before_action :authorize_write_project_snippet!, only: [:new, :create]
+ before_action :authorize_create_project_snippet!, only: [:new, :create]
# Allow modify snippet
- before_action :authorize_modify_project_snippet!, only: [:edit, :update]
+ before_action :authorize_update_project_snippet!, only: [:edit, :update]
# Allow destroy snippet
before_action :authorize_admin_project_snippet!, only: [:destroy]
@@ -75,8 +75,8 @@ class Projects::SnippetsController < Projects::ApplicationController
@snippet ||= @project.snippets.find(params[:id])
end
- def authorize_modify_project_snippet!
- return render_404 unless can?(current_user, :modify_project_snippet, @snippet)
+ def authorize_update_project_snippet!
+ return render_404 unless can?(current_user, :update_project_snippet, @snippet)
end
def authorize_admin_project_snippet!
diff --git a/app/controllers/projects/wikis_controller.rb b/app/controllers/projects/wikis_controller.rb
index 36ef86e1909..50512cb6dc3 100644
--- a/app/controllers/projects/wikis_controller.rb
+++ b/app/controllers/projects/wikis_controller.rb
@@ -2,7 +2,7 @@ require 'project_wiki'
class Projects::WikisController < Projects::ApplicationController
before_action :authorize_read_wiki!
- before_action :authorize_write_wiki!, only: [:edit, :create, :history]
+ before_action :authorize_create_wiki!, only: [:edit, :create, :history]
before_action :authorize_admin_wiki!, only: :destroy
before_action :load_project_wiki
include WikiHelper
@@ -28,7 +28,7 @@ class Projects::WikisController < Projects::ApplicationController
)
end
else
- return render('empty') unless can?(current_user, :write_wiki, @project)
+ return render('empty') unless can?(current_user, :create_wiki, @project)
@page = WikiPage.new(@project_wiki)
@page.title = params[:id]
@@ -43,7 +43,7 @@ class Projects::WikisController < Projects::ApplicationController
def update
@page = @project_wiki.find_page(params[:id])
- return render('empty') unless can?(current_user, :write_wiki, @project)
+ return render('empty') unless can?(current_user, :create_wiki, @project)
if @page.update(content, format, message)
redirect_to(
diff --git a/app/controllers/snippets_controller.rb b/app/controllers/snippets_controller.rb
index cf672c5c093..8e7e45c781f 100644
--- a/app/controllers/snippets_controller.rb
+++ b/app/controllers/snippets_controller.rb
@@ -2,7 +2,7 @@ class SnippetsController < ApplicationController
before_action :snippet, only: [:show, :edit, :destroy, :update, :raw]
# Allow modify snippet
- before_action :authorize_modify_snippet!, only: [:edit, :update]
+ before_action :authorize_update_snippet!, only: [:edit, :update]
# Allow destroy snippet
before_action :authorize_admin_snippet!, only: [:destroy]
@@ -87,8 +87,8 @@ class SnippetsController < ApplicationController
end
end
- def authorize_modify_snippet!
- return render_404 unless can?(current_user, :modify_personal_snippet, @snippet)
+ def authorize_update_snippet!
+ return render_404 unless can?(current_user, :update_personal_snippet, @snippet)
end
def authorize_admin_snippet!
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index 9aabe01f60e..a801d3b10aa 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -98,6 +98,29 @@ module GitlabMarkdownHelper
end
end
+ MARKDOWN_TIPS = [
+ "End a line with two or more spaces for a line-break, or soft-return",
+ "Inline code can be denoted by `surrounding it with backticks`",
+ "Blocks of code can be denoted by three backticks ``` or four leading spaces",
+ "Emoji can be added by :emoji_name:, for example :thumbsup:",
+ "Notify other participants using @user_name",
+ "Notify a specific group using @group_name",
+ "Notify the entire team using @all",
+ "Reference an issue using a hash, for example issue #123",
+ "Reference a merge request using an exclamation point, for example MR !123",
+ "Italicize words or phrases using *asterisks* or _underscores_",
+ "Bold words or phrases using **double asterisks** or __double underscores__",
+ "Strikethrough words or phrases using ~~two tildes~~",
+ "Make a bulleted list using + pluses, - minuses, or * asterisks",
+ "Denote blockquotes using > at the beginning of a line",
+ "Make a horizontal line using three or more hyphens ---, asterisks ***, or underscores ___"
+ ].freeze
+
+ # Returns a random markdown tip for use as a textarea placeholder
+ def random_markdown_tip
+ "Tip: #{MARKDOWN_TIPS.sample}"
+ end
+
private
# Return +text+, truncated to +max_chars+ characters, excluding any HTML
diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb
index 9703c8d9e9c..9d072f81092 100644
--- a/app/helpers/gitlab_routing_helper.rb
+++ b/app/helpers/gitlab_routing_helper.rb
@@ -52,4 +52,12 @@ module GitlabRoutingHelper
def project_snippet_url(entity, *args)
namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
end
+
+ def toggle_subscription_path(entity, *args)
+ if entity.is_a?(Issue)
+ toggle_subscription_namespace_project_issue_path(entity.project.namespace, entity.project, entity)
+ else
+ toggle_subscription_namespace_project_merge_request_path(entity.project.namespace, entity.project, entity)
+ end
+ end
end
diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb
index 3569ac2af63..b067cb54a43 100644
--- a/app/helpers/groups_helper.rb
+++ b/app/helpers/groups_helper.rb
@@ -19,14 +19,6 @@ module GroupsHelper
end
end
- def group_settings_page?
- if current_controller?('groups')
- current_action?('edit') || current_action?('projects')
- else
- false
- end
- end
-
def group_icon(group)
if group.is_a?(String)
group = Group.find_by(path: group)
diff --git a/app/helpers/oauth_helper.rb b/app/helpers/oauth_helper.rb
index 997b91de077..2fdca13ed40 100644
--- a/app/helpers/oauth_helper.rb
+++ b/app/helpers/oauth_helper.rb
@@ -13,7 +13,7 @@ module OauthHelper
def enabled_social_providers
enabled_oauth_providers.select do |name|
- [:twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym)
+ [:saml, :twitter, :gitlab, :github, :bitbucket, :google_oauth2].include?(name.to_sym)
end
end
diff --git a/app/helpers/submodule_helper.rb b/app/helpers/submodule_helper.rb
index 6def7793dc3..b3f50ceebe4 100644
--- a/app/helpers/submodule_helper.rb
+++ b/app/helpers/submodule_helper.rb
@@ -63,7 +63,7 @@ module SubmoduleHelper
namespace = components.pop.gsub(/^\.\.$/, '')
if namespace.empty?
- namespace = @project.namespace.name
+ namespace = @project.namespace.path
end
[
diff --git a/app/models/ability.rb b/app/models/ability.rb
index a5db22040e0..d3631d49ec6 100644
--- a/app/models/ability.rb
+++ b/app/models/ability.rb
@@ -68,6 +68,7 @@ class Ability
def project_abilities(user, project)
rules = []
key = "/user/#{user.id}/project/#{project.id}"
+
RequestStore.store[key] ||= begin
team = project.team
@@ -144,9 +145,9 @@ class Ability
:read_project_member,
:read_merge_request,
:read_note,
- :write_project,
- :write_issue,
- :write_note
+ :create_project,
+ :create_issue,
+ :create_note
]
end
@@ -154,27 +155,27 @@ class Ability
project_guest_rules + [
:download_code,
:fork_project,
- :write_project_snippet
+ :create_project_snippet,
+ :update_issue,
+ :admin_issue,
+ :admin_label,
]
end
def project_dev_rules
project_report_rules + [
- :write_merge_request,
- :write_wiki,
- :modify_issue,
- :admin_issue,
- :admin_label,
+ :create_merge_request,
+ :create_wiki,
:push_code
]
end
def project_archived_rules
[
- :write_merge_request,
+ :create_merge_request,
:push_code,
:push_code_to_protected_branches,
- :modify_merge_request,
+ :update_merge_request,
:admin_merge_request
]
end
@@ -182,10 +183,8 @@ class Ability
def project_master_rules
project_dev_rules + [
:push_code_to_protected_branches,
- :modify_issue,
- :modify_project_snippet,
- :modify_merge_request,
- :admin_issue,
+ :update_project_snippet,
+ :update_merge_request,
:admin_milestone,
:admin_project_snippet,
:admin_project_member,
@@ -245,30 +244,40 @@ class Ability
rules.flatten
end
- [:issue, :note, :project_snippet, :personal_snippet, :merge_request].each do |name|
+
+ [:issue, :merge_request].each do |name|
define_method "#{name}_abilities" do |user, subject|
- if subject.author == user || user.is_admin?
- rules = [
+ rules = []
+
+ if subject.author == user || (subject.respond_to?(:assignee) && subject.assignee == user)
+ rules += [
:"read_#{name}",
- :"write_#{name}",
- :"modify_#{name}",
- :"admin_#{name}"
+ :"update_#{name}",
]
- rules.push(:change_visibility_level) if subject.is_a?(Snippet)
- rules
- elsif subject.respond_to?(:assignee) && subject.assignee == user
- [
+ end
+
+ rules += project_abilities(user, subject.project)
+ rules
+ end
+ end
+
+ [:note, :project_snippet, :personal_snippet].each do |name|
+ define_method "#{name}_abilities" do |user, subject|
+ rules = []
+
+ if subject.author == user
+ rules += [
:"read_#{name}",
- :"write_#{name}",
- :"modify_#{name}",
+ :"update_#{name}",
+ :"admin_#{name}"
]
- else
- if subject.respond_to?(:project) && subject.project
- project_abilities(user, subject.project)
- else
- []
- end
end
+
+ if subject.respond_to?(:project) && subject.project
+ rules += project_abilities(user, subject.project)
+ end
+
+ rules
end
end
@@ -277,13 +286,16 @@ class Ability
target_user = subject.user
group = subject.group
can_manage = group_abilities(user, group).include?(:admin_group)
+
if can_manage && (user != target_user)
- rules << :modify_group_member
+ rules << :update_group_member
rules << :destroy_group_member
end
+
if !group.last_owner?(user) && (can_manage || (user == target_user))
rules << :destroy_group_member
end
+
rules
end
@@ -300,8 +312,8 @@ class Ability
def named_abilities(name)
[
:"read_#{name}",
- :"write_#{name}",
- :"modify_#{name}",
+ :"create_#{name}",
+ :"update_#{name}",
:"admin_#{name}"
]
end
diff --git a/app/models/commit.rb b/app/models/commit.rb
index 9d721661629..aff329d71fa 100644
--- a/app/models/commit.rb
+++ b/app/models/commit.rb
@@ -157,11 +157,11 @@ class Commit
end
def author
- User.find_for_commit(author_email, author_name)
+ @author ||= User.find_by_any_email(author_email)
end
def committer
- User.find_for_commit(committer_email, committer_name)
+ @committer ||= User.find_by_any_email(committer_email)
end
def notes
diff --git a/app/models/concerns/participable.rb b/app/models/concerns/participable.rb
index 9f667f47e0d..7c9597333dd 100644
--- a/app/models/concerns/participable.rb
+++ b/app/models/concerns/participable.rb
@@ -14,7 +14,7 @@
#
# participant :author, :assignee, :mentioned_users, :notes
# end
-#
+#
# issue = Issue.last
# users = issue.participants
# # `users` will contain the issue's author, its assignee,
@@ -35,11 +35,13 @@ module Participable
end
end
+ # Be aware that this method makes a lot of sql queries.
+ # Save result into variable if you are going to reuse it inside same request
def participants(current_user = self.author, project = self.project)
participants = self.class.participant_attrs.flat_map do |attr|
meth = method(attr)
- value =
+ value =
if meth.arity == 1 || meth.arity == -1
meth.call(current_user)
else
@@ -59,7 +61,7 @@ module Participable
end
private
-
+
def participants_for(value, current_user = nil, project = nil)
case value
when User
diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb
index 7ecdaf6b2e0..53b3fc10ccb 100644
--- a/app/models/merge_request.rb
+++ b/app/models/merge_request.rb
@@ -205,7 +205,14 @@ class MergeRequest < ActiveRecord::Base
end
def check_if_can_be_merged
- if Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
+ can_be_merged =
+ if for_fork?
+ Gitlab::Satellite::MergeAction.new(self.author, self).can_be_merged?
+ else
+ project.repository.can_be_merged?(source_branch, target_branch)
+ end
+
+ if can_be_merged
mark_as_mergeable
else
mark_as_unmergeable
diff --git a/app/models/project_services/gitlab_ci_service.rb b/app/models/project_services/gitlab_ci_service.rb
index 19b5859d5c9..c284e19fe50 100644
--- a/app/models/project_services/gitlab_ci_service.rb
+++ b/app/models/project_services/gitlab_ci_service.rb
@@ -76,6 +76,7 @@ class GitlabCiService < CiService
params = {
id: new_project.id,
name_with_namespace: new_project.name_with_namespace,
+ path_with_namespace: new_project.path_with_namespace,
web_url: new_project.web_url,
default_branch: new_project.default_branch,
ssh_url_to_repo: new_project.ssh_url_to_repo
diff --git a/app/models/repository.rb b/app/models/repository.rb
index b32e8847bb5..c767d1051d1 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -8,7 +8,7 @@ class Repository
@project = project
if path_with_namespace
- @raw_repository = Gitlab::Git::Repository.new(path_to_repo)
+ @raw_repository = Gitlab::Git::Repository.new(path_to_repo)
@raw_repository.autocrlf = :input
end
@@ -173,7 +173,9 @@ class Repository
end
def blob_at(sha, path)
- Gitlab::Git::Blob.find(self, sha, path)
+ unless Gitlab::Git.blank_ref?(sha)
+ Gitlab::Git::Blob.find(self, sha, path)
+ end
end
def blob_by_oid(oid)
@@ -412,8 +414,6 @@ class Repository
Gitlab::Git::Blob.remove(raw_repository, options)
end
- private
-
def user_to_comitter(user)
{
email: user.email,
@@ -422,6 +422,17 @@ class Repository
}
end
+ def can_be_merged?(source_branch, target_branch)
+ our_commit = rugged.branches[target_branch].target
+ their_commit = rugged.branches[source_branch].target
+
+ if our_commit && their_commit
+ !rugged.merge_commits(our_commit, their_commit).conflicts?
+ end
+ end
+
+ private
+
def cache
@cache ||= RepositoryCache.new(path_with_namespace)
end
diff --git a/app/models/user.rb b/app/models/user.rb
index 22cd15bf971..dc84f5141d8 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -225,7 +225,8 @@ class User < ActiveRecord::Base
end
end
- def find_for_commit(email, name)
+ # Find a User by their primary email or any associated secondary email
+ def find_by_any_email(email)
user_table = arel_table
email_table = Email.arel_table
@@ -237,13 +238,8 @@ class User < ActiveRecord::Base
join(email_table, Arel::Nodes::OuterJoin).
# ON "users"."id" = "emails"."user_id"
on(user_table[:id].eq(email_table[:user_id])).
- # WHERE ("user"."email" = '<email>' OR "user"."name" = '<name>')
- # OR "emails"."email" = '<email>'
- where(
- user_table[:email].eq(email).
- or(user_table[:name].eq(name)).
- or(email_table[:email].eq(email))
- )
+ # WHERE ("user"."email" = '<email>' OR "emails"."email" = '<email>')
+ where(user_table[:email].eq(email).or(email_table[:email].eq(email)))
find_by_sql(query.to_sql).first
end
@@ -351,6 +347,8 @@ class User < ActiveRecord::Base
end
def owns_public_email
+ return if self.public_email.blank?
+
self.errors.add(:public_email, "is not an email you own") unless self.all_emails.include?(self.public_email)
end
@@ -531,7 +529,7 @@ class User < ActiveRecord::Base
def set_public_email
if self.public_email.blank? || !self.all_emails.include?(self.public_email)
- self.public_email = nil
+ self.public_email = ''
end
end
diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb
index 1d99223cfe6..f1ef5ca84fe 100644
--- a/app/services/issuable_base_service.rb
+++ b/app/services/issuable_base_service.rb
@@ -26,4 +26,12 @@ class IssuableBaseService < BaseService
issuable, issuable.project, current_user, branch_type,
old_branch, new_branch)
end
+
+ def filter_params
+ unless can?(current_user, :admin_issue, project)
+ params.delete(:milestone_id)
+ params.delete(:label_ids)
+ params.delete(:assignee_id)
+ end
+ end
end
diff --git a/app/services/issues/bulk_update_service.rb b/app/services/issues/bulk_update_service.rb
index eb07413ee94..de8387c4900 100644
--- a/app/services/issues/bulk_update_service.rb
+++ b/app/services/issues/bulk_update_service.rb
@@ -10,7 +10,7 @@ module Issues
issues = Issue.where(id: issues_ids)
issues.each do |issue|
- next unless can?(current_user, :modify_issue, issue)
+ next unless can?(current_user, :update_issue, issue)
Issues::UpdateService.new(issue.project, current_user, issue_params).execute(issue)
end
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index d5c17906a55..1ea4b72216c 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -1,6 +1,7 @@
module Issues
class CreateService < Issues::BaseService
def execute
+ filter_params
label_params = params[:label_ids]
issue = project.issues.new(params.except(:label_ids))
issue.author = current_user
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index 6af942a5ca4..3220facaf7c 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -17,6 +17,7 @@ module Issues
params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
+ filter_params
old_labels = issue.labels.to_a
if params.present? && issue.update_attributes(params.except(:state_event,
diff --git a/app/services/merge_requests/auto_merge_service.rb b/app/services/merge_requests/auto_merge_service.rb
index 378b39bb9d6..df793fc997d 100644
--- a/app/services/merge_requests/auto_merge_service.rb
+++ b/app/services/merge_requests/auto_merge_service.rb
@@ -5,17 +5,20 @@ module MergeRequests
# mark merge request as merged and execute all hooks and notifications
# Called when you do merge via GitLab UI
class AutoMergeService < BaseMergeService
+ attr_reader :merge_request, :commit_message
+
def execute(merge_request, commit_message)
+ @commit_message = commit_message
+ @merge_request = merge_request
+
merge_request.lock_mr
- if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
+ if merge!
merge_request.merge
-
create_merge_event(merge_request, current_user)
create_note(merge_request)
notification_service.merge_mr(merge_request, current_user)
- execute_hooks(merge_request)
-
+ execute_hooks(merge_request, 'merge')
true
else
merge_request.unlock_mr
@@ -26,5 +29,39 @@ module MergeRequests
merge_request.mark_as_unmergeable
false
end
+
+ def merge!
+ if merge_request.for_fork?
+ Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
+ else
+ # Merge local branches using rugged instead of satellites
+ if sha = commit
+ after_commit(sha, merge_request.target_branch)
+ end
+ end
+ end
+
+ def commit
+ committer = repository.user_to_comitter(current_user)
+
+ options = {
+ message: commit_message,
+ author: committer,
+ committer: committer
+ }
+
+ repository.merge(merge_request.source_branch, merge_request.target_branch, options)
+ end
+
+ def after_commit(sha, branch)
+ commit = repository.commit(sha)
+ full_ref = 'refs/heads/' + branch
+ old_sha = commit.parent_id || Gitlab::Git::BLANK_SHA
+ GitPushService.new.execute(project, current_user, old_sha, sha, full_ref)
+ end
+
+ def repository
+ project.repository
+ end
end
end
diff --git a/app/services/merge_requests/create_service.rb b/app/services/merge_requests/create_service.rb
index ca8d80f6c0c..f431c5d5534 100644
--- a/app/services/merge_requests/create_service.rb
+++ b/app/services/merge_requests/create_service.rb
@@ -1,6 +1,7 @@
module MergeRequests
class CreateService < MergeRequests::BaseService
def execute
+ filter_params
label_params = params[:label_ids]
merge_request = MergeRequest.new(params.except(:label_ids))
merge_request.source_project = project
diff --git a/app/services/merge_requests/update_service.rb b/app/services/merge_requests/update_service.rb
index 4f6c6cba9a9..f6570f52241 100644
--- a/app/services/merge_requests/update_service.rb
+++ b/app/services/merge_requests/update_service.rb
@@ -27,6 +27,7 @@ module MergeRequests
params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
+ filter_params
old_labels = merge_request.labels.to_a
if params.present? && merge_request.update_attributes(
diff --git a/app/services/update_snippet_service.rb b/app/services/update_snippet_service.rb
index 9d181c2d2ab..e9328bb7323 100644
--- a/app/services/update_snippet_service.rb
+++ b/app/services/update_snippet_service.rb
@@ -9,9 +9,9 @@ class UpdateSnippetService < BaseService
def execute
# check that user is allowed to set specified visibility_level
new_visibility = params[:visibility_level]
+
if new_visibility && new_visibility.to_i != snippet.visibility_level
- unless can?(current_user, :change_visibility_level, snippet) &&
- Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
+ unless Gitlab::VisibilityLevel.allowed_for?(current_user, new_visibility)
deny_visibility_level(snippet, new_visibility)
return snippet
end
diff --git a/app/views/admin/application_settings/_form.html.haml b/app/views/admin/application_settings/_form.html.haml
index d5a49fc41f4..6bef33c6d7a 100644
--- a/app/views/admin/application_settings/_form.html.haml
+++ b/app/views/admin/application_settings/_form.html.haml
@@ -6,19 +6,36 @@
%p= msg
%fieldset
- %legend Features
+ %legend Visibility and Access Controls
.form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :signup_enabled do
- = f.check_box :signup_enabled
- Signup enabled
+ = f.label :default_branch_protection, class: 'control-label col-sm-2'
+ .col-sm-10
+ = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
+ .form-group.project-visibility-level-holder
+ = f.label :default_project_visibility, class: 'control-label col-sm-2'
+ .col-sm-10
+ = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: 'Project')
+ .form-group.project-visibility-level-holder
+ = f.label :default_snippet_visibility, class: 'control-label col-sm-2'
+ .col-sm-10
+ = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: 'Snippet')
+ .form-group
+ = f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
+ .col-sm-10
+ - data_attrs = { toggle: 'buttons' }
+ .btn-group{ data: data_attrs }
+ - restricted_level_checkboxes('restricted-visibility-help').each do |level|
+ = level
+ %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
- = f.label :signin_enabled do
- = f.check_box :signin_enabled
- Signin enabled
+ = f.label :version_check_enabled do
+ = f.check_box :version_check_enabled
+ Version check enabled
+
+ %fieldset
+ %legend Account and Limit Settings
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
@@ -33,37 +50,45 @@
Twitter enabled
%span.help-block#twitter_help_block Show users a button to share their newly created public or internal projects on twitter
.form-group
- .col-sm-offset-2.col-sm-10
- .checkbox
- = f.label :version_check_enabled do
- = f.check_box :version_check_enabled
- Version check enabled
- %fieldset
- %legend Misc
- .form-group
= f.label :default_projects_limit, class: 'control-label col-sm-2'
.col-sm-10
= f.number_field :default_projects_limit, class: 'form-control'
.form-group
- = f.label :default_branch_protection, class: 'control-label col-sm-2'
+ = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
.col-sm-10
- = f.select :default_branch_protection, options_for_select(Gitlab::Access.protection_options, @application_setting.default_branch_protection), {}, class: 'form-control'
- .form-group.project-visibility-level-holder
- = f.label :default_project_visibility, class: 'control-label col-sm-2'
+ = f.number_field :max_attachment_size, class: 'form-control'
+ .form-group
+ = f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
.col-sm-10
- = render('shared/visibility_radios', model_method: :default_project_visibility, form: f, selected_level: @application_setting.default_project_visibility, form_model: 'Project')
- .form-group.project-visibility-level-holder
- = f.label :default_snippet_visibility, class: 'control-label col-sm-2'
+ = f.number_field :session_expire_delay, class: 'form-control'
+ %span.help-block#session_expire_delay_help_block GitLab restart is required to apply changes
+ .form-group
+ = f.label :user_oauth_applications, 'User OAuth applications', class: 'control-label col-sm-2'
.col-sm-10
- = render('shared/visibility_radios', model_method: :default_snippet_visibility, form: f, selected_level: @application_setting.default_snippet_visibility, form_model: 'Snippet')
+ .checkbox
+ = f.label :user_oauth_applications do
+ = f.check_box :user_oauth_applications
+ Allow users to register any application to use GitLab as an OAuth provider
+
+ %fieldset
+ %legend Sign-in Restrictions
.form-group
- = f.label :restricted_visibility_levels, class: 'control-label col-sm-2'
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :signup_enabled do
+ = f.check_box :signup_enabled
+ Sign-up enabled
+ .form-group
+ .col-sm-offset-2.col-sm-10
+ .checkbox
+ = f.label :signin_enabled do
+ = f.check_box :signin_enabled
+ Sign-in enabled
+ .form-group
+ = f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2'
.col-sm-10
- - data_attrs = { toggle: 'buttons' }
- .btn-group{ data: data_attrs }
- - restricted_level_checkboxes('restricted-visibility-help').each do |level|
- = level
- %span.help-block#restricted-visibility-help Selected levels cannot be used by non-admin users for projects or snippets
+ = f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control'
+ .help-block Only users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
.form-group
= f.label :home_page_url, class: 'control-label col-sm-2'
.col-sm-10
@@ -79,27 +104,6 @@
.col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled
- .form-group
- = f.label :max_attachment_size, 'Maximum attachment size (MB)', class: 'control-label col-sm-2'
- .col-sm-10
- = f.number_field :max_attachment_size, class: 'form-control'
- .form-group
- = f.label :session_expire_delay, 'Session duration (minutes)', class: 'control-label col-sm-2'
- .col-sm-10
- = f.number_field :session_expire_delay, class: 'form-control'
- %span.help-block#session_expire_delay_help_block GitLab restart is required to apply changes
- .form-group
- = f.label :restricted_signup_domains, 'Restricted domains for sign-ups', class: 'control-label col-sm-2'
- .col-sm-10
- = f.text_area :restricted_signup_domains_raw, placeholder: 'domain.com', class: 'form-control'
- .help-block Only users with e-mail addresses that match these domain(s) will be able to sign-up. Wildcards allowed. Use separate lines for multiple entries. Ex: domain.com, *.domain.com
- .form_group
- = f.label :user_oauth_applications, 'User OAuth applications', class: 'control-label col-sm-2'
- .col-sm-10
- .checkbox
- = f.label :user_oauth_applications do
- = f.check_box :user_oauth_applications
- Allow users to register any application to use GitLab as an OAuth provider
.form-actions
= f.submit 'Save', class: 'btn btn-primary'
diff --git a/app/views/admin/application_settings/show.html.haml b/app/views/admin/application_settings/show.html.haml
index 1632dd8affa..e9c7ca9d5aa 100644
--- a/app/views/admin/application_settings/show.html.haml
+++ b/app/views/admin/application_settings/show.html.haml
@@ -1,4 +1,4 @@
- page_title "Settings"
-%h3.page-title Application settings
+%h3.page-title Settings
%hr
= render 'form'
diff --git a/app/views/admin/identities/_form.html.haml b/app/views/admin/identities/_form.html.haml
index b405aa6e8e3..0525552ebf8 100644
--- a/app/views/admin/identities/_form.html.haml
+++ b/app/views/admin/identities/_form.html.haml
@@ -12,7 +12,7 @@
.form-group
= f.label :extern_uid, "Identifier", class: 'control-label'
.col-sm-10
- = f.text_field :extern_uid, required: true, class: 'form-control', required: true
+ = f.text_field :extern_uid, class: 'form-control', required: true
.form-actions
= f.submit 'Save changes', class: "btn btn-save"
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 0dd2edbb1bc..94318d1bcf5 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -17,5 +17,5 @@
= link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
%i.fa.fa-rss
- = render 'shared/issuable_filter', type: :issues
+ = render 'shared/issuable/filter', type: :issues
= render 'shared/issues'
diff --git a/app/views/dashboard/merge_requests.html.haml b/app/views/dashboard/merge_requests.html.haml
index 61d2fbe538c..90611d562b0 100644
--- a/app/views/dashboard/merge_requests.html.haml
+++ b/app/views/dashboard/merge_requests.html.haml
@@ -7,5 +7,5 @@
List all merge requests from all projects you have access to.
%hr
.append-bottom-20
- = render 'shared/issuable_filter', type: :merge_requests
+ = render 'shared/issuable/filter', type: :merge_requests
= render 'shared/merge_requests'
diff --git a/app/views/events/_event.html.haml b/app/views/events/_event.html.haml
index 02b1dec753c..b2e5d11279b 100644
--- a/app/views/events/_event.html.haml
+++ b/app/views/events/_event.html.haml
@@ -3,14 +3,15 @@
.event-item-timestamp
#{time_ago_with_tooltip(event.created_at)}
- = cache [event, current_user] do
- = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
-
- - if event.push?
- = render "events/event/push", event: event
- - elsif event.commented?
- = render "events/event/note", event: event
- - elsif event.created_project?
+ - if event.created_project?
+ = cache [event, current_user] do
= render "events/event/created_project", event: event
- - else
- = render "events/event/common", event: event \ No newline at end of file
+ - else
+ = cache event do
+ = image_tag avatar_icon(event.author_email, 24), class: "avatar s24", alt:''
+ - if event.push?
+ = render "events/event/push", event: event
+ - elsif event.commented?
+ = render "events/event/note", event: event
+ - else
+ = render "events/event/common", event: event
diff --git a/app/views/groups/edit.html.haml b/app/views/groups/edit.html.haml
index aa13ed85b53..2ff4b7e23ea 100644
--- a/app/views/groups/edit.html.haml
+++ b/app/views/groups/edit.html.haml
@@ -1,4 +1,3 @@
-- page_title "Settings"
.panel.panel-default
.panel-heading
%strong= @group.name
diff --git a/app/views/groups/group_members/_group_member.html.haml b/app/views/groups/group_members/_group_member.html.haml
index ec39a755f0f..b460e0ff59e 100644
--- a/app/views/groups/group_members/_group_member.html.haml
+++ b/app/views/groups/group_members/_group_member.html.haml
@@ -32,7 +32,7 @@
%span.pull-right
%strong= member.human_access
- if show_controls
- - if can?(current_user, :modify_group_member, member)
+ - if can?(current_user, :update_group_member, member)
= button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o
diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml
index e0756e909be..f0d90782556 100644
--- a/app/views/groups/issues.html.haml
+++ b/app/views/groups/issues.html.haml
@@ -21,5 +21,5 @@
= link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
%i.fa.fa-rss
- = render 'shared/issuable_filter', type: :issues
+ = render 'shared/issuable/filter', type: :issues
= render 'shared/issues'
diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml
index 3d9e857cc52..ca85a158707 100644
--- a/app/views/groups/merge_requests.html.haml
+++ b/app/views/groups/merge_requests.html.haml
@@ -10,5 +10,5 @@
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
%hr
.append-bottom-20
- = render 'shared/issuable_filter', type: :merge_requests
+ = render 'shared/issuable/filter', type: :merge_requests
= render 'shared/merge_requests'
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 5edc03129d2..db7dbf9bfe3 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -1,5 +1,5 @@
- page_title @group.name
- header_title @group.name, group_path(@group)
-- sidebar "group"
+- sidebar "group" unless sidebar
= render template: "layouts/application"
diff --git a/app/views/layouts/group_settings.html.haml b/app/views/layouts/group_settings.html.haml
new file mode 100644
index 00000000000..e303a561628
--- /dev/null
+++ b/app/views/layouts/group_settings.html.haml
@@ -0,0 +1,4 @@
+- page_title "Settings"
+- sidebar "group_settings"
+
+= render template: "layouts/group"
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 9f1654b25b4..9d216be151a 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -29,25 +29,9 @@
= icon('users fw')
%span
Members
-
- if can?(current_user, :admin_group, @group)
- = nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do
- = link_to edit_group_path(@group), title: 'Settings', class: 'tab no-highlight', data: {placement: 'right'} do
+ = nav_link(html_options: { class: "separate-item" }) do
+ = link_to edit_group_path(@group), title: 'Settings', data: {placement: 'right'} do
= icon ('cogs fw')
%span
Settings
- = icon ('angle-down fw')
-
- - if group_settings_page?
- %ul.sidebar-subnav
- = nav_link(path: 'groups#edit') do
- = link_to edit_group_path(@group), title: 'Group', data: {placement: 'right'} do
- = icon('pencil-square-o')
- %span
- Group Settings
- = nav_link(path: 'groups#projects') do
- = link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do
- = icon('folder')
- %span
- Projects
-
diff --git a/app/views/layouts/nav/_group_settings.html.haml b/app/views/layouts/nav/_group_settings.html.haml
new file mode 100644
index 00000000000..72ada771ca4
--- /dev/null
+++ b/app/views/layouts/nav/_group_settings.html.haml
@@ -0,0 +1,20 @@
+%ul.nav.nav-sidebar
+ = nav_link do
+ = link_to group_path(@group), title: 'Back to group', data: {placement: 'right'} do
+ = icon('caret-square-o-left fw')
+ %span
+ Back to group
+
+ %li.separate-item
+
+ %ul.sidebar-subnav
+ = nav_link(path: 'groups#edit') do
+ = link_to edit_group_path(@group), title: 'Group Settings', data: {placement: 'right'} do
+ = icon ('pencil-square-o fw')
+ %span
+ Group Settings
+ = nav_link(path: 'groups#projects') do
+ = link_to projects_group_path(@group), title: 'Projects', data: {placement: 'right'} do
+ = icon('folder fw')
+ %span
+ Projects
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index cbcf560d0af..6de97302dc1 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,4 +1,4 @@
-%ul.project-navigation.nav.nav-sidebar
+%ul.nav.nav-sidebar
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project', data: {placement: 'right'} do
= icon('dashboard fw')
@@ -86,7 +86,7 @@
- if project_nav_tab? :settings
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
- = link_to edit_project_path(@project), title: 'Settings', class: 'stat-tab tab no-highlight', data: {placement: 'right'} do
+ = link_to edit_project_path(@project), title: 'Settings', data: {placement: 'right'} do
= icon('cogs fw')
%span
Settings
diff --git a/app/views/layouts/nav/_project_settings.html.haml b/app/views/layouts/nav/_project_settings.html.haml
index 633c6ae6bfb..9c86d3c09b2 100644
--- a/app/views/layouts/nav/_project_settings.html.haml
+++ b/app/views/layouts/nav/_project_settings.html.haml
@@ -1,4 +1,4 @@
-%ul.project-navigation.nav.nav-sidebar
+%ul.nav.nav-sidebar
= nav_link do
= link_to project_path(@project), title: 'Back to project', data: {placement: 'right'} do
= icon('caret-square-o-left fw')
@@ -7,9 +7,9 @@
%li.separate-item
- %ul.project-settings-nav.sidebar-subnav
+ %ul.sidebar-subnav
= nav_link(path: 'projects#edit') do
- = link_to edit_project_path(@project), title: 'Project', class: 'stat-tab tab', data: {placement: 'right'} do
+ = link_to edit_project_path(@project), title: 'Project Settings', data: {placement: 'right'} do
= icon('pencil-square-o fw')
%span
Project Settings
@@ -32,5 +32,5 @@
= link_to namespace_project_protected_branches_path(@project.namespace, @project), title: 'Protected Branches', data: {placement: 'right'} do
= icon('lock fw')
%span
- Protected branches
+ Protected Branches
diff --git a/app/views/projects/_aside.html.haml b/app/views/projects/_aside.html.haml
index c9c17110d2b..72aea8814f5 100644
--- a/app/views/projects/_aside.html.haml
+++ b/app/views/projects/_aside.html.haml
@@ -22,14 +22,12 @@
Contribution guide
.actions
- - if can? current_user, :write_issue, @project
+ - if can? current_user, :create_issue, @project
= link_to url_for_new_issue(@project, only_path: true), title: "New Issue", class: 'btn btn-sm append-right-10' do
- = icon("exclamation-circle fw")
New Issue
- - if can? current_user, :write_merge_request, @project
+ - if can? current_user, :create_merge_request, @project
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-sm", title: "New Merge Request" do
- = icon("plus fw")
New Merge Request
- if forked_from_project = @project.forked_from_project
diff --git a/app/views/projects/_zen.html.haml b/app/views/projects/_zen.html.haml
index cf1c55ecca6..a4e41eeb363 100644
--- a/app/views/projects/_zen.html.haml
+++ b/app/views/projects/_zen.html.haml
@@ -2,7 +2,7 @@
%input#zen-toggle-comment.zen-toggle-comment{ tabindex: '-1', type: 'checkbox' }
.zen-backdrop
- classes << ' js-gfm-input markdown-area'
- = f.text_area attr, class: classes, placeholder: 'Leave a comment'
+ = f.text_area attr, class: classes, placeholder: random_markdown_tip
= link_to nil, class: 'zen-enter-link', tabindex: '-1' do
%i.fa.fa-expand
Edit in fullscreen
diff --git a/app/views/projects/blob/_remove.html.haml b/app/views/projects/blob/_remove.html.haml
index b8d8451880a..cae5ff01099 100644
--- a/app/views/projects/blob/_remove.html.haml
+++ b/app/views/projects/blob/_remove.html.haml
@@ -9,13 +9,10 @@
%strong= @ref
.modal-body
- = form_tag namespace_project_blob_path(@project.namespace, @project, @id), method: :delete, class: 'form-horizontal' do
+ = form_tag namespace_project_blob_path(@project.namespace, @project, @id), method: :delete, class: 'form-horizontal js-requires-input' do
= render 'shared/commit_message_container', params: params,
placeholder: 'Removed this file because...'
.form-group
.col-sm-offset-2.col-sm-10
= button_tag 'Remove file', class: 'btn btn-remove btn-remove-file'
= link_to "Cancel", '#', class: "btn btn-cancel", "data-dismiss" => "modal"
-
-:javascript
- disableButtonIfEmptyField('#commit_message', '.btn-remove-file')
diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml
index e78181f8801..a12cd660fc1 100644
--- a/app/views/projects/blob/edit.html.haml
+++ b/app/views/projects/blob/edit.html.haml
@@ -11,10 +11,9 @@
%i.fa.fa-eye
= editing_preview_title(@blob.name)
- = form_tag(namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put, class: "form-horizontal") do
+ = form_tag(namespace_project_update_blob_path(@project.namespace, @project, @id), method: :put, class: 'form-horizontal js-requires-input') do
= render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
- = render 'shared/commit_message_container', params: params,
- placeholder: "Update #{@blob.name}"
+ = render 'shared/commit_message_container', params: params, placeholder: "Update #{@blob.name}"
.form-group.branch
= label_tag 'branch', class: 'control-label' do
@@ -25,8 +24,7 @@
= hidden_field_tag 'last_commit', @last_commit
= hidden_field_tag 'content', '', id: "file-content"
= hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
- = render 'projects/commit_button', ref: @ref,
- cancel_path: @after_edit_path
+ = render 'projects/commit_button', ref: @ref, cancel_path: @after_edit_path
:javascript
blob = new EditBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", "#{@blob.language.try(:ace_mode)}")
diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml
index f7ddf74b4fc..7c2a4fece94 100644
--- a/app/views/projects/blob/new.html.haml
+++ b/app/views/projects/blob/new.html.haml
@@ -1,7 +1,7 @@
- page_title "New File", @ref
%h3.page-title New file
.file-editor
- = form_tag(namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post, class: 'form-horizontal form-new-file') do
+ = form_tag(namespace_project_create_blob_path(@project.namespace, @project, @id), method: :post, class: 'form-horizontal form-new-file js-requires-input') do
= render 'projects/blob/editor', ref: @ref
= render 'shared/commit_message_container', params: params,
placeholder: 'Add new file'
diff --git a/app/views/projects/branches/new.html.haml b/app/views/projects/branches/new.html.haml
index cac5dc91afd..29e82b93883 100644
--- a/app/views/projects/branches/new.html.haml
+++ b/app/views/projects/branches/new.html.haml
@@ -6,7 +6,7 @@
%h3.page-title
%i.fa.fa-code-fork
New branch
-= form_tag namespace_project_branches_path, method: :post, id: "new-branch-form", class: "form-horizontal" do
+= form_tag namespace_project_branches_path, method: :post, id: "new-branch-form", class: "form-horizontal js-requires-input" do
.form-group
= label_tag :branch_name, 'Name for new branch', class: 'control-label'
.col-sm-10
@@ -20,7 +20,6 @@
= link_to 'Cancel', namespace_project_branches_path(@project.namespace, @project), class: 'btn btn-cancel'
:javascript
- disableButtonIfAnyEmptyField($("#new-branch-form"), ".form-control", ".btn-create");
var availableTags = #{@project.repository.ref_names.to_json};
$("#ref").autocomplete({
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index f9106564a27..74f8d8b15cf 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -1,33 +1,34 @@
-%li.commit.js-toggle-container
- .commit-row-title
- %strong.str-truncated
- = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
- - if commit.description?
- %a.text-expander.js-toggle-button ...
+- if @note_counts
+ - note_count = @note_counts.fetch(commit.id, 0)
+- else
+ - notes = commit.notes
+ - note_count = notes.user.count
- .pull-right
- = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
+= cache [project.id, commit.id, note_count] do
+ %li.commit.js-toggle-container
+ .commit-row-title
+ %strong.str-truncated
+ = link_to_gfm commit.title, namespace_project_commit_path(project.namespace, project, commit.id), class: "commit-row-message"
+ - if commit.description?
+ %a.text-expander.js-toggle-button ...
- .notes_count
- - if @note_counts
- - note_count = @note_counts.fetch(commit.id, 0)
- - else
- - notes = commit.notes
- - note_count = notes.user.count
+ .pull-right
+ = link_to commit.short_id, namespace_project_commit_path(project.namespace, project, commit), class: "commit_short_id"
- - if note_count > 0
- %span.light
- %i.fa.fa-comments
- = note_count
+ .notes_count
+ - if note_count > 0
+ %span.light
+ %i.fa.fa-comments
+ = note_count
- - if commit.description?
- .commit-row-description.js-toggle-content
- %pre
- = preserve(gfm(escape_once(commit.description)))
+ - if commit.description?
+ .commit-row-description.js-toggle-content
+ %pre
+ = preserve(gfm(escape_once(commit.description)))
- .commit-row-info
- = commit_author_link(commit, avatar: true, size: 24)
- authored
- .committed_ago
- #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} &nbsp;
- = link_to_browse_code(project, commit)
+ .commit-row-info
+ = commit_author_link(commit, avatar: true, size: 24)
+ authored
+ .committed_ago
+ #{time_ago_with_tooltip(commit.committed_date, skip_js: true)} &nbsp;
+ = link_to_browse_code(project, commit)
diff --git a/app/views/projects/commits/show.html.haml b/app/views/projects/commits/show.html.haml
index 9682100a54c..55054a31977 100644
--- a/app/views/projects/commits/show.html.haml
+++ b/app/views/projects/commits/show.html.haml
@@ -15,9 +15,8 @@
Create Merge Request
- if current_user && current_user.private_token
- = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Feed", class: 'prepend-left-10 btn' do
+ = link_to namespace_project_commits_path(@project.namespace, @project, @ref, {format: :atom, private_token: current_user.private_token}), title: "Commits Feed", class: 'prepend-left-10 btn' do
= icon("rss")
- Commits Feed
%ul.breadcrumb.repo-breadcrumb
diff --git a/app/views/projects/compare/_form.html.haml b/app/views/projects/compare/_form.html.haml
index a0e904cfd8b..3019893d12c 100644
--- a/app/views/projects/compare/_form.html.haml
+++ b/app/views/projects/compare/_form.html.haml
@@ -1,16 +1,16 @@
-= form_tag namespace_project_compare_index_path(@project.namespace, @project), method: :post, class: 'form-inline' do
+= form_tag namespace_project_compare_index_path(@project.namespace, @project), method: :post, class: 'form-inline js-requires-input' do
.clearfix.append-bottom-20
- if params[:to] && params[:from]
= link_to 'switch', {from: params[:to], to: params[:from]}, {class: 'commits-compare-switch has_tooltip', title: 'Switch base of comparison'}
.form-group
.input-group.inline-input-group
%span.input-group-addon from
- = text_field_tag :from, params[:from], class: "form-control"
+ = text_field_tag :from, params[:from], class: "form-control", required: true
= "..."
.form-group
.input-group.inline-input-group
%span.input-group-addon to
- = text_field_tag :to, params[:to], class: "form-control"
+ = text_field_tag :to, params[:to], class: "form-control", required: true
&nbsp;
= button_tag "Compare", class: "btn btn-create commits-compare-btn"
- if create_mr_button?
@@ -26,5 +26,3 @@
source: availableTags,
minLength: 1
});
-
- disableButtonIfEmptyField('#to', '.commits-compare-btn');
diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml
index cb41dd852d3..37fd1b1ec8a 100644
--- a/app/views/projects/diffs/_parallel_view.html.haml
+++ b/app/views/projects/diffs/_parallel_view.html.haml
@@ -18,7 +18,7 @@
- elsif type_left == 'old' || type_left.nil?
%td.old_line{id: line_code_left, class: "#{type_left}"}
= link_to raw(line_number_left), "##{line_code_left}", id: line_code_left
- - if @comments_allowed && can?(current_user, :write_note, @project)
+ - if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_left, 'old')
%td.line_content{class: "parallel noteable_line #{type_left} #{line_code_left}", "line_code" => line_code_left }= raw line_content_left
@@ -31,7 +31,7 @@
%td.new_line{id: new_line_code, class: "#{new_line_class}", data: { linenumber: line_number_right }}
= link_to raw(line_number_right), "##{new_line_code}", id: new_line_code
- - if @comments_allowed && can?(current_user, :write_note, @project)
+ - if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code_right, 'new')
%td.line_content.parallel{class: "noteable_line #{new_line_class} #{new_line_code}", "line_code" => new_line_code}= raw line_content_right
diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml
index a6373181b45..ed4c601bcdb 100644
--- a/app/views/projects/diffs/_text_file.html.haml
+++ b/app/views/projects/diffs/_text_file.html.haml
@@ -16,7 +16,7 @@
- else
%td.old_line
= link_to raw(type == "new" ? "&nbsp;" : line_old), "##{line_code}", id: line_code
- - if @comments_allowed && can?(current_user, :write_note, @project)
+ - if @comments_allowed && can?(current_user, :create_note, @project)
= link_to_new_diff_note(line_code)
%td.new_line{data: {linenumber: line.new_pos}}
= link_to raw(type == "old" ? "&nbsp;" : line.new_pos) , "##{line_code}", id: line_code
diff --git a/app/views/projects/issues/_discussion.html.haml b/app/views/projects/issues/_discussion.html.haml
index 48858fa32da..f61ae957208 100644
--- a/app/views/projects/issues/_discussion.html.haml
+++ b/app/views/projects/issues/_discussion.html.haml
@@ -1,5 +1,5 @@
- content_for :note_actions do
- - if can?(current_user, :modify_issue, @issue)
+ - if can?(current_user, :update_issue, @issue)
- if @issue.closed?
= link_to 'Reopen Issue', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen js-note-target-reopen', title: 'Reopen Issue'
- else
@@ -12,8 +12,8 @@
.votes-holder.pull-right
#votes= render 'votes/votes_block', votable: @issue
.participants
- %span= pluralize(@issue.participants(current_user).count, 'participant')
- - @issue.participants(current_user).each do |participant|
+ %span= pluralize(@participants.count, 'participant')
+ - @participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
.voting_notes#notes= render 'projects/notes/notes_with_form'
%aside.col-md-3
@@ -23,7 +23,7 @@
= cross_project_reference(@project, @issue)
%hr
.context
- = render partial: 'issue_context', locals: { issue: @issue }
+ = render 'shared/issuable/context', issuable: @issue
- if @issue.labels.any?
.issuable-context-title
diff --git a/app/views/projects/issues/_form.html.haml b/app/views/projects/issues/_form.html.haml
index 8d2564be55e..f39bb7d2574 100644
--- a/app/views/projects/issues/_form.html.haml
+++ b/app/views/projects/issues/_form.html.haml
@@ -3,7 +3,7 @@
%hr
= form_for [@project.namespace.becomes(Namespace), @project, @issue], html: { class: 'form-horizontal issue-form gfm-form' } do |f|
- = render 'projects/issuable_form', f: f, issuable: @issue
+ = render 'shared/issuable/form', f: f, issuable: @issue
:javascript
$('.assign-to-me-link').on('click', function(e){
diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml
index 2c296cab977..1b45bb1af0c 100644
--- a/app/views/projects/issues/_issue.html.haml
+++ b/app/views/projects/issues/_issue.html.haml
@@ -1,44 +1,45 @@
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue) }
- - if controller.controller_name == 'issues'
+ - if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.issue-check
- = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
+ = check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
- .issue-title
- %span.issue-title-text
- = link_to_gfm issue.title, issue_path(issue), class: "row_title"
- .issue-labels
- - issue.labels.each do |label|
- = link_to_label(label, project: issue.project)
- .pull-right.light
- - if issue.closed?
- %span
- CLOSED
- - if issue.assignee
- = link_to_member(@project, issue.assignee, name: false)
- - note_count = issue.notes.user.count
- - if note_count > 0
+ = cache issue do
+ .issue-title
+ %span.issue-title-text
+ = link_to_gfm issue.title, issue_path(issue), class: "row_title"
+ .issue-labels
+ - issue.labels.each do |label|
+ = link_to_label(label, project: issue.project)
+ .pull-right.light
+ - if issue.closed?
+ %span
+ CLOSED
+ - if issue.assignee
+ = link_to_member(@project, issue.assignee, name: false)
+ - note_count = issue.notes.user.count
+ - if note_count > 0
+ &nbsp;
+ %span
+ %i.fa.fa-comments
+ = note_count
+ - else
+ &nbsp;
+ %span.issue-no-comments
+ %i.fa.fa-comments
+ = 0
+
+ .issue-info
+ = "#{issue.to_reference} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
+ - if issue.votes_count > 0
+ = render 'votes/votes_inline', votable: issue
+ - if issue.milestone
&nbsp;
%span
- %i.fa.fa-comments
- = note_count
- - else
- &nbsp;
- %span.issue-no-comments
- %i.fa.fa-comments
- = 0
-
- .issue-info
- = "##{issue.iid} opened #{time_ago_with_tooltip(issue.created_at, placement: 'bottom')} by #{link_to_member(@project, issue.author, avatar: false)}".html_safe
- - if issue.votes_count > 0
- = render 'votes/votes_inline', votable: issue
- - if issue.milestone
- &nbsp;
- %span
- %i.fa.fa-clock-o
- = issue.milestone.title
- - if issue.tasks?
- %span.task-status
- = issue.task_status
+ %i.fa.fa-clock-o
+ = issue.milestone.title
+ - if issue.tasks?
+ %span.task-status
+ = issue.task_status
- .pull-right.issue-updated-at
- %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
+ .pull-right.issue-updated-at
+ %small updated #{time_ago_with_tooltip(issue.updated_at, placement: 'bottom', html_class: 'issue_update_ago')}
diff --git a/app/views/projects/issues/_issue_context.html.haml b/app/views/projects/issues/_issue_context.html.haml
deleted file mode 100644
index 323f5c84a85..00000000000
--- a/app/views/projects/issues/_issue_context.html.haml
+++ /dev/null
@@ -1,46 +0,0 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @issue], remote: true, html: {class: 'edit-issue inline-update js-issue-update'} do |f|
- %div.prepend-top-20
- .issuable-context-title
- %label
- Assignee:
- - if issue.assignee
- %strong= link_to_member(@project, @issue.assignee, size: 24)
- - else
- none
- - if can?(current_user, :modify_issue, @issue)
- = users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id, null_user: true, first_user: true)
-
- %div.prepend-top-20.clearfix
- .issuable-context-title
- %label
- Milestone:
- - if issue.milestone
- %span.back-to-milestone
- = link_to namespace_project_milestone_path(@project.namespace, @project, @issue.milestone) do
- %strong
- %i.fa.fa-clock-o
- = @issue.milestone.title
- - else
- none
- - if can?(current_user, :modify_issue, @issue)
- = f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
- = hidden_field_tag :issue_context
- = f.submit class: 'btn'
-
- - if current_user
- %div.prepend-top-20.clearfix
- .issuable-context-title
- %label
- Subscription:
- %button.btn.btn-block.subscribe-button{:type => 'button'}
- %i.fa.fa-eye
- %span= @issue.subscribed?(current_user) ? "Unsubscribe" : "Subscribe"
- - subscribtion_status = @issue.subscribed?(current_user) ? "subscribed" : "unsubscribed"
- .subscription-status{"data-status" => subscribtion_status}
- .description-block.unsubscribed{class: ( "hidden" if @issue.subscribed?(current_user) )}
- You're not receiving notifications from this thread.
- .description-block.subscribed{class: ( "hidden" unless @issue.subscribed?(current_user) )}
- You're receiving notifications because you're subscribed to this thread.
-
-:coffeescript
- new Subscription("#{toggle_subscription_namespace_project_issue_path(@issue.project.namespace, @project, @issue)}")
diff --git a/app/views/projects/issues/index.html.haml b/app/views/projects/issues/index.html.haml
index 1d5597602d1..d06225f5488 100644
--- a/app/views/projects/issues/index.html.haml
+++ b/app/views/projects/issues/index.html.haml
@@ -11,14 +11,14 @@
= link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
%i.fa.fa-rss
- = render 'shared/issuable_search_form', path: namespace_project_issues_path(@project.namespace, @project)
+ = render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
- - if can? current_user, :write_issue, @project
+ - if can? current_user, :create_issue, @project
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
%i.fa.fa-plus
New Issue
- = render 'shared/issuable_filter', type: :issues
+ = render 'shared/issuable/filter', type: :issues
.issues-holder
= render "issues"
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index ee1b2a08bc4..54d33a5ddd1 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -1,6 +1,6 @@
- page_title "#{@issue.title} (##{@issue.iid})", "Issues"
.issue
- .issue-details
+ .issue-details.issuable-details
%h4.page-title
.issue-box{ class: issue_box_class(@issue) }
- if @issue.closed?
@@ -12,11 +12,11 @@
&middot; created by #{link_to_member(@project, @issue.author)} #{issue_timestamp(@issue)}
.pull-right
- - if can?(current_user, :write_issue, @project)
+ - if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'btn btn-grouped new-issue-link', title: 'New Issue', id: 'new_issue_link' do
= icon('plus')
New Issue
- - if can?(current_user, :modify_issue, @issue)
+ - if can?(current_user, :update_issue, @issue)
- if @issue.closed?
= link_to 'Reopen', issue_path(@issue, issue: {state_event: :reopen}, status_only: true), method: :put, class: 'btn btn-grouped btn-reopen'
- else
@@ -31,7 +31,7 @@
= gfm escape_once(@issue.title)
%div
- if @issue.description.present?
- .description{class: can?(current_user, :modify_issue, @issue) ? 'js-task-list-container' : ''}
+ .description{class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : ''}
.wiki
= preserve do
= markdown(@issue.description)
diff --git a/app/views/projects/issues/update.js.haml b/app/views/projects/issues/update.js.haml
index 1d38662bff8..b7735aaf3c1 100644
--- a/app/views/projects/issues/update.js.haml
+++ b/app/views/projects/issues/update.js.haml
@@ -1,17 +1,3 @@
-- if params[:status_only]
- - if @issue.valid?
- :plain
- $("##{dom_id(@issue)}").fadeOut();
-- elsif params[:issue_context]
- $('.context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
- $('.context').effect('highlight');
- - if @issue.milestone
- $('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, namespace_project_milestone_path(@issue.project.namespace, @issue.project, @issue.milestone))}</span>")
- - else
- $('.milestone-nav-link').html('')
-
-
-$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
-$('.edit-issue.inline-update input[type="submit"]').hide();
-new UsersSelect()
+$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @issue)}");
+$('.context').effect('highlight')
new Issue();
diff --git a/app/views/projects/labels/_form.html.haml b/app/views/projects/labels/_form.html.haml
index d791ed3410c..534c545329b 100644
--- a/app/views/projects/labels/_form.html.haml
+++ b/app/views/projects/labels/_form.html.haml
@@ -1,4 +1,4 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @label], html: { class: 'form-horizontal label-form js-requires-input' } do |f|
-if @label.errors.any?
.row
.col-sm-offset-2.col-sm-10
diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml
index eb3dba6858d..f855dfec321 100644
--- a/app/views/projects/merge_requests/_discussion.html.haml
+++ b/app/views/projects/merge_requests/_discussion.html.haml
@@ -1,5 +1,5 @@
- content_for :note_actions do
- - if can?(current_user, :modify_merge_request, @merge_request)
+ - if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open?
= link_to 'Close', merge_request_path(@merge_request, merge_request: {state_event: :close }), method: :put, class: "btn btn-grouped btn-close close-mr-link js-note-target-close", title: "Close merge request"
- if @merge_request.closed?
@@ -20,7 +20,7 @@
= cross_project_reference(@project, @merge_request)
%hr
.context
- = render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
+ = render 'shared/issuable/context', issuable: @merge_request
- if @merge_request.labels.any?
.issuable-context-title
diff --git a/app/views/projects/merge_requests/_form.html.haml b/app/views/projects/merge_requests/_form.html.haml
index be73f087449..9cf389dbe38 100644
--- a/app/views/projects/merge_requests/_form.html.haml
+++ b/app/views/projects/merge_requests/_form.html.haml
@@ -1,9 +1,8 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form js-requires-input' } do |f|
.merge-request-form-info
- = render 'projects/issuable_form', f: f, issuable: @merge_request
+ = render 'shared/issuable/form', f: f, issuable: @merge_request
:javascript
- disableButtonIfEmptyField("#merge_request_title", ".btn-save");
$('.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/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
index e611b23bca6..ff9c0cdb283 100644
--- a/app/views/projects/merge_requests/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -1,6 +1,6 @@
%p.lead Compare branches for new Merge Request
-= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: new_namespace_project_merge_request_path(@project.namespace, @project), method: :get, html: { class: "merge-request-form form-inline" } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], url: new_namespace_project_merge_request_path(@project.namespace, @project), method: :get, html: { class: "merge-request-form form-inline js-requires-input" } do |f|
.hide.alert.alert-danger.mr-compare-errors
.merge-request-branches.row
.col-md-6
@@ -8,9 +8,9 @@
.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? })
+ = f.select(:source_project_id, [[@merge_request.source_project_path,@merge_request.source_project.id]] , {}, { class: 'source_project select2 span3', disabled: @merge_request.persisted?, required: true })
&nbsp;
- = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2'})
+ = f.select(:source_branch, @merge_request.source_branches, { include_blank: "Select branch" }, {class: 'source_branch select2 span2', required: true})
.panel-footer
.mr_source_commit
@@ -20,9 +20,9 @@
%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? })
+ = 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?, required: true })
&nbsp;
- = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2'})
+ = f.select(:target_branch, @merge_request.target_branches, { include_blank: "Select branch" }, {class: 'target_branch select2 span2', required: true})
.panel-footer
.mr_target_commit
diff --git a/app/views/projects/merge_requests/_new_submit.html.haml b/app/views/projects/merge_requests/_new_submit.html.haml
index 6792104569b..633a54f3620 100644
--- a/app/views/projects/merge_requests/_new_submit.html.haml
+++ b/app/views/projects/merge_requests/_new_submit.html.haml
@@ -9,9 +9,9 @@
%span.pull-right
= link_to 'Change branches', mr_change_branches_path(@merge_request)
%hr
-= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form js-requires-input' } do |f|
.merge-request-form-info
- = render 'projects/issuable_form', f: f, issuable: @merge_request
+ = render 'shared/issuable/form', f: f, issuable: @merge_request
= f.hidden_field :source_project_id
= f.hidden_field :source_branch
= f.hidden_field :target_project_id
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 9dc4a47258e..b6d9b135c70 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -1,6 +1,6 @@
- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
.merge-request{'data-url' => merge_request_path(@merge_request)}
- .merge-request-details
+ .merge-request-details.issuable-details
= render "projects/merge_requests/show/mr_title"
%hr
= render "projects/merge_requests/show/mr_box"
diff --git a/app/views/projects/merge_requests/index.html.haml b/app/views/projects/merge_requests/index.html.haml
index fa591b0537e..e0bc1df97ee 100644
--- a/app/views/projects/merge_requests/index.html.haml
+++ b/app/views/projects/merge_requests/index.html.haml
@@ -1,13 +1,13 @@
- page_title "Merge Requests"
.append-bottom-10
.pull-right
- = render 'shared/issuable_search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
+ = render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
- - if can? current_user, :write_merge_request, @project
+ - if can? current_user, :create_merge_request, @project
.pull-left.hidden-xs
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new", title: "New Merge Request" do
%i.fa.fa-plus
New Merge Request
- = render 'shared/issuable_filter', type: :merge_requests
+ = render 'shared/issuable/filter', type: :merge_requests
.merge-requests-holder
= render 'merge_requests'
diff --git a/app/views/projects/merge_requests/show/_context.html.haml b/app/views/projects/merge_requests/show/_context.html.haml
deleted file mode 100644
index 1d0e2e350b0..00000000000
--- a/app/views/projects/merge_requests/show/_context.html.haml
+++ /dev/null
@@ -1,48 +0,0 @@
-= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update js-merge-request-update'} do |f|
- %div.prepend-top-20
- .issuable-context-title
- %label
- Assignee:
- - if @merge_request.assignee
- %strong= link_to_member(@project, @merge_request.assignee, size: 24)
- - else
- none
- .issuable-context-selectbox
- - if can?(current_user, :modify_merge_request, @merge_request)
- = users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id, project: @target_project, null_user: true)
-
- %div.prepend-top-20.clearfix
- .issuable-context-title
- %label
- Milestone:
- - if @merge_request.milestone
- %span.back-to-milestone
- = link_to namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone) do
- %strong
- = icon('clock-o')
- = @merge_request.milestone.title
- - else
- none
- .issuable-context-selectbox
- - 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 js-select2 js-milestone'})
- = hidden_field_tag :merge_request_context
- = f.submit class: 'btn'
-
- - if current_user
- %div.prepend-top-20.clearfix
- .issuable-context-title
- %label
- Subscription:
- %button.btn.btn-block.subscribe-button{:type => 'button'}
- = icon('eye')
- %span= @merge_request.subscribed?(current_user) ? 'Unsubscribe' : 'Subscribe'
- - subscribtion_status = @merge_request.subscribed?(current_user) ? 'subscribed' : 'unsubscribed'
- .subscription-status{data: {status: subscribtion_status}}
- .description-block.unsubscribed{class: ( 'hidden' if @merge_request.subscribed?(current_user) )}
- You're not receiving notifications from this thread.
- .description-block.subscribed{class: ( 'hidden' unless @merge_request.subscribed?(current_user) )}
- You're receiving notifications because you're subscribed to this thread.
-
-:coffeescript
- new Subscription("#{toggle_subscription_namespace_project_merge_request_path(@merge_request.project.namespace, @project, @merge_request)}")
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 b3470ba37d6..e3cd4346872 100644
--- a/app/views/projects/merge_requests/show/_mr_box.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_box.html.haml
@@ -3,7 +3,7 @@
%div
- if @merge_request.description.present?
- .description{class: can?(current_user, :modify_merge_request, @merge_request) ? 'js-task-list-container' : ''}
+ .description{class: can?(current_user, :update_merge_request, @merge_request) ? 'js-task-list-container' : ''}
.wiki
= preserve do
= markdown(@merge_request.description)
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 83baf157a92..4e8144b4de2 100644
--- a/app/views/projects/merge_requests/show/_mr_title.html.haml
+++ b/app/views/projects/merge_requests/show/_mr_title.html.haml
@@ -7,7 +7,7 @@
created by #{link_to_member(@project, @merge_request.author)} #{time_ago_with_tooltip(@merge_request.created_at)}
.issue-btn-group.pull-right
- - if can?(current_user, :modify_merge_request, @merge_request)
+ - if can?(current_user, :update_merge_request, @merge_request)
- if @merge_request.open?
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "btn btn-grouped btn-close", title: "Close merge request"
= link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "btn btn-grouped issuable-edit", id: "edit_merge_request" do
diff --git a/app/views/projects/merge_requests/show/_participants.html.haml b/app/views/projects/merge_requests/show/_participants.html.haml
index 9c93fa55fe6..c67afe963e7 100644
--- a/app/views/projects/merge_requests/show/_participants.html.haml
+++ b/app/views/projects/merge_requests/show/_participants.html.haml
@@ -1,4 +1,4 @@
.participants
- %span #{@merge_request.participants(current_user).count} participants
- - @merge_request.participants(current_user).each do |participant|
+ %span #{@participants.count} participants
+ - @participants.each do |participant|
= link_to_member(@project, participant, name: false, size: 24)
diff --git a/app/views/projects/merge_requests/update.js.haml b/app/views/projects/merge_requests/update.js.haml
index b4df1d20737..25583b2cc6f 100644
--- a/app/views/projects/merge_requests/update.js.haml
+++ b/app/views/projects/merge_requests/update.js.haml
@@ -1,8 +1,3 @@
-- if params[:merge_request_context]
- $('.context').html("#{escape_javascript(render partial: 'projects/merge_requests/show/context', locals: { issue: @issue })}");
- $('.context').effect('highlight');
-
- new UsersSelect()
-
- $('select.select2').select2({width: 'resolve', dropdownAutoWidth: true});
- merge_request = new MergeRequest();
+$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @merge_request)}");
+$('.context').effect('highlight')
+merge_request = new MergeRequest();
diff --git a/app/views/projects/merge_requests/widget/_heading.html.haml b/app/views/projects/merge_requests/widget/_heading.html.haml
index 107c61477e3..4cc9c652b61 100644
--- a/app/views/projects/merge_requests/widget/_heading.html.haml
+++ b/app/views/projects/merge_requests/widget/_heading.html.haml
@@ -23,6 +23,12 @@
= icon("spinner spin")
Checking for CI status for #{@merge_request.last_commit_short_sha}
+ .ci_widget.ci-not_found{style: "display:none"}
+ = icon("times")
+ %span Can not find commit in the CI server
+ for #{@merge_request.last_commit_short_sha}.
+
+
.ci_widget.ci-canceled{style: "display:none"}
= icon("times")
%span CI build canceled
diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml
index 41aa66dd76b..f5bacaf280a 100644
--- a/app/views/projects/merge_requests/widget/open/_accept.html.haml
+++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml
@@ -1,4 +1,4 @@
-= form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form' } do |f|
+= form_for [:automerge, @project.namespace.becomes(Namespace), @project, @merge_request], remote: true, method: :post, html: { class: 'accept-mr-form js-requires-input' } do |f|
= hidden_field_tag :authenticity_token, form_authenticity_token
.accept-merge-holder.clearfix.js-toggle-container
.accept-action
@@ -25,8 +25,6 @@
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link vlink", title: "How To Merge", "data-toggle" => "modal"
:coffeescript
- disableButtonIfEmptyField '#commit_message', '.accept_merge_request'
-
$('.accept-mr-form').on 'ajax:before', ->
btn = $('.accept_merge_request')
btn.disable()
diff --git a/app/views/projects/milestones/_form.html.haml b/app/views/projects/milestones/_form.html.haml
index 5650607f31f..b93462e5bdf 100644
--- a/app/views/projects/milestones/_form.html.haml
+++ b/app/views/projects/milestones/_form.html.haml
@@ -5,7 +5,7 @@
%hr
-= form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form'} do |f|
+= form_for [@project.namespace.becomes(Namespace), @project, @milestone], html: {class: 'form-horizontal milestone-form gfm-form js-requires-input'} do |f|
-if @milestone.errors.any?
.alert.alert-danger
%ul
@@ -16,7 +16,7 @@
.form-group
= f.label :title, "Title", class: "control-label"
.col-sm-10
- = f.text_field :title, maxlength: 255, class: "form-control"
+ = f.text_field :title, maxlength: 255, class: "form-control", required: true
%p.hint Required
.form-group.milestone-description
= f.label :description, "Description", class: "control-label"
@@ -45,7 +45,6 @@
:javascript
- disableButtonIfEmptyField("#milestone_title", ".btn-save");
$( ".datepicker" ).datepicker({
dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
diff --git a/app/views/projects/milestones/show.html.haml b/app/views/projects/milestones/show.html.haml
index 5c85092a045..5947498e379 100644
--- a/app/views/projects/milestones/show.html.haml
+++ b/app/views/projects/milestones/show.html.haml
@@ -62,7 +62,7 @@
%span.badge= @users.count
.pull-right
- - if can?(current_user, :write_issue, @project)
+ - if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { milestone_id: @milestone.id }), class: "btn btn-grouped", title: "New Issue" do
%i.fa.fa-plus
New Issue
diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml
index c67a7d256a8..a88cf167511 100644
--- a/app/views/projects/network/show.html.haml
+++ b/app/views/projects/network/show.html.haml
@@ -4,8 +4,8 @@
.controls
= form_tag namespace_project_network_path(@project.namespace, @project, @id), method: :get, class: 'form-inline network-form' do |f|
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: "Input an extended SHA1 syntax", class: 'search-input form-control input-mx-250 search-sha'
- = button_tag class: 'btn btn-success btn-search-sha' do
- %i.fa.fa-search
+ = button_tag class: 'btn btn-success' do
+ = icon('search')
.inline.prepend-left-20
.checkbox.light
= label_tag :filter_ref do
@@ -16,8 +16,6 @@
= spinner nil, true
:javascript
- disableButtonIfEmptyField('#extended_sha1', '.btn-search-sha')
-
network_graph = new Network({
url: '#{namespace_project_network_path(@project.namespace, @project, @ref, @options.merge(format: :json))}',
commit_url: '#{namespace_project_commit_path(@project.namespace, @project, 'ae45ca32').gsub("ae45ca32", "%s")}',
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index e56d8615132..5114e63c05f 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -5,13 +5,13 @@
= render 'projects/errors'
.project-edit-content
- = form_for @project, html: { class: 'new_project form-horizontal' } do |f|
+ = form_for @project, html: { class: 'new_project form-horizontal js-requires-input' } do |f|
.form-group.project-name-holder
= f.label :path, class: 'control-label' do
%strong Project path
.col-sm-10
.input-group
- = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 1, autofocus: true
+ = f.text_field :path, placeholder: "my-awesome-project", class: "form-control", tabindex: 1, autofocus: true, required: true
.input-group-addon
\.git
diff --git a/app/views/projects/notes/_note.html.haml b/app/views/projects/notes/_note.html.haml
index 0a77f200f56..5478a887f91 100644
--- a/app/views/projects/notes/_note.html.haml
+++ b/app/views/projects/notes/_note.html.haml
@@ -21,7 +21,7 @@
- if member
%span.note-role.label
= member.human_access
-
+
- if note.system
= link_to user_path(note.author) do
= image_tag avatar_icon(note.author_email), class: 'avatar s16', alt: ''
@@ -56,9 +56,10 @@
.note-body{class: note_editable?(note) ? 'js-task-list-container' : ''}
- .note-text
- = preserve do
- = markdown(note.note, {no_header_anchors: true})
+ = cache [note, 'markdown'] do
+ .note-text
+ = preserve do
+ = markdown(note.note, {no_header_anchors: true})
= render 'projects/notes/edit_form', note: note
- if note.attachment.url
diff --git a/app/views/projects/notes/_notes_with_form.html.haml b/app/views/projects/notes/_notes_with_form.html.haml
index a202e74a892..04222b8f7c4 100644
--- a/app/views/projects/notes/_notes_with_form.html.haml
+++ b/app/views/projects/notes/_notes_with_form.html.haml
@@ -3,7 +3,7 @@
.js-notes-busy
.js-main-target-form
-- if can? current_user, :write_note, @project
+- if can? current_user, :create_note, @project
= render "projects/notes/form", view: params[:view]
:javascript
diff --git a/app/views/projects/snippets/index.html.haml b/app/views/projects/snippets/index.html.haml
index da9401bd8c1..30081673ffc 100644
--- a/app/views/projects/snippets/index.html.haml
+++ b/app/views/projects/snippets/index.html.haml
@@ -1,7 +1,7 @@
- page_title "Snippets"
%h3.page-title
Snippets
- - if can? current_user, :write_project_snippet, @project
+ - if can? current_user, :create_project_snippet, @project
= link_to new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new pull-right", title: "New Snippet" do
Add new snippet
diff --git a/app/views/projects/snippets/show.html.haml b/app/views/projects/snippets/show.html.haml
index 5725d804df3..8cbb813c758 100644
--- a/app/views/projects/snippets/show.html.haml
+++ b/app/views/projects/snippets/show.html.haml
@@ -28,7 +28,7 @@
= @snippet.file_name
.file-actions
.btn-group
- - if can?(current_user, :modify_project_snippet, @snippet)
+ - if can?(current_user, :update_project_snippet, @snippet)
= link_to "edit", edit_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", title: 'Edit Snippet'
= link_to "raw", raw_namespace_project_snippet_path(@project.namespace, @project, @snippet), class: "btn btn-sm", target: "_blank"
- if can?(current_user, :admin_project_snippet, @snippet)
diff --git a/app/views/projects/wikis/_main_links.html.haml b/app/views/projects/wikis/_main_links.html.haml
index 633214a4e86..788bb8cf1e2 100644
--- a/app/views/projects/wikis/_main_links.html.haml
+++ b/app/views/projects/wikis/_main_links.html.haml
@@ -2,7 +2,7 @@
- if (@page && @page.persisted?)
= link_to history_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
Page History
- - if can?(current_user, :write_wiki, @project)
+ - if can?(current_user, :create_wiki, @project)
= link_to edit_namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-grouped" do
%i.fa.fa-pencil-square-o
Edit
diff --git a/app/views/projects/wikis/_nav.html.haml b/app/views/projects/wikis/_nav.html.haml
index 693c3facb32..804a1b52dbe 100644
--- a/app/views/projects/wikis/_nav.html.haml
+++ b/app/views/projects/wikis/_nav.html.haml
@@ -10,7 +10,7 @@
%i.fa.fa-download
Git Access
- - if can?(current_user, :write_wiki, @project)
+ - if can?(current_user, :create_wiki, @project)
.pull-right
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
%i.fa.fa-plus
diff --git a/app/views/shared/issuable/_context.html.haml b/app/views/shared/issuable/_context.html.haml
new file mode 100644
index 00000000000..46990895d33
--- /dev/null
+++ b/app/views/shared/issuable/_context.html.haml
@@ -0,0 +1,50 @@
+= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
+ %div.prepend-top-20
+ .issuable-context-title
+ %label
+ Assignee:
+ - if issuable.assignee
+ %strong= link_to_member(@project, issuable.assignee, size: 24)
+ - else
+ none
+ .issuable-context-selectbox
+ - if can?(current_user, :admin_issue, @project)
+ = users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true)
+
+ %div.prepend-top-20.clearfix
+ .issuable-context-title
+ %label
+ Milestone:
+ - if issuable.milestone
+ %span.back-to-milestone
+ = link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
+ %strong
+ = icon('clock-o')
+ = issuable.milestone.title
+ - else
+ none
+ .issuable-context-selectbox
+ - if can?(current_user, :admin_issue, @project)
+ = f.select(:milestone_id, milestone_options(issuable), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
+ = hidden_field_tag :issuable_context
+ = f.submit class: 'btn hide'
+
+ - if current_user
+ - subscribed = issuable.subscribed?(current_user)
+ %div.prepend-top-20.clearfix
+ .issuable-context-title
+ %label
+ Subscription:
+ %button.btn.btn-block.subscribe-button{:type => 'button'}
+ = icon('eye')
+ %span= subscribed ? 'Unsubscribe' : 'Subscribe'
+ - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
+ .subscription-status{data: {status: subscribtion_status}}
+ .description-block.unsubscribed{class: ( 'hidden' if subscribed )}
+ You're not receiving notifications from this thread.
+ .description-block.subscribed{class: ( 'hidden' unless subscribed )}
+ You're receiving notifications because you're subscribed to this thread.
+
+:coffeescript
+ new Subscription("#{toggle_subscription_path(issuable)}")
+ new IssuableContext()
diff --git a/app/views/shared/_issuable_filter.html.haml b/app/views/shared/issuable/_filter.html.haml
index a355eb62813..a829782fc4f 100644
--- a/app/views/shared/_issuable_filter.html.haml
+++ b/app/views/shared/issuable/_filter.html.haml
@@ -29,11 +29,10 @@
.issues-details-filters
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
- - if controller.controller_name == 'issues'
+ - if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
.check-all-holder
= check_box_tag "check_all_issues", nil, false,
- class: "check_all_issues left",
- disabled: !can?(current_user, :modify_issue, @project)
+ class: "check_all_issues left"
.issues-other-filters
.filter-item.inline
= users_select_tag(:assignee_id, selected: params[:assignee_id],
@@ -64,6 +63,8 @@
= button_tag "Update issues", class: "btn update_selected_issues btn-save"
:coffeescript
+ new UsersSelect()
+
$('form.filter-form').on 'submit', (event) ->
event.preventDefault()
Turbolinks.visit @.action + '&' + $(@).serialize()
diff --git a/app/views/projects/_issuable_form.html.haml b/app/views/shared/issuable/_form.html.haml
index 496fad34dc2..e434e1b6b98 100644
--- a/app/views/projects/_issuable_form.html.haml
+++ b/app/views/shared/issuable/_form.html.haml
@@ -37,47 +37,48 @@
.clearfix
.error-alert
-%hr
-.form-group
- .issue-assignee
- = f.label :assignee_id, class: 'control-label' do
- %i.fa.fa-user
- Assign to
- .col-sm-10
- = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
- placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
- selected: issuable.assignee_id, project: @target_project || @project)
- &nbsp;
- = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
-.form-group
- .issue-milestone
- = f.label :milestone_id, class: 'control-label' do
- %i.fa.fa-clock-o
- Milestone
+ %hr
+- if can?(current_user, :admin_issue, @project)
+ .form-group
+ .issue-assignee
+ = f.label :assignee_id, class: 'control-label' do
+ %i.fa.fa-user
+ Assign to
+ .col-sm-10
+ = users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
+ placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
+ selected: issuable.assignee_id, project: @target_project || @project)
+ &nbsp;
+ = link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
+ .form-group
+ .issue-milestone
+ = f.label :milestone_id, class: 'control-label' do
+ %i.fa.fa-clock-o
+ Milestone
+ .col-sm-10
+ - if milestone_options(issuable).present?
+ = f.select(:milestone_id, milestone_options(issuable),
+ { include_blank: 'Select milestone' }, { class: 'select2' })
+ - else
+ .prepend-top-10
+ %span.light No open milestones available.
+ &nbsp;
+ - if can? current_user, :admin_milestone, issuable.project
+ = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
+ .form-group
+ = f.label :label_ids, class: 'control-label' do
+ %i.fa.fa-tag
+ Labels
.col-sm-10
- - if milestone_options(issuable).present?
- = f.select(:milestone_id, milestone_options(issuable),
- { include_blank: 'Select milestone' }, { class: 'select2' })
+ - if issuable.project.labels.any?
+ = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
+ { selected: issuable.label_ids }, multiple: true, class: 'select2'
- else
.prepend-top-10
- %span.light No open milestones available.
+ %span.light No labels yet.
&nbsp;
- - if can? current_user, :admin_milestone, issuable.project
- = link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
-.form-group
- = f.label :label_ids, class: 'control-label' do
- %i.fa.fa-tag
- Labels
- .col-sm-10
- - if issuable.project.labels.any?
- = f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
- { selected: issuable.label_ids }, multiple: true, class: 'select2'
- - else
- .prepend-top-10
- %span.light No labels yet.
- &nbsp;
- - if can? current_user, :admin_label, issuable.project
- = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
+ - if can? current_user, :admin_label, issuable.project
+ = link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
- if issuable.is_a?(MergeRequest)
%hr
diff --git a/app/views/shared/_issuable_search_form.html.haml b/app/views/shared/issuable/_search_form.html.haml
index 58c3de64b77..58c3de64b77 100644
--- a/app/views/shared/_issuable_search_form.html.haml
+++ b/app/views/shared/issuable/_search_form.html.haml
diff --git a/app/views/snippets/show.html.haml b/app/views/snippets/show.html.haml
index 70a95abde6f..089e8122918 100644
--- a/app/views/snippets/show.html.haml
+++ b/app/views/snippets/show.html.haml
@@ -36,7 +36,7 @@
= @snippet.file_name
.file-actions
.btn-group
- - if can?(current_user, :modify_personal_snippet, @snippet)
+ - if can?(current_user, :update_personal_snippet, @snippet)
= link_to "edit", edit_snippet_path(@snippet), class: "btn btn-sm", title: 'Edit Snippet'
= link_to "raw", raw_snippet_path(@snippet), class: "btn btn-sm", target: "_blank"
- if can?(current_user, :admin_personal_snippet, @snippet)
diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml
index 15d53499e03..43d847831d6 100644
--- a/app/views/users/show.html.haml
+++ b/app/views/users/show.html.haml
@@ -9,7 +9,7 @@
.row
%section.col-md-8
.header-with-avatar
- = link_to avatar_icon(@user.email), target: '_blank' do
+ = link_to avatar_icon(@user.email, 400), target: '_blank' do
= image_tag avatar_icon(@user.email, 90), class: "avatar avatar-tile s90", alt: ''
%h3
= @user.name
diff --git a/config/initializers/6_rack_profiler.rb b/config/initializers/6_rack_profiler.rb
index 5312fd8e89a..1d958904e8f 100644
--- a/config/initializers/6_rack_profiler.rb
+++ b/config/initializers/6_rack_profiler.rb
@@ -5,6 +5,6 @@ if Rails.env.development?
Rack::MiniProfilerRails.initialize!(Rails.application)
Rack::MiniProfiler.config.position = 'right'
- Rack::MiniProfiler.config.start_hidden = true
+ Rack::MiniProfiler.config.start_hidden = false
Rack::MiniProfiler.config.skip_paths << '/teaspoon'
end
diff --git a/db/fixtures/development/01_admin.rb b/db/fixtures/development/01_admin.rb
index bba2fc4b186..b25d0dfc701 100644
--- a/db/fixtures/development/01_admin.rb
+++ b/db/fixtures/development/01_admin.rb
@@ -5,7 +5,7 @@ Gitlab::Seeder.quiet do
s.email = 'admin@example.com'
s.notification_email = 'admin@example.com'
s.username = 'root'
- s.password = '5iveL!fe'
+ s.password = 'password'
s.admin = true
s.projects_limit = 100
s.confirmed_at = DateTime.now
diff --git a/db/fixtures/production/001_admin.rb b/db/fixtures/production/001_admin.rb
index 1c8740f6ba9..1af8dfc0ef0 100644
--- a/db/fixtures/production/001_admin.rb
+++ b/db/fixtures/production/001_admin.rb
@@ -1,5 +1,5 @@
if ENV['GITLAB_ROOT_PASSWORD'].blank?
- password = '5iveL!fe'
+ password = 'password'
expire_time = Time.now
else
password = ENV['GITLAB_ROOT_PASSWORD']
diff --git a/doc/README.md b/doc/README.md
index 28459613252..424b9e9a47e 100644
--- a/doc/README.md
+++ b/doc/README.md
@@ -4,6 +4,7 @@
- [API](api/README.md) Automate GitLab via a simple and powerful API.
- [GitLab as OAuth2 authentication service provider](integration/oauth_provider.md). It allows you to login to other applications from GitLab.
+- [GitLab Basics](gitlab_basics/README.md) Find step by step how to start working on your commandline and on GitLab.
- [Importing to GitLab](workflow/importing/README.md).
- [Markdown](markdown/markdown.md) GitLab's advanced formatting system.
- [Permissions](permissions/permissions.md) Learn what each role in a project (guest/reporter/developer/master/owner) can do.
diff --git a/doc/api/users.md b/doc/api/users.md
index cd141daadc8..8b04282f160 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -58,7 +58,8 @@ GET /users
"is_admin": false,
"avatar_url": "http://localhost:3000/uploads/user/avatar/1/cd8.jpeg",
"can_create_group": true,
- "current_sign_in_at": "2014-03-19T13:12:15Z"
+ "current_sign_in_at": "2014-03-19T13:12:15Z",
+ "two_factor_enabled": true
},
{
"id": 2,
@@ -81,7 +82,8 @@ GET /users
"can_create_group": true,
"can_create_project": true,
"projects_limit": 100,
- "current_sign_in_at": "2014-03-19T17:54:13Z"
+ "current_sign_in_at": "2014-03-19T17:54:13Z",
+ "two_factor_enabled": false
}
]
```
diff --git a/doc/gitlab-basics/README.md b/doc/gitlab-basics/README.md
new file mode 100644
index 00000000000..ffe1c358424
--- /dev/null
+++ b/doc/gitlab-basics/README.md
@@ -0,0 +1,11 @@
+# GitLab basics
+
+Step-by-step guides on the basics of working with Git and GitLab.
+
+* [Start using Git on the commandline](start-using-git.md)
+
+* [Create and add your SSH Keys](create-your-ssh-keys.md)
+
+* [Command Line basic commands](command-line-commands.md)
+
+* [Basic Git commands](basic-git-commands.md)
diff --git a/doc/gitlab-basics/basic-git-commands.md b/doc/gitlab-basics/basic-git-commands.md
new file mode 100644
index 00000000000..ed210ba5420
--- /dev/null
+++ b/doc/gitlab-basics/basic-git-commands.md
@@ -0,0 +1,59 @@
+# Basic Git commands
+
+* Go to the master branch to pull the latest changes from there
+```
+git checkout master
+```
+
+* Download the latest changes in the project, so that you work on an up-to-date copy (this is important to do every time you work on a project), while you setup tracking branches
+```
+git pull REMOTE NAME-OF-BRANCH -u
+```
+(REMOTE: origin) (NAME-OF-BRANCH: could be "master" or an existing branch)
+
+* Create a branch (remember that spaces won't be recognized, you need to use a hyphen or underscore)
+```
+git checkout -b NAME-OF-BRANCH
+```
+
+* Work on a branch that has already been created
+```
+git checkout NAME-OF-BRANCH
+```
+
+* To see the changes you've made (it's important to be aware of what's happening and what's the status of your changes)
+```
+git status
+```
+
+* Add changes to commit (you'll be able to see your changes in red when you type "git status")
+```
+git add CHANGES IN RED
+git commit -m "DESCRIBE THE INTENTION OF THE COMMIT"
+```
+
+* Send changes to gitlab.com
+```
+git push origin NAME-OF-BRANCH
+```
+
+* Throw away all changes in the Git repository, but leave unstaged things
+```
+git checkout .
+```
+
+* Delete all changes in the Git repository, including untracked files
+```
+git clean -f
+```
+
+* Remove all the changes that you don't want to send to gitlab.com
+```
+git add NAME-OF-FILE -all
+```
+
+* Merge created branch with master branch. You need to be in the created branch
+```
+git checkout NAME-OF-BRANCH
+git merge master
+```
diff --git a/doc/gitlab_basics/basicsimages/add_new_merge_request.png b/doc/gitlab-basics/basicsimages/add_new_merge_request.png
index 9d93b217a59..9d93b217a59 100644
--- a/doc/gitlab_basics/basicsimages/add_new_merge_request.png
+++ b/doc/gitlab-basics/basicsimages/add_new_merge_request.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/add_sshkey.png b/doc/gitlab-basics/basicsimages/add_sshkey.png
index 2dede97aa40..2dede97aa40 100644
--- a/doc/gitlab_basics/basicsimages/add_sshkey.png
+++ b/doc/gitlab-basics/basicsimages/add_sshkey.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branch_info.png b/doc/gitlab-basics/basicsimages/branch_info.png
index c5e38b552a5..c5e38b552a5 100644
--- a/doc/gitlab_basics/basicsimages/branch_info.png
+++ b/doc/gitlab-basics/basicsimages/branch_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branch_name.png b/doc/gitlab-basics/basicsimages/branch_name.png
index 06e77f5eea9..06e77f5eea9 100644
--- a/doc/gitlab_basics/basicsimages/branch_name.png
+++ b/doc/gitlab-basics/basicsimages/branch_name.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/branches.png b/doc/gitlab-basics/basicsimages/branches.png
index c18fa83b968..c18fa83b968 100644
--- a/doc/gitlab_basics/basicsimages/branches.png
+++ b/doc/gitlab-basics/basicsimages/branches.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commit_changes.png b/doc/gitlab-basics/basicsimages/commit_changes.png
index 81588336f37..81588336f37 100644
--- a/doc/gitlab_basics/basicsimages/commit_changes.png
+++ b/doc/gitlab-basics/basicsimages/commit_changes.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commit_message.png b/doc/gitlab-basics/basicsimages/commit_message.png
index 0df2c32653c..0df2c32653c 100644
--- a/doc/gitlab_basics/basicsimages/commit_message.png
+++ b/doc/gitlab-basics/basicsimages/commit_message.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/commits.png b/doc/gitlab-basics/basicsimages/commits.png
index 7e606539077..7e606539077 100644
--- a/doc/gitlab_basics/basicsimages/commits.png
+++ b/doc/gitlab-basics/basicsimages/commits.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/compare_braches.png b/doc/gitlab-basics/basicsimages/compare_braches.png
index 7eebaed9075..7eebaed9075 100644
--- a/doc/gitlab_basics/basicsimages/compare_braches.png
+++ b/doc/gitlab-basics/basicsimages/compare_braches.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/create_file.png b/doc/gitlab-basics/basicsimages/create_file.png
index 688e355cca2..688e355cca2 100644
--- a/doc/gitlab_basics/basicsimages/create_file.png
+++ b/doc/gitlab-basics/basicsimages/create_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/create_group.png b/doc/gitlab-basics/basicsimages/create_group.png
index 57da898abdc..57da898abdc 100644
--- a/doc/gitlab_basics/basicsimages/create_group.png
+++ b/doc/gitlab-basics/basicsimages/create_group.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/edit_file.png b/doc/gitlab-basics/basicsimages/edit_file.png
index afa68760108..afa68760108 100644
--- a/doc/gitlab_basics/basicsimages/edit_file.png
+++ b/doc/gitlab-basics/basicsimages/edit_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/file_located.png b/doc/gitlab-basics/basicsimages/file_located.png
index 1def489d16b..1def489d16b 100644
--- a/doc/gitlab_basics/basicsimages/file_located.png
+++ b/doc/gitlab-basics/basicsimages/file_located.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/file_name.png b/doc/gitlab-basics/basicsimages/file_name.png
index 9ac2f1c355f..9ac2f1c355f 100644
--- a/doc/gitlab_basics/basicsimages/file_name.png
+++ b/doc/gitlab-basics/basicsimages/file_name.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/find_file.png b/doc/gitlab-basics/basicsimages/find_file.png
index 98639149a39..98639149a39 100644
--- a/doc/gitlab_basics/basicsimages/find_file.png
+++ b/doc/gitlab-basics/basicsimages/find_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/find_group.png b/doc/gitlab-basics/basicsimages/find_group.png
index 5ac33c7e953..5ac33c7e953 100644
--- a/doc/gitlab_basics/basicsimages/find_group.png
+++ b/doc/gitlab-basics/basicsimages/find_group.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/fork.png b/doc/gitlab-basics/basicsimages/fork.png
index b1f94938613..b1f94938613 100644
--- a/doc/gitlab_basics/basicsimages/fork.png
+++ b/doc/gitlab-basics/basicsimages/fork.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/group_info.png b/doc/gitlab-basics/basicsimages/group_info.png
index e78d84e4d80..e78d84e4d80 100644
--- a/doc/gitlab_basics/basicsimages/group_info.png
+++ b/doc/gitlab-basics/basicsimages/group_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/groups.png b/doc/gitlab-basics/basicsimages/groups.png
index b8104343afa..b8104343afa 100644
--- a/doc/gitlab_basics/basicsimages/groups.png
+++ b/doc/gitlab-basics/basicsimages/groups.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/https.png b/doc/gitlab-basics/basicsimages/https.png
index 2a31b4cf751..2a31b4cf751 100644
--- a/doc/gitlab_basics/basicsimages/https.png
+++ b/doc/gitlab-basics/basicsimages/https.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/image_file.png b/doc/gitlab-basics/basicsimages/image_file.png
index 1061d9c5082..1061d9c5082 100644
--- a/doc/gitlab_basics/basicsimages/image_file.png
+++ b/doc/gitlab-basics/basicsimages/image_file.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/issue_title.png b/doc/gitlab-basics/basicsimages/issue_title.png
index 7b69c705392..7b69c705392 100644
--- a/doc/gitlab_basics/basicsimages/issue_title.png
+++ b/doc/gitlab-basics/basicsimages/issue_title.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/issues.png b/doc/gitlab-basics/basicsimages/issues.png
index 9354d05319e..9354d05319e 100644
--- a/doc/gitlab_basics/basicsimages/issues.png
+++ b/doc/gitlab-basics/basicsimages/issues.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/key.png b/doc/gitlab-basics/basicsimages/key.png
index 321805cda98..321805cda98 100644
--- a/doc/gitlab_basics/basicsimages/key.png
+++ b/doc/gitlab-basics/basicsimages/key.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/merge_requests.png b/doc/gitlab-basics/basicsimages/merge_requests.png
index 7601d40de47..7601d40de47 100644
--- a/doc/gitlab_basics/basicsimages/merge_requests.png
+++ b/doc/gitlab-basics/basicsimages/merge_requests.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_issue.png b/doc/gitlab-basics/basicsimages/new_issue.png
index 94e7503dd8b..94e7503dd8b 100644
--- a/doc/gitlab_basics/basicsimages/new_issue.png
+++ b/doc/gitlab-basics/basicsimages/new_issue.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_merge_request.png b/doc/gitlab-basics/basicsimages/new_merge_request.png
index 9120d2b1ab1..9120d2b1ab1 100644
--- a/doc/gitlab_basics/basicsimages/new_merge_request.png
+++ b/doc/gitlab-basics/basicsimages/new_merge_request.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/new_project.png b/doc/gitlab-basics/basicsimages/new_project.png
index ac255270a66..ac255270a66 100644
--- a/doc/gitlab_basics/basicsimages/new_project.png
+++ b/doc/gitlab-basics/basicsimages/new_project.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/newbranch.png b/doc/gitlab-basics/basicsimages/newbranch.png
index da1a6b604ea..da1a6b604ea 100644
--- a/doc/gitlab_basics/basicsimages/newbranch.png
+++ b/doc/gitlab-basics/basicsimages/newbranch.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/paste_sshkey.png b/doc/gitlab-basics/basicsimages/paste_sshkey.png
index 9880ddfead1..9880ddfead1 100644
--- a/doc/gitlab_basics/basicsimages/paste_sshkey.png
+++ b/doc/gitlab-basics/basicsimages/paste_sshkey.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/profile_settings.png b/doc/gitlab-basics/basicsimages/profile_settings.png
index 5f2e7a7e10c..5f2e7a7e10c 100644
--- a/doc/gitlab_basics/basicsimages/profile_settings.png
+++ b/doc/gitlab-basics/basicsimages/profile_settings.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/project_info.png b/doc/gitlab-basics/basicsimages/project_info.png
index 6c06ff351fa..6c06ff351fa 100644
--- a/doc/gitlab_basics/basicsimages/project_info.png
+++ b/doc/gitlab-basics/basicsimages/project_info.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/public_file_link.png b/doc/gitlab-basics/basicsimages/public_file_link.png
index 1a60a3d880a..1a60a3d880a 100644
--- a/doc/gitlab_basics/basicsimages/public_file_link.png
+++ b/doc/gitlab-basics/basicsimages/public_file_link.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/select_branch.png b/doc/gitlab-basics/basicsimages/select_branch.png
index 3475b2df576..3475b2df576 100644
--- a/doc/gitlab_basics/basicsimages/select_branch.png
+++ b/doc/gitlab-basics/basicsimages/select_branch.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/select_project.png b/doc/gitlab-basics/basicsimages/select_project.png
index 6d5aa439124..6d5aa439124 100644
--- a/doc/gitlab_basics/basicsimages/select_project.png
+++ b/doc/gitlab-basics/basicsimages/select_project.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/settings.png b/doc/gitlab-basics/basicsimages/settings.png
index 9bf9c5a0d39..9bf9c5a0d39 100644
--- a/doc/gitlab_basics/basicsimages/settings.png
+++ b/doc/gitlab-basics/basicsimages/settings.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/shh_keys.png b/doc/gitlab-basics/basicsimages/shh_keys.png
index d7ef4dafe77..d7ef4dafe77 100644
--- a/doc/gitlab_basics/basicsimages/shh_keys.png
+++ b/doc/gitlab-basics/basicsimages/shh_keys.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/submit_new_issue.png b/doc/gitlab-basics/basicsimages/submit_new_issue.png
index 18944417085..18944417085 100644
--- a/doc/gitlab_basics/basicsimages/submit_new_issue.png
+++ b/doc/gitlab-basics/basicsimages/submit_new_issue.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/title_description_mr.png b/doc/gitlab-basics/basicsimages/title_description_mr.png
index e08eb628414..e08eb628414 100644
--- a/doc/gitlab_basics/basicsimages/title_description_mr.png
+++ b/doc/gitlab-basics/basicsimages/title_description_mr.png
Binary files differ
diff --git a/doc/gitlab_basics/basicsimages/white_space.png b/doc/gitlab-basics/basicsimages/white_space.png
index 6363a09360e..6363a09360e 100644
--- a/doc/gitlab_basics/basicsimages/white_space.png
+++ b/doc/gitlab-basics/basicsimages/white_space.png
Binary files differ
diff --git a/doc/gitlab-basics/command-line-commands.md b/doc/gitlab-basics/command-line-commands.md
new file mode 100644
index 00000000000..a15e275f27a
--- /dev/null
+++ b/doc/gitlab-basics/command-line-commands.md
@@ -0,0 +1,72 @@
+# Command Line basic commands
+
+## Start working on your project
+
+* In Git, when you copy a project you say you "clone" it. To work on a git project locally (from your own computer), you will need to clone it. To do this, start by signing in at GitLab.com.. To do it, go to your [gitlab.com](https://gitlab.com) account
+
+* When you are on your Dashboard, click on the project that you'd like to clone, which you'll find at the right side of your screen
+
+![Select a project](basicsimages/select_project.png)
+
+* To work in the project, you can copy a link to the Git repository through a SSH or a HTTPS protocol. SSH is easier to use after it's been [setup](create-your-ssh-keys.md). When you're in the project, click on the HTTPS or SSH button at the right side of your screen. Then copy the link (you'll have to paste it on your shell in the next step)
+
+![Copy the HTTPS or SSH](basicsimages/https.png)
+
+## On the command line
+
+* To clone your project, go to your computer's shell and type the following command
+```
+git clone PASTE HTTPS OR SSH HERE
+```
+
+* A clone of the project will be created in your computer
+
+* Go into a project, directory or file to work in it
+```
+cd NAME-OF-PROJECT-OR-FILE
+```
+
+* Go back one directory or file
+```
+cd ../
+```
+
+* To see what’s in the directory that you are in
+```
+ls
+```
+
+* Create a directory
+```
+mkdir NAME-OF-YOUR-DIRECTORY
+```
+
+* Create a README.md or file in directory
+```
+touch README.md
+nano README.md
+#### ADD YOUR INFORMATION
+#### Press: control + X
+#### Type: Y
+#### Press: enter
+```
+
+* Remove a file
+```
+rm NAME-OF-FILE
+```
+
+* Remove a directory and all of its contents
+```
+rm -rf NAME-OF-DIRECTORY
+```
+
+* View history in the command line
+```
+history
+```
+
+* Carry out commands for which the account you are using lacks authority. (You will be asked for an administrator’s password)
+```
+sudo
+```
diff --git a/doc/gitlab-basics/create-your-ssh-keys.md b/doc/gitlab-basics/create-your-ssh-keys.md
new file mode 100644
index 00000000000..2b6a1f2d808
--- /dev/null
+++ b/doc/gitlab-basics/create-your-ssh-keys.md
@@ -0,0 +1,37 @@
+# How to create your SSH Keys
+
+You need to connect your computer to your GitLab account through SSH Keys. They are unique for every computer that you link your GitLab account with.
+
+## Generate your SSH Key
+
+* Create an account on GitLab. Sign up and check your email for your confirmation link
+
+* After you confirm, go to [gitlab.com](https://about.gitlab.com/) and sign in to your account
+
+## Add your SSH Key
+
+* At the top right corner, click on "profile settings"
+
+![profile settings](basicsimages/profile_settings.png)
+
+* On the left side menu click on "SSH Keys"
+
+![SSH Keys](basicsimages/shh_keys.png)
+
+* Then click on the green button "Add SSH Key"
+
+![Add SSH Key](basicsimages/add_sshkey.png)
+
+* There, you should paste the SSH Key that your commandline will generate for you. Below you'll find the steps to generate it
+
+![Paste SSH Key](basicsimages/paste_sshkey.png)
+
+## To generate an SSH Key on your commandline
+
+* Go to your [commandline](start-using-git.md) and follow the [instructions](https://gitlab.com/help/ssh/README) to generate it
+
+* Copy the SSH Key that your commandline created and paste it on the "Key" box on the GitLab page. The title will be added automatically
+
+![Paste SSH Key](basicsimages/key.png)
+
+* Now, you'll be able to use Git over SSH, instead of Git over HTTP.
diff --git a/doc/gitlab_basics/start_using_git.md b/doc/gitlab-basics/start-using-git.md
index f01a2f77eec..99103469ccc 100644
--- a/doc/gitlab_basics/start_using_git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -40,7 +40,7 @@ git config --global user.name ADD YOUR USERNAME
* Then verify that you have the correct username
-```
+```
git config --global user.name
```
@@ -52,7 +52,7 @@ git config --global user.email ADD YOUR EMAIL
* To verify that you entered your email correctly, type
-```
+```
git config --global user.email
```
@@ -62,6 +62,6 @@ git config --global user.email
* To view the information that you entered, type
-```
+```
git config --global --list
```
diff --git a/doc/gitlab_basics/README.md b/doc/gitlab_basics/README.md
deleted file mode 100644
index c434e0146e3..00000000000
--- a/doc/gitlab_basics/README.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# GitLab basics
-
-Step-by-step guides on the basics of working with Git and GitLab.
-
-* [Start using Git on the commandline](start_using_git.md)
-
-
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 8b918cba133..cf58abea4eb 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -404,7 +404,7 @@ NOTE: Supply `SANITIZE=true` environment variable to `gitlab:check` to omit proj
Visit YOUR_SERVER in your web browser for your first GitLab login. The setup has created a default admin account for you. You can use it to log in:
root
- 5iveL!fe
+ password
**Important Note:** On login you'll be prompted to change the password.
diff --git a/doc/integration/README.md b/doc/integration/README.md
index 286bd34a0bd..6d856951d4e 100644
--- a/doc/integration/README.md
+++ b/doc/integration/README.md
@@ -7,6 +7,7 @@ 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, GitLab, and Google via OAuth.
+- [SAML](saml.md) Configure GitLab as a SAML 2.0 Service Provider
- [Slack](slack.md) Integrate with the Slack chat service
- [OAuth2 provider](oauth_provider.md) OAuth2 application creation
- [Gmail](gitlab_buttons_in_gmail.md) Adds GitLab actions to messages
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index 8cfa7f9c876..70b7e17795d 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -15,6 +15,8 @@ If a user is a GitLab administrator they receive all permissions.
| Pull project code | | ✓ | ✓ | ✓ | ✓ |
| Download project | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
+| Manage issue tracker | | ✓ | ✓ | ✓ | ✓ |
+| Manage labels | | ✓ | ✓ | ✓ | ✓ |
| Create new merge request | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
@@ -22,8 +24,6 @@ If a user is a GitLab administrator they receive all permissions.
| Remove non-protected branches | | | ✓ | ✓ | ✓ |
| Add tags | | | ✓ | ✓ | ✓ |
| Write a wiki | | | ✓ | ✓ | ✓ |
-| Manage issue tracker | | | ✓ | ✓ | ✓ |
-| Manage labels | | | ✓ | ✓ | ✓ |
| Create new milestones | | | | ✓ | ✓ |
| Add new team members | | | | ✓ | ✓ |
| Push to protected branches | | | | ✓ | ✓ |
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index ae2d465e0c1..39a13b14fba 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -19,7 +19,7 @@ sudo gitlab-rake gitlab:backup:create
sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
```
-Also you can choose what should be backed up by adding environment variable SKIP. Available options: db,
+Also you can choose what should be backed up by adding environment variable SKIP. Available options: db,
uploads (attachments), repositories. Use a comma to specify several options at the same time.
```
@@ -300,6 +300,25 @@ Example: LVM snapshots + rsync
If you are running GitLab on a virtualized server you can possibly also create VM snapshots of the entire GitLab server.
It is not uncommon however for a VM snapshot to require you to power down the server, so this approach is probably of limited practical use.
-### Note
-This documentation is for GitLab CE.
-We backup GitLab.com and make sure your data is secure, but you can't use these methods to export / backup your data yourself from GitLab.com. \ No newline at end of file
+## Troubleshooting
+
+### Restoring database backup using omnibus packages outputs warnings
+If you are using backup restore procedures you might encounter the following warnings:
+
+```
+psql:/var/opt/gitlab/backups/db/database.sql:22: ERROR: must be owner of extension plpgsql
+psql:/var/opt/gitlab/backups/db/database.sql:2931: WARNING: no privileges could be revoked for "public" (two occurences)
+psql:/var/opt/gitlab/backups/db/database.sql:2933: WARNING: no privileges were granted for "public" (two occurences)
+
+```
+
+Be advised that, backup is successfully restored in spite of these warnings.
+
+The rake task runs this as the `gitlab` user which does not have the superuser access to the database. When restore is initiated it will also run as `gitlab` user but it will also try to alter the objects it does not have access to.
+Those objects have no influence on the database backup/restore but they give this annoying warning.
+
+For more information see similar questions on postgresql issue tracker[here](http://www.postgresql.org/message-id/201110220712.30886.adrian.klaver@gmail.com) and [here](http://www.postgresql.org/message-id/2039.1177339749@sss.pgh.pa.us) as well as [stack overflow](http://stackoverflow.com/questions/4368789/error-must-be-owner-of-language-plpgsql).
+
+## Note
+This documentation is for GitLab CE.
+We backup GitLab.com and make sure your data is secure, but you can't use these methods to export / backup your data yourself from GitLab.com.
diff --git a/doc/workflow/importing/import_projects_from_github.md b/doc/workflow/importing/import_projects_from_github.md
index aad2c63817d..3efa92cb868 100644
--- a/doc/workflow/importing/import_projects_from_github.md
+++ b/doc/workflow/importing/import_projects_from_github.md
@@ -3,6 +3,8 @@
It takes just a couple of steps to import your existing GitHub projects to GitLab. Keep in mind that it is possible only if
GitHub support is enabled on your GitLab instance. You can read more about GitHub support [here](http://doc.gitlab.com/ce/integration/github.html)
+If you want to import from a GitHub Enterprise instance, you need to use GitLab Enterprise; please see the [EE docs for the GitHub integration](http://doc.gitlab.com/ee/integration/github.html).
+
* Sign in to GitLab.com and go to your dashboard.
* To get to the importer page, you need to go to the "New project" page.
@@ -15,4 +17,4 @@ GitHub support is enabled on your GitLab instance. You can read more about GitHu
* To import a project, you can simple click "Add". The importer will import your repository and issues. Once the importer is done, a new GitLab project will be created with your imported data.
### Note
-When you import your projects from GitHub, it is not possible to keep your labels and milestones and issue numbers won't match. We are working on improving this in the near future. \ No newline at end of file
+When you import your projects from GitHub, it is not possible to keep your labels and milestones and issue numbers won't match. We are working on improving this in the near future.
diff --git a/doc_styleguide.md b/doc_styleguide.md
index db30a737f14..656bb1d17ff 100644
--- a/doc_styleguide.md
+++ b/doc_styleguide.md
@@ -4,20 +4,21 @@ This styleguide recommends best practices to improve documentation and to keep i
## Text
-* Make sure that the documentation is added in the correct directory and that there's a link to it somewhere useful.
-
-* Add only one H1 or title in each document, by adding '#' at the begining of it (when using markdown). For subtitles, use '##', '###' and so on.
-
-* Do not duplicate information.
-
-* Be brief and clear.
-
-* Whenever it applies, add documents in alphabetical order.
-
-## When adding images to a document
-
-* Create a directory to store the images with the specific name of the document where the images belong. It could be in the same directory where the .md document that you're working on is located.
-
-* Images should have a specific, non-generic name that will differentiate them.
-
-* Keep all file names in lower case. \ No newline at end of file
+- Split up long lines, this makes it much easier to review and edit. Only
+double line breaks are shown as a full line break in markdown. 80 characters
+is a good line length.
+- For subtitles, make sure to start with the largest and go down, meaning:
+`#` for the title, `##` for subtitles and `###` for subtitles of the subtitles, etc.
+- Make sure that the documentation is added in the correct directory and that there's a link to it somewhere useful.
+- Add only one H1 or title in each document, by adding '#' at the begining of it (when using markdown).
+For subtitles, use '##', '###' and so on.
+- Do not duplicate information.
+- Be brief and clear.
+- Whenever it applies, add documents in alphabetical order.
+
+## Images
+
+- Create a directory to store the images with the specific name of the document where the images belong.
+It could be in the same directory where the .md document that you're working on is located.
+- Images should have a specific, non-generic name that will differentiate them.
+- Keep all file names in lower case. \ No newline at end of file
diff --git a/docker/README.md b/docker/README.md
index fb3bde5016d..9507aa6a63c 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -13,7 +13,7 @@ It might take a while before the docker container is responding to queries.
You can check the status with something like `sudo docker logs -f 7c10172d7705`.
-You can login to the web interface with username `root` and password `5iveL!fe`.
+You can login to the web interface with username `root` and password `password`.
Next time, you can just use docker start and stop to run the container.
@@ -159,4 +159,4 @@ sudo docker push sytse/gitlab-data
## Troubleshooting
-Please see the [troubleshooting](troubleshooting.md) file in this directory. \ No newline at end of file
+Please see the [troubleshooting](troubleshooting.md) file in this directory.
diff --git a/features/project/forked_merge_requests.feature b/features/project/forked_merge_requests.feature
index ad1160e3343..10bd6fec803 100644
--- a/features/project/forked_merge_requests.feature
+++ b/features/project/forked_merge_requests.feature
@@ -26,7 +26,6 @@ Feature: Project Forked Merge Requests
#And I save the merge request
#Then I should see the edited merge request
- @javascript
Scenario: I cannot submit an invalid merge request
Given I visit project "Forked Shop" merge requests page
And I click link "New Merge Request"
diff --git a/features/project/issues/issues.feature b/features/project/issues/issues.feature
index bf84e2f8e87..a15298fc452 100644
--- a/features/project/issues/issues.feature
+++ b/features/project/issues/issues.feature
@@ -184,3 +184,15 @@ Feature: Project Issues
Then I should see that I am subscribed
When I click button "Unsubscribe"
Then I should see that I am unsubscribed
+
+ Scenario: I submit new unassigned issue as guest
+ Given I logout
+ Given public project "Community"
+ When I visit project "Community" page
+ And I click link "New Issue"
+ And I should not see assignee field
+ And I should not see milestone field
+ And I should not see labels field
+ And I submit new issue "500 error on profile"
+ Then I should see issue "500 error on profile"
+
diff --git a/features/project/merge_requests.feature b/features/project/merge_requests.feature
index 35ffa9fc6e1..947f668e432 100644
--- a/features/project/merge_requests.feature
+++ b/features/project/merge_requests.feature
@@ -63,7 +63,7 @@ Feature: Project Merge Requests
Scenario: I comment on a merge request diff
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is wrong" on diff
And I switch to the merge request's comments tab
Then I should see a discussion has started on diff
@@ -114,7 +114,7 @@ Feature: Project Merge Requests
Scenario: I hide comments on a merge request diff with comments in a single file
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is wrong" on line 39 of the second file
And I click link "Hide inline discussion" of the second file
Then I should not see a comment like "Line is wrong here" in the second file
@@ -123,7 +123,7 @@ Feature: Project Merge Requests
Scenario: I show comments on a merge request diff with comments in a single file
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is wrong" on line 39 of the second file
Then I should see a comment like "Line is wrong" in the second file
@@ -131,7 +131,7 @@ Feature: Project Merge Requests
Scenario: I hide comments on a merge request diff with comments in multiple files
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is correct" on line 12 of the first file
And I leave a comment like "Line is wrong" on line 39 of the second file
And I click link "Hide inline discussion" of the second file
@@ -142,7 +142,7 @@ Feature: Project Merge Requests
Scenario: I show comments on a merge request diff with comments in multiple files
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is correct" on line 12 of the first file
And I leave a comment like "Line is wrong" on line 39 of the second file
And I click link "Hide inline discussion" of the second file
@@ -154,7 +154,7 @@ Feature: Project Merge Requests
Scenario: I unfold diff
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I unfold diff
Then I should see additional file lines
@@ -162,7 +162,7 @@ Feature: Project Merge Requests
Scenario: I show comments on a merge request side-by-side diff with comments in multiple files
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I switch to the diff tab
+ And I click on the Changes tab
And I leave a comment like "Line is correct" on line 12 of the first file
And I leave a comment like "Line is wrong" on line 39 of the second file
And I click Side-by-side Diff tab
@@ -172,7 +172,7 @@ Feature: Project Merge Requests
Scenario: I view diffs on a merge request
Given project "Shop" have "Bug NS-05" open merge request with diffs inside
And I visit merge request page "Bug NS-05"
- And I click on the Changes tab via Javascript
+ And I click on the Changes tab
Then I should see the proper Inline and Side-by-side links
# Description preview
diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb
index fabbc1d3d81..9e96fa5ba49 100644
--- a/features/steps/project/active_tab.rb
+++ b/features/steps/project/active_tab.rb
@@ -20,8 +20,8 @@ class Spinach::Features::ProjectActiveTab < Spinach::FeatureSteps
end
step 'I click the "Edit" tab' do
- page.within '.project-settings-nav' do
- click_link('Project')
+ page.within '.sidebar-subnav' do
+ click_link('Project Settings')
end
end
diff --git a/features/steps/project/issues/issues.rb b/features/steps/project/issues/issues.rb
index 6873c043e19..9ace6436b15 100644
--- a/features/steps/project/issues/issues.rb
+++ b/features/steps/project/issues/issues.rb
@@ -19,12 +19,11 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
step 'I should see that I am subscribed' do
- expect(find(".subscribe-button span").text).to eq "Unsubscribe"
+ expect(find('.subscribe-button span')).to have_content 'Unsubscribe'
end
step 'I should see that I am unsubscribed' do
- sleep 0.2
- expect(find(".subscribe-button span").text).to eq "Subscribe"
+ expect(find('.subscribe-button span')).to have_content 'Subscribe'
end
step 'I click link "Closed"' do
@@ -262,6 +261,24 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
end
end
+ step 'I should not see labels field' do
+ page.within '.issue-form' do
+ expect(page).not_to have_content("Labels")
+ end
+ end
+
+ step 'I should not see milestone field' do
+ page.within '.issue-form' do
+ expect(page).not_to have_content("Milestone")
+ end
+ end
+
+ step 'I should not see assignee field' do
+ page.within '.issue-form' do
+ expect(page).not_to have_content("Assign to")
+ end
+ end
+
def filter_issue(text)
fill_in 'issue_search', with: text
end
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index f11edb659d5..a1a26abd8ca 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -58,11 +58,11 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see that I am subscribed' do
- expect(find(".subscribe-button span").text).to eq "Unsubscribe"
+ expect(find('.subscribe-button span')).to have_content 'Unsubscribe'
end
step 'I should see that I am unsubscribed' do
- expect(find(".subscribe-button span")).to have_content("Subscribe")
+ expect(find('.subscribe-button span')).to have_content 'Subscribe'
end
step 'I click button "Unsubscribe"' do
@@ -118,25 +118,17 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
author: project.users.first)
end
- step 'I switch to the diff tab' do
- visit diffs_namespace_project_merge_request_path(project.namespace, project, merge_request)
- end
-
- step 'I click on the Changes tab via Javascript' do
+ step 'I click on the Changes tab' do
page.within '.merge-request-tabs' do
click_link 'Changes'
end
- sleep 2
+ # Waits for load
+ expect(page).to have_css('.tab-content #diffs.active')
end
step 'I should see the proper Inline and Side-by-side links' do
- buttons = page.all('#commit-diff-viewtype')
- expect(buttons.count).to eq(2)
-
- buttons.each do |b|
- expect(b['href']).not_to have_content('json')
- end
+ expect(page).to have_css('#commit-diff-viewtype', count: 2)
end
step 'I switch to the merge request\'s comments tab' do
@@ -301,6 +293,8 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I unfold diff' do
+ expect(page).to have_css('.js-unfold')
+
first('.js-unfold').click
end
diff --git a/lib/api/entities.rb b/lib/api/entities.rb
index b23eff3661c..14a8f929d76 100644
--- a/lib/api/entities.rb
+++ b/lib/api/entities.rb
@@ -24,6 +24,7 @@ module API
expose :identities, using: Entities::Identity
expose :can_create_group?, as: :can_create_group
expose :can_create_project?, as: :can_create_project
+ expose :two_factor_enabled
end
class UserLogin < UserFull
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index c8db93eb778..6e7a7672070 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -144,7 +144,7 @@ module API
# PUT /projects/:id/issues/:issue_id
put ":id/issues/:issue_id" do
issue = user_project.issues.find(params[:issue_id])
- authorize! :modify_issue, issue
+ authorize! :update_issue, issue
attrs = attributes_for_keys [:title, :description, :assignee_id, :milestone_id, :state_event]
# Validate label names in advance
@@ -157,7 +157,7 @@ module API
if issue.valid?
# Find or create labels and attach to issue. Labels are valid because
# we already checked its name, so there can't be an error here
- unless params[:labels].nil?
+ if params[:labels] && can?(current_user, :admin_issue, user_project)
issue.remove_labels
# Create and add labels to the new created issue
issue.add_labels_by_names(params[:labels].split(','))
diff --git a/lib/api/merge_requests.rb b/lib/api/merge_requests.rb
index d835dce2ded..aa43e1dffd9 100644
--- a/lib/api/merge_requests.rb
+++ b/lib/api/merge_requests.rb
@@ -109,7 +109,7 @@ module API
# POST /projects/:id/merge_requests
#
post ":id/merge_requests" do
- authorize! :write_merge_request, user_project
+ authorize! :create_merge_request, user_project
required_attributes! [:source_branch, :target_branch, :title]
attrs = attributes_for_keys [:source_branch, :target_branch, :assignee_id, :title, :target_project_id, :description]
@@ -149,7 +149,7 @@ module API
put ":id/merge_request/:merge_request_id" do
attrs = attributes_for_keys [:target_branch, :assignee_id, :title, :state_event, :description]
merge_request = user_project.merge_requests.find(params[:merge_request_id])
- authorize! :modify_merge_request, merge_request
+ authorize! :update_merge_request, merge_request
# Ensure source_branch is not specified
if params[:source_branch].present?
diff --git a/lib/api/project_snippets.rb b/lib/api/project_snippets.rb
index 54f2555903f..22ce3c6a066 100644
--- a/lib/api/project_snippets.rb
+++ b/lib/api/project_snippets.rb
@@ -46,7 +46,7 @@ module API
# Example Request:
# POST /projects/:id/snippets
post ":id/snippets" do
- authorize! :write_project_snippet, user_project
+ authorize! :create_project_snippet, user_project
required_attributes! [:title, :file_name, :code, :visibility_level]
attrs = attributes_for_keys [:title, :file_name, :visibility_level]
@@ -74,7 +74,7 @@ module API
# PUT /projects/:id/snippets/:snippet_id
put ":id/snippets/:snippet_id" do
@snippet = user_project.snippets.find(params[:snippet_id])
- authorize! :modify_project_snippet, @snippet
+ authorize! :update_project_snippet, @snippet
attrs = attributes_for_keys [:title, :file_name, :visibility_level]
attrs[:content] = params[:code] if params[:code].present?
@@ -98,7 +98,7 @@ module API
delete ":id/snippets/:snippet_id" do
begin
@snippet = user_project.snippets.find(params[:snippet_id])
- authorize! :modify_project_snippet, @snippet
+ authorize! :update_project_snippet, @snippet
@snippet.destroy
rescue
not_found!('Snippet')
diff --git a/lib/extracts_path.rb b/lib/extracts_path.rb
index 6e4ed01e079..3f420553d42 100644
--- a/lib/extracts_path.rb
+++ b/lib/extracts_path.rb
@@ -55,12 +55,16 @@ module ExtractsPath
valid_refs = @project.repository.ref_names
valid_refs.select! { |v| id.start_with?("#{v}/") }
- if valid_refs.length != 1
+ if valid_refs.length == 0
# No exact ref match, so just try our best
pair = id.match(/([^\/]+)(.*)/).captures
else
+ # There is a distinct possibility that multiple refs prefix the ID.
+ # Use the longest match to maximize the chance that we have the
+ # right ref.
+ best_match = valid_refs.max_by(&:length)
# Partition the string into the ref and the path, ignoring the empty first value
- pair = id.partition(valid_refs.first)[1..-1]
+ pair = id.partition(best_match)[1..-1]
end
end
diff --git a/lib/gitlab/git_access_wiki.rb b/lib/gitlab/git_access_wiki.rb
index 8ba97184e69..8672cbc0ec4 100644
--- a/lib/gitlab/git_access_wiki.rb
+++ b/lib/gitlab/git_access_wiki.rb
@@ -1,7 +1,7 @@
module Gitlab
class GitAccessWiki < GitAccess
def change_access_check(change)
- if user.can?(:write_wiki, project)
+ if user.can?(:create_wiki, project)
build_status_object(true)
else
build_status_object(false, "You are not allowed to write to this project's wiki.")
diff --git a/lib/gitlab/github_import/importer.rb b/lib/gitlab/github_import/importer.rb
index 23832b3233c..98039a76dcd 100644
--- a/lib/gitlab/github_import/importer.rb
+++ b/lib/gitlab/github_import/importer.rb
@@ -11,7 +11,9 @@ module Gitlab
def execute
#Issues && Comments
- client.list_issues(project.import_source, state: :all).each do |issue|
+ client.list_issues(project.import_source, state: :all,
+ sort: :created,
+ direction: :asc).each do |issue|
if issue.pull_request.nil?
body = @formatter.author_line(issue.user.login, issue.body)
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index fa9c0975bb8..889decc9b48 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -54,7 +54,7 @@ module Gitlab
current_user: current_user
)
- pipeline = HTML::Pipeline.new(filters)
+ @pipeline ||= HTML::Pipeline.new(filters)
context = {
# SanitizationFilter
@@ -79,7 +79,7 @@ module Gitlab
project_wiki: @project_wiki
}
- result = pipeline.call(text, context)
+ result = @pipeline.call(text, context)
save_options = 0
if options[:xhtml]
diff --git a/lib/tasks/jasmine.rake b/lib/tasks/jasmine.rake
deleted file mode 100644
index ac307a9e929..00000000000
--- a/lib/tasks/jasmine.rake
+++ /dev/null
@@ -1,12 +0,0 @@
-# Since we no longer explicitly require the 'jasmine' gem, we lost the
-# `jasmine:ci` task used by GitLab CI jobs.
-#
-# This provides a simple alias to run the `spec:javascript` task from the
-# 'jasmine-rails' gem.
-task jasmine: ['jasmine:ci']
-
-namespace :jasmine do
- task :ci do
- Rake::Task['teaspoon'].invoke
- end
-end
diff --git a/scripts/prepare_build.sh b/scripts/prepare_build.sh
index 5525ab77435..dca5e1c5db3 100755
--- a/scripts/prepare_build.sh
+++ b/scripts/prepare_build.sh
@@ -4,7 +4,7 @@ if [ -f /.dockerinit ]; then
dpkg -i phantomjs_1.9.0-1+b1_amd64.deb
apt-get update -qq
- apt-get install -y -qq libicu-dev libkrb5-dev cmake nodejs
+ apt-get install -y -qq libicu-dev libkrb5-dev cmake nodejs postgresql-client mysql-client
cp config/database.yml.mysql config/database.yml
sed -i 's/username:.*/username: root/g' config/database.yml
diff --git a/spec/features/issues_spec.rb b/spec/features/issues_spec.rb
index 158a5c0c29c..808a6eeb958 100644
--- a/spec/features/issues_spec.rb
+++ b/spec/features/issues_spec.rb
@@ -218,7 +218,7 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.edit-issue.inline-update #issue_assignee_id').
+ find('.context #issue_assignee_id').
set project.team.members.first.id
click_button 'Update Issue'
@@ -257,7 +257,7 @@ describe 'Issues', feature: true do
it 'with dropdown menu' do
visit namespace_project_issue_path(project.namespace, project, issue)
- find('.edit-issue.inline-update').
+ find('.context').
select(milestone.title, from: 'issue_milestone_id')
click_button 'Update Issue'
diff --git a/spec/features/notes_on_merge_requests_spec.rb b/spec/features/notes_on_merge_requests_spec.rb
index 12ab4b844d8..ad37b589b84 100644
--- a/spec/features/notes_on_merge_requests_spec.rb
+++ b/spec/features/notes_on_merge_requests_spec.rb
@@ -223,8 +223,7 @@ describe 'Comments' do
sample_compare.changes.last[:line_code]
end
- def click_diff_line(data = nil)
- data ||= line_code
- find("button[data-line-code=\"#{data}\"]").click
+ def click_diff_line(data = line_code)
+ page.find(%Q{button[data-line-code="#{data}"]}, visible: false).click
end
end
diff --git a/spec/features/security/project/internal_access_spec.rb b/spec/features/security/project/internal_access_spec.rb
index 8d1bfd25223..4649e58cb1a 100644
--- a/spec/features/security/project/internal_access_spec.rb
+++ b/spec/features/security/project/internal_access_spec.rb
@@ -138,6 +138,18 @@ describe "Internal Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
+ describe "GET /:project_path/issues/:id/edit" do
+ let(:issue) { create(:issue, project: project) }
+ subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
describe "GET /:project_path/snippets" do
subject { namespace_project_snippets_path(project.namespace, project) }
diff --git a/spec/features/security/project/private_access_spec.rb b/spec/features/security/project/private_access_spec.rb
index 9021ff33186..2866bf0355b 100644
--- a/spec/features/security/project/private_access_spec.rb
+++ b/spec/features/security/project/private_access_spec.rb
@@ -138,6 +138,18 @@ describe "Private Project Access", feature: true do
it { is_expected.to be_denied_for :visitor }
end
+ describe "GET /:project_path/issues/:id/edit" do
+ let(:issue) { create(:issue, project: project) }
+ subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
describe "GET /:project_path/snippets" do
subject { namespace_project_snippets_path(project.namespace, project) }
diff --git a/spec/features/security/project/public_access_spec.rb b/spec/features/security/project/public_access_spec.rb
index 6ec190ed777..554c96bcdc5 100644
--- a/spec/features/security/project/public_access_spec.rb
+++ b/spec/features/security/project/public_access_spec.rb
@@ -143,6 +143,18 @@ describe "Public Project Access", feature: true do
it { is_expected.to be_allowed_for :visitor }
end
+ describe "GET /:project_path/issues/:id/edit" do
+ let(:issue) { create(:issue, project: project) }
+ subject { edit_namespace_project_issue_path(project.namespace, project, issue) }
+
+ it { is_expected.to be_allowed_for master }
+ it { is_expected.to be_allowed_for reporter }
+ it { is_expected.to be_allowed_for :admin }
+ it { is_expected.to be_denied_for guest }
+ it { is_expected.to be_denied_for :user }
+ it { is_expected.to be_denied_for :visitor }
+ end
+
describe "GET /:project_path/snippets" do
subject { namespace_project_snippets_path(project.namespace, project) }
diff --git a/spec/features/task_lists_spec.rb b/spec/features/task_lists_spec.rb
index 2099fc40cca..fca3c77fc64 100644
--- a/spec/features/task_lists_spec.rb
+++ b/spec/features/task_lists_spec.rb
@@ -1,6 +1,6 @@
require 'spec_helper'
-feature 'Task Lists' do
+feature 'Task Lists', feature: true do
include Warden::Test::Helpers
let(:project) { create(:project) }
@@ -52,7 +52,7 @@ feature 'Task Lists' do
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
expect(page).to have_selector("#{container} .js-task-list-field")
- expect(page).to have_selector('form.js-issue-update')
+ expect(page).to have_selector('form.js-issuable-update')
expect(page).to have_selector('a.btn-close')
end
@@ -128,7 +128,7 @@ feature 'Task Lists' do
expect(page).to have_selector(container)
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
expect(page).to have_selector("#{container} .js-task-list-field")
- expect(page).to have_selector('form.js-merge-request-update')
+ expect(page).to have_selector('form.js-issuable-update')
expect(page).to have_selector('a.btn-close')
end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index 8fd3d8f407b..742420f550e 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -2,157 +2,177 @@ require 'spec_helper'
describe ApplicationHelper do
describe 'current_controller?' do
- before do
- allow(controller).to receive(:controller_name).and_return('foo')
- end
-
it 'returns true when controller matches argument' do
- expect(current_controller?(:foo)).to be_truthy
+ stub_controller_name('foo')
+
+ expect(helper.current_controller?(:foo)).to eq true
end
it 'returns false when controller does not match argument' do
- expect(current_controller?(:bar)).not_to be_truthy
+ stub_controller_name('foo')
+
+ expect(helper.current_controller?(:bar)).to eq false
end
- it 'should take any number of arguments' do
- expect(current_controller?(:baz, :bar)).not_to be_truthy
- expect(current_controller?(:baz, :bar, :foo)).to be_truthy
+ it 'takes any number of arguments' do
+ stub_controller_name('foo')
+
+ expect(helper.current_controller?(:baz, :bar)).to eq false
+ expect(helper.current_controller?(:baz, :bar, :foo)).to eq true
+ end
+
+ def stub_controller_name(value)
+ allow(helper.controller).to receive(:controller_name).and_return(value)
end
end
describe 'current_action?' do
- before do
- allow(self).to receive(:action_name).and_return('foo')
+ it 'returns true when action matches' do
+ stub_action_name('foo')
+
+ expect(helper.current_action?(:foo)).to eq true
end
- it 'returns true when action matches argument' do
- expect(current_action?(:foo)).to be_truthy
+ it 'returns false when action does not match' do
+ stub_action_name('foo')
+
+ expect(helper.current_action?(:bar)).to eq false
end
- it 'returns false when action does not match argument' do
- expect(current_action?(:bar)).not_to be_truthy
+ it 'takes any number of arguments' do
+ stub_action_name('foo')
+
+ expect(helper.current_action?(:baz, :bar)).to eq false
+ expect(helper.current_action?(:baz, :bar, :foo)).to eq true
end
- it 'should take any number of arguments' do
- expect(current_action?(:baz, :bar)).not_to be_truthy
- expect(current_action?(:baz, :bar, :foo)).to be_truthy
+ def stub_action_name(value)
+ allow(helper).to receive(:action_name).and_return(value)
end
end
describe 'project_icon' do
- avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
+ let(:avatar_file_path) { File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') }
it 'should return an url for the avatar' do
- project = create(:project)
- project.avatar = File.open(avatar_file_path)
- project.save!
- avatar_url = "http://localhost/uploads/project/avatar/#{ project.id }/banana_sample.gif"
- expect(project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to eq(
- "<img alt=\"Banana sample\" src=\"#{avatar_url}\" />"
- )
+ project = create(:project, avatar: File.open(avatar_file_path))
+
+ avatar_url = "http://localhost/uploads/project/avatar/#{project.id}/banana_sample.gif"
+ expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).
+ to eq "<img alt=\"Banana sample\" src=\"#{avatar_url}\" />"
end
it 'should give uploaded icon when present' do
project = create(:project)
- project.save!
allow_any_instance_of(Project).to receive(:avatar_in_git).and_return(true)
avatar_url = 'http://localhost' + namespace_project_avatar_path(project.namespace, project)
- expect(project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to match(
+ expect(helper.project_icon("#{project.namespace.to_param}/#{project.to_param}").to_s).to match(
image_tag(avatar_url))
end
end
describe 'avatar_icon' do
- avatar_file_path = File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif')
+ let(:avatar_file_path) { File.join(Rails.root, 'spec', 'fixtures', 'banana_sample.gif') }
it 'should return an url for the avatar' do
- user = create(:user)
- user.avatar = File.open(avatar_file_path)
- user.save!
- expect(avatar_icon(user.email).to_s).
- to match("/uploads/user/avatar/#{ user.id }/banana_sample.gif")
+ user = create(:user, avatar: File.open(avatar_file_path))
+
+ expect(helper.avatar_icon(user.email).to_s).
+ to match("/uploads/user/avatar/#{user.id}/banana_sample.gif")
end
it 'should return an url for the avatar with relative url' do
- allow(Gitlab.config.gitlab).to receive(:relative_url_root).and_return('/gitlab')
- allow(Gitlab.config.gitlab).to receive(:url).and_return(Settings.send(:build_gitlab_url))
+ stub_config_setting(relative_url_root: '/gitlab')
+ # Must be stubbed after the stub above, and separately
+ stub_config_setting(url: Settings.send(:build_gitlab_url))
- user = create(:user)
- user.avatar = File.open(avatar_file_path)
- user.save!
- expect(avatar_icon(user.email).to_s).
- to match("/gitlab/uploads/user/avatar/#{ user.id }/banana_sample.gif")
+ user = create(:user, avatar: File.open(avatar_file_path))
+
+ expect(helper.avatar_icon(user.email).to_s).
+ to match("/gitlab/uploads/user/avatar/#{user.id}/banana_sample.gif")
end
- it 'should call gravatar_icon when no avatar is present' do
- user = create(:user, email: 'test@example.com')
- user.save!
- expect(avatar_icon(user.email).to_s).to eq('http://www.gravatar.com/avatar/55502f40dc8b7c769880b10874abc9d0?s=40&d=identicon')
+ it 'should call gravatar_icon when no User exists with the given email' do
+ expect(helper).to receive(:gravatar_icon).with('foo@example.com', 20)
+
+ helper.avatar_icon('foo@example.com', 20)
end
end
describe 'gravatar_icon' do
let(:user_email) { 'user@email.com' }
- it 'should return a generic avatar path when Gravatar is disabled' do
- allow_any_instance_of(ApplicationSetting).to receive(:gravatar_enabled?).and_return(false)
- expect(gravatar_icon(user_email)).to match('no_avatar.png')
- end
+ context 'with Gravatar disabled' do
+ before do
+ stub_application_setting(gravatar_enabled?: false)
+ end
- it 'should return a generic avatar path when email is blank' do
- expect(gravatar_icon('')).to match('no_avatar.png')
+ it 'returns a generic avatar' do
+ expect(helper.gravatar_icon(user_email)).to match('no_avatar.png')
+ end
end
- it 'should return default gravatar url' do
- allow(Gitlab.config.gitlab).to receive(:https).and_return(false)
- url = 'http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118'
- expect(gravatar_icon(user_email)).to match(url)
- end
+ context 'with Gravatar enabled' do
+ before do
+ stub_application_setting(gravatar_enabled?: true)
+ end
- it 'should use SSL when appropriate' do
- allow(Gitlab.config.gitlab).to receive(:https).and_return(true)
- expect(gravatar_icon(user_email)).to match('https://secure.gravatar.com')
- end
+ it 'returns a generic avatar when email is blank' do
+ expect(helper.gravatar_icon('')).to match('no_avatar.png')
+ end
- it 'should return custom gravatar path when gravatar_url is set' do
- allow(self).to receive(:request).and_return(double(:ssl? => false))
- allow(Gitlab.config.gravatar).
- to receive(:plain_url).
- and_return('http://example.local/?s=%{size}&hash=%{hash}')
- url = 'http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118'
- expect(gravatar_icon(user_email, 20)).to eq(url)
- end
+ it 'returns a valid Gravatar URL' do
+ stub_config_setting(https: false)
- it 'should accept a custom size' do
- allow(self).to receive(:request).and_return(double(:ssl? => false))
- expect(gravatar_icon(user_email, 64)).to match(/\?s=64/)
- end
+ expect(helper.gravatar_icon(user_email)).
+ to match('http://www.gravatar.com/avatar/b58c6f14d292556214bd64909bcdb118')
+ end
- it 'should use default size when size is wrong' do
- allow(self).to receive(:request).and_return(double(:ssl? => false))
- expect(gravatar_icon(user_email, nil)).to match(/\?s=40/)
- end
+ it 'uses HTTPs when configured' do
+ stub_config_setting(https: true)
+
+ expect(helper.gravatar_icon(user_email)).
+ to match('https://secure.gravatar.com')
+ end
+
+ it 'should return custom gravatar path when gravatar_url is set' do
+ stub_gravatar_setting(plain_url: 'http://example.local/?s=%{size}&hash=%{hash}')
- it 'should be case insensitive' do
- allow(self).to receive(:request).and_return(double(:ssl? => false))
- expect(gravatar_icon(user_email)).
- to eq(gravatar_icon(user_email.upcase + ' '))
+ expect(gravatar_icon(user_email, 20)).
+ to eq('http://example.local/?s=20&hash=b58c6f14d292556214bd64909bcdb118')
+ end
+
+ it 'accepts a custom size argument' do
+ expect(helper.gravatar_icon(user_email, 64)).to include '?s=64'
+ end
+
+ it 'defaults size to 40 when given an invalid size' do
+ expect(helper.gravatar_icon(user_email, nil)).to include '?s=40'
+ end
+
+ it 'ignores case and surrounding whitespace' do
+ normal = helper.gravatar_icon('foo@example.com')
+ upcase = helper.gravatar_icon(' FOO@EXAMPLE.COM ')
+
+ expect(normal).to eq upcase
+ end
end
end
describe 'grouped_options_refs' do
- # Override Rails' grouped_options_for_select helper since HTML is harder to work with
- def grouped_options_for_select(options, *args)
- options
- end
-
- let(:options) { grouped_options_refs }
+ let(:options) { helper.grouped_options_refs }
+ let(:project) { create(:project) }
before do
- # Must be an instance variable
- @project = create(:project)
+ assign(:project, project)
+
+ # Override Rails' grouped_options_for_select helper to just return the
+ # first argument (`options`), since it's easier to work with than the
+ # generated HTML.
+ allow(helper).to receive(:grouped_options_for_select).
+ and_wrap_original { |_, *args| args.first }
end
it 'includes a list of branch names' do
@@ -167,15 +187,16 @@ describe ApplicationHelper do
it 'includes a specific commit ref if defined' do
# Must be an instance variable
- @ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8'
+ ref = '2ed06dc41dbb5936af845b87d79e05bbf24c73b8'
+ assign(:ref, ref)
expect(options[2][0]).to eq('Commit')
- expect(options[2][1]).to eq([@ref])
+ expect(options[2][1]).to eq([ref])
end
it 'sorts tags in a natural order' do
# Stub repository.tag_names to make sure we get some valid testing data
- expect(@project.repository).to receive(:tag_names).
+ expect(project.repository).to receive(:tag_names).
and_return(['v1.0.9', 'v1.0.10', 'v2.0', 'v3.1.4.2', 'v2.0rc1¿',
'v1.0.9a', 'v2.0-rc1', 'v2.0rc2'])
@@ -189,17 +210,17 @@ describe ApplicationHelper do
let(:a_tag) { '<a href="#">Foo</a>' }
it 'allows the a tag' do
- expect(simple_sanitize(a_tag)).to eq(a_tag)
+ expect(helper.simple_sanitize(a_tag)).to eq(a_tag)
end
it 'allows the span tag' do
input = '<span class="foo">Bar</span>'
- expect(simple_sanitize(input)).to eq(input)
+ expect(helper.simple_sanitize(input)).to eq(input)
end
it 'disallows other tags' do
input = "<strike><b>#{a_tag}</b></strike>"
- expect(simple_sanitize(input)).to eq(a_tag)
+ expect(helper.simple_sanitize(input)).to eq(a_tag)
end
end
@@ -207,7 +228,7 @@ describe ApplicationHelper do
def element(*arguments)
Time.zone = 'UTC'
time = Time.zone.parse('2015-07-02 08:00')
- element = time_ago_with_tooltip(time, *arguments)
+ element = helper.time_ago_with_tooltip(time, *arguments)
Nokogiri::HTML::DocumentFragment.parse(element).first_element_child
end
@@ -257,21 +278,21 @@ describe ApplicationHelper do
it 'should preserve encoding' do
expect(content.encoding.name).to eq('UTF-8')
- expect(render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
+ expect(helper.render_markup('foo.rst', content).encoding.name).to eq('UTF-8')
end
it "should delegate to #markdown when file name corresponds to Markdown" do
- expect(self).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
- expect(self).to receive(:markdown).and_return('NOEL')
+ expect(helper).to receive(:gitlab_markdown?).with('foo.md').and_return(true)
+ expect(helper).to receive(:markdown).and_return('NOEL')
- expect(render_markup('foo.md', content)).to eq('NOEL')
+ expect(helper.render_markup('foo.md', content)).to eq('NOEL')
end
it "should delegate to #asciidoc when file name corresponds to AsciiDoc" do
- expect(self).to receive(:asciidoc?).with('foo.adoc').and_return(true)
- expect(self).to receive(:asciidoc).and_return('NOEL')
+ expect(helper).to receive(:asciidoc?).with('foo.adoc').and_return(true)
+ expect(helper).to receive(:asciidoc).and_return('NOEL')
- expect(render_markup('foo.adoc', content)).to eq('NOEL')
+ expect(helper.render_markup('foo.adoc', content)).to eq('NOEL')
end
end
end
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index bbb434638ce..14c8c29d008 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -133,4 +133,11 @@ describe GitlabMarkdownHelper do
helper.render_wiki_content(@wiki)
end
end
+
+ describe 'random_markdown_tip' do
+ it 'returns a random Markdown tip' do
+ stub_const("#{described_class}::MARKDOWN_TIPS", ['Random tip'])
+ expect(random_markdown_tip).to eq 'Tip: Random tip'
+ end
+ end
end
diff --git a/spec/helpers/submodule_helper_spec.rb b/spec/helpers/submodule_helper_spec.rb
index a7abf9d3839..10121759132 100644
--- a/spec/helpers/submodule_helper_spec.rb
+++ b/spec/helpers/submodule_helper_spec.rb
@@ -115,7 +115,7 @@ describe SubmoduleHelper do
end
context 'submodules with relative links' do
- let(:group) { create(:group) }
+ let(:group) { create(:group, name: "Master Project", path: "master-project") }
let(:project) { create(:project, group: group) }
let(:commit_id) { sample_commit[:id] }
diff --git a/spec/javascripts/behaviors/requires_input_spec.js.coffee b/spec/javascripts/behaviors/requires_input_spec.js.coffee
new file mode 100644
index 00000000000..61a17632173
--- /dev/null
+++ b/spec/javascripts/behaviors/requires_input_spec.js.coffee
@@ -0,0 +1,49 @@
+#= require behaviors/requires_input
+
+describe 'requiresInput', ->
+ fixture.preload('behaviors/requires_input.html')
+
+ beforeEach ->
+ fixture.load('behaviors/requires_input.html')
+
+ it 'disables submit when any field is required', ->
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).toBeDisabled()
+
+ it 'enables submit when no field is required', ->
+ $('*[required=required]').removeAttr('required')
+
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'enables submit when all required fields are pre-filled', ->
+ $('*[required=required]').remove()
+
+ $('.js-requires-input').requiresInput()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'enables submit when all required fields receive input', ->
+ $('.js-requires-input').requiresInput()
+
+ $('#required1').val('input1').change()
+ expect($('.submit')).toBeDisabled()
+
+ $('#optional1').val('input1').change()
+ expect($('.submit')).toBeDisabled()
+
+ $('#required2').val('input2').change()
+ $('#required3').val('input3').change()
+ $('#required4').val('input4').change()
+ $('#required5').val('1').change()
+
+ expect($('.submit')).not.toBeDisabled()
+
+ it 'is called on page:load event', ->
+ spy = spyOn($.fn, 'requiresInput')
+
+ $(document).trigger('page:load')
+
+ expect(spy).toHaveBeenCalled()
diff --git a/spec/javascripts/fixtures/behaviors/requires_input.html.haml b/spec/javascripts/fixtures/behaviors/requires_input.html.haml
new file mode 100644
index 00000000000..c3f905e912e
--- /dev/null
+++ b/spec/javascripts/fixtures/behaviors/requires_input.html.haml
@@ -0,0 +1,18 @@
+%form.js-requires-input
+ %input{type: 'text', id: 'required1', required: 'required'}
+ %input{type: 'text', id: 'required2', required: 'required'}
+ %input{type: 'text', id: 'required3', required: 'required', value: 'Pre-filled'}
+ %input{type: 'text', id: 'optional1'}
+
+ %textarea{id: 'required4', required: 'required'}
+ %textarea{id: 'optional2'}
+
+ %select{id: 'required5', required: 'required'}
+ %option Zero
+ %option{value: '1'} One
+ %select{id: 'optional3', required: 'required'}
+ %option Zero
+ %option{value: '1'} One
+
+ %button.submit{type: 'submit', value: 'Submit'}
+ %input.submit{type: 'submit', value: 'Submit'}
diff --git a/spec/javascripts/fixtures/issues_show.html.haml b/spec/javascripts/fixtures/issues_show.html.haml
index db5abe0cae3..7e8b2a64351 100644
--- a/spec/javascripts/fixtures/issues_show.html.haml
+++ b/spec/javascripts/fixtures/issues_show.html.haml
@@ -10,4 +10,4 @@
%textarea.js-task-list-field
\- [ ] Task List Item
-%form.js-issue-update{action: '/foo'}
+%form.js-issuable-update{action: '/foo'}
diff --git a/spec/javascripts/fixtures/merge_requests_show.html.haml b/spec/javascripts/fixtures/merge_requests_show.html.haml
index c4329b8f94a..f0c622935f8 100644
--- a/spec/javascripts/fixtures/merge_requests_show.html.haml
+++ b/spec/javascripts/fixtures/merge_requests_show.html.haml
@@ -10,4 +10,4 @@
%textarea.js-task-list-field
\- [ ] Task List Item
-%form.js-merge-request-update{action: '/foo'}
+%form.js-issuable-update{action: '/foo'}
diff --git a/spec/javascripts/merge_request_spec.js.coffee b/spec/javascripts/merge_request_spec.js.coffee
index a4735af0343..22ebc7039d1 100644
--- a/spec/javascripts/merge_request_spec.js.coffee
+++ b/spec/javascripts/merge_request_spec.js.coffee
@@ -1,7 +1,5 @@
#= require merge_request
-window.disableButtonIfEmptyField = -> null
-
describe 'MergeRequest', ->
describe 'task lists', ->
fixture.preload('merge_requests_show.html')
diff --git a/spec/lib/extracts_path_spec.rb b/spec/lib/extracts_path_spec.rb
index f077c80d478..4439775f612 100644
--- a/spec/lib/extracts_path_spec.rb
+++ b/spec/lib/extracts_path_spec.rb
@@ -10,7 +10,8 @@ describe ExtractsPath do
before do
@project = project
- repo = double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0'])
+ repo = double(ref_names: ['master', 'foo/bar/baz', 'v1.0.0', 'v2.0.0',
+ 'release/app', 'release/app/v1.0.0'])
allow(project).to receive(:repository).and_return(repo)
allow(project).to receive(:path_with_namespace).
and_return('gitlab/gitlab-ci')
@@ -54,11 +55,17 @@ describe ExtractsPath do
it "falls back to a primitive split for an invalid ref" do
expect(extract_ref('stable')).to eq(['stable', ''])
end
+
+ it "extracts the longest matching ref" do
+ expect(extract_ref('release/app/v1.0.0/README.md')).to eq(
+ ['release/app/v1.0.0', 'README.md'])
+ end
end
context "with a path" do
it "extracts a valid branch" do
- expect(extract_ref('foo/bar/baz/CHANGELOG')).to eq(['foo/bar/baz', 'CHANGELOG'])
+ expect(extract_ref('foo/bar/baz/CHANGELOG')).to eq(
+ ['foo/bar/baz', 'CHANGELOG'])
end
it "extracts a valid tag" do
diff --git a/spec/models/members/project_member_spec.rb b/spec/models/members/project_member_spec.rb
index 5c72cfe1d6a..ee912bf12a2 100644
--- a/spec/models/members/project_member_spec.rb
+++ b/spec/models/members/project_member_spec.rb
@@ -43,7 +43,7 @@ describe ProjectMember do
it { expect(@project_2.users).to include(@user_1) }
it { expect(@project_2.users).to include(@user_2) }
- it { expect(@abilities.allowed?(@user_1, :write_project, @project_2)).to be_truthy }
+ it { expect(@abilities.allowed?(@user_1, :create_project, @project_2)).to be_truthy }
it { expect(@abilities.allowed?(@user_2, :read_project, @project_2)).to be_truthy }
end
diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb
index 9037992bb08..eba33dd510f 100644
--- a/spec/models/note_spec.rb
+++ b/spec/models/note_spec.rb
@@ -172,9 +172,9 @@ describe Note do
@p2.project_members.create(user: @u3, access_level: ProjectMember::DEVELOPER)
end
- it { expect(@abilities.allowed?(@u1, :write_note, @p1)).to be_falsey }
- it { expect(@abilities.allowed?(@u2, :write_note, @p1)).to be_truthy }
- it { expect(@abilities.allowed?(@u3, :write_note, @p1)).to be_falsey }
+ it { expect(@abilities.allowed?(@u1, :create_note, @p1)).to be_falsey }
+ it { expect(@abilities.allowed?(@u2, :create_note, @p1)).to be_truthy }
+ it { expect(@abilities.allowed?(@u3, :create_note, @p1)).to be_falsey }
end
describe 'admin' do
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index f41e5a97ca3..a083dcb1274 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -25,4 +25,26 @@ describe Repository do
it { is_expected.to eq('c1acaa58bbcbc3eafe538cb8274ba387047b69f8') }
end
+
+ describe :blob_at do
+ context 'blank sha' do
+ subject { repository.blob_at(Gitlab::Git::BLANK_SHA, '.gitignore') }
+
+ it { is_expected.to be_nil }
+ end
+ end
+
+ describe :can_be_merged? do
+ context 'mergeable branches' do
+ subject { repository.can_be_merged?('feature', 'master') }
+
+ it { is_expected.to be_truthy }
+ end
+
+ context 'non-mergeable branches' do
+ subject { repository.can_be_merged?('feature_conflict', 'feature') }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index b80273c053d..6d2423ae27a 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -366,28 +366,22 @@ describe User do
end
end
- describe '.find_for_commit' do
+ describe '.find_by_any_email' do
it 'finds by primary email' do
user = create(:user, email: 'foo@example.com')
- expect(User.find_for_commit(user.email, '')).to eq user
+ expect(User.find_by_any_email(user.email)).to eq user
end
it 'finds by secondary email' do
email = create(:email, email: 'foo@example.com')
user = email.user
- expect(User.find_for_commit(email.email, '')).to eq user
- end
-
- it 'finds by name' do
- user = create(:user, name: 'Joey JoJo')
-
- expect(User.find_for_commit('', 'Joey JoJo')).to eq user
+ expect(User.find_by_any_email(email.email)).to eq user
end
it 'returns nil when nothing found' do
- expect(User.find_for_commit('', '')).to be_nil
+ expect(User.find_by_any_email('')).to be_nil
end
end
diff --git a/spec/requests/api/users_spec.rb b/spec/requests/api/users_spec.rb
index c10998e171f..1a29058f3f1 100644
--- a/spec/requests/api/users_spec.rb
+++ b/spec/requests/api/users_spec.rb
@@ -35,6 +35,7 @@ describe API::API, api: true do
expect(json_response.first.keys).to include 'email'
expect(json_response.first.keys).to include 'identities'
expect(json_response.first.keys).to include 'can_create_project'
+ expect(json_response.first.keys).to include 'two_factor_enabled'
end
end
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 666d56079d7..682a8863bad 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -13,12 +13,12 @@ RSpec.configure do |config|
config.use_instantiated_fixtures = false
config.mock_with :rspec
- config.include LoginHelpers, type: :feature
- config.include LoginHelpers, type: :request
- config.include FactoryGirl::Syntax::Methods
config.include Devise::TestHelpers, type: :controller
-
+ config.include LoginHelpers, type: :feature
+ config.include LoginHelpers, type: :request
+ config.include StubConfiguration
config.include TestEnv
+
config.infer_spec_type_from_file_location!
config.raise_errors_for_deprecations!
diff --git a/spec/support/factory_girl.rb b/spec/support/factory_girl.rb
new file mode 100644
index 00000000000..eec437fb3aa
--- /dev/null
+++ b/spec/support/factory_girl.rb
@@ -0,0 +1,3 @@
+RSpec.configure do |config|
+ config.include FactoryGirl::Syntax::Methods
+end
diff --git a/spec/support/stub_configuration.rb b/spec/support/stub_configuration.rb
new file mode 100644
index 00000000000..ad86abdbb41
--- /dev/null
+++ b/spec/support/stub_configuration.rb
@@ -0,0 +1,14 @@
+module StubConfiguration
+ def stub_application_setting(messages)
+ allow(Gitlab::CurrentSettings.current_application_settings).
+ to receive_messages(messages)
+ end
+
+ def stub_config_setting(messages)
+ allow(Gitlab.config.gitlab).to receive_messages(messages)
+ end
+
+ def stub_gravatar_setting(messages)
+ allow(Gitlab.config.gravatar).to receive_messages(messages)
+ end
+end