Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.teatro.yml8
-rw-r--r--CHANGELOG10
-rw-r--r--CONTRIBUTING.md15
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock3
-rw-r--r--VERSION2
-rw-r--r--app/assets/javascripts/application.js.coffee8
-rw-r--r--app/assets/javascripts/markdown_area.js.coffee102
-rw-r--r--app/assets/javascripts/merge_request.js.coffee4
-rw-r--r--app/assets/javascripts/notes.js.coffee11
-rw-r--r--app/assets/stylesheets/application.scss8
-rw-r--r--app/assets/stylesheets/generic/common.scss10
-rw-r--r--app/assets/stylesheets/generic/forms.scss28
-rw-r--r--app/assets/stylesheets/generic/jquery.scss4
-rw-r--r--app/assets/stylesheets/generic/selects.scss2
-rw-r--r--app/assets/stylesheets/gl_bootstrap.scss2
-rw-r--r--app/assets/stylesheets/main/variables.scss6
-rw-r--r--app/assets/stylesheets/sections/commits.scss24
-rw-r--r--app/assets/stylesheets/sections/errors.scss14
-rw-r--r--app/assets/stylesheets/sections/events.scss3
-rw-r--r--app/assets/stylesheets/sections/header.scss6
-rw-r--r--app/assets/stylesheets/sections/nav.scss2
-rw-r--r--app/assets/stylesheets/sections/notes.scss46
-rw-r--r--app/assets/stylesheets/sections/profile.scss15
-rw-r--r--app/assets/stylesheets/themes/ui_basic.scss18
-rw-r--r--app/controllers/admin/users_controller.rb10
-rw-r--r--app/controllers/application_controller.rb2
-rw-r--r--app/controllers/omniauth_callbacks_controller.rb19
-rw-r--r--app/controllers/projects/commits_controller.rb2
-rw-r--r--app/controllers/projects/issues_controller.rb2
-rw-r--r--app/controllers/projects/merge_requests_controller.rb5
-rw-r--r--app/controllers/projects/notes_controller.rb16
-rw-r--r--app/controllers/projects/refs_controller.rb2
-rw-r--r--app/controllers/projects_controller.rb34
-rw-r--r--app/controllers/users_sessions_controller.rb6
-rw-r--r--app/helpers/events_helper.rb6
-rw-r--r--app/helpers/gitlab_markdown_helper.rb21
-rw-r--r--app/helpers/notes_helper.rb25
-rw-r--r--app/models/concerns/mentionable.rb12
-rw-r--r--app/models/event.rb9
-rw-r--r--app/models/note.rb29
-rw-r--r--app/models/repository.rb13
-rw-r--r--app/models/user.rb38
-rw-r--r--app/models/users_group.rb17
-rw-r--r--app/models/users_project.rb37
-rw-r--r--app/observers/base_observer.rb13
-rw-r--r--app/observers/note_observer.rb20
-rw-r--r--app/observers/project_activity_cache_observer.rb8
-rw-r--r--app/observers/project_observer.rb30
-rw-r--r--app/observers/system_hook_observer.rb17
-rw-r--r--app/observers/user_observer.rb20
-rw-r--r--app/observers/users_group_observer.rb9
-rw-r--r--app/observers/users_project_observer.rb23
-rw-r--r--app/services/base_service.rb4
-rw-r--r--app/services/issues/base_service.rb7
-rw-r--r--app/services/issues/close_service.rb2
-rw-r--r--app/services/issues/create_service.rb2
-rw-r--r--app/services/issues/reopen_service.rb2
-rw-r--r--app/services/issues/update_service.rb2
-rw-r--r--app/services/notes/create_service.rb19
-rw-r--r--app/services/projects/create_service.rb3
-rw-r--r--app/services/projects/destroy_service.rb28
-rw-r--r--app/services/projects/participants_service.rb43
-rw-r--r--app/services/projects/update_service.rb10
-rw-r--r--app/services/search/global_service.rb1
-rw-r--r--app/services/search/project_service.rb6
-rw-r--r--app/views/admin/users/show.html.haml2
-rw-r--r--app/views/dashboard/show.html.haml4
-rw-r--r--app/views/devise/sessions/_new_base.html.haml4
-rw-r--r--app/views/errors/access_denied.html.haml4
-rw-r--r--app/views/errors/encoding.html.haml4
-rw-r--r--app/views/errors/git_not_found.html.haml4
-rw-r--r--app/views/errors/not_found.html.haml4
-rw-r--r--app/views/errors/omniauth_error.html.haml12
-rw-r--r--app/views/groups/_filter.html.haml29
-rw-r--r--app/views/groups/new.html.haml8
-rw-r--r--app/views/groups/show.html.haml4
-rw-r--r--app/views/layouts/_head.html.haml14
-rw-r--r--app/views/layouts/_public_head_panel.html.haml4
-rw-r--r--app/views/layouts/_search.html.haml2
-rw-r--r--app/views/layouts/devise.html.haml2
-rw-r--r--app/views/layouts/errors.html.haml7
-rw-r--r--app/views/layouts/nav/_admin.html.haml6
-rw-r--r--app/views/layouts/nav/_dashboard.html.haml2
-rw-r--r--app/views/layouts/nav/_group.html.haml2
-rw-r--r--app/views/layouts/nav/_profile.html.haml2
-rw-r--r--app/views/layouts/nav/_project.html.haml2
-rw-r--r--app/views/profiles/keys/new.html.haml4
-rw-r--r--app/views/profiles/show.html.haml10
-rw-r--r--app/views/projects/_home_panel.html.haml5
-rw-r--r--app/views/projects/blob/_blob.html.haml2
-rw-r--r--app/views/projects/blob/_download.html.haml2
-rw-r--r--app/views/projects/commits/_commit.html.haml12
-rw-r--r--app/views/projects/commits/_diffs.html.haml4
-rw-r--r--app/views/projects/compare/show.html.haml2
-rw-r--r--app/views/projects/edit.html.haml2
-rw-r--r--app/views/projects/edit_tree/show.html.haml2
-rw-r--r--app/views/projects/graphs/show.html.haml2
-rw-r--r--app/views/projects/import.html.haml4
-rw-r--r--app/views/projects/merge_requests/_new_compare.html.haml2
-rw-r--r--app/views/projects/merge_requests/_show.html.haml3
-rw-r--r--app/views/projects/new.html.haml2
-rw-r--r--app/views/projects/notes/_commit_discussion.html.haml0
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply.html.haml6
-rw-r--r--app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml8
-rw-r--r--app/views/projects/notes/_discussion.html.haml52
-rw-r--r--app/views/projects/notes/_discussion_reply_button.html.haml10
-rw-r--r--app/views/projects/notes/_form.html.haml4
-rw-r--r--app/views/projects/notes/discussions/_active.html.haml21
-rw-r--r--app/views/projects/notes/discussions/_commit.html.haml28
-rw-r--r--app/views/projects/notes/discussions/_diff.html.haml (renamed from app/views/projects/notes/_discussion_diff.html.haml)0
-rw-r--r--app/views/projects/notes/discussions/_outdated.html.haml20
-rw-r--r--app/views/projects/show.html.haml10
-rw-r--r--app/views/projects/tree/_blob_item.html.haml2
-rw-r--r--app/views/projects/tree/_readme.html.haml2
-rw-r--r--app/views/projects/tree/_tree_item.html.haml2
-rw-r--r--app/views/search/_project_results.html.haml1
-rw-r--r--app/views/search/results/_note.html.haml9
-rw-r--r--app/workers/repository_import_worker.rb3
-rw-r--r--config/application.rb9
-rw-r--r--config/gitlab.teatro.yml86
-rw-r--r--config/routes.rb6
-rw-r--r--doc/api/users.md2
-rw-r--r--doc/install/installation.md6
-rw-r--r--doc/install/requirements.md45
-rw-r--r--doc/permissions/permissions.md1
-rw-r--r--doc/raketasks/backup_restore.md10
-rw-r--r--doc/raketasks/cleanup.md8
-rw-r--r--doc/raketasks/import.md4
-rw-r--r--doc/raketasks/maintenance.md8
-rw-r--r--doc/raketasks/user_management.md16
-rw-r--r--doc/raketasks/web_hooks.md18
-rw-r--r--doc/release/monthly.md22
-rw-r--r--doc/update/6.9-to-7.0.md48
-rw-r--r--doc/update/README.md1
-rw-r--r--doc/update/ruby.md59
-rw-r--r--doc/workflow/README.md1
-rw-r--r--doc/workflow/groups.md71
-rw-r--r--doc/workflow/groups/add_member_to_group.pngbin0 -> 138184 bytes
-rw-r--r--doc/workflow/groups/group_dashboard.pngbin0 -> 107332 bytes
-rw-r--r--doc/workflow/groups/group_with_two_projects.pngbin0 -> 129319 bytes
-rw-r--r--doc/workflow/groups/new_group_button.pngbin0 -> 185406 bytes
-rw-r--r--doc/workflow/groups/new_group_form.pngbin0 -> 106491 bytes
-rw-r--r--doc/workflow/groups/override_access_level.pngbin0 -> 157193 bytes
-rw-r--r--doc/workflow/groups/project_members_via_group.pngbin0 -> 151339 bytes
-rw-r--r--doc/workflow/groups/transfer_project.pngbin0 -> 164958 bytes
-rw-r--r--features/admin/users.feature8
-rw-r--r--features/project/project.feature5
-rw-r--r--features/project/redirects.feature7
-rw-r--r--features/steps/admin/active_tab.rb2
-rw-r--r--features/steps/admin/users.rb19
-rw-r--r--features/steps/dashboard/active_tab.rb2
-rw-r--r--features/steps/profile/active_tab.rb2
-rw-r--r--features/steps/project/active_tab.rb2
-rw-r--r--features/steps/project/merge_requests.rb12
-rw-r--r--features/steps/project/project.rb12
-rw-r--r--features/steps/project/redirects.rb22
-rw-r--r--features/steps/shared/active_tab.rb6
-rw-r--r--features/steps/shared/diff_note.rb48
-rw-r--r--lib/api/notes.rb13
-rw-r--r--lib/gitlab/markdown.rb7
-rw-r--r--lib/gitlab/oauth/user.rb8
-rw-r--r--lib/gitlab/url_builder.rb25
-rw-r--r--lib/tasks/cache.rake7
-rw-r--r--spec/features/admin/admin_users_spec.rb18
-rw-r--r--spec/features/profile_spec.rb2
-rw-r--r--spec/features/projects_spec.rb2
-rw-r--r--spec/features/search_spec.rb1
-rw-r--r--spec/helpers/gitlab_markdown_helper_spec.rb14
-rw-r--r--spec/lib/gitlab/url_builder_spec.rb11
-rw-r--r--spec/models/event_spec.rb22
-rw-r--r--spec/models/project_spec.rb3
-rw-r--r--spec/models/system_hook_spec.rb9
-rw-r--r--spec/models/user_spec.rb6
-rw-r--r--spec/models/users_group_spec.rb28
-rw-r--r--spec/observers/note_observer_spec.rb56
-rw-r--r--spec/observers/user_observer_spec.rb27
-rw-r--r--spec/observers/users_group_observer_spec.rb32
-rw-r--r--spec/observers/users_project_observer_spec.rb63
-rw-r--r--spec/requests/api/branches_spec.rb2
-rw-r--r--spec/requests/api/commits_spec.rb3
-rw-r--r--spec/requests/api/files_spec.rb3
-rw-r--r--spec/requests/api/internal_spec.rb3
-rw-r--r--spec/requests/api/issues_spec.rb3
-rw-r--r--spec/requests/api/merge_requests_spec.rb2
-rw-r--r--spec/requests/api/milestones_spec.rb6
-rw-r--r--spec/requests/api/namespaces_spec.rb3
-rw-r--r--spec/requests/api/notes_spec.rb7
-rw-r--r--spec/requests/api/project_hooks_spec.rb3
-rw-r--r--spec/requests/api/project_members_spec.rb3
-rw-r--r--spec/requests/api/projects_spec.rb3
-rw-r--r--spec/requests/api/repositories_spec.rb3
-rw-r--r--spec/requests/api/services_spec.rb3
-rw-r--r--spec/services/issues/bulk_update_context_spec.rb13
-rw-r--r--spec/services/notes/create_service_spec.rb27
-rw-r--r--spec/services/notification_service_spec.rb44
-rw-r--r--spec/services/projects/create_service_spec.rb19
-rw-r--r--spec/services/projects/image_service_spec.rb3
-rw-r--r--spec/services/projects/transfer_service_spec.rb3
-rw-r--r--spec/services/projects/update_service_spec.rb3
-rw-r--r--spec/services/search_service_spec.rb23
-rw-r--r--spec/spec_helper.rb2
-rw-r--r--spec/support/login_helpers.rb4
-rw-r--r--spec/support/test_env.rb20
204 files changed, 1434 insertions, 980 deletions
diff --git a/.teatro.yml b/.teatro.yml
new file mode 100644
index 00000000000..30054361981
--- /dev/null
+++ b/.teatro.yml
@@ -0,0 +1,8 @@
+stage:
+ before:
+ - cp config/gitlab.teatro.yml config/gitlab.yml
+ - mkdir /apps/gitlab-satellites
+ - mkdir /apps/repositories
+
+ database:
+ - RAILS_ENV=development force=yes bundle exec rake db:create gitlab:setup \ No newline at end of file
diff --git a/CHANGELOG b/CHANGELOG
index 495d20e8b04..a5962fdfdc7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,13 @@
+v 7.1.0
+ - Remove observers
+ - Improve MR discussions
+ - Filter by description on Issues#index page
+ - Fix bug with namespace select when create new project page
+ - Show README link after description for non-master members
+ - Add @all mention for comments
+ - Dont show reply button if user is not signed in
+ - Expose more information for issues with webhook
+
v 7.0.0
- The CPU no longer overheats when you hold down the spacebar
- Improve edit file UI
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3b6212c960d..a08ffa449d8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,8 +1,8 @@
# Contribute to GitLab
-This guide details how contribute to GitLab.
-
-If you want to know how the GitLab team handles contributions have a look at [the GitLab contributing process](PROCESS.md).
+Thank you for your interest in contributing to GitLab.
+This guide details how contribute to GitLab in a way that is efficient for everyone.
+If you have read this guide and want to know how the GitLab core-team operates please see [the GitLab contributing process](PROCESS.md).
## Contributor license agreement
@@ -75,9 +75,9 @@ If you can, please submit a merge request with the fix or improvements including
The **official merge window** is in the beginning of the month from the 1st to the 7th day of the month. The best time to submit a MR and get feedback fast. Before this time the GitLab B.V. team is still dealing with work that is created by the monthly release such as assisting subscribers with upgrade issues, the release of Enterprise Edition and the upgrade of GitLab Cloud. After the 7th it is already getting closer to the release date of the next version. This means there is less time to fix the issues created by merging large new features.
-Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? The smaller a MR is the more likely it is it will be merged, after that you can send more MR's to enhance it.
+Please keep the change in a single MR **as small as possible**. If you want to contribute a large feature think very hard what the minimum viable change is. Can you split functionality? Can you only submit the backend/API code? Can you start with a very simple UI? Can you do part of the refactor? The increased reviewability of small MR's that leads to higher code quality is more important to us than having a mimimal commit log. The smaller a MR is the more likely it is it will be merged (quickly), after that you can send more MR's to enhance it.
-For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). Please ensure that your merge request meets the following contribution acceptance criteria.
+For examples of feedback on merge requests please look at already [closed merge requests](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests?assignee_id=&label_name=&milestone_id=&scope=&sort=&state=closed). If you would like quick feedback on your merge request feel free to mention one of the Merge Marshalls of [the core-team](https://about.gitlab.com/core-team/). Please ensure that your merge request meets the following contribution acceptance criteria.
**Please format your merge request description as follows:**
@@ -97,7 +97,8 @@ For examples of feedback on merge requests please look at already [closed merge
1. Keeps the GitLab code base clean and well structured
1. Contains functionality we think other users will benefit from too
1. Doesn't add configuration options since they complicate future changes
-1. Contains a single commit (please use `git rebase -i` to squash commits)
+1. Initially contains a single commit (please use `git rebase -i` to squash commits)
+1. Changes after submitting the merge request should be in separate commits (no squashing)
1. It conforms to the following style guides
## Style guides
@@ -113,4 +114,4 @@ For examples of feedback on merge requests please look at already [closed merge
1. [Shell commands](doc/development/shell_commands.md) created by GitLab contributors to enhance security
1. [Markdown](http://www.cirosantilli.com/markdown-styleguide)
-This is also the style used by linting tools such as [Rubocop](https://github.com/bbatsov/rubocop), PullReview[https://www.pullreview.com/] and [Hound CI](https://houndci.com).
+This is also the style used by linting tools such as [Rubocop](https://github.com/bbatsov/rubocop), [PullReview](https://www.pullreview.com/) and [Hound CI](https://houndci.com).
diff --git a/Gemfile b/Gemfile
index c64213479f7..39ffd95b2e2 100644
--- a/Gemfile
+++ b/Gemfile
@@ -11,7 +11,6 @@ end
gem "rails", "~> 4.1.0"
gem "protected_attributes"
-gem 'rails-observers'
# Make links from text
gem 'rails_autolink', '~> 1.1'
diff --git a/Gemfile.lock b/Gemfile.lock
index 6c27b6e3739..382633c2246 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -365,8 +365,6 @@ GEM
bundler (>= 1.3.0, < 2.0)
railties (= 4.1.1)
sprockets-rails (~> 2.0)
- rails-observers (0.1.2)
- activemodel (~> 4.0)
rails_autolink (1.1.6)
rails (> 3.1)
rails_best_practices (1.14.4)
@@ -644,7 +642,6 @@ DEPENDENCIES
rack-cors
rack-mini-profiler
rails (~> 4.1.0)
- rails-observers
rails_autolink (~> 1.1)
rails_best_practices
raphael-rails (~> 2.1.2)
diff --git a/VERSION b/VERSION
index 66ce77b7ead..0802f6378d4 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-7.0.0
+7.1.0.pre
diff --git a/app/assets/javascripts/application.js.coffee b/app/assets/javascripts/application.js.coffee
index 9bcd8f0a171..5b124554c38 100644
--- a/app/assets/javascripts/application.js.coffee
+++ b/app/assets/javascripts/application.js.coffee
@@ -143,6 +143,14 @@ $ ->
$(@).next('table').show()
$(@).remove()
+ # Show/hide comments on diff
+ $("body").on "click", ".js-toggle-diff-comments", (e) ->
+ $(@).find('i').
+ toggleClass('icon-chevron-down').
+ toggleClass('icon-chevron-up')
+ $(@).closest(".diff-file").find(".notes_holder").toggle()
+ e.preventDefault()
+
(($) ->
# Disable an element and add the 'disabled' Bootstrap class
$.fn.extend disable: ->
diff --git a/app/assets/javascripts/markdown_area.js.coffee b/app/assets/javascripts/markdown_area.js.coffee
index 12b69fa4fdc..516a40b25c2 100644
--- a/app/assets/javascripts/markdown_area.js.coffee
+++ b/app/assets/javascripts/markdown_area.js.coffee
@@ -21,7 +21,6 @@ $(document).ready ->
$(".div-dropzone").append divSpinner
$(".div-dropzone-spinner").append iconSpinner
-
dropzone = $(".div-dropzone").dropzone(
url: project_image_path_upload
dictDefaultMessage: ""
@@ -77,6 +76,107 @@ $(document).ready ->
return
)
+ child = $(dropzone[0]).children("textarea")
+
+ formatLink = (str) ->
+ "![" + str.alt + "](" + str.url + ")"
+
+ handlePaste = (e) ->
+ e.preventDefault()
+ my_event = e.originalEvent
+
+ if my_event.clipboardData and my_event.clipboardData.items
+ processItem(my_event)
+
+ processItem = (e) ->
+ image = isImage(e)
+ if image
+ filename = getFilename(e) or "image.png"
+ text = "{{" + filename + "}}"
+ pasteText(text)
+ uploadFile image.getAsFile(), filename
+
+ else
+ text = e.clipboardData.getData("text/plain")
+ pasteText(text)
+
+ isImage = (data) ->
+ i = 0
+ while i < data.clipboardData.items.length
+ item = data.clipboardData.items[i]
+ if item.type.indexOf("image") isnt -1
+ return item
+ i++
+ return false
+
+ pasteText = (text) ->
+ caretStart = $(child)[0].selectionStart
+ caretEnd = $(child)[0].selectionEnd
+ textEnd = $(child).val().length
+
+ beforeSelection = $(child).val().substring 0, caretStart
+ afterSelection = $(child).val().substring caretEnd, textEnd
+ $(child).val beforeSelection + text + afterSelection
+ $(".markdown-area").trigger "input"
+
+ getFilename = (e) ->
+ if window.clipboardData and window.clipboardData.getData
+ value = window.clipboardData.getData("Text")
+ else if e.clipboardData and e.clipboardData.getData
+ value = e.clipboardData.getData("text/plain")
+
+ value = value.split("\r")
+ value.first()
+
+ uploadFile = (item, filename) ->
+ formData = new FormData()
+ formData.append "markdown_img", item, filename
+ $.ajax
+ url: project_image_path_upload
+ type: "POST"
+ data: formData
+ dataType: "json"
+ processData: false
+ contentType: false
+ headers:
+ "X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
+
+ beforeSend: ->
+ showSpinner()
+ closeAlertMessage()
+
+ success: (e, textStatus, response) ->
+ insertToTextArea(filename, formatLink(response.responseJSON.link))
+
+ error: (response) ->
+ showError(response.responseJSON.message)
+
+ complete: ->
+ closeSpinner()
+
+ insertToTextArea = (filename, url) ->
+ $(child).val (index, val) ->
+ val.replace("{{" + filename + "}}", url + "\n")
+
+ appendToTextArea = (url) ->
+ $(child).val (index, val) ->
+ val + url + "\n"
+
+ showSpinner = (e) ->
+ $(".div-dropzone-spinner").css "opacity", 0.7
+
+ closeSpinner = ->
+ $(".div-dropzone-spinner").css "opacity", 0
+
+ showError = (message) ->
+ checkIfMsgExists = $(".error-alert").children().length
+ if checkIfMsgExists is 0
+ $(".error-alert").append divAlert
+ $(".div-dropzone-alert").append btnAlert + message
+
+ closeAlertMessage = ->
+ $(".div-dropzone-alert").alert "close"
+
$(".markdown-selector").click (e) ->
e.preventDefault()
$(".div-dropzone").click()
diff --git a/app/assets/javascripts/merge_request.js.coffee b/app/assets/javascripts/merge_request.js.coffee
index b04a81c85eb..59e53b69e3d 100644
--- a/app/assets/javascripts/merge_request.js.coffee
+++ b/app/assets/javascripts/merge_request.js.coffee
@@ -109,10 +109,10 @@ class MergeRequest
type: 'GET'
url: this.$('.merge-request-tabs .diffs-tab a').attr('href')
beforeSend: =>
- this.$('.status').addClass 'loading'
+ this.$('.mr-loading-status .loading').show()
complete: =>
@diffs_loaded = true
- this.$('.status').removeClass 'loading'
+ this.$('.mr-loading-status .loading').hide()
success: (data) =>
this.$(".diffs").html(data.html)
dataType: 'json'
diff --git a/app/assets/javascripts/notes.js.coffee b/app/assets/javascripts/notes.js.coffee
index a41ee67a841..91a4ccaba43 100644
--- a/app/assets/javascripts/notes.js.coffee
+++ b/app/assets/javascripts/notes.js.coffee
@@ -142,8 +142,15 @@ class Notes
# remove the note (will be added again below)
row.next().find(".note").remove()
- # append new note to all matching discussions
- $(".notes[rel='" + note.discussion_id + "']").append note.html
+ # Add note to 'Changes' page discussions
+ $(".notes[rel='" + note.discussion_id + "']").append note.html
+
+ # Init discussion on 'Discussion' page if it is merge request page
+ if $('body').attr('data-page').indexOf('projects:merge_request') == 0
+ $('ul.main-notes-list').append(note.discussion_with_diff_html)
+ else
+ # append new note to all matching discussions
+ $(".notes[rel='" + note.discussion_id + "']").append note.html
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm(form)
diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss
index 7d058ad7719..b596af38311 100644
--- a/app/assets/stylesheets/application.scss
+++ b/app/assets/stylesheets/application.scss
@@ -8,8 +8,6 @@
*= require select2
*= require highlightjs.min
*= require_self
- *= require nprogress
- *= require nprogress-bootstrap
*= require dropzone/basic
*/
@@ -21,6 +19,12 @@
@import 'gl_bootstrap';
/**
+ * NProgress load bar css
+ */
+@import 'nprogress';
+@import 'nprogress-bootstrap';
+
+/**
* Font icons
*
*/
diff --git a/app/assets/stylesheets/generic/common.scss b/app/assets/stylesheets/generic/common.scss
index da2c1b0cbd8..b9942b5cb5d 100644
--- a/app/assets/stylesheets/generic/common.scss
+++ b/app/assets/stylesheets/generic/common.scss
@@ -16,6 +16,7 @@
.append-bottom-15 { margin-bottom:15px }
.append-bottom-20 { margin-bottom:20px }
.inline { display: inline-block }
+.center { text-align: center }
.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
@@ -55,7 +56,7 @@ pre {
.dropdown-menu > li > a:hover,
.dropdown-menu > li > a:focus {
- background: $bg_style_color;
+ background: $bg_primary;
color: #FFF
}
@@ -256,13 +257,6 @@ li.note {
}
}
-h1.http_status_code {
- font-size: 56px;
- line-height: 100px;
- font-weight: normal;
- color: #456;
-}
-
.control-group {
.controls {
span {
diff --git a/app/assets/stylesheets/generic/forms.scss b/app/assets/stylesheets/generic/forms.scss
index 5258acca466..2a31cae5dfb 100644
--- a/app/assets/stylesheets/generic/forms.scss
+++ b/app/assets/stylesheets/generic/forms.scss
@@ -76,30 +76,10 @@ label {
}
}
-.commit-message-container {
- background-color: $body-bg;
- position: relative;
- font-family: $monospace_font;
- $left: 12px;
- .max-width-marker {
- width: 72ch;
- color: rgba(0, 0, 0, 0.0);
- font-family: inherit;
- left: $left;
- height: 100%;
- border-right: 1px solid mix($input-border, white);
- position: absolute;
- z-index: 1;
- }
- > textarea {
- background-color: rgba(0, 0, 0, 0.0);
- font-family: inherit;
- padding-left: $left;
- position: relative;
- z-index: 2;
- }
-}
-
.fieldset-form fieldset {
margin-bottom: 20px;
}
+
+.form-control {
+ @include box-shadow(none);
+}
diff --git a/app/assets/stylesheets/generic/jquery.scss b/app/assets/stylesheets/generic/jquery.scss
index 6b29accb315..bfbbc7d25e3 100644
--- a/app/assets/stylesheets/generic/jquery.scss
+++ b/app/assets/stylesheets/generic/jquery.scss
@@ -41,8 +41,8 @@
}
.ui-state-active {
- border: 1px solid $bg_style_color;
- background: $bg_style_color;
+ border: 1px solid $bg_primary;
+ background: $bg_primary;
color: #FFF;
}
diff --git a/app/assets/stylesheets/generic/selects.scss b/app/assets/stylesheets/generic/selects.scss
index 0afd85aedf6..e0f508d2695 100644
--- a/app/assets/stylesheets/generic/selects.scss
+++ b/app/assets/stylesheets/generic/selects.scss
@@ -42,7 +42,7 @@
.select2-results {
max-height: 350px;
.select2-highlighted {
- background: $bg_style_color;
+ background: $bg_primary;
}
}
}
diff --git a/app/assets/stylesheets/gl_bootstrap.scss b/app/assets/stylesheets/gl_bootstrap.scss
index 4271a7b310c..34b0608646c 100644
--- a/app/assets/stylesheets/gl_bootstrap.scss
+++ b/app/assets/stylesheets/gl_bootstrap.scss
@@ -9,7 +9,7 @@
$font-size-base: 13px !default;
$nav-pills-active-link-hover-bg: $bg_primary;
$pagination-active-bg: $bg_primary;
-$list-group-active-bg: $bg_style_color;
+$list-group-active-bg: $bg_primary;
// Core variables and mixins
@import "bootstrap/variables";
diff --git a/app/assets/stylesheets/main/variables.scss b/app/assets/stylesheets/main/variables.scss
index 68f7f6b8581..c49f7db788e 100644
--- a/app/assets/stylesheets/main/variables.scss
+++ b/app/assets/stylesheets/main/variables.scss
@@ -2,7 +2,6 @@
* General Colors
*/
$style_color: #474D57;
-$bg_style_color: #2299BB;
$hover: #D9EDF7;
/*
@@ -40,3 +39,8 @@ $border_warning: #EB9532;
*/
$added: #63c363;
$deleted: #f77;
+
+/**
+ *
+ */
+$nprogress-color: #3498db;
diff --git a/app/assets/stylesheets/sections/commits.scss b/app/assets/stylesheets/sections/commits.scss
index ef8c5f089b9..f00d024f389 100644
--- a/app/assets/stylesheets/sections/commits.scss
+++ b/app/assets/stylesheets/sections/commits.scss
@@ -213,3 +213,27 @@ li.commit {
padding: 4px 12px;
}
}
+
+.commit-message-container {
+ background-color: $body-bg;
+ position: relative;
+ font-family: $monospace_font;
+ $left: 12px;
+ .max-width-marker {
+ width: 72ch;
+ color: rgba(0, 0, 0, 0.0);
+ font-family: inherit;
+ left: $left;
+ height: 100%;
+ border-right: 1px solid mix($input-border, white);
+ position: absolute;
+ z-index: 1;
+ }
+ > textarea {
+ background-color: rgba(0, 0, 0, 0.0);
+ font-family: inherit;
+ padding-left: $left;
+ position: relative;
+ z-index: 2;
+ }
+}
diff --git a/app/assets/stylesheets/sections/errors.scss b/app/assets/stylesheets/sections/errors.scss
new file mode 100644
index 00000000000..32d2d7b1dbf
--- /dev/null
+++ b/app/assets/stylesheets/sections/errors.scss
@@ -0,0 +1,14 @@
+.error-page {
+ max-width: 400px;
+ margin: 0 auto;
+
+ h1, h2, h3 {
+ text-align: center;
+ }
+
+ h1 {
+ font-size: 56px;
+ line-height: 100px;
+ font-weight: 300;
+ }
+}
diff --git a/app/assets/stylesheets/sections/events.scss b/app/assets/stylesheets/sections/events.scss
index 957af62c0ea..656aa5b18a6 100644
--- a/app/assets/stylesheets/sections/events.scss
+++ b/app/assets/stylesheets/sections/events.scss
@@ -156,12 +156,13 @@
.filter_icon {
a {
text-align:center;
- background: #EEE;
+ background: $bg_primary;
margin-bottom: 10px;
float: left;
padding: 9px 6px;
font-size: 18px;
width: 40px;
+ color: #FFF;
@include border-radius(3px);
}
diff --git a/app/assets/stylesheets/sections/header.scss b/app/assets/stylesheets/sections/header.scss
index b811b0bc665..29cb0f4b87c 100644
--- a/app/assets/stylesheets/sections/header.scss
+++ b/app/assets/stylesheets/sections/header.scss
@@ -6,14 +6,12 @@ header {
&.navbar-gitlab {
margin-bottom: 0;
min-height: 40px;
+ border: none;
.navbar-inner {
- background: #F1F1F1;
- border-bottom: 1px solid #DDD;
filter: none;
.nav > li > a {
- color: $style_color;
font-size: 14px;
line-height: 32px;
padding: 6px 10px;
@@ -248,8 +246,6 @@ header {
float: left;
height: 46px;
width: 2px;
- background: white;
- border-left: 1px solid #DDD;
margin-left: 10px;
margin-right: 10px;
}
diff --git a/app/assets/stylesheets/sections/nav.scss b/app/assets/stylesheets/sections/nav.scss
index 59eaaec9498..f5d09c2df10 100644
--- a/app/assets/stylesheets/sections/nav.scss
+++ b/app/assets/stylesheets/sections/nav.scss
@@ -3,7 +3,7 @@
margin: 20px 0;
margin-top: 0;
padding-top: 4px;
- border-bottom: 1px solid #E1E1E1;
+ border-bottom: 1px solid #E9E9E9;
ul {
padding: 0;
diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss
index e8d6ec3e29a..18db7abc64e 100644
--- a/app/assets/stylesheets/sections/notes.scss
+++ b/app/assets/stylesheets/sections/notes.scss
@@ -43,38 +43,14 @@ ul.notes {
}
.discussion {
- padding: 8px 0;
+ padding: 10px 0;
overflow: hidden;
display: block;
position:relative;
+ border-bottom: 1px solid #EEE;
.discussion-body {
margin-left: 50px;
-
- .diff-file,
- .discussion-hidden,
- .notes {
- background-color: #F9F9F9;
- }
- .diff-file .notes {
- /* reset */
- background: inherit;
- border: none;
- @include box-shadow(none);
-
- }
- .discussion-hidden .note {
- @extend .cgray;
- padding: 8px;
- text-align: center;
- }
- .notes .note {
- border-color: #ddd;
- padding: 8px;
- }
- .reply-btn {
- margin-top: 8px;
- }
}
}
@@ -137,10 +113,6 @@ ul.notes {
vertical-align: top;
}
}
-
- .reply-btn {
- margin: 5px;
- }
}
/**
@@ -376,3 +348,17 @@ ul.notes {
margin-top: 5px;
margin-bottom: 5px;
}
+
+.discussion-body,
+.diff-file {
+ .notes .note {
+ border-color: #ddd;
+ padding: 10px 15px;
+ }
+
+ .discussion-reply-holder {
+ background: #f9f9f9;
+ padding: 10px 15px;
+ border-top: 1px solid #DDD;
+ }
+}
diff --git a/app/assets/stylesheets/sections/profile.scss b/app/assets/stylesheets/sections/profile.scss
index ed73e1630f2..086875582f3 100644
--- a/app/assets/stylesheets/sections/profile.scss
+++ b/app/assets/stylesheets/sections/profile.scss
@@ -56,10 +56,10 @@
text-align: center;
.prev {
- @extend .thumbnail;
- height: 30px;
- width: 175px;
+ height: 80px;
+ width: 160px;
margin-bottom: 10px;
+ @include border-radius(4px);
&.classic {
background: #31363e;
@@ -92,10 +92,13 @@
text-align: center;
.prev {
- @extend .thumbnail;
- height: 151px;
- width: 220px;
+ width: 160px;
margin-bottom: 10px;
+
+ img {
+ max-width: 100%;
+ @include border-radius(4px);
+ }
}
}
}
diff --git a/app/assets/stylesheets/themes/ui_basic.scss b/app/assets/stylesheets/themes/ui_basic.scss
index 30f0bbaf4c8..3e3744fdc33 100644
--- a/app/assets/stylesheets/themes/ui_basic.scss
+++ b/app/assets/stylesheets/themes/ui_basic.scss
@@ -4,11 +4,21 @@
*
*/
.ui_basic {
- .separator {
- background: #F9F9F9;
- border-left: 1px solid #DDD;
+ header {
+ &.navbar-gitlab {
+ .navbar-inner {
+ background: #F1F1F1;
+ border-bottom: 1px solid #DDD;
+ .nav > li > a {
+ color: $style_color;
+ }
+ .separator {
+ background: #F9F9F9;
+ border-left: 1px solid #DDD;
+ }
+ }
+ }
}
-
.main-nav {
background: #FFF;
}
diff --git a/app/controllers/admin/users_controller.rb b/app/controllers/admin/users_controller.rb
index 5ecdfbd807e..f0040bf5e87 100644
--- a/app/controllers/admin/users_controller.rb
+++ b/app/controllers/admin/users_controller.rb
@@ -100,6 +100,16 @@ class Admin::UsersController < Admin::ApplicationController
end
end
+ def remove_email
+ email = user.emails.find(params[:email_id])
+ email.destroy
+
+ respond_to do |format|
+ format.html { redirect_to :back, notice: "Successfully removed email." }
+ format.js { render nothing: true }
+ end
+ end
+
protected
def user
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 603e89a5e29..d58890fa33b 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -48,7 +48,7 @@ class ApplicationController < ActionController::Base
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
new_user_session_path
else
- super
+ @return_to || root_path
end
end
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index 0c87fe0d9ae..ef2afec52dc 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -31,6 +31,12 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
end
end
+ def omniauth_error
+ @provider = params[:provider]
+ @error = params[:error]
+ render 'errors/omniauth_error', layout: "errors", status: 422
+ end
+
private
def handle_omniauth
@@ -45,14 +51,19 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
# Create user if does not exist
# and allow_single_sign_on is true
- if Gitlab.config.omniauth['allow_single_sign_on']
- @user ||= Gitlab::OAuth::User.create(oauth)
+ if Gitlab.config.omniauth['allow_single_sign_on'] && !@user
+ @user, errors = Gitlab::OAuth::User.create(oauth)
end
- if @user
+ if @user && !errors
sign_in_and_redirect(@user)
else
- flash[:notice] = "There's no such user!"
+ if errors
+ error_message = errors.map{ |attribute, message| "#{attribute} #{message}" }.join(", ")
+ redirect_to omniauth_error_path(oauth['provider'], error: error_message) and return
+ else
+ flash[:notice] = "There's no such user!"
+ end
redirect_to new_user_session_path
end
end
diff --git a/app/controllers/projects/commits_controller.rb b/app/controllers/projects/commits_controller.rb
index 12856191c26..038645aa497 100644
--- a/app/controllers/projects/commits_controller.rb
+++ b/app/controllers/projects/commits_controller.rb
@@ -13,6 +13,8 @@ class Projects::CommitsController < Projects::ApplicationController
@limit, @offset = (params[:limit] || 40), (params[:offset] || 0)
@commits = @repo.commits(@ref, @path, @limit, @offset)
+ @note_counts = Note.where(commit_id: @commits.map(&:id)).
+ group(:commit_id).count
respond_to do |format|
format.html # index.html.erb
diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb
index ddea8901f9b..ffe65cb41c5 100644
--- a/app/controllers/projects/issues_controller.rb
+++ b/app/controllers/projects/issues_controller.rb
@@ -20,7 +20,7 @@ class Projects::IssuesController < Projects::ApplicationController
terms = params['issue_search']
@issues = issues_filtered
- @issues = @issues.where("title LIKE ?", "%#{terms}%") if terms.present?
+ @issues = @issues.where("title LIKE ? OR description LIKE ?", "%#{terms}%", "%#{terms}%") if terms.present?
@issues = @issues.page(params[:page]).per(20)
assignee_id, milestone_id = params[:assignee_id], params[:milestone_id]
diff --git a/app/controllers/projects/merge_requests_controller.rb b/app/controllers/projects/merge_requests_controller.rb
index 1abedc1f272..89f4ab01a3f 100644
--- a/app/controllers/projects/merge_requests_controller.rb
+++ b/app/controllers/projects/merge_requests_controller.rb
@@ -32,6 +32,8 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end
def show
+ @note_counts = Note.where(commit_id: @merge_request.commits.map(&:id)).
+ group(:commit_id).count
respond_to do |format|
format.html
format.diff { render text: @merge_request.to_diff(current_user) }
@@ -86,6 +88,9 @@ class Projects::MergeRequestsController < Projects::ApplicationController
@compare_failed = true
end
+ @note_counts = Note.where(commit_id: @commits.map(&:id)).
+ group(:commit_id).count
+
@diffs = compare_action.diffs
@merge_request.title = @merge_request.source_branch.titleize.humanize
@target_project = @merge_request.target_project
diff --git a/app/controllers/projects/notes_controller.rb b/app/controllers/projects/notes_controller.rb
index b5b0446b43f..66cc1a3dec7 100644
--- a/app/controllers/projects/notes_controller.rb
+++ b/app/controllers/projects/notes_controller.rb
@@ -21,7 +21,7 @@ class Projects::NotesController < Projects::ApplicationController
end
def create
- @note = Notes::CreateService.new(project, current_user, params).execute
+ @note = Notes::CreateService.new(project, current_user, params[:note]).execute
respond_to do |format|
format.json { render_note_json(@note) }
@@ -85,12 +85,24 @@ class Projects::NotesController < Projects::ApplicationController
)
end
+ def note_to_discussion_with_diff_html(note)
+ return unless note.for_diff_line?
+
+ render_to_string(
+ "projects/notes/_discussion",
+ layout: false,
+ formats: [:html],
+ locals: { discussion_notes: [note] }
+ )
+ end
+
def render_note_json(note)
render json: {
id: note.id,
discussion_id: note.discussion_id,
html: note_to_html(note),
- discussion_html: note_to_discussion_html(note)
+ discussion_html: note_to_discussion_html(note),
+ discussion_with_diff_html: note_to_discussion_with_diff_html(note)
}
end
diff --git a/app/controllers/projects/refs_controller.rb b/app/controllers/projects/refs_controller.rb
index 8834a995081..7997c726fbb 100644
--- a/app/controllers/projects/refs_controller.rb
+++ b/app/controllers/projects/refs_controller.rb
@@ -37,7 +37,7 @@ class Projects::RefsController < Projects::ApplicationController
0
end
- @limit = 10
+ @limit = 25
@path = params[:path]
diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb
index 9e14af62048..0d15b458b70 100644
--- a/app/controllers/projects_controller.rb
+++ b/app/controllers/projects_controller.rb
@@ -98,8 +98,7 @@ class ProjectsController < ApplicationController
def destroy
return access_denied! unless can?(current_user, :remove_project, project)
- project.team.truncate
- project.destroy
+ ::Projects::DestroyService.new(@project, current_user, {}).execute
respond_to do |format|
format.html { redirect_to root_path }
@@ -125,18 +124,12 @@ class ProjectsController < ApplicationController
def autocomplete_sources
note_type = params['type']
note_id = params['type_id']
- participating = if note_type && note_id
- participants_in(note_type, note_id)
- else
- []
- end
- team_members = sorted(@project.team.members)
- participants = team_members + participating
+ participants = ::Projects::ParticipantsService.new(@project).execute(note_type, note_id)
@suggestions = {
emojis: Emoji.names.map { |e| { name: e, path: view_context.image_url("emoji/#{e}.png") } },
issues: @project.issues.select([:iid, :title, :description]),
mergerequests: @project.merge_requests.select([:iid, :title, :description]),
- members: participants.uniq
+ members: participants
}
respond_to do |format|
@@ -192,25 +185,4 @@ class ProjectsController < ApplicationController
def user_layout
current_user ? "projects" : "public_projects"
end
-
- def participants_in(type, id)
- users = case type
- when "Issue"
- issue = @project.issues.find_by_iid(id)
- issue ? issue.participants : []
- when "MergeRequest"
- merge_request = @project.merge_requests.find_by_iid(id)
- merge_request ? merge_request.participants : []
- when "Commit"
- author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
- User.where(id: author_ids)
- else
- []
- end
- sorted(users)
- end
-
- def sorted(users)
- users.uniq.to_a.compact.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
- end
end
diff --git a/app/controllers/users_sessions_controller.rb b/app/controllers/users_sessions_controller.rb
new file mode 100644
index 00000000000..656c92376fd
--- /dev/null
+++ b/app/controllers/users_sessions_controller.rb
@@ -0,0 +1,6 @@
+class UsersSessionsController < Devise::SessionsController
+ def create
+ @return_to = params[:return_to]
+ super
+ end
+end
diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb
index d3904e16c11..f0530c74828 100644
--- a/app/helpers/events_helper.rb
+++ b/app/helpers/events_helper.rb
@@ -45,15 +45,15 @@ module EventsHelper
def event_feed_title(event)
if event.issue?
- "#{event.author_name} #{event.action_name} issue ##{event.target_id}: #{event.issue_title} at #{event.project_name}"
+ "#{event.author_name} #{event.action_name} issue ##{event.target_iid}: #{event.issue_title} at #{event.project_name}"
elsif event.merge_request?
- "#{event.author_name} #{event.action_name} MR ##{event.target_id}: #{event.merge_request_title} at #{event.project_name}"
+ "#{event.author_name} #{event.action_name} MR ##{event.target_iid}: #{event.merge_request_title} at #{event.project_name}"
elsif event.push?
"#{event.author_name} #{event.push_action_name} #{event.ref_type} #{event.ref_name} at #{event.project_name}"
elsif event.membership_changed?
"#{event.author_name} #{event.action_name} #{event.project_name}"
elsif event.note?
- "#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_id} at #{event.project_name}"
+ "#{event.author_name} commented on #{event.note_target_type} ##{truncate event.note_target_iid} at #{event.project_name}"
else
""
end
diff --git a/app/helpers/gitlab_markdown_helper.rb b/app/helpers/gitlab_markdown_helper.rb
index db5b4eacd1f..c7f769cee64 100644
--- a/app/helpers/gitlab_markdown_helper.rb
+++ b/app/helpers/gitlab_markdown_helper.rb
@@ -63,10 +63,14 @@ module GitlabMarkdownHelper
paths = extract_paths(text)
paths.uniq.each do |file_path|
- new_path = rebuild_path(file_path)
- # Finds quoted path so we don't replace other mentions of the string
- # eg. "doc/api" will be replaced and "/home/doc/api/text" won't
- text.gsub!("\"#{file_path}\"", "\"/#{new_path}\"")
+ # If project does not have repository
+ # its nothing to rebuild
+ if @repository.exists? && !@repository.empty?
+ new_path = rebuild_path(file_path)
+ # Finds quoted path so we don't replace other mentions of the string
+ # eg. "doc/api" will be replaced and "/home/doc/api/text" won't
+ text.gsub!("\"#{file_path}\"", "\"/#{new_path}\"")
+ end
end
text
@@ -91,7 +95,12 @@ module GitlabMarkdownHelper
end
def link_to_ignore?(link)
- ignored_protocols.map{ |protocol| link.include?(protocol) }.any?
+ if link =~ /\#\w+/
+ # ignore anchors like <a href="#my-header">
+ true
+ else
+ ignored_protocols.map{ |protocol| link.include?(protocol) }.any?
+ end
end
def ignored_protocols
@@ -169,7 +178,7 @@ module GitlabMarkdownHelper
def current_sha
if @commit
@commit.id
- else
+ elsif @repository && !@repository.empty?
@repository.head_commit.sha
end
end
diff --git a/app/helpers/notes_helper.rb b/app/helpers/notes_helper.rb
index 9ed38ba84b2..53ac5febd61 100644
--- a/app/helpers/notes_helper.rb
+++ b/app/helpers/notes_helper.rb
@@ -15,12 +15,6 @@ module NotesHelper
end
end
- def link_to_merge_request_diff_line_note(note)
- if note.for_merge_request_diff_line? and note.diff
- link_to "#{note.diff_file_name}:L#{note.diff_new_line}", diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code)
- end
- end
-
def note_timestamp(note)
# Shows the created at time and the updated at time if different
ts = "#{time_ago_with_tooltip(note.created_at, 'bottom', 'note_created_ago')}"
@@ -61,4 +55,23 @@ module NotesHelper
link_to "", "javascript:;", class: "add-diff-note js-add-diff-note-button",
data: data, title: "Add a comment to this line"
end
+
+ def link_to_reply_diff(note)
+ return unless current_user
+
+ data = {
+ noteable_type: note.noteable_type,
+ noteable_id: note.noteable_id,
+ commit_id: note.commit_id,
+ line_code: note.line_code,
+ discussion_id: note.discussion_id
+ }
+
+ link_to "javascript:;", class: "btn reply-btn js-discussion-reply-button",
+ data: data, title: "Add a reply" do
+ link_text = ""
+ link_text < content_tag(:i, nil, class: 'icon-comment')
+ link_text << "Reply"
+ end
+ end
end
diff --git a/app/models/concerns/mentionable.rb b/app/models/concerns/mentionable.rb
index a46a593c6e3..81414959f3b 100644
--- a/app/models/concerns/mentionable.rb
+++ b/app/models/concerns/mentionable.rb
@@ -49,12 +49,16 @@ module Mentionable
matches = mentionable_text.scan(/@[a-zA-Z][a-zA-Z0-9_\-\.]*/)
matches.each do |match|
identifier = match.delete "@"
- if has_project
- id = project.team.members.find_by(username: identifier).try(:id)
+ if identifier == "all"
+ users += project.team.members.flatten
else
- id = User.where(username: identifier).pluck(:id).first
+ if has_project
+ id = project.team.members.find_by(username: identifier).try(:id)
+ else
+ id = User.find_by(username: identifier).try(:id)
+ end
+ users << User.find(id) unless id.blank?
end
- users << User.find(id) unless id.blank?
end
users.uniq
end
diff --git a/app/models/event.rb b/app/models/event.rb
index b88635ccb59..1a8d55c54b4 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -41,6 +41,9 @@ class Event < ActiveRecord::Base
# For Hash only
serialize :data
+ # Callbacks
+ after_create :reset_project_activity
+
# Scopes
scope :recent, -> { order("created_at DESC") }
scope :code_push, -> { where(action: PUSHED) }
@@ -303,4 +306,10 @@ class Event < ActiveRecord::Base
target.respond_to? :title
end
end
+
+ def reset_project_activity
+ if project
+ project.update_column(:last_activity_at, self.created_at)
+ end
+ end
end
diff --git a/app/models/note.rb b/app/models/note.rb
index 659cd752071..94d45aa43db 100644
--- a/app/models/note.rb
+++ b/app/models/note.rb
@@ -57,6 +57,7 @@ class Note < ActiveRecord::Base
serialize :st_diff
before_create :set_diff, if: ->(n) { n.line_code.present? }
+ after_update :set_references
class << self
def create_status_change_note(noteable, project, author, status, source)
@@ -178,10 +179,28 @@ class Note < ActiveRecord::Base
@diff ||= Gitlab::Git::Diff.new(st_diff) if st_diff.respond_to?(:map)
end
+ # Check if such line of code exists in merge request diff
+ # If exists - its active discussion
+ # If not - its outdated diff
def active?
- # TODO: determine if discussion is outdated
- # according to recent MR diff or not
- true
+ return true unless self.diff
+
+ noteable.diffs.each do |mr_diff|
+ next unless mr_diff.new_path == self.diff.new_path
+
+ Gitlab::DiffParser.new(mr_diff.diff.lines.to_a, mr_diff.new_path).
+ each do |full_line, type, line_code, line_new, line_old|
+ if full_line == diff_line
+ return true
+ end
+ end
+ end
+
+ false
+ end
+
+ def outdated?
+ !active?
end
def diff_file_index
@@ -314,4 +333,8 @@ class Note < ActiveRecord::Base
order('id DESC').limit(100).
update_all(updated_at: Time.now)
end
+
+ def set_references
+ notice_added_references(project, author)
+ end
end
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 00a1032b6c4..22c16abe480 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -128,6 +128,7 @@ class Repository
Rails.cache.delete(cache_key(:commit_count))
Rails.cache.delete(cache_key(:graph_log))
Rails.cache.delete(cache_key(:readme))
+ Rails.cache.delete(cache_key(:version))
Rails.cache.delete(cache_key(:contribution_guide))
end
@@ -156,12 +157,24 @@ class Repository
Gitlab::Git::Blob.find(self, sha, path)
end
+ def blob_by_oid(oid)
+ Gitlab::Git::Blob.raw(self, oid)
+ end
+
def readme
Rails.cache.fetch(cache_key(:readme)) do
tree(:head).readme
end
end
+ def version
+ Rails.cache.fetch(cache_key(:version)) do
+ tree(:head).blobs.find do |file|
+ file.name.downcase == 'version'
+ end
+ end
+ end
+
def contribution_guide
Rails.cache.fetch(cache_key(:contribution_guide)) do
tree(:head).contribution_guide
diff --git a/app/models/user.rb b/app/models/user.rb
index 2352f8c050b..63d819a0f36 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -132,6 +132,10 @@ class User < ActiveRecord::Base
before_validation :sanitize_attrs
before_save :ensure_authentication_token
+ after_save :ensure_namespace_correct
+ after_create :post_create_hook
+ after_destroy :post_destroy_hook
+
alias_attribute :private_token, :authentication_token
@@ -368,7 +372,7 @@ class User < ActiveRecord::Base
end
def several_namespaces?
- owned_groups.any?
+ owned_groups.any? || masters_groups.any?
end
def namespace_id
@@ -490,4 +494,36 @@ class User < ActiveRecord::Base
GravatarService.new.execute(email, size)
end
end
+
+ def ensure_namespace_correct
+ # Ensure user has namespace
+ self.create_namespace!(path: self.username, name: self.username) unless self.namespace
+
+ if self.username_changed?
+ self.namespace.update_attributes(path: self.username, name: self.username)
+ end
+ end
+
+ def post_create_hook
+ log_info("User \"#{self.name}\" (#{self.email}) was created")
+ notification_service.new_user(self)
+ system_hook_service.execute_hooks_for(self, :create)
+ end
+
+ def post_destroy_hook
+ log_info("User \"#{self.name}\" (#{self.email}) was removed")
+ system_hook_service.execute_hooks_for(self, :destroy)
+ end
+
+ def notification_service
+ NotificationService.new
+ end
+
+ def log_info message
+ Gitlab::AppLogger.info message
+ end
+
+ def system_hook_service
+ SystemHooksService.new
+ end
end
diff --git a/app/models/users_group.rb b/app/models/users_group.rb
index 5f8b832d51e..242c8abb3ca 100644
--- a/app/models/users_group.rb
+++ b/app/models/users_group.rb
@@ -33,6 +33,9 @@ class UsersGroup < ActiveRecord::Base
scope :with_group, ->(group) { where(group_id: group.id) }
scope :with_user, ->(user) { where(user_id: user.id) }
+ after_create :notify_create
+ after_update :notify_update
+
validates :group_access, inclusion: { in: UsersGroup.group_access_roles.values }, presence: true
validates :user_id, presence: true
validates :group_id, presence: true
@@ -43,4 +46,18 @@ class UsersGroup < ActiveRecord::Base
def access_field
group_access
end
+
+ def notify_create
+ notification_service.new_group_member(self)
+ end
+
+ def notify_update
+ if group_access_changed?
+ notification_service.update_group_member(self)
+ end
+ end
+
+ def notification_service
+ NotificationService.new
+ end
end
diff --git a/app/models/users_project.rb b/app/models/users_project.rb
index e8810f56def..6495bed4e61 100644
--- a/app/models/users_project.rb
+++ b/app/models/users_project.rb
@@ -37,6 +37,10 @@ class UsersProject < ActiveRecord::Base
scope :in_projects, ->(projects) { where(project_id: projects.map { |p| p.id }) }
scope :with_user, ->(user) { where(user_id: user.id) }
+ after_create :post_create_hook
+ after_update :post_update_hook
+ after_destroy :post_destroy_hook
+
class << self
# Add users to project teams with passed access option
@@ -114,4 +118,37 @@ class UsersProject < ActiveRecord::Base
def owner?
project.owner == user
end
+
+ def post_create_hook
+ Event.create(
+ project_id: self.project.id,
+ action: Event::JOINED,
+ author_id: self.user.id
+ )
+
+ notification_service.new_team_member(self)
+ system_hook_service.execute_hooks_for(self, :create)
+ end
+
+ def post_update_hook
+ notification_service.update_team_member(self) if self.project_access_changed?
+ end
+
+ def post_destroy_hook
+ Event.create(
+ project_id: self.project.id,
+ action: Event::LEFT,
+ author_id: self.user.id
+ )
+
+ system_hook_service.execute_hooks_for(self, :destroy)
+ end
+
+ def notification_service
+ NotificationService.new
+ end
+
+ def system_hook_service
+ SystemHooksService.new
+ end
end
diff --git a/app/observers/base_observer.rb b/app/observers/base_observer.rb
deleted file mode 100644
index 260d1f05db3..00000000000
--- a/app/observers/base_observer.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-class BaseObserver < ActiveRecord::Observer
- def notification
- NotificationService.new
- end
-
- def event_service
- EventCreateService.new
- end
-
- def log_info message
- Gitlab::AppLogger.info message
- end
-end
diff --git a/app/observers/note_observer.rb b/app/observers/note_observer.rb
deleted file mode 100644
index bb0b0876eca..00000000000
--- a/app/observers/note_observer.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class NoteObserver < BaseObserver
- def after_create(note)
- notification.new_note(note)
-
- # Skip system notes, like status changes and cross-references.
- unless note.system
- event_service.leave_note(note, note.author)
-
- # Create a cross-reference note if this Note contains GFM that names an
- # issue, merge request, or commit.
- note.references.each do |mentioned|
- Note.create_cross_reference_note(mentioned, note.noteable, note.author, note.project)
- end
- end
- end
-
- def after_update(note)
- note.notice_added_references(note.project, note.author)
- end
-end
diff --git a/app/observers/project_activity_cache_observer.rb b/app/observers/project_activity_cache_observer.rb
deleted file mode 100644
index 96ced90db80..00000000000
--- a/app/observers/project_activity_cache_observer.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-class ProjectActivityCacheObserver < BaseObserver
- observe :event
-
- def after_create(event)
- event.project.update_column(:last_activity_at, event.created_at) if event.project
- end
-end
-
diff --git a/app/observers/project_observer.rb b/app/observers/project_observer.rb
deleted file mode 100644
index ad41ddad58f..00000000000
--- a/app/observers/project_observer.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-class ProjectObserver < BaseObserver
- def after_create(project)
- log_info("#{project.owner.name} created a new project \"#{project.name_with_namespace}\"")
- end
-
- def after_update(project)
- project.send_move_instructions if project.namespace_id_changed?
- project.rename_repo if project.path_changed?
- end
-
- def before_destroy(project)
- project.repository.expire_cache unless project.empty_repo?
- end
-
- def after_destroy(project)
- GitlabShellWorker.perform_async(
- :remove_repository,
- project.path_with_namespace
- )
-
- GitlabShellWorker.perform_async(
- :remove_repository,
- project.path_with_namespace + ".wiki"
- )
-
- project.satellite.destroy
-
- log_info("Project \"#{project.name}\" was removed")
- end
-end
diff --git a/app/observers/system_hook_observer.rb b/app/observers/system_hook_observer.rb
deleted file mode 100644
index 80de177b9a2..00000000000
--- a/app/observers/system_hook_observer.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-class SystemHookObserver < BaseObserver
- observe :user, :project, :users_project
-
- def after_create(model)
- system_hook_service.execute_hooks_for(model, :create)
- end
-
- def after_destroy(model)
- system_hook_service.execute_hooks_for(model, :destroy)
- end
-
- private
-
- def system_hook_service
- SystemHooksService.new
- end
-end
diff --git a/app/observers/user_observer.rb b/app/observers/user_observer.rb
deleted file mode 100644
index fba0f1006d9..00000000000
--- a/app/observers/user_observer.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-class UserObserver < BaseObserver
- def after_create(user)
- log_info("User \"#{user.name}\" (#{user.email}) was created")
-
- notification.new_user(user)
- end
-
- def after_destroy user
- log_info("User \"#{user.name}\" (#{user.email}) was removed")
- end
-
- def after_save user
- # Ensure user has namespace
- user.create_namespace!(path: user.username, name: user.username) unless user.namespace
-
- if user.username_changed?
- user.namespace.update_attributes(path: user.username, name: user.username)
- end
- end
-end
diff --git a/app/observers/users_group_observer.rb b/app/observers/users_group_observer.rb
deleted file mode 100644
index 42a05b5e177..00000000000
--- a/app/observers/users_group_observer.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class UsersGroupObserver < BaseObserver
- def after_create(membership)
- notification.new_group_member(membership)
- end
-
- def after_update(membership)
- notification.update_group_member(membership) if membership.group_access_changed?
- end
-end
diff --git a/app/observers/users_project_observer.rb b/app/observers/users_project_observer.rb
deleted file mode 100644
index 44c72b30187..00000000000
--- a/app/observers/users_project_observer.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-class UsersProjectObserver < BaseObserver
- def after_create(users_project)
- Event.create(
- project_id: users_project.project.id,
- action: Event::JOINED,
- author_id: users_project.user.id
- )
-
- notification.new_team_member(users_project)
- end
-
- def after_update(users_project)
- notification.update_team_member(users_project) if users_project.project_access_changed?
- end
-
- def after_destroy(users_project)
- Event.create(
- project_id: users_project.project.id,
- action: Event::LEFT,
- author_id: users_project.user.id
- )
- end
-end
diff --git a/app/services/base_service.rb b/app/services/base_service.rb
index 9ad80923152..31b38aca530 100644
--- a/app/services/base_service.rb
+++ b/app/services/base_service.rb
@@ -28,4 +28,8 @@ class BaseService
def log_info message
Gitlab::AppLogger.info message
end
+
+ def system_hook_service
+ SystemHooksService.new
+ end
end
diff --git a/app/services/issues/base_service.rb b/app/services/issues/base_service.rb
index eac774210ae..71b9ffc3489 100644
--- a/app/services/issues/base_service.rb
+++ b/app/services/issues/base_service.rb
@@ -7,8 +7,11 @@ module Issues
Note.create_assignee_change_note(issue, issue.project, current_user, issue.assignee)
end
- def execute_hooks(issue)
- issue.project.execute_hooks(issue.to_hook_data, :issue_hooks)
+ def execute_hooks(issue, action = 'open')
+ issue_data = issue.to_hook_data
+ issue_url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
+ issue_data[:object_attributes].merge!(url: issue_url, action: action)
+ issue.project.execute_hooks(issue_data, :issue_hooks)
end
def create_milestone_note(issue)
diff --git a/app/services/issues/close_service.rb b/app/services/issues/close_service.rb
index 85c0226ccab..ffed13a12e1 100644
--- a/app/services/issues/close_service.rb
+++ b/app/services/issues/close_service.rb
@@ -5,7 +5,7 @@ module Issues
notification_service.close_issue(issue, current_user)
event_service.close_issue(issue, current_user)
create_note(issue, commit)
- execute_hooks(issue)
+ execute_hooks(issue, 'close')
end
issue
diff --git a/app/services/issues/create_service.rb b/app/services/issues/create_service.rb
index d6137833bb9..6d05d417f1b 100644
--- a/app/services/issues/create_service.rb
+++ b/app/services/issues/create_service.rb
@@ -8,7 +8,7 @@ module Issues
notification_service.new_issue(issue, current_user)
event_service.open_issue(issue, current_user)
issue.create_cross_references!(issue.project, current_user)
- execute_hooks(issue)
+ execute_hooks(issue, 'open')
end
issue
diff --git a/app/services/issues/reopen_service.rb b/app/services/issues/reopen_service.rb
index a931398aff6..b23d56258a8 100644
--- a/app/services/issues/reopen_service.rb
+++ b/app/services/issues/reopen_service.rb
@@ -4,7 +4,7 @@ module Issues
if issue.reopen
event_service.reopen_issue(issue, current_user)
create_note(issue)
- execute_hooks(issue)
+ execute_hooks(issue, 'reopen')
end
issue
diff --git a/app/services/issues/update_service.rb b/app/services/issues/update_service.rb
index b4a742b0037..169e1e95b4b 100644
--- a/app/services/issues/update_service.rb
+++ b/app/services/issues/update_service.rb
@@ -23,7 +23,7 @@ module Issues
end
issue.notice_added_references(issue.project, current_user)
- execute_hooks(issue)
+ execute_hooks(issue, 'update')
end
issue
diff --git a/app/services/notes/create_service.rb b/app/services/notes/create_service.rb
index ff6dfb61139..f64006a4edc 100644
--- a/app/services/notes/create_service.rb
+++ b/app/services/notes/create_service.rb
@@ -1,10 +1,25 @@
module Notes
class CreateService < BaseService
def execute
- note = project.notes.new(params[:note])
+ note = project.notes.new(params)
note.author = current_user
note.system = false
- note.save
+
+ if note.save
+ notification_service.new_note(note)
+
+ # Skip system notes, like status changes and cross-references.
+ unless note.system
+ event_service.leave_note(note, note.author)
+
+ # Create a cross-reference note if this Note contains GFM that names an
+ # issue, merge request, or commit.
+ note.references.each do |mentioned|
+ Note.create_cross_reference_note(mentioned, note.noteable, note.author, note.project)
+ end
+ end
+ end
+
note
end
end
diff --git a/app/services/projects/create_service.rb b/app/services/projects/create_service.rb
index 3d2b9bf4875..dfadcfd296a 100644
--- a/app/services/projects/create_service.rb
+++ b/app/services/projects/create_service.rb
@@ -51,6 +51,9 @@ module Projects
@project.creator = current_user
if @project.save
+ log_info("#{@project.owner.name} created a new project \"#{@project.name_with_namespace}\"")
+ system_hook_service.execute_hooks_for(@project, :create)
+
unless @project.group
@project.users_projects.create(
project_access: UsersProject::MASTER,
diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb
new file mode 100644
index 00000000000..7e1d753b021
--- /dev/null
+++ b/app/services/projects/destroy_service.rb
@@ -0,0 +1,28 @@
+module Projects
+ class DestroyService < BaseService
+ def execute
+ return false unless can?(current_user, :remove_project, project)
+
+ project.team.truncate
+ project.repository.expire_cache unless project.empty_repo?
+
+ if project.destroy
+ GitlabShellWorker.perform_async(
+ :remove_repository,
+ project.path_with_namespace
+ )
+
+ GitlabShellWorker.perform_async(
+ :remove_repository,
+ project.path_with_namespace + ".wiki"
+ )
+
+ project.satellite.destroy
+
+ log_info("Project \"#{project.name}\" was removed")
+ system_hook_service.execute_hooks_for(project, :destroy)
+ true
+ end
+ end
+ end
+end
diff --git a/app/services/projects/participants_service.rb b/app/services/projects/participants_service.rb
new file mode 100644
index 00000000000..c4d2c0963b7
--- /dev/null
+++ b/app/services/projects/participants_service.rb
@@ -0,0 +1,43 @@
+module Projects
+ class ParticipantsService < BaseService
+ def initialize(project)
+ @project = project
+ end
+
+ def execute(note_type, note_id)
+ participating = if note_type && note_id
+ participants_in(note_type, note_id)
+ else
+ []
+ end
+ team_members = sorted(@project.team.members)
+ participants = all_members + team_members + participating
+ participants.uniq
+ end
+
+ def participants_in(type, id)
+ users = case type
+ when "Issue"
+ issue = @project.issues.find_by_iid(id)
+ issue ? issue.participants : []
+ when "MergeRequest"
+ merge_request = @project.merge_requests.find_by_iid(id)
+ merge_request ? merge_request.participants : []
+ when "Commit"
+ author_ids = Note.for_commit_id(id).pluck(:author_id).uniq
+ User.where(id: author_ids)
+ else
+ []
+ end
+ sorted(users)
+ end
+
+ def sorted(users)
+ users.uniq.to_a.compact.sort_by(&:username).map { |user| { username: user.username, name: user.name } }
+ end
+
+ def all_members
+ [{ username: "all", name: "Project and Group Members" }]
+ end
+ end
+end
diff --git a/app/services/projects/update_service.rb b/app/services/projects/update_service.rb
index d9d371da5c4..551a3653cad 100644
--- a/app/services/projects/update_service.rb
+++ b/app/services/projects/update_service.rb
@@ -13,7 +13,15 @@ module Projects
project.change_head(new_branch)
end
- project.update_attributes(params[:project], as: role)
+ if project.update_attributes(params[:project], as: role)
+ if project.previous_changes.include?('namespace_id')
+ project.send_move_instructions
+ end
+
+ if project.previous_changes.include?('path')
+ project.rename_repo
+ end
+ end
end
end
end
diff --git a/app/services/search/global_service.rb b/app/services/search/global_service.rb
index 21214511182..d213e1375e0 100644
--- a/app/services/search/global_service.rb
+++ b/app/services/search/global_service.rb
@@ -28,6 +28,7 @@ module Search
projects: [],
merge_requests: [],
issues: [],
+ notes: [],
total_results: 0,
}
end
diff --git a/app/services/search/project_service.rb b/app/services/search/project_service.rb
index 3ebaafc752c..493dee95f90 100644
--- a/app/services/search/project_service.rb
+++ b/app/services/search/project_service.rb
@@ -18,8 +18,9 @@ module Search
result[:total_results] = blobs.total_count
else
result[:merge_requests] = project.merge_requests.search(query).order('updated_at DESC').limit(20)
- result[:issues] = project.issues.search(query).order('updated_at DESC').limit(20)
- result[:total_results] = %w(issues merge_requests).sum { |items| result[items.to_sym].size }
+ result[:issues] = project.issues.where("title like :query OR description like :query ", query: "%#{query}%").order('updated_at DESC').limit(20)
+ result[:notes] = Note.where(noteable_type: 'issue').where(project_id: project.id).where("note like :query", query: "%#{query}%").order('updated_at DESC').limit(20)
+ result[:total_results] = %w(issues merge_requests notes).sum { |items| result[items.to_sym].size }
end
result
@@ -30,6 +31,7 @@ module Search
merge_requests: [],
issues: [],
blobs: [],
+ notes: [],
total_results: 0,
}
end
diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml
index a255c64fc27..3c30ccd78b3 100644
--- a/app/views/admin/users/show.html.haml
+++ b/app/views/admin/users/show.html.haml
@@ -44,6 +44,8 @@
%li
%span.light Secondary email:
%strong= email.email
+ = link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-tiny btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
+ %i.icon-remove
%li
%span.light Can create groups:
diff --git a/app/views/dashboard/show.html.haml b/app/views/dashboard/show.html.haml
index 306b71717ef..6a08b1aa640 100644
--- a/app/views/dashboard/show.html.haml
+++ b/app/views/dashboard/show.html.haml
@@ -1,8 +1,8 @@
- if @has_authorized_projects
.dashboard.row
- .activities.col-md-8
+ %section.activities.col-md-8
= render 'activities'
- .side.col-md-4.left.responsive-side
+ %aside.side.col-md-4.left.responsive-side
= render 'sidebar'
.fixed.sidebar-expand-button.hidden-lg.hidden-md
diff --git a/app/views/devise/sessions/_new_base.html.haml b/app/views/devise/sessions/_new_base.html.haml
index a2f85fa3fe2..989fcb4a63f 100644
--- a/app/views/devise/sessions/_new_base.html.haml
+++ b/app/views/devise/sessions/_new_base.html.haml
@@ -7,8 +7,8 @@
= f.check_box :remember_me
%span Remember me
%div
+ = hidden_field_tag 'return_to', params[:return_to]
= f.submit "Sign in", class: "btn-create btn"
+
.pull-right
= link_to "Forgot your password?", new_password_path(resource_name), class: "btn"
-
-
diff --git a/app/views/errors/access_denied.html.haml b/app/views/errors/access_denied.html.haml
index e005a7c4409..a1d8664c4ce 100644
--- a/app/views/errors/access_denied.html.haml
+++ b/app/views/errors/access_denied.html.haml
@@ -1,5 +1,5 @@
-%h1.http_status_code 403
-%h3.page-title Access Denied
+%h1 403
+%h3 Access Denied
%hr
%p You are not allowed to access this page.
%p Read more about project permissions #{link_to "here", help_page_path("permissions", "permissions"), class: "vlink"}
diff --git a/app/views/errors/encoding.html.haml b/app/views/errors/encoding.html.haml
index 7021f06dd7f..64c7451a8da 100644
--- a/app/views/errors/encoding.html.haml
+++ b/app/views/errors/encoding.html.haml
@@ -1,4 +1,4 @@
-%h1.http_status_code 500
-%h3.page-title Encoding Error
+%h1 500
+%h3 Encoding Error
%hr
%p Page can't be loaded because of an encoding error.
diff --git a/app/views/errors/git_not_found.html.haml b/app/views/errors/git_not_found.html.haml
index d8ed7773207..189e53bca55 100644
--- a/app/views/errors/git_not_found.html.haml
+++ b/app/views/errors/git_not_found.html.haml
@@ -1,5 +1,5 @@
-%h1.http_status_code 404
-%h3.page-title Git Resource Not found
+%h1 404
+%h3 Git Resource Not found
%hr
%p
Application can't get access to some branch or commit in your repository. It
diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml
index 4b97ddefc72..7bf88f592cf 100644
--- a/app/views/errors/not_found.html.haml
+++ b/app/views/errors/not_found.html.haml
@@ -1,4 +1,4 @@
-%h1.http_status_code 404
-%h3.page-title The resource you were looking for doesn't exist.
+%h1 404
+%h3 The resource you were looking for doesn't exist.
%hr
%p You may have mistyped the address or the page may have moved.
diff --git a/app/views/errors/omniauth_error.html.haml b/app/views/errors/omniauth_error.html.haml
new file mode 100644
index 00000000000..f3c8221a9d9
--- /dev/null
+++ b/app/views/errors/omniauth_error.html.haml
@@ -0,0 +1,12 @@
+%h1 422
+%h3 Sign-in using #{@provider} auth failed
+%hr
+%p Sign-in failed because #{@error}.
+%p There are couple of steps you can take:
+
+%ul
+ %li Try logging in using your email
+ %li Try logging in using your username
+ %li If you have forgotten your password, try recovering it using #{ link_to "Password recovery", new_password_path(resource_name) }
+
+%p If none of the options work, try contacting the GitLab administrator.
diff --git a/app/views/groups/_filter.html.haml b/app/views/groups/_filter.html.haml
deleted file mode 100644
index fe8c0669c0e..00000000000
--- a/app/views/groups/_filter.html.haml
+++ /dev/null
@@ -1,29 +0,0 @@
-= form_tag group_filter_path(entity), method: 'get' do
- %fieldset
- %ul.nav.nav-pills.nav-stacked
- %li{class: ("active" if !params[:status])}
- = link_to group_filter_path(entity, status: nil) do
- Open
- %li{class: ("active" if params[:status] == 'closed')}
- = link_to group_filter_path(entity, status: 'closed') do
- Closed
- %li{class: ("active" if params[:status] == 'all')}
- = link_to group_filter_path(entity, status: 'all') do
- All
-
- %fieldset
- %legend Projects:
- %ul.nav.nav-pills.nav-stacked
- - @projects.each do |project|
- - unless entities_per_project(project, entity).zero?
- %li{class: ("active" if params[:project_id] == project.id.to_s)}
- = link_to group_filter_path(entity, project_id: project.id) do
- = project.name_with_namespace
- %small.pull-right= entities_per_project(project, entity)
- - if @projects.blank?
- .nothing-here-block This group has no projects yet
-
- %fieldset
- %hr
- = link_to "Reset", group_filter_path(entity), class: 'btn pull-right'
-
diff --git a/app/views/groups/new.html.haml b/app/views/groups/new.html.haml
index ebf5e8571aa..cdc087f949a 100644
--- a/app/views/groups/new.html.haml
+++ b/app/views/groups/new.html.haml
@@ -6,12 +6,12 @@
= f.label :name, class: 'control-label' do
Group name
.col-sm-10
- = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control"
+ = f.text_field :name, placeholder: "Ex. OpenSource", class: "form-control", tabindex: 1, autofocus: true
.form-group.group-description-holder
= f.label :description, "Details", class: 'control-label'
.col-sm-10
- = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4
+ = f.text_area :description, maxlength: 250, class: "form-control js-gfm-input", rows: 4, tabindex: 2
.form-group.group-description-holder
= f.label :avatar, "Group avatar", class: 'control-label'
@@ -35,6 +35,4 @@
%li Existing projects may be moved into a group
.form-actions
- = f.submit 'Create group', class: "btn btn-create"
-
-
+ = f.submit 'Create group', class: "btn btn-create", tabindex: 3
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 06183dd74a9..6db393c882c 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,5 +1,5 @@
.dashboard
- .activities.col-md-8.hidden-sm.hidden-xs
+ %section.activities.col-md-8.hidden-sm.hidden-xs
- if current_user
= render "events/event_last_push", event: @last_push
= link_to dashboard_path, class: 'btn btn-tiny' do
@@ -16,7 +16,7 @@
- else
.nothing-here-block Project activity will be displayed here
= spinner
- .side.col-md-4
+ %aside.side.col-md-4
.light-well.append-bottom-20
= image_tag group_icon(@group.path), class: "avatar s90"
.clearfix.light
diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml
index d9a7a2d31cf..0c27f679dee 100644
--- a/app/views/layouts/_head.html.haml
+++ b/app/views/layouts/_head.html.haml
@@ -1,5 +1,14 @@
%head
%meta{charset: "utf-8"}
+
+ -# Go repository retrieval support
+ -# Need to be the fist thing in the head
+ -# Since Go is using an XML parser to process HTML5
+ -# https://github.com/gitlabhq/gitlabhq/pull/5958#issuecomment-45397555
+ - if controller_name == 'projects' && action_name == 'show'
+ %meta{name: "go-import", content: "#{@project.web_url_without_protocol} git #{@project.web_url}.git"}
+ %meta{content: "GitLab Community Edition", name: "description"}
+
%title
= "#{title} | " if defined?(title)
GitLab
@@ -24,8 +33,3 @@
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, format: :atom, private_token: current_user.private_token), title: "Recent commits to #{@project.name}:#{@ref}")
- if current_controller?(:issues)
= auto_discovery_link_tag(:atom, project_issues_url(@project, :atom, private_token: current_user.private_token), title: "#{@project.name} issues")
-
- -# Go repository retrieval support.
- - if controller_name == 'projects' && action_name == 'show'
- %meta{name: "go-import", content: "#{@project.web_url_without_protocol} git #{@project.web_url}.git"}
-
diff --git a/app/views/layouts/_public_head_panel.html.haml b/app/views/layouts/_public_head_panel.html.haml
index 63992a22f32..25984df0444 100644
--- a/app/views/layouts/_public_head_panel.html.haml
+++ b/app/views/layouts/_public_head_panel.html.haml
@@ -13,10 +13,10 @@
%i.icon-reorder
.pull-right.hidden-xs
- = link_to "Sign in", new_session_path(:user), class: 'btn btn-sign-in btn-new'
+ = link_to "Sign in", new_session_path(:user, return_to: request.fullpath), class: 'btn btn-sign-in btn-new'
.navbar-collapse.collapse
%ul.nav.navbar-nav
%li.visible-xs
- = link_to "Sign in", new_session_path(:user)
+ = link_to "Sign in", new_session_path(:user, return_to: request.fullpath)
diff --git a/app/views/layouts/_search.html.haml b/app/views/layouts/_search.html.haml
index a0e55b21c32..caf0e39234a 100644
--- a/app/views/layouts/_search.html.haml
+++ b/app/views/layouts/_search.html.haml
@@ -1,6 +1,6 @@
.search
= form_tag search_path, method: :get, class: 'navbar-form pull-left' do |f|
- = text_field_tag "search", nil, placeholder: search_placeholder, class: "search-input"
+ = search_field_tag "search", nil, placeholder: search_placeholder, class: "search-input"
= hidden_field_tag :group_id, @group.try(:id)
- if @project && @project.persisted?
= hidden_field_tag :project_id, @project.id
diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml
index 5d93ffa50ad..36c682c48a6 100644
--- a/app/views/layouts/devise.html.haml
+++ b/app/views/layouts/devise.html.haml
@@ -5,7 +5,7 @@
= render "layouts/flash"
.container
.content
- %center
+ .center
%h1 GitLab
%p.light
GitLab is open source software to collaborate on code.
diff --git a/app/views/layouts/errors.html.haml b/app/views/layouts/errors.html.haml
index df2350b1535..d0e276d751a 100644
--- a/app/views/layouts/errors.html.haml
+++ b/app/views/layouts/errors.html.haml
@@ -4,7 +4,6 @@
%body{class: "#{app_theme} application"}
= render "layouts/head_panel", title: "" if current_user
= render "layouts/flash"
- .container
- .content
- %center.padded.prepend-top-20
- = yield
+ .container.navless-container
+ .error-page
+ = yield
diff --git a/app/views/layouts/nav/_admin.html.haml b/app/views/layouts/nav/_admin.html.haml
index 48c569f8684..c57216f01c8 100644
--- a/app/views/layouts/nav/_admin.html.haml
+++ b/app/views/layouts/nav/_admin.html.haml
@@ -1,13 +1,13 @@
%ul
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: "Stats" do
- %i.icon-home
+ Overview
= nav_link(controller: :projects) do
= link_to "Projects", admin_projects_path
- = nav_link(controller: :groups) do
- = link_to "Groups", admin_groups_path
= nav_link(controller: :users) do
= link_to "Users", admin_users_path
+ = nav_link(controller: :groups) do
+ = link_to "Groups", admin_groups_path
= nav_link(controller: :logs) do
= link_to "Logs", admin_logs_path
= nav_link(controller: :broadcast_messages) do
diff --git a/app/views/layouts/nav/_dashboard.html.haml b/app/views/layouts/nav/_dashboard.html.haml
index 12fd49e609f..a300bbc1904 100644
--- a/app/views/layouts/nav/_dashboard.html.haml
+++ b/app/views/layouts/nav/_dashboard.html.haml
@@ -1,7 +1,7 @@
%ul
= nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
= link_to root_path, title: "Home" do
- %i.icon-home
+ Activity
= nav_link(path: 'dashboard#projects') do
= link_to projects_dashboard_path do
Projects
diff --git a/app/views/layouts/nav/_group.html.haml b/app/views/layouts/nav/_group.html.haml
index 36b102dc25a..d306e1eeb54 100644
--- a/app/views/layouts/nav/_group.html.haml
+++ b/app/views/layouts/nav/_group.html.haml
@@ -1,7 +1,7 @@
%ul
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
= link_to group_path(@group), title: "Home" do
- %i.icon-home
+ Activity
= nav_link(path: 'groups#issues') do
= link_to issues_group_path(@group) do
Issues
diff --git a/app/views/layouts/nav/_profile.html.haml b/app/views/layouts/nav/_profile.html.haml
index 35d0d417502..1de5ee99cf4 100644
--- a/app/views/layouts/nav/_profile.html.haml
+++ b/app/views/layouts/nav/_profile.html.haml
@@ -1,7 +1,7 @@
%ul
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: "Profile" do
- %i.icon-home
+ Profile
= nav_link(controller: :accounts) do
= link_to "Account", profile_account_path
= nav_link(controller: :emails) do
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index dd48ff6ce38..69491c2529e 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -1,7 +1,7 @@
%ul
= nav_link(path: 'projects#show', html_options: {class: "home"}) do
= link_to project_path(@project), title: "Project" do
- %i.icon-home
+ Activity
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
diff --git a/app/views/profiles/keys/new.html.haml b/app/views/profiles/keys/new.html.haml
index 126afa55540..46b7fc72869 100644
--- a/app/views/profiles/keys/new.html.haml
+++ b/app/views/profiles/keys/new.html.haml
@@ -5,7 +5,7 @@
= render 'form'
:javascript
- $('#key_key').on('keyup', function(){
+ $('#key_key').on('focusout', function(){
var title = $('#key_title'),
val = $('#key_key').val(),
key_mail = val.match(/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+|\.[a-zA-Z0-9._-]+)/gi);
@@ -13,4 +13,4 @@
if( key_mail && key_mail.length > 0 && title.val() == '' ){
$('#key_title').val( key_mail );
}
- });
+ }); \ No newline at end of file
diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml
index 9a4c13af975..e03a43cbf1f 100644
--- a/app/views/profiles/show.html.haml
+++ b/app/views/profiles/show.html.haml
@@ -68,12 +68,14 @@
%p.light
- if @user.avatar?
You can change your avatar here
- %br
- or remove the current avatar to revert to #{link_to "gravatar.com", "http://gravatar.com"}
+ - if Gitlab.config.gravatar.enabled
+ %br
+ or remove the current avatar to revert to #{link_to "gravatar.com", "http://gravatar.com"}
- else
You can upload an avatar here
- %br
- or change it at #{link_to "gravatar.com", "http://gravatar.com"}
+ - if Gitlab.config.gravatar.enabled
+ %br
+ or change it at #{link_to "gravatar.com", "http://gravatar.com"}
%hr
%a.choose-btn.btn.btn-small.js-choose-user-avatar-button
%i.icon-paper-clip
diff --git a/app/views/projects/_home_panel.html.haml b/app/views/projects/_home_panel.html.haml
index 81bb0e20a35..2a97cb49039 100644
--- a/app/views/projects/_home_panel.html.haml
+++ b/app/views/projects/_home_panel.html.haml
@@ -21,6 +21,11 @@
- if can?(current_user, :admin_project, @project)
&ndash;
%strong= link_to 'Edit', edit_project_path
+ - elsif !@project.empty_repo? && @repository.readme
+ - readme = @repository.readme
+ &ndash;
+ = link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)) do
+ = readme.name
- unless empty_repo
.col-md-5
diff --git a/app/views/projects/blob/_blob.html.haml b/app/views/projects/blob/_blob.html.haml
index 87574d4648b..be785dacedb 100644
--- a/app/views/projects/blob/_blob.html.haml
+++ b/app/views/projects/blob/_blob.html.haml
@@ -20,7 +20,7 @@
= render blob_commit, project: @project
%div#tree-content-holder.tree-content-holder
- .file-holder
+ %article.file-holder
.file-title.clearfix
%i.icon-file
%span.file_name
diff --git a/app/views/projects/blob/_download.html.haml b/app/views/projects/blob/_download.html.haml
index ff317f90209..cdbfee7cc68 100644
--- a/app/views/projects/blob/_download.html.haml
+++ b/app/views/projects/blob/_download.html.haml
@@ -1,5 +1,5 @@
.file-content.blob_file.blob-no-preview
- %center
+ .center
= link_to project_raw_path(@project, @id) do
%h1.light
%i.icon-download-alt
diff --git a/app/views/projects/commits/_commit.html.haml b/app/views/projects/commits/_commit.html.haml
index a0606662807..74146b5f196 100644
--- a/app/views/projects/commits/_commit.html.haml
+++ b/app/views/projects/commits/_commit.html.haml
@@ -9,11 +9,15 @@
= link_to "Browse Code »", project_tree_path(project, commit), class: "pull-right"
.notes_count
- - notes = project.notes.for_commit_id(commit.id)
- - if notes.any?
+ - if @note_counts
+ - note_count = @note_counts.fetch(commit.id, 0)
+ - else
+ - notes = project.notes.for_commit_id(commit.id)
+ - note_count = notes.count
+
+ - if note_count > 0
%span.label.label-gray
- %i.icon-comment
- = notes.count
+ %i.icon-comment= note_count
- if commit.description?
.commit-row-description.js-toggle-content
diff --git a/app/views/projects/commits/_diffs.html.haml b/app/views/projects/commits/_diffs.html.haml
index a62f50776fa..fcdb40468d9 100644
--- a/app/views/projects/commits/_diffs.html.haml
+++ b/app/views/projects/commits/_diffs.html.haml
@@ -45,7 +45,7 @@
- file = project.repository.blob_at(@commit.id, diff.new_path)
- file = project.repository.blob_at(@commit.parent_id, diff.old_path) unless file
- next unless file
- .diff-file.js-toggle-container{id: "diff-#{i}"}
+ .diff-file{id: "diff-#{i}"}
.diff-header{id: "file-path-#{hexdigest(diff.new_path || diff.old_path)}"}
- if diff.deleted_file
%span= diff.old_path
@@ -61,7 +61,7 @@
%span.file-mode= "#{diff.a_mode} → #{diff.b_mode}"
.diff-btn-group
- = link_to "#", class: "js-toggle-button btn btn-small" do
+ = link_to "#", class: "js-toggle-diff-comments btn btn-small" do
%i.icon-chevron-down
Diff comments
&nbsp;
diff --git a/app/views/projects/compare/show.html.haml b/app/views/projects/compare/show.html.haml
index 88122a73bba..b232d2a6b26 100644
--- a/app/views/projects/compare/show.html.haml
+++ b/app/views/projects/compare/show.html.haml
@@ -33,7 +33,7 @@
- else
.light-well
- %center
+ .center
%h4
There isn't anything to compare.
%p.slead
diff --git a/app/views/projects/edit.html.haml b/app/views/projects/edit.html.haml
index 4195a491a0f..6eaa3e7559a 100644
--- a/app/views/projects/edit.html.haml
+++ b/app/views/projects/edit.html.haml
@@ -183,7 +183,7 @@
.nothing-here-block Only project owner can remove a project
.save-project-loader.hide
- %center
+ .center
%h2
%i.icon-spinner.icon-spin
Saving project.
diff --git a/app/views/projects/edit_tree/show.html.haml b/app/views/projects/edit_tree/show.html.haml
index 32a6d4ef36e..16fc1ab1f91 100644
--- a/app/views/projects/edit_tree/show.html.haml
+++ b/app/views/projects/edit_tree/show.html.haml
@@ -18,7 +18,7 @@
.file-content.code
%pre.js-edit-mode-pane#editor= @blob.data
.js-edit-mode-pane#preview.hide
- %center
+ .center
%h2
%i.icon-spinner.icon-spin
diff --git a/app/views/projects/graphs/show.html.haml b/app/views/projects/graphs/show.html.haml
index 27348232ba2..8e4548f26d0 100644
--- a/app/views/projects/graphs/show.html.haml
+++ b/app/views/projects/graphs/show.html.haml
@@ -1,5 +1,5 @@
.loading-graph
- %center
+ .center
%h3.page-title
%i.icon-spinner.icon-spin
Building repository graph.
diff --git a/app/views/projects/import.html.haml b/app/views/projects/import.html.haml
index d11372be61b..f883b24fc21 100644
--- a/app/views/projects/import.html.haml
+++ b/app/views/projects/import.html.haml
@@ -1,6 +1,6 @@
- if @project.import_in_progress?
.save-project-loader
- %center
+ .center
%h2
%i.icon-spinner.icon-spin
Import in progress.
@@ -11,7 +11,7 @@
- elsif @project.import_failed?
.save-project-loader
- %center
+ .center
%h2
Import failed. Retry?
%hr
diff --git a/app/views/projects/merge_requests/_new_compare.html.haml b/app/views/projects/merge_requests/_new_compare.html.haml
index f8f14a71a11..18e3f419c72 100644
--- a/app/views/projects/merge_requests/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/_new_compare.html.haml
@@ -39,7 +39,7 @@
%p We can't compare selected branches. It may be because of huge diff or satellite timeout. Please try again or select different branches.
- else
.light-well
- %center
+ .center
%h4
There isn't anything to merge.
%p.slead
diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml
index 486454793ba..8fca9f0212b 100644
--- a/app/views/projects/merge_requests/_show.html.haml
+++ b/app/views/projects/merge_requests/_show.html.haml
@@ -31,7 +31,8 @@
= render "projects/merge_requests/show/diffs"
.notes.tab-content.voting_notes#notes{ class: (controller.action_name == 'show') ? "" : "hide" }
= render "projects/notes/notes_with_form"
- .status
+ .mr-loading-status
+ = spinner
:javascript
var merge_request;
diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml
index 5d5637c1588..7efaf5a087b 100644
--- a/app/views/projects/new.html.haml
+++ b/app/views/projects/new.html.haml
@@ -72,7 +72,7 @@
Create a group
.save-project-loader.hide
- %center
+ .center
%h2
%i.icon-spinner.icon-spin
Creating project &amp; repository.
diff --git a/app/views/projects/notes/_commit_discussion.html.haml b/app/views/projects/notes/_commit_discussion.html.haml
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/app/views/projects/notes/_commit_discussion.html.haml
diff --git a/app/views/projects/notes/_diff_notes_with_reply.html.haml b/app/views/projects/notes/_diff_notes_with_reply.html.haml
index 9acadc6a14e..79a66eff129 100644
--- a/app/views/projects/notes/_diff_notes_with_reply.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply.html.haml
@@ -1,7 +1,7 @@
- note = notes.first # example note
-# Check if line want not changed since comment was left
- if !defined?(line) || line == note.diff_line
- %tr.notes_holder.js-toggle-content
+ %tr.notes_holder
%td.notes_line{ colspan: 2 }
%span.btn.disabled
%i.icon-comment
@@ -9,5 +9,5 @@
%td.notes_content
%ul.notes{ rel: note.discussion_id }
= render notes
-
- = render "projects/notes/discussion_reply_button", note: note
+ .discussion-reply-holder
+ = link_to_reply_diff(note)
diff --git a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
index 399ce30d1a9..8adf903a9a1 100644
--- a/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
+++ b/app/views/projects/notes/_diff_notes_with_reply_parallel.html.haml
@@ -2,7 +2,7 @@
- note2 = notes2.first # example note
-# Check if line want not changed since comment was left
/- if !defined?(line) || line == note.diff_line
-%tr.notes_holder.js-toggle-content
+%tr.notes_holder
- if note1
%td.notes_line
%span.btn.disabled
@@ -12,7 +12,8 @@
%ul.notes{ rel: note1.discussion_id }
= render notes1
- = render "projects/notes/discussion_reply_button", note: note1
+ .discussion-reply-holder
+ = link_to_reply_diff(note1)
- else
%td= ""
%td= ""
@@ -26,7 +27,8 @@
%ul.notes{ rel: note2.discussion_id }
= render notes2
- = render "projects/notes/discussion_reply_button", note: note2
+ .discussion-reply-holder
+ = link_to_reply_diff(note2)
- else
%td= ""
%td= ""
diff --git a/app/views/projects/notes/_discussion.html.haml b/app/views/projects/notes/_discussion.html.haml
index 78793eb860f..8c7964cbf3e 100644
--- a/app/views/projects/notes/_discussion.html.haml
+++ b/app/views/projects/notes/_discussion.html.haml
@@ -1,46 +1,8 @@
- note = discussion_notes.first
-.discussion.js-toggle-container{ class: note.discussion_id }
- .discussion-header
- .discussion-actions
- = link_to "#", class: "js-toggle-button" do
- %i.icon-chevron-up
- Show/hide discussion
- = image_tag avatar_icon(note.author_email), class: "avatar s32"
- %div
- = link_to_member(@project, note.author, avatar: false)
- - if note.for_merge_request?
- - if note.diff
- started a discussion on this merge request diff
- = link_to_merge_request_diff_line_note(note)
- - else
- started
- %strong
- %i.icon-remove
- outdated
- discussion on this merge request diff
- - elsif note.for_commit?
- started a discussion on commit
- #{link_to note.noteable.short_id, project_commit_path(note.project, note.noteable)}
- = link_to_commit_diff_line_note(note) if note.for_diff_line?
- - else
- %cite.cgray started a discussion
- %div
- - last_note = discussion_notes.last
- last updated by
- = link_to_member(@project, last_note.author, avatar: false)
- %span.discussion-last-update
- #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
- .discussion-body.js-toggle-content
- - if note.for_diff_line?
- - if note.active?
- = render "projects/notes/discussion_diff", discussion_notes: discussion_notes, note: note
- - else
- = link_to 'show outdated discussion', '#', class: 'js-show-outdated-discussion'
- %div.hide.outdated-discussion
- .notes{ rel: discussion_notes.first.discussion_id }
- = render discussion_notes
-
- - else
- .notes{ rel: discussion_notes.first.discussion_id }
- = render discussion_notes
- = render "projects/notes/discussion_reply_button", note: discussion_notes.first
+- if note.for_merge_request?
+ - if note.outdated?
+ = render "projects/notes/discussions/outdated", discussion_notes: discussion_notes
+ - else
+ = render "projects/notes/discussions/active", discussion_notes: discussion_notes
+- else
+ = render "projects/notes/discussions/commit", discussion_notes: discussion_notes
diff --git a/app/views/projects/notes/_discussion_reply_button.html.haml b/app/views/projects/notes/_discussion_reply_button.html.haml
deleted file mode 100644
index d1c5ccc29db..00000000000
--- a/app/views/projects/notes/_discussion_reply_button.html.haml
+++ /dev/null
@@ -1,10 +0,0 @@
-= link_to "javascript:;",
- class: "btn reply-btn js-discussion-reply-button",
- data: { noteable_type: note.noteable_type,
- noteable_id: note.noteable_id,
- commit_id: note.commit_id,
- line_code: note.line_code,
- discussion_id: note.discussion_id },
- title: "Add a reply" do
- %i.icon-comment
- Reply
diff --git a/app/views/projects/notes/_form.html.haml b/app/views/projects/notes/_form.html.haml
index b62aada3a9a..5ebafb13f1c 100644
--- a/app/views/projects/notes/_form.html.haml
+++ b/app/views/projects/notes/_form.html.haml
@@ -17,8 +17,8 @@
= f.text_area :note, size: 255, class: 'note_text js-note-text js-gfm-input markdown-area'
.light.clearfix
- .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}
- .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector' }.
+ .pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
+ .pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-preview-holder.hide
.js-note-preview
diff --git a/app/views/projects/notes/discussions/_active.html.haml b/app/views/projects/notes/discussions/_active.html.haml
new file mode 100644
index 00000000000..ef296b35dd5
--- /dev/null
+++ b/app/views/projects/notes/discussions/_active.html.haml
@@ -0,0 +1,21 @@
+- note = discussion_notes.first
+.discussion.js-toggle-container{ class: note.discussion_id }
+ .discussion-header
+ .discussion-actions
+ = link_to "#", class: "js-toggle-button" do
+ %i.icon-chevron-up
+ Show/hide discussion
+ = image_tag avatar_icon(note.author_email), class: "avatar s32"
+ %div
+ = link_to_member(@project, note.author, avatar: false)
+ started a discussion
+ = link_to diffs_project_merge_request_path(note.project, note.noteable, anchor: note.line_code) do
+ %strong on the diff
+ .last-update.hide.js-toggle-content
+ - last_note = discussion_notes.last
+ last updated by
+ = link_to_member(@project, last_note.author, avatar: false)
+ %span.discussion-last-update
+ #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
+ .discussion-body.js-toggle-content
+ = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
diff --git a/app/views/projects/notes/discussions/_commit.html.haml b/app/views/projects/notes/discussions/_commit.html.haml
new file mode 100644
index 00000000000..78460974a9b
--- /dev/null
+++ b/app/views/projects/notes/discussions/_commit.html.haml
@@ -0,0 +1,28 @@
+- note = discussion_notes.first
+.discussion.js-toggle-container{ class: note.discussion_id }
+ .discussion-header
+ .discussion-actions
+ = link_to "#", class: "js-toggle-button" do
+ %i.icon-chevron-up
+ Show/hide discussion
+ = image_tag avatar_icon(note.author_email), class: "avatar s32"
+ %div
+ = link_to_member(@project, note.author, avatar: false)
+ started a discussion on commit
+ = link_to(note.noteable.short_id, project_commit_path(note.project, note.noteable), class: 'monospace')
+ .last-update.hide.js-toggle-content
+ - last_note = discussion_notes.last
+ last updated by
+ = link_to_member(@project, last_note.author, avatar: false)
+ %span.discussion-last-update
+ #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
+ .discussion-body.js-toggle-content
+ - if note.for_diff_line?
+ = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
+ - else
+ .panel.panel-default
+ .notes{ rel: discussion_notes.first.discussion_id }
+ = render discussion_notes
+ .discussion-reply-holder
+ = link_to_reply_diff(discussion_notes.first)
+
diff --git a/app/views/projects/notes/_discussion_diff.html.haml b/app/views/projects/notes/discussions/_diff.html.haml
index 26c5494f466..26c5494f466 100644
--- a/app/views/projects/notes/_discussion_diff.html.haml
+++ b/app/views/projects/notes/discussions/_diff.html.haml
diff --git a/app/views/projects/notes/discussions/_outdated.html.haml b/app/views/projects/notes/discussions/_outdated.html.haml
new file mode 100644
index 00000000000..67c29be8ac1
--- /dev/null
+++ b/app/views/projects/notes/discussions/_outdated.html.haml
@@ -0,0 +1,20 @@
+- note = discussion_notes.first
+.discussion.js-toggle-container{ class: note.discussion_id }
+ .discussion-header
+ .discussion-actions
+ = link_to "#", class: "js-toggle-button" do
+ %i.icon-chevron-down
+ Show/hide discussion
+ = image_tag avatar_icon(note.author_email), class: "avatar s32"
+ %div
+ = link_to_member(@project, note.author, avatar: false)
+ started a discussion on the
+ %strong outdated diff
+ %div
+ - last_note = discussion_notes.last
+ last updated by
+ = link_to_member(@project, last_note.author, avatar: false)
+ %span.discussion-last-update
+ #{time_ago_with_tooltip(last_note.updated_at, 'bottom', 'discussion_updated_ago')}
+ .discussion-body.js-toggle-content.hide
+ = render "projects/notes/discussions/diff", discussion_notes: discussion_notes, note: note
diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml
index 7e9f1122aa9..c4e5087b0a1 100644
--- a/app/views/projects/show.html.haml
+++ b/app/views/projects/show.html.haml
@@ -1,12 +1,12 @@
= render "home_panel"
.row
- .col-md-9
+ %section.col-md-9
= render "events/event_last_push", event: @last_push
= render 'shared/event_filter'
.content_list
= spinner
- .col-md-3.project-side.hidden-sm.hidden-xs
+ %aside.col-md-3.project-side.hidden-sm.hidden-xs
.clearfix
- if @project.archived?
.alert.alert-warning
@@ -44,6 +44,12 @@
= link_to project_blob_path(@project, tree_join(@repository.root_ref, readme.name)), class: 'btn btn-block' do
= readme.name
+ - if @repository.version
+ - version = @repository.version
+ = link_to project_blob_path(@project, tree_join(@repository.root_ref, version.name)), class: 'btn btn-block' do
+ Version:
+ = @repository.blob_by_oid(version.id).data
+
.prepend-top-10
%p
%span.light Created on
diff --git a/app/views/projects/tree/_blob_item.html.haml b/app/views/projects/tree/_blob_item.html.haml
index 0971a426527..393ef0e24bd 100644
--- a/app/views/projects/tree/_blob_item.html.haml
+++ b/app/views/projects/tree/_blob_item.html.haml
@@ -5,4 +5,4 @@
= link_to blob_item.name, project_blob_path(@project, tree_join(@id || @commit.id, blob_item.name))
%td.tree_time_ago.cgray
= render 'spinner'
- %td.hidden-xs.tree_commit{ colspan: 2 }
+ %td.hidden-xs.tree_commit
diff --git a/app/views/projects/tree/_readme.html.haml b/app/views/projects/tree/_readme.html.haml
index 0c19109445a..c066b7102fd 100644
--- a/app/views/projects/tree/_readme.html.haml
+++ b/app/views/projects/tree/_readme.html.haml
@@ -1,4 +1,4 @@
-.readme-holder#README
+%article.readme-holder#README
%h4.readme-file-title
%i.icon-file
= readme.name
diff --git a/app/views/projects/tree/_tree_item.html.haml b/app/views/projects/tree/_tree_item.html.haml
index 760e95e84f0..f8cecf9be1f 100644
--- a/app/views/projects/tree/_tree_item.html.haml
+++ b/app/views/projects/tree/_tree_item.html.haml
@@ -5,4 +5,4 @@
= link_to tree_item.name, project_tree_path(@project, tree_join(@id || @commit.id, tree_item.name))
%td.tree_time_ago.cgray
= render 'spinner'
- %td.hidden-xs.tree_commit{ colspan: 2 }
+ %td.hidden-xs.tree_commit
diff --git a/app/views/search/_project_results.html.haml b/app/views/search/_project_results.html.haml
index f285bda5736..af3b97879c7 100644
--- a/app/views/search/_project_results.html.haml
+++ b/app/views/search/_project_results.html.haml
@@ -15,3 +15,4 @@
%ul.bordered-list
= render partial: "search/results/merge_request", collection: @search_results[:merge_requests]
= render partial: "search/results/issue", collection: @search_results[:issues]
+ = render partial: "search/results/note", collection: @search_results[:notes]
diff --git a/app/views/search/results/_note.html.haml b/app/views/search/results/_note.html.haml
new file mode 100644
index 00000000000..97e892bdd4d
--- /dev/null
+++ b/app/views/search/results/_note.html.haml
@@ -0,0 +1,9 @@
+%li
+ note on issue:
+ = link_to [note.project, note.noteable] do
+ %span ##{note.noteable.iid}
+ %strong.term
+ = truncate note.noteable.title, length: 50
+ %span.light (#{note.project.name_with_namespace})
+ - if note.noteable.closed?
+ %span.label Closed
diff --git a/app/workers/repository_import_worker.rb b/app/workers/repository_import_worker.rb
index e66df8c4db1..43ef54631a9 100644
--- a/app/workers/repository_import_worker.rb
+++ b/app/workers/repository_import_worker.rb
@@ -14,8 +14,9 @@ class RepositoryImportWorker
project.import_finish
project.save
project.satellite.create unless project.satellite.exists?
+ project.update_repository_size
else
project.import_fail
end
end
-end
+end \ No newline at end of file
diff --git a/config/application.rb b/config/application.rb
index 540426b6672..0a77f58f6d1 100644
--- a/config/application.rb
+++ b/config/application.rb
@@ -18,15 +18,6 @@ module Gitlab
# :all can be used as a placeholder for all plugins not explicitly named.
# config.plugins = [ :exception_notification, :ssl_requirement, :all ]
- # Activate observers that should always be running.
- config.active_record.observers = :project_activity_cache_observer,
- :note_observer,
- :project_observer,
- :system_hook_observer,
- :user_observer,
- :users_group_observer,
- :users_project_observer
-
# Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
# Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
# config.time_zone = 'Central Time (US & Canada)'
diff --git a/config/gitlab.teatro.yml b/config/gitlab.teatro.yml
new file mode 100644
index 00000000000..f0656400beb
--- /dev/null
+++ b/config/gitlab.teatro.yml
@@ -0,0 +1,86 @@
+
+production: &base
+ gitlab:
+ host: localhost
+ port: 80
+ https: false
+
+ user: root
+
+ email_from: example@example.com
+
+ support_email: support@example.com
+
+ default_projects_features:
+ issues: true
+ merge_requests: true
+ wiki: true
+ wall: false
+ snippets: false
+ visibility_level: "private" # can be "private" | "internal" | "public"
+
+ issues_tracker:
+
+ gravatar:
+ enabled: true # Use user avatar image from Gravatar.com (default: true)
+
+ ldap:
+ enabled: false
+ host: '_your_ldap_server'
+ port: 636
+ uid: 'sAMAccountName'
+ method: 'ssl' # "tls" or "ssl" or "plain"
+ bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
+ password: '_the_password_of_the_bind_user'
+ allow_username_or_email_login: true
+
+ base: ''
+
+ user_filter: ''
+
+ omniauth:
+ enabled: false
+
+ satellites:
+ # Relative paths are relative to Rails.root (default: tmp/repo_satellites/)
+ path: /apps/gitlab-satellites/
+
+ backup:
+ path: "tmp/backups" # Relative paths are relative to Rails.root (default: tmp/backups/)
+
+ gitlab_shell:
+ path: /apps/gitlab-shell/
+
+ # REPOS_PATH MUST NOT BE A SYMLINK!!!
+ repos_path: /apps/repositories/
+ hooks_path: /apps/gitlab-shell/hooks/
+
+ upload_pack: true
+ receive_pack: true
+
+ git:
+ bin_path: /usr/bin/git
+ max_size: 5242880 # 5.megabytes
+ timeout: 10
+
+ extra:
+
+development:
+ <<: *base
+
+test:
+ <<: *base
+ gravatar:
+ enabled: true
+ gitlab:
+ host: localhost
+ port: 80
+ issues_tracker:
+ redmine:
+ title: "Redmine"
+ project_url: "http://redmine/projects/:issues_tracker_id"
+ issues_url: "http://redmine/:project_id/:issues_tracker_id/:id"
+ new_issue_url: "http://redmine/projects/:issues_tracker_id/issues/new"
+
+staging:
+ <<: *base
diff --git a/config/routes.rb b/config/routes.rb
index 746e532a0ec..14ff52f387a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -68,6 +68,7 @@ Gitlab::Application.routes.draw do
put :team_update
put :block
put :unblock
+ delete 'remove/:email_id', action: 'remove_email', as: 'remove_email'
end
end
@@ -157,8 +158,11 @@ Gitlab::Application.routes.draw do
resources :projects, constraints: { id: /[^\/]+/ }, only: [:new, :create]
- devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords}
+ devise_for :users, controllers: { omniauth_callbacks: :omniauth_callbacks, registrations: :registrations , passwords: :passwords, sessions: :users_sessions }
+ devise_scope :user do
+ get "/users/auth/:provider/omniauth_error" => "omniauth_callbacks#omniauth_error", as: :omniauth_error
+ end
#
# Project Area
#
diff --git a/doc/api/users.md b/doc/api/users.md
index 4ddbf739774..a7e9518408c 100644
--- a/doc/api/users.md
+++ b/doc/api/users.md
@@ -84,7 +84,7 @@ GET /users
]
```
-You can search for a users by email or username with: `/users?search=John`
+You can search for users by email or username with: `/users?search=John`
Also see `def search query` in `app/models/user.rb`.
diff --git a/doc/install/installation.md b/doc/install/installation.md
index 1b5139e8bb9..37f9377256c 100644
--- a/doc/install/installation.md
+++ b/doc/install/installation.md
@@ -95,8 +95,8 @@ Remove the old Ruby 1.8 if present
Download Ruby and compile it:
mkdir /tmp/ruby && cd /tmp/ruby
- curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p481.tar.gz | tar xz
- cd ruby-2.0.0-p481
+ curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.gz | tar xz
+ cd ruby-2.1.2
./configure --disable-install-rdoc
make
sudo make install
@@ -243,7 +243,7 @@ GitLab Shell is an ssh access and repository management software developed speci
# By default, the gitlab-shell config is generated from your main gitlab config.
#
# Note: When using GitLab with HTTPS please change the following:
- # - Provide paths to the certificates under `ca_file` and `ca_path options.
+ # - Provide paths to the certificates under `ca_file` and `ca_path` options.
# - The `gitlab_url` option must point to the https endpoint of GitLab.
# - In case you are using self signed certificate set `self_signed_cert` to `true`.
# See #using-https for all necessary details.
diff --git a/doc/install/requirements.md b/doc/install/requirements.md
index d7c4c4da2ed..10370d54fb1 100644
--- a/doc/install/requirements.md
+++ b/doc/install/requirements.md
@@ -2,9 +2,7 @@
## Operating Systems
-GitLab is developed for the Linux operating system. For the installations options and instructions please see [the installation section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#installation).
-
-### Supported Linux distributions
+### Supported Unix distributions
- Ubuntu
- Debian
@@ -13,36 +11,29 @@ GitLab is developed for the Linux operating system. For the installations option
- Scientific Linux
- Oracle Linux
-### Unsupported Linux distributions
+For the installations options please see [the installation page on the GitLab website](https://about.gitlab.com/installation/).
+
+### Unsupported Unix distributions
+- OS X
- Arch Linux
- Fedora
- Gentoo
+- FreeBSD
-But on the above unsupported distributions is still possible to install GitLab yourself with the [manual installation guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md).
-
-### Unsupported Unix operating systems
-
-There is nothing that prevents GitLab from running on other Unix operating systems.
+On the above unsupported distributions is still possible to install GitLab yourself.
+Please see the [manual installation guide](https://github.com/gitlabhq/gitlabhq/blob/master/doc/install/installation.md) and the [unofficial installation guides](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Unofficial-Installation-Guides) on the public wiki for more information.
-This means you may get it to work on systems running FreeBSD or OS X.
-
-If you want to do this, please be aware it could be a lot of work.
-
-Please consider using a virtual machine to run GitLab.
-
-### Other operating systems such as Windows
+### Non Unix operating systems such as Windows
+GitLab is developed for Unix operating systems.
GitLab does **not** run on Windows and we have no plans of supporting it in the near future.
-
Please consider using a virtual machine to run GitLab.
## Ruby versions
GitLab requires Ruby (MRI) 2.0 or 2.1
-
You will have to use the standard MRI implementation of Ruby.
-
We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) but GitLab needs several Gems that have native extensions.
## Hardware requirements
@@ -59,7 +50,11 @@ We love [JRuby](http://jruby.org/) and [Rubinius](http://rubini.us/)) but GitLab
### Memory
-- 512MB is the absolute minimum but we do not recommend this amount of memory, you'll need to configure a minimum swap of 256MB, you're memory will only allow you to run one slow unicorn worker, things will case only git ssh access to work because the git http access requires two running workers (one to receive the user request and one for the authorization check),
+- 512MB is the absolute minimum but we do not recommend this amount of memory.
+You will either need to configure a minimum swap of 256MB and this will only allow you to run one slow unicorn worker.
+One unicorn worker will cause only git ssh access to work because the git http access requires two running workers.
+It requires one worker to receive the user request and one worker for the authorization check.
+Or if you use SSD you can configure 2GB of swap to use two Unicorn workers and have slow operation with http access.
- 1GB supports up to 100 users (with individual repositories under 250MB, otherwise git memory usage necessitates configuring swap space)
- **2GB** is the **recommended** memory size and supports up to 500 users
- 4GB supports up to 2,000 users
@@ -80,7 +75,15 @@ If you have enough RAM memory and a recent CPU the speed of GitLab is mainly lim
## Database
-If you want to run the database separately, the **recommended** database size is **1 MB per user**
+If you want to run the database separately, the **recommended** database size is **1 MB per user**.
+
+## Redis and Sidekiq
+
+Redis stores all user sessions and the background task queue.
+The storage requirements for Redis are minimal, about 25kB per user.
+Sidekiq processes the background jobs with a multithreaded process.
+This process starts with the entire Rails stack (200MB+) but it can grow over time due to memory leaks.
+On a very active server (10.000 active users) the Sidekiq process can use 1GB+ of memory.
## Supported webbrowsers
diff --git a/doc/permissions/permissions.md b/doc/permissions/permissions.md
index e01b02212b6..d1da1496520 100644
--- a/doc/permissions/permissions.md
+++ b/doc/permissions/permissions.md
@@ -16,6 +16,7 @@ If a user is a GitLab administrator they receive all permissions.
| Pull project code | | ✓ | ✓ | ✓ | ✓ |
| Download project | | ✓ | ✓ | ✓ | ✓ |
| Create code snippets | | ✓ | ✓ | ✓ | ✓ |
+| Create new milestones | | | ✓ | ✓ | ✓ |
| Create new merge request | | | ✓ | ✓ | ✓ |
| Create new branches | | | ✓ | ✓ | ✓ |
| Push to non-protected branches | | | ✓ | ✓ | ✓ |
diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md
index 5c1594d13d8..00ce6ed27c2 100644
--- a/doc/raketasks/backup_restore.md
+++ b/doc/raketasks/backup_restore.md
@@ -7,6 +7,10 @@ Creates a backup archive of the database and all repositories. This archive will
The filename will be `[TIMESTAMP]_gitlab_backup.tar`. This timestamp can be used to restore an specific backup.
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:backup:create
+
+# installation from source or cookbook
bundle exec rake gitlab:backup:create RAILS_ENV=production
```
@@ -42,6 +46,10 @@ Deleting old backups... [SKIPPING]
## Restore a previously created backup
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:backup:restore
+
+# installation from source or cookbook
bundle exec rake gitlab:backup:restore RAILS_ENV=production
```
@@ -84,6 +92,8 @@ Deleting tmp directories...[DONE]
## Configure cron to make daily backups
+For omnibus-gitlab, see https://gitlab.com/gitlab-org/omnibus-gitlab/blob/master/README.md#scheduling-a-backup .
+
```
cd /home/git/gitlab
sudo -u git -H editor config/gitlab.yml # Enable keep_time in the backup section to automatically delete old backups
diff --git a/doc/raketasks/cleanup.md b/doc/raketasks/cleanup.md
index 4b3b6d71a75..9e48f56c951 100644
--- a/doc/raketasks/cleanup.md
+++ b/doc/raketasks/cleanup.md
@@ -5,11 +5,19 @@
Remove namespaces(dirs) from `/home/git/repositories` if they don't exist in GitLab database.
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:cleanup:dirs
+
+# installation from source or cookbook
bundle exec rake gitlab:cleanup:dirs RAILS_ENV=production
```
Remove repositories (global only for now) from `/home/git/repositories` if they don't exist in GitLab database.
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:cleanup:repos
+
+# installation from source or cookbook
bundle exec rake gitlab:cleanup:repos RAILS_ENV=production
```
diff --git a/doc/raketasks/import.md b/doc/raketasks/import.md
index 628bd373b8d..39b1a52a44d 100644
--- a/doc/raketasks/import.md
+++ b/doc/raketasks/import.md
@@ -15,6 +15,10 @@ How to use:
2. run the command below
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:import:repos
+
+# installation from source or cookbook
bundle exec rake gitlab:import:repos RAILS_ENV=production
```
diff --git a/doc/raketasks/maintenance.md b/doc/raketasks/maintenance.md
index 30276dd7629..3339dfb03ac 100644
--- a/doc/raketasks/maintenance.md
+++ b/doc/raketasks/maintenance.md
@@ -5,6 +5,10 @@
This command gathers information about your GitLab installation and the System it runs on. These may be useful when asking for help or reporting issues.
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:env:info
+
+# installation from source or cookbook
bundle exec rake gitlab:env:info RAILS_ENV=production
```
@@ -52,6 +56,10 @@ It will check that each component was setup according to the installation guide
You may also have a look at our [Trouble Shooting Guide](https://github.com/gitlabhq/gitlab-public-wiki/wiki/Trouble-Shooting-Guide).
```
+# omnibus-gitlab
+sudo gitlab-rake gitlab:check
+
+# installation from source or cookbook
bundle exec rake gitlab:check RAILS_ENV=production
```
diff --git a/doc/raketasks/user_management.md b/doc/raketasks/user_management.md
index 81378494c6b..eb9eebb4b4a 100644
--- a/doc/raketasks/user_management.md
+++ b/doc/raketasks/user_management.md
@@ -3,6 +3,10 @@
## Add user as a developer to all projects
```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:import:user_to_projects[username@domain.tld]
+
+# installation from source or cookbook
bundle exec rake gitlab:import:user_to_projects[username@domain.tld]
```
@@ -13,12 +17,20 @@ Notes:
- admin users are added as masters
```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:import:all_users_to_all_projects
+
+# installation from source or cookbook
bundle exec rake gitlab:import:all_users_to_all_projects
```
## Add user as a developer to all groups
```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:import:user_to_groups[username@domain.tld]
+
+# installation from source or cookbook
bundle exec rake gitlab:import:user_to_groups[username@domain.tld]
```
@@ -29,5 +41,9 @@ Notes:
- admin users are added as owners so they can add additional users to the group
```bash
+# omnibus-gitlab
+sudo gitlab-rake gitlab:import:all_users_to_all_groups
+
+# installation from source or cookbook
bundle exec rake gitlab:import:all_users_to_all_groups
```
diff --git a/doc/raketasks/web_hooks.md b/doc/raketasks/web_hooks.md
index 704473af2d9..ac32c01289d 100644
--- a/doc/raketasks/web_hooks.md
+++ b/doc/raketasks/web_hooks.md
@@ -2,26 +2,44 @@
## Add a web hook for **ALL** projects:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook"
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:add URL="http://example.com/hook"
## Add a web hook for projects in a given **NAMESPACE**:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:add URL="http://example.com/hook" NAMESPACE=acme
## Remove a web hook from **ALL** projects using:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook"
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook"
## Remove a web hook from projects in a given **NAMESPACE**:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:rm URL="http://example.com/hook" NAMESPACE=acme
## List **ALL** web hooks:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:list
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:list
## List the web hooks from projects in a given **NAMESPACE**:
+ # omnibus-gitlab
+ sudo gitlab-rake gitlab:web_hook:list NAMESPACE=/
+ # source installations or cookbook
RAILS_ENV=production bundle exec rake gitlab:web_hook:list NAMESPACE=/
> Note: `/` is the global namespace.
diff --git a/doc/release/monthly.md b/doc/release/monthly.md
index 45040084dfc..22824016f26 100644
--- a/doc/release/monthly.md
+++ b/doc/release/monthly.md
@@ -120,6 +120,17 @@ Merge the RC1 code into GitLab.com. Once the build is green, deploy in the morni
It is important to do this as soon as possible, so we can catch any errors before we release the full version.
+### **9. Create a regressions issue**
+
+On [the GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues/) create an issue titled "GitLab X.X regressions" add the following text:
+
+This is a meta issue to discuss possible regressions in this monthly release and any patch versions.
+Please do not raise issues directly in this issue but link to issues that might warrant a patch release.
+The decision to create a patch release or not is with the release manager who is assigned to this issue.
+The release manager will comment here about the plans for patch releases.
+
+Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
+
# **21st - Preparation **
### **1. Prepare the blog post**
@@ -219,17 +230,6 @@ Include a link to the blog post and keep it short.
Proposed email for CE: "We have released a new version of GitLab Community Edition and its packages. See our blog post(<link>) for more information."
-### **10. Create a regressions issue**
-
-On [the GitLab CE issue tracker on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/issues/) create an issue titled "GitLab X.X regressions" add the following text:
-
-This is a meta issue to discuss possible regressions in this monthly release and any patch versions.
-Please do not raise issues directly in this issue but link to issues that might warrant a patch release.
-The decision to create a patch release or not is with the release manager who is assigned to this issue.
-The release manager will comment here about the plans for patch releases.
-
-Assign the issue to the release manager and /cc all the core-team members active on the issue tracker. If there are any known bugs in the release add them immediately.
-
# **23rd - Optional Patch Release**
# **24th - Update GitLab.com**
diff --git a/doc/update/6.9-to-7.0.md b/doc/update/6.9-to-7.0.md
index d6e9c9f3155..70a30a58687 100644
--- a/doc/update/6.9-to-7.0.md
+++ b/doc/update/6.9-to-7.0.md
@@ -13,7 +13,39 @@ sudo -u git -H bundle exec rake gitlab:backup:create RAILS_ENV=production
sudo service gitlab stop
```
-### 2. Get latest code
+### 2. Update Ruby
+
+If you are still using Ruby 1.9.3 or below, you will need to update Ruby.
+You can check which version you are running with `ruby -v`.
+
+If you are you running Ruby 2.0.x, you do not need to upgrade ruby, but can consider doing so for performance reasons.
+
+If you are running Ruby 2.1.1 consider upgrading to 2.1.2, because of the high memory usage of Ruby 2.1.1.
+
+Install, update dependencies:
+
+```bash
+sudo apt-get install build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl
+```
+
+Download and compile Ruby:
+
+```bash
+mkdir /tmp/ruby && cd /tmp/ruby
+curl --progress ftp://ftp.ruby-lang.org/pub/ruby/2.1/ruby-2.1.2.tar.gz | tar xz
+cd ruby-2.1.2
+./configure --disable-install-rdoc
+make
+sudo make install
+```
+
+Install Bundler:
+
+```bash
+sudo gem install bundler --no-ri --no-rdoc
+```
+
+### 3. Get latest code
```bash
cd /home/git/gitlab
@@ -34,7 +66,7 @@ For GitLab Enterprise Edition:
sudo -u git -H git checkout 7-0-stable-ee
```
-### 3. Update gitlab-shell (and its config)
+### 4. Update gitlab-shell (and its config)
```bash
cd /home/git/gitlab-shell
@@ -42,7 +74,7 @@ sudo -u git -H git fetch
sudo -u git -H git checkout v1.9.6
```
-### 4. Install libs, migrations, etc.
+### 5. Install libs, migrations, etc.
```bash
cd /home/git/gitlab
@@ -58,9 +90,13 @@ sudo -u git -H bundle exec rake db:migrate RAILS_ENV=production
# Clean up assets and cache
sudo -u git -H bundle exec rake assets:clean assets:precompile cache:clear RAILS_ENV=production
+
+# Update init.d script
+sudo cp lib/support/init.d/gitlab /etc/init.d/gitlab
+sudo chmod +x /etc/init.d/gitlab
```
-### 5. Update config files
+### 6. Update config files
#### New configuration options for gitlab.yml
@@ -70,12 +106,12 @@ There are new configuration options available for gitlab.yml. View them with the
git diff 6-9-stable:config/gitlab.yml.example 7-0-stable:config/gitlab.yml.example
```
-### 6. Start application
+### 7. Start application
sudo service gitlab start
sudo service nginx restart
-### 7. Check application status
+### 8. Check application status
Check if GitLab and its environment are configured correctly:
diff --git a/doc/update/README.md b/doc/update/README.md
index 8c0cf5f7b26..9a6f09b370a 100644
--- a/doc/update/README.md
+++ b/doc/update/README.md
@@ -1,5 +1,4 @@
- [The individual upgrade guides](https://gitlab.com/gitlab-org/gitlab-ce/tree/master/doc/update)
- [Upgrader](upgrader.md)
-- [Ruby](ruby.md)
- [Patch versions](patch_versions.md)
- [MySQL to PostgreSQL](mysql_to_postgresql.md)
diff --git a/doc/update/ruby.md b/doc/update/ruby.md
deleted file mode 100644
index d1d9d3e77f5..00000000000
--- a/doc/update/ruby.md
+++ /dev/null
@@ -1,59 +0,0 @@
-# Updating Ruby from source
-
-This guide explains how to update Ruby in case you installed it from source according to the [instructions](../install/installation.md#2-ruby).
-
-## 1. Look for Ruby versions
-
-This guide will only update `/usr/local/bin/ruby`. You can see which Ruby binaries are installed on your system by running:
-
-```bash
-ls -l $(which -a ruby)
-```
-
-## 2. Stop GitLab
-
-```bash
-sudo service gitlab stop
-```
-
-## 3. Install or update dependencies
-
-Here we are assuming you are using Debian/Ubuntu.
-
-```bash
-sudo apt-get install build-essential zlib1g-dev libyaml-dev libssl-dev libgdbm-dev libreadline-dev libncurses5-dev libffi-dev curl
-```
-
-## 4. Download, compile and install Ruby
-
-Find the latest stable version of Ruby 1.9 or 2.0 at <https://www.ruby-lang.org/en/downloads/>. We recommend at least 2.0.0-p353, which is patched against [CVE-2013-4164](https://www.ruby-lang.org/en/news/2013/11/22/heap-overflow-in-floating-point-parsing-cve-2013-4164/).
-
-```bash
-cd /tmp
-curl --progress http://cache.ruby-lang.org/pub/ruby/2.0/ruby-2.0.0-p353.tar.gz | tar xz
-cd ruby-2.0.0-p353
-./configure --disable-install-rdoc
-make
-sudo make install # overwrite the existing Ruby in /usr/local/bin
-sudo gem install bundler
-```
-
-### 5. Reinstall GitLab gem bundle
-
-Just to be sure we will reinstall the gems used by GitLab. Note that the `bundle install` command [depends on your choice of database](../install/installation.md#install-gems).
-
-```bash
-cd /home/git/gitlab
-sudo -u git -H rm -rf vendor/bundle # remove existing Gem bundle
-sudo -u git -H bundle install --deployment --without development test mysql aws # Assuming PostgreSQL
-```
-
-## 6. Start GitLab
-
-We are now ready to restart GitLab.
-
-```bash
-sudo service gitlab start
-```
-
-## Done
diff --git a/doc/workflow/README.md b/doc/workflow/README.md
index c715f6e5943..00d4bed1cc7 100644
--- a/doc/workflow/README.md
+++ b/doc/workflow/README.md
@@ -1,3 +1,4 @@
- [Workflow](workflow.md)
- [Project Features](project_features.md)
- [Authorization for merge requests](authorization_for_merge_requests.md)
+- [Groups](groups.md)
diff --git a/doc/workflow/groups.md b/doc/workflow/groups.md
new file mode 100644
index 00000000000..611f871cf77
--- /dev/null
+++ b/doc/workflow/groups.md
@@ -0,0 +1,71 @@
+# GitLab Groups
+
+GitLab groups allow you to group projects into directories and give users to several projects at once.
+
+When you create a new project in GitLab, the default namespace for the project is the personal namespace associated with your GitLab user.
+In this document we will see how to create groups, put projects in groups and manage who can access the projects in a group.
+
+## Creating groups
+
+You can create a group by going to the 'Groups' tab of the GitLab dashboard and clicking the 'New group' button.
+
+![Click the 'New group' button in the 'Groups' tab](groups/new_group_button.png)
+
+Next, enter the name (required) and the optional description and group avatar.
+
+![Fill in the name for your new group](groups/new_group_form.png)
+
+When your group has been created you are presented with the group dashboard feed, which will be empty.
+
+![Group dashboard](groups/group_dashboard.png)
+
+You can use the 'New project' button to add a project to the new group.
+
+## Transfering an existing project into a group
+
+You can transfer an existing project into a group you own from the project settings page.
+First scroll down to the 'Dangerous settings' and click 'Show them to me'.
+Now you can pick any of the groups you manage as the new namespace for the group.
+
+![Transfer a project to a new namespace](groups/transfer_project.png)
+
+GitLab administrators can use the admin interface to move any project to any namespace if needed.
+
+## Adding users to a group
+
+One of the benefits of putting multiple projects in one group is that you can give a user to access to all projects in the group with one action.
+
+Suppose we have a group with two projects.
+
+![Group with two projects](groups/group_with_two_projects.png)
+
+On the 'Group Members' page we can now add a new user Barry to the group.
+
+![Add user Barry to the group](groups/add_member_to_group.png)
+
+Now because Barry is a 'Developer' member of the 'Open Source' group, he automatically gets 'Developer' access to all projects in the 'Open Source' group.
+
+![Barry has 'Developer' access to GitLab CI](groups/project_members_via_group.png)
+
+If necessary, you can increase the access level of an individual user for a specific project, by adding them as a Member to the project.
+
+![Barry effectively has 'Master' access to GitLab CI now](groups/override_access_level.png)
+
+## Managing group memberships via LDAP
+
+In GitLab Enterprise Edition it is possible to manage GitLab group memberships using LDAP groups.
+See [the GitLab Enterprise Edition documentation](http://doc.gitlab.com/ee/integration/ldap.html) for more information.
+
+## Allowing only admins to create groups
+
+By default, any GitLab user can create new groups.
+This ability can be disabled for individual users from the admin panel.
+It is also possible to configure GitLab so that new users default to not being able to create groups:
+
+```
+# For omnibus-gitlab, put the following in /etc/gitlab/gitlab.rb
+gitlab_rails['gitlab_default_can_create_group'] = false
+
+# For installations from source, uncomment the 'default_can_create_group'
+# line in /home/git/gitlab/config/gitlab.yml
+```
diff --git a/doc/workflow/groups/add_member_to_group.png b/doc/workflow/groups/add_member_to_group.png
new file mode 100644
index 00000000000..fa340ce572f
--- /dev/null
+++ b/doc/workflow/groups/add_member_to_group.png
Binary files differ
diff --git a/doc/workflow/groups/group_dashboard.png b/doc/workflow/groups/group_dashboard.png
new file mode 100644
index 00000000000..7fc9048d74d
--- /dev/null
+++ b/doc/workflow/groups/group_dashboard.png
Binary files differ
diff --git a/doc/workflow/groups/group_with_two_projects.png b/doc/workflow/groups/group_with_two_projects.png
new file mode 100644
index 00000000000..87242781e4f
--- /dev/null
+++ b/doc/workflow/groups/group_with_two_projects.png
Binary files differ
diff --git a/doc/workflow/groups/new_group_button.png b/doc/workflow/groups/new_group_button.png
new file mode 100644
index 00000000000..51e82798658
--- /dev/null
+++ b/doc/workflow/groups/new_group_button.png
Binary files differ
diff --git a/doc/workflow/groups/new_group_form.png b/doc/workflow/groups/new_group_form.png
new file mode 100644
index 00000000000..bf992c40bc2
--- /dev/null
+++ b/doc/workflow/groups/new_group_form.png
Binary files differ
diff --git a/doc/workflow/groups/override_access_level.png b/doc/workflow/groups/override_access_level.png
new file mode 100644
index 00000000000..f4225a63679
--- /dev/null
+++ b/doc/workflow/groups/override_access_level.png
Binary files differ
diff --git a/doc/workflow/groups/project_members_via_group.png b/doc/workflow/groups/project_members_via_group.png
new file mode 100644
index 00000000000..b13cb1cfd95
--- /dev/null
+++ b/doc/workflow/groups/project_members_via_group.png
Binary files differ
diff --git a/doc/workflow/groups/transfer_project.png b/doc/workflow/groups/transfer_project.png
new file mode 100644
index 00000000000..044fe10d073
--- /dev/null
+++ b/doc/workflow/groups/transfer_project.png
Binary files differ
diff --git a/features/admin/users.feature b/features/admin/users.feature
index ce31aafd290..d8c1288e5f0 100644
--- a/features/admin/users.feature
+++ b/features/admin/users.feature
@@ -21,3 +21,11 @@ Feature: Admin Users
And click edit on my user
When I submit modified user
Then I see user attributes changed
+
+@javascript
+ Scenario: Remove users secondary email
+ Given I visit admin users page
+ And I view the user with secondary email
+ And I see the secondary email
+ When I click remove secondary email
+ Then I should not see secondary email anymore
diff --git a/features/project/project.feature b/features/project/project.feature
index d8bb1d55e2d..d561c6e440e 100644
--- a/features/project/project.feature
+++ b/features/project/project.feature
@@ -24,3 +24,8 @@ Feature: Project Feature
When I visit edit project "Shop" page
And change project path settings
Then I should see project with new path settings
+
+ Scenario: I should see project readme and version
+ When I visit project "Shop" page
+ Then I should see project "Shop" README link
+ And I should see project "Shop" version
diff --git a/features/project/redirects.feature b/features/project/redirects.feature
index ce197912f64..776ab83a876 100644
--- a/features/project/redirects.feature
+++ b/features/project/redirects.feature
@@ -24,3 +24,10 @@ Feature: Project Redirects
Given I sign in as a user
When I visit project "Enterprise" page
Then page status code should be 404
+
+ Scenario: I visit a public project without signing in
+ When I visit project "Community" page
+ And I should see project "Community" home page
+ And I click on "Sign In"
+ And Authenticate
+ Then I should be redirected to "Community" page
diff --git a/features/steps/admin/active_tab.rb b/features/steps/admin/active_tab.rb
index ccafe09c18f..8f09e51ccef 100644
--- a/features/steps/admin/active_tab.rb
+++ b/features/steps/admin/active_tab.rb
@@ -4,7 +4,7 @@ class AdminActiveTab < Spinach::FeatureSteps
include SharedActiveTab
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Overview')
end
Then 'the active main tab should be Projects' do
diff --git a/features/steps/admin/users.rb b/features/steps/admin/users.rb
index 659008dd875..253c4609e82 100644
--- a/features/steps/admin/users.rb
+++ b/features/steps/admin/users.rb
@@ -44,4 +44,23 @@ class AdminUsers < Spinach::FeatureSteps
step 'click edit on my user' do
find("#edit_user_#{current_user.id}").click
end
+
+ step 'I view the user with secondary email' do
+ @user_with_secondary_email = User.last
+ @user_with_secondary_email.emails.new(email: "secondary@example.com")
+ @user_with_secondary_email.save
+ visit "/admin/users/#{@user_with_secondary_email.username}"
+ end
+
+ step 'I see the secondary email' do
+ page.should have_content "Secondary email: #{@user_with_secondary_email.emails.last.email}"
+ end
+
+ step 'I click remove secondary email' do
+ find("#remove_email_#{@user_with_secondary_email.emails.last.id}").click
+ end
+
+ step 'I should not see secondary email anymore' do
+ page.should_not have_content "Secondary email:"
+ end
end
diff --git a/features/steps/dashboard/active_tab.rb b/features/steps/dashboard/active_tab.rb
index 8f5f0eed816..68d32ed971a 100644
--- a/features/steps/dashboard/active_tab.rb
+++ b/features/steps/dashboard/active_tab.rb
@@ -4,7 +4,7 @@ class DashboardActiveTab < Spinach::FeatureSteps
include SharedActiveTab
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Activity')
end
Then 'the active main tab should be Issues' do
diff --git a/features/steps/profile/active_tab.rb b/features/steps/profile/active_tab.rb
index ee9f5f201cf..1924a6fa785 100644
--- a/features/steps/profile/active_tab.rb
+++ b/features/steps/profile/active_tab.rb
@@ -4,7 +4,7 @@ class ProfileActiveTab < Spinach::FeatureSteps
include SharedActiveTab
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Profile')
end
Then 'the active main tab should be Account' do
diff --git a/features/steps/project/active_tab.rb b/features/steps/project/active_tab.rb
index dcc252f4765..dfafbc6fc0e 100644
--- a/features/steps/project/active_tab.rb
+++ b/features/steps/project/active_tab.rb
@@ -7,7 +7,7 @@ class ProjectActiveTab < Spinach::FeatureSteps
# Main Tabs
Then 'the active main tab should be Home' do
- ensure_active_main_tab('Home')
+ ensure_active_main_tab('Activity')
end
Then 'the active main tab should be Settings' do
diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb
index e0aec699a56..b0a6e530e8a 100644
--- a/features/steps/project/merge_requests.rb
+++ b/features/steps/project/merge_requests.rb
@@ -131,21 +131,21 @@ class ProjectMergeRequests < Spinach::FeatureSteps
end
step 'I should see a discussion has started on line 185' do
- page.should have_content "#{current_user.name} started a discussion on this merge request diff"
- page.should have_content "app/assets/stylesheets/tree.scss:L185"
+ page.should have_content "#{current_user.name} started a discussion"
+ page.should have_content "app/assets/stylesheets/tree.scss"
page.should have_content "Line is wrong"
end
step 'I should see a discussion has started on commit b1e6a9dbf1:L185' do
page.should have_content "#{current_user.name} started a discussion on commit"
- page.should have_content "app/assets/stylesheets/tree.scss:L185"
+ page.should have_content "app/assets/stylesheets/tree.scss"
page.should have_content "Line is wrong"
end
step 'I should see a discussion has started on commit b1e6a9dbf1' do
page.should have_content "#{current_user.name} started a discussion on commit"
page.should have_content "One comment to rule them all"
- page.should have_content "app/assets/stylesheets/tree.scss:L185"
+ page.should have_content "app/assets/stylesheets/tree.scss"
end
step 'merge request is mergeable' do
@@ -257,9 +257,7 @@ class ProjectMergeRequests < Spinach::FeatureSteps
click_button "Add Comment"
end
- within ".note-text" do
- page.should have_content message
- end
+ page.should have_content message
end
def init_diff_note_first_file
diff --git a/features/steps/project/project.rb b/features/steps/project/project.rb
index 92728d474b2..7c0b2509416 100644
--- a/features/steps/project/project.rb
+++ b/features/steps/project/project.rb
@@ -24,4 +24,16 @@ class ProjectFeature < Spinach::FeatureSteps
step 'I should see project with new path settings' do
project.path.should == "new-path"
end
+
+ step 'I should see project "Shop" README link' do
+ within '.project-side' do
+ page.should have_content "README.md"
+ end
+ end
+
+ step 'I should see project "Shop" version' do
+ within '.project-side' do
+ page.should have_content "Version: 2.2.0"
+ end
+ end
end
diff --git a/features/steps/project/redirects.rb b/features/steps/project/redirects.rb
index cfa4ce82be3..5a4342dba30 100644
--- a/features/steps/project/redirects.rb
+++ b/features/steps/project/redirects.rb
@@ -31,5 +31,27 @@ class Spinach::Features::ProjectRedirects < Spinach::FeatureSteps
project = Project.find_by(name: 'Community')
visit project_path(project) + 'DoesNotExist'
end
+
+ step 'I click on "Sign In"' do
+ within '.pull-right' do
+ click_link "Sign in"
+ end
+ end
+
+ step 'Authenticate' do
+ admin = create(:admin)
+ project = Project.find_by(name: 'Community')
+ find(:xpath, "//input[@id='return_to']").set "/#{project.path_with_namespace}"
+ fill_in "user_login", with: admin.email
+ fill_in "user_password", with: admin.password
+ click_button "Sign in"
+ Thread.current[:current_user] = admin
+ end
+
+ step 'I should be redirected to "Community" page' do
+ project = Project.find_by(name: 'Community')
+ page.current_path.should == "/#{project.path_with_namespace}"
+ page.status_code.should == 200
+ end
end
diff --git a/features/steps/shared/active_tab.rb b/features/steps/shared/active_tab.rb
index d504fda3327..e3cd5fcfe85 100644
--- a/features/steps/shared/active_tab.rb
+++ b/features/steps/shared/active_tab.rb
@@ -2,11 +2,7 @@ module SharedActiveTab
include Spinach::DSL
def ensure_active_main_tab(content)
- if content == "Home"
- page.find('.main-nav li.active').should have_css('i.icon-home')
- else
- page.find('.main-nav li.active').should have_content(content)
- end
+ page.find('.main-nav li.active').should have_content(content)
end
def ensure_active_sub_tab(content)
diff --git a/features/steps/shared/diff_note.rb b/features/steps/shared/diff_note.rb
index f917d7bde08..201642a086e 100644
--- a/features/steps/shared/diff_note.rb
+++ b/features/steps/shared/diff_note.rb
@@ -2,7 +2,7 @@ module SharedDiffNote
include Spinach::DSL
Given 'I cancel the diff comment' do
- within(".diff-file") do
+ within(diff_file_selector) do
find(".js-close-discussion-note-form").click
end
end
@@ -13,14 +13,14 @@ module SharedDiffNote
end
Given 'I haven\'t written any diff comment text' do
- within(".diff-file") do
+ within(diff_file_selector) do
fill_in "note[note]", with: ""
end
end
Given 'I leave a diff comment like "Typo, please fix"' do
find('a[data-line-code="586fb7c4e1add2d4d24e27566ed7064680098646_29_14"]').click
- within(".diff-file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
+ within("#{diff_file_selector} form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
fill_in "note[note]", with: "Typo, please fix"
find(".js-comment-button").trigger("click")
sleep 0.05
@@ -29,7 +29,7 @@ module SharedDiffNote
Given 'I preview a diff comment text like "Should fix it :smile:"' do
find('a[data-line-code="586fb7c4e1add2d4d24e27566ed7064680098646_29_14"]').click
- within(".diff-file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
+ within("#{diff_file_selector} form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_29_14']") do
fill_in "note[note]", with: "Should fix it :smile:"
find(".js-note-preview-button").trigger("click")
end
@@ -38,7 +38,7 @@ module SharedDiffNote
Given 'I preview another diff comment text like "DRY this up"' do
find('a[data-line-code="586fb7c4e1add2d4d24e27566ed7064680098646_57_41"]').click
- within(".diff-file form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do
+ within("#{diff_file_selector} form[rel$='586fb7c4e1add2d4d24e27566ed7064680098646_57_41']") do
fill_in "note[note]", with: "DRY this up"
find(".js-note-preview-button").trigger("click")
end
@@ -53,63 +53,61 @@ module SharedDiffNote
end
Given 'I write a diff comment like ":-1: I don\'t like this"' do
- within(".diff-file") do
+ within(diff_file_selector) do
fill_in "note[note]", with: ":-1: I don\'t like this"
end
end
Given 'I submit the diff comment' do
- within(".diff-file") do
+ within(diff_file_selector) do
click_button("Add Comment")
end
end
-
-
Then 'I should not see the diff comment form' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should_not have_css("form.new_note")
end
end
Then 'I should not see the diff comment preview button' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: false)
end
end
Then 'I should not see the diff comment text field' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-note-text", visible: false)
end
end
Then 'I should only see one diff form' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css("form.new_note", count: 1)
end
end
Then 'I should see a diff comment form with ":-1: I don\'t like this"' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_field("note[note]", with: ":-1: I don\'t like this")
end
end
Then 'I should see a diff comment saying "Typo, please fix"' do
- within(".diff-file .note") do
+ within("#{diff_file_selector} .note") do
page.should have_content("Typo, please fix")
end
end
Then 'I should see a discussion reply button' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_link("Reply")
end
end
Then 'I should see a temporary diff comment form' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-temp-notes-holder form.new_note")
end
end
@@ -119,40 +117,44 @@ module SharedDiffNote
end
Then 'I should see an empty diff comment form' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_field("note[note]", with: "")
end
end
Then 'I should see the cancel comment button' do
- within(".diff-file form") do
+ within("#{diff_file_selector} form") do
page.should have_css(".js-close-discussion-note-form", text: "Cancel")
end
end
Then 'I should see the diff comment preview' do
- within(".diff-file form") do
+ within("#{diff_file_selector} form") do
page.should have_css(".js-note-preview", visible: false)
end
end
Then 'I should see the diff comment edit button' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-note-write-button", visible: true)
end
end
Then 'I should see the diff comment preview button' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: true)
end
end
Then 'I should see two separate previews' do
- within(".diff-file") do
+ within(diff_file_selector) do
page.should have_css(".js-note-preview", visible: true, count: 2)
page.should have_content("Should fix it")
page.should have_content("DRY this up")
end
end
+
+ def diff_file_selector
+ ".diff-file"
+ end
end
diff --git a/lib/api/notes.rb b/lib/api/notes.rb
index 413faf0cf2d..0ef9a3c4beb 100644
--- a/lib/api/notes.rb
+++ b/lib/api/notes.rb
@@ -50,12 +50,15 @@ module API
post ":id/#{noteables_str}/:#{noteable_id_str}/notes" do
required_attributes! [:body]
- @noteable = user_project.send(:"#{noteables_str}").find(params[:"#{noteable_id_str}"])
- @note = @noteable.notes.new(note: params[:body])
- @note.author = current_user
- @note.project = user_project
+ opts = {
+ note: params[:body],
+ noteable_type: noteables_str.classify,
+ noteable_id: params[noteable_id_str]
+ }
+
+ @note = ::Notes::CreateService.new(user_project, current_user, opts).execute
- if @note.save
+ if @note.valid?
present @note, with: Entities::Note
else
not_found!
diff --git a/lib/gitlab/markdown.rb b/lib/gitlab/markdown.rb
index c04be788f07..b248d8f9436 100644
--- a/lib/gitlab/markdown.rb
+++ b/lib/gitlab/markdown.rb
@@ -169,10 +169,13 @@ module Gitlab
end
def reference_user(identifier, project = @project)
- if user = User.find_by(username: identifier)
- options = html_options.merge(
+ options = html_options.merge(
class: "gfm gfm-team_member #{html_options[:class]}"
)
+
+ if identifier == "all"
+ link_to("@all", project_url(project), options)
+ elsif user = User.find_by(username: identifier)
link_to("@#{identifier}", user_url(identifier), options)
end
end
diff --git a/lib/gitlab/oauth/user.rb b/lib/gitlab/oauth/user.rb
index c5be884a895..38e33c0eee5 100644
--- a/lib/gitlab/oauth/user.rb
+++ b/lib/gitlab/oauth/user.rb
@@ -44,7 +44,13 @@ module Gitlab
user.username = email_username.gsub("'", "")
end
- user.save!
+ begin
+ user.save!
+ rescue ActiveRecord::RecordInvalid => e
+ log.info "(OAuth) Email #{e.record.errors[:email]}. Username #{e.record.errors[:username]}"
+ return nil, e.record.errors
+ end
+
log.info "(OAuth) Creating user #{email} from login with extern_uid => #{uid}"
if Gitlab.config.omniauth['block_auto_created_users'] && !ldap?
diff --git a/lib/gitlab/url_builder.rb b/lib/gitlab/url_builder.rb
new file mode 100644
index 00000000000..de7e0404086
--- /dev/null
+++ b/lib/gitlab/url_builder.rb
@@ -0,0 +1,25 @@
+module Gitlab
+ class UrlBuilder
+ include Rails.application.routes.url_helpers
+
+ def initialize(type)
+ @type = type
+ end
+
+ def build(id)
+ case @type
+ when :issue
+ issue_url(id)
+ end
+ end
+
+ private
+
+ def issue_url(id)
+ issue = Issue.find(id)
+ project_issue_url(id: issue.iid,
+ project_id: issue.project,
+ host: Settings.gitlab['url'])
+ end
+ end
+end
diff --git a/lib/tasks/cache.rake b/lib/tasks/cache.rake
index 8320b9b2576..753a5a11070 100644
--- a/lib/tasks/cache.rake
+++ b/lib/tasks/cache.rake
@@ -1,6 +1,11 @@
namespace :cache do
desc "GITLAB | Clear redis cache"
task :clear => :environment do
- Rails.cache.clear
+ # Hack into Rails.cache until https://github.com/redis-store/redis-store/pull/225
+ # is accepted (I hope) and we can update the redis-store gem.
+ redis_store = Rails.cache.instance_variable_get(:@data)
+ redis_store.keys.each_slice(1000) do |key_slice|
+ redis_store.del(*key_slice)
+ end
end
end
diff --git a/spec/features/admin/admin_users_spec.rb b/spec/features/admin/admin_users_spec.rb
index 1aba40966c4..82da19746f8 100644
--- a/spec/features/admin/admin_users_spec.rb
+++ b/spec/features/admin/admin_users_spec.rb
@@ -47,20 +47,16 @@ describe "Admin::Users", feature: true do
it "should call send mail" do
Notify.should_receive(:new_user_email)
- User.observers.enable :user_observer do
- click_button "Create user"
- end
+ click_button "Create user"
end
it "should send valid email to user with email & password" do
- User.observers.enable :user_observer do
- click_button "Create user"
- user = User.last
- email = ActionMailer::Base.deliveries.last
- email.subject.should have_content("Account was created")
- email.text_part.body.should have_content(user.email)
- email.text_part.body.should have_content('password')
- end
+ click_button "Create user"
+ user = User.last
+ email = ActionMailer::Base.deliveries.last
+ email.subject.should have_content("Account was created")
+ email.text_part.body.should have_content(user.email)
+ email.text_part.body.should have_content('password')
end
end
diff --git a/spec/features/profile_spec.rb b/spec/features/profile_spec.rb
index e8364bbb962..bdf7b59114b 100644
--- a/spec/features/profile_spec.rb
+++ b/spec/features/profile_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe "Profile account page", feature: true do
- before(:each) { enable_observers }
- after(:each) {disable_observers}
let(:user) { create(:user) }
before do
diff --git a/spec/features/projects_spec.rb b/spec/features/projects_spec.rb
index 1e24782c39a..524c4d5fa21 100644
--- a/spec/features/projects_spec.rb
+++ b/spec/features/projects_spec.rb
@@ -1,8 +1,6 @@
require 'spec_helper'
describe "Projects", feature: true do
- before(:each) { enable_observers }
- after(:each) {disable_observers}
before { login_as :user }
describe "DELETE /projects/:id" do
diff --git a/spec/features/search_spec.rb b/spec/features/search_spec.rb
index f12eb124296..cce9f06cb69 100644
--- a/spec/features/search_spec.rb
+++ b/spec/features/search_spec.rb
@@ -2,7 +2,6 @@ require 'spec_helper'
describe "Search", feature: true do
before do
- ActiveRecord::Base.observers.enable(:user_observer)
login_as :user
@project = create(:project, namespace: @user.namespace)
@project.team << [@user, :reporter]
diff --git a/spec/helpers/gitlab_markdown_helper_spec.rb b/spec/helpers/gitlab_markdown_helper_spec.rb
index fc9d1ac90c0..f176a393415 100644
--- a/spec/helpers/gitlab_markdown_helper_spec.rb
+++ b/spec/helpers/gitlab_markdown_helper_spec.rb
@@ -5,6 +5,7 @@ describe GitlabMarkdownHelper do
include IssuesHelper
let!(:project) { create(:project) }
+ let(:empty_project) { create(:empty_project) }
let(:user) { create(:user, username: 'gfm') }
let(:commit) { project.repository.commit }
@@ -506,6 +507,19 @@ describe GitlabMarkdownHelper do
end
end
+ describe "markdwon for empty repository" do
+ before do
+ @project = empty_project
+ @repository = empty_project.repository
+ end
+
+ it "should not touch relative urls" do
+ actual = "[GitLab API doc][GitLab readme]\n [GitLab readme]: doc/api/README.md\n"
+ expected = "<p><a href=\"doc/api/README.md\">GitLab API doc</a></p>\n"
+ markdown(actual).should match(expected)
+ end
+ end
+
describe "#render_wiki_content" do
before do
@wiki = double('WikiPage')
diff --git a/spec/lib/gitlab/url_builder_spec.rb b/spec/lib/gitlab/url_builder_spec.rb
new file mode 100644
index 00000000000..eb47bee8336
--- /dev/null
+++ b/spec/lib/gitlab/url_builder_spec.rb
@@ -0,0 +1,11 @@
+require 'spec_helper'
+
+describe Gitlab::UrlBuilder do
+ describe 'When asking for an issue' do
+ it 'returns the issue url' do
+ issue = create(:issue)
+ url = Gitlab::UrlBuilder.new(:issue).build(issue.id)
+ expect(url).to eq "#{Settings.gitlab['url']}/#{issue.project.to_param}/issues/#{issue.iid}"
+ end
+ end
+end
diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb
index f415e750dd5..1fdd959da9d 100644
--- a/spec/models/event_spec.rb
+++ b/spec/models/event_spec.rb
@@ -65,26 +65,4 @@ describe Event do
it { @event.branch_name.should == "master" }
it { @event.author.should == @user }
end
-
- describe 'Team events' do
- let(:user_project) { double.as_null_object }
- let(:observer) { UsersProjectObserver.instance }
-
- before {
- Event.should_receive :create
- observer.stub(notification: double.as_null_object)
- }
-
- describe "Joined project team" do
- it "should create event" do
- observer.after_create user_project
- end
- end
-
- describe "Left project team" do
- it "should create event" do
- observer.after_destroy user_project
- end
- end
- end
end
diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb
index a2519fbd684..93eae5a9ebd 100644
--- a/spec/models/project_spec.rb
+++ b/spec/models/project_spec.rb
@@ -27,9 +27,6 @@
require 'spec_helper'
describe Project do
- before { enable_observers }
- after { disable_observers }
-
describe "Associations" do
it { should belong_to(:group) }
it { should belong_to(:namespace) }
diff --git a/spec/models/system_hook_spec.rb b/spec/models/system_hook_spec.rb
index 47d6d861d70..2b98acdeb6c 100644
--- a/spec/models/system_hook_spec.rb
+++ b/spec/models/system_hook_spec.rb
@@ -19,21 +19,20 @@ require "spec_helper"
describe SystemHook do
describe "execute" do
- before(:each) { ActiveRecord::Base.observers.enable(:all) }
-
before(:each) do
@system_hook = create(:system_hook)
WebMock.stub_request(:post, @system_hook.url)
end
it "project_create hook" do
- project = create(:project)
+ Projects::CreateService.new(create(:user), name: 'empty').execute
WebMock.should have_requested(:post, @system_hook.url).with(body: /project_create/).once
end
it "project_destroy hook" do
- project = create(:project)
- project.destroy
+ user = create(:user)
+ project = create(:empty_project, namespace: user.namespace)
+ Projects::DestroyService.new(project, user, {}).execute
WebMock.should have_requested(:post, @system_hook.url).with(body: /project_destroy/).once
end
diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb
index 4e0ebb584d1..0a665b7defb 100644
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -145,7 +145,6 @@ describe User do
describe 'projects' do
before do
- ActiveRecord::Base.observers.enable(:user_observer)
@user = create :user
@project = create :project, namespace: @user.namespace
@project_2 = create :project, group: create(:group) # Grant MASTER access to the user
@@ -168,7 +167,6 @@ describe User do
describe 'groups' do
before do
- ActiveRecord::Base.observers.enable(:user_observer)
@user = create :user
@group = create :group
@group.add_owner(@user)
@@ -181,7 +179,6 @@ describe User do
describe 'group multiple owners' do
before do
- ActiveRecord::Base.observers.enable(:user_observer)
@user = create :user
@user2 = create :user
@group = create :group
@@ -195,7 +192,6 @@ describe User do
describe 'namespaced' do
before do
- ActiveRecord::Base.observers.enable(:user_observer)
@user = create :user
@project = create :project, namespace: @user.namespace
end
@@ -339,7 +335,7 @@ describe User do
user.all_ssh_keys.should include(key.key)
end
end
-
+
describe :avatar_type do
let(:user) { create(:user) }
diff --git a/spec/models/users_group_spec.rb b/spec/models/users_group_spec.rb
index acecae07146..05dd97d92d4 100644
--- a/spec/models/users_group_spec.rb
+++ b/spec/models/users_group_spec.rb
@@ -37,4 +37,32 @@ describe UsersGroup do
it { should respond_to(:user_name) }
it { should respond_to(:user_email) }
end
+
+ context 'notification' do
+ describe "#after_create" do
+ it "should send email to user" do
+ membership = build(:users_group)
+ membership.stub(notification_service: double('NotificationService').as_null_object)
+ membership.should_receive(:notification_service)
+ membership.save
+ end
+ end
+
+ describe "#after_update" do
+ before do
+ @membership = create :users_group
+ @membership.stub(notification_service: double('NotificationService').as_null_object)
+ end
+
+ it "should send email to user" do
+ @membership.should_receive(:notification_service)
+ @membership.update_attribute(:group_access, UsersGroup::MASTER)
+ end
+
+ it "does not send an email when the access level has not changed" do
+ @membership.should_not_receive(:notification_service)
+ @membership.update_attribute(:group_access, UsersGroup::OWNER)
+ end
+ end
+ end
end
diff --git a/spec/observers/note_observer_spec.rb b/spec/observers/note_observer_spec.rb
deleted file mode 100644
index f8693355b23..00000000000
--- a/spec/observers/note_observer_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require 'spec_helper'
-
-describe NoteObserver do
- subject { NoteObserver.instance }
- before { subject.stub(notification: double('NotificationService').as_null_object) }
-
- let(:team_without_author) { (1..2).map { |n| double :user, id: n } }
- let(:note) { double(:note).as_null_object }
-
- describe '#after_create' do
-
- it 'is called after a note is created' do
- subject.should_receive :after_create
-
- Note.observers.enable :note_observer do
- create(:note)
- end
- end
-
- it 'sends out notifications' do
- subject.should_receive(:notification)
-
- subject.after_create(note)
- end
-
- it 'creates cross-reference notes as appropriate' do
- @p = create(:project)
- @referenced = create(:issue, project: @p)
- @referencer = create(:issue, project: @p)
- @author = create(:user)
-
- Note.should_receive(:create_cross_reference_note).with(@referenced, @referencer, @author, @p)
-
- Note.observers.enable :note_observer do
- create(:note, project: @p, author: @author, noteable: @referencer,
- note: "Duplicate of ##{@referenced.iid}")
- end
- end
-
- it "doesn't cross-reference system notes" do
- Note.should_receive(:create_cross_reference_note).once
-
- Note.observers.enable :note_observer do
- Note.create_cross_reference_note(create(:issue), create(:issue))
- end
- end
- end
-
- describe '#after_update' do
- it 'checks for new cross-references' do
- note.should_receive(:notice_added_references)
-
- subject.after_update(note)
- end
- end
-end
diff --git a/spec/observers/user_observer_spec.rb b/spec/observers/user_observer_spec.rb
deleted file mode 100644
index 9aeade535f9..00000000000
--- a/spec/observers/user_observer_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require 'spec_helper'
-
-describe UserObserver do
- before(:each) { enable_observers }
- after(:each) {disable_observers}
- subject { UserObserver.instance }
- before { subject.stub(notification: double('NotificationService').as_null_object) }
-
- it 'calls #after_create when new users are created' do
- new_user = build(:user)
- subject.should_receive(:after_create).with(new_user)
- new_user.save
- end
-
- context 'when a new user is created' do
- it 'sends an email' do
- subject.should_receive(:notification)
- create(:user)
- end
-
- it 'trigger logger' do
- user = double(:user, id: 42, password: 'P@ssword!', name: 'John', email: 'u@mail.local', extern_uid?: false)
- Gitlab::AppLogger.should_receive(:info)
- create(:user)
- end
- end
-end
diff --git a/spec/observers/users_group_observer_spec.rb b/spec/observers/users_group_observer_spec.rb
deleted file mode 100644
index 2ab99c33b78..00000000000
--- a/spec/observers/users_group_observer_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require 'spec_helper'
-
-describe UsersGroupObserver do
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
- subject { UsersGroupObserver.instance }
- before { subject.stub(notification: double('NotificationService').as_null_object) }
-
- describe "#after_create" do
- it "should send email to user" do
- subject.should_receive(:notification)
- create(:users_group)
- end
- end
-
- describe "#after_update" do
- before do
- @membership = create :users_group
- end
-
- it "should send email to user" do
- subject.should_receive(:notification)
- @membership.update_attribute(:group_access, UsersGroup::MASTER)
- end
-
- it "does not send an email when the access level has not changed" do
- subject.should_not_receive(:notification)
- @membership.update_attribute(:group_access, UsersGroup::OWNER)
- end
- end
-end
diff --git a/spec/observers/users_project_observer_spec.rb b/spec/observers/users_project_observer_spec.rb
deleted file mode 100644
index b024465e8c3..00000000000
--- a/spec/observers/users_project_observer_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require 'spec_helper'
-
-describe UsersProjectObserver do
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
- let(:user) { create(:user) }
- let(:project) { create(:project) }
- subject { UsersProjectObserver.instance }
- before { subject.stub(notification: double('NotificationService').as_null_object) }
-
- describe "#after_update" do
- before do
- @users_project = create :users_project
- end
-
- it "should called when UsersProject updated" do
- subject.should_receive(:after_update)
- @users_project.update_attribute(:project_access, UsersProject::MASTER)
- end
-
- it "should send email to user" do
- subject.should_receive(:notification)
- @users_project.update_attribute(:project_access, UsersProject::OWNER)
- end
-
- it "should not called after UsersProject destroyed" do
- subject.should_not_receive(:after_update)
- @users_project.destroy
- end
- end
-
- describe "#after_destroy" do
- before do
- @users_project = create :users_project
- end
-
- it "should called when UsersProject destroyed" do
- subject.should_receive(:after_destroy)
- @users_project.destroy
- end
-
- it "should create new event" do
- Event.should_receive(:create)
- @users_project.destroy
- end
- end
-
- describe "#after_create" do
- it "should send email to user" do
- subject.should_receive(:notification)
- Event.stub(create: true)
-
- create(:users_project)
- end
-
- it "should create new event" do
- Event.should_receive(:create)
-
- create(:users_project)
- end
- end
-end
diff --git a/spec/requests/api/branches_spec.rb b/spec/requests/api/branches_spec.rb
index 72589da5d40..b145e620122 100644
--- a/spec/requests/api/branches_spec.rb
+++ b/spec/requests/api/branches_spec.rb
@@ -3,8 +3,6 @@ require 'mime/types'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) {disable_observers}
let(:user) { create(:user) }
let(:user2) { create(:user) }
diff --git a/spec/requests/api/commits_spec.rb b/spec/requests/api/commits_spec.rb
index 165276d1435..b56269d275d 100644
--- a/spec/requests/api/commits_spec.rb
+++ b/spec/requests/api/commits_spec.rb
@@ -3,9 +3,6 @@ require 'mime/types'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) {disable_observers}
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, creator_id: user.id) }
diff --git a/spec/requests/api/files_spec.rb b/spec/requests/api/files_spec.rb
index edfe935d985..e84122f2fbc 100644
--- a/spec/requests/api/files_spec.rb
+++ b/spec/requests/api/files_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
before { project.team << [user, :developer] }
diff --git a/spec/requests/api/internal_spec.rb b/spec/requests/api/internal_spec.rb
index 8797c3fbbbf..dbe8043c633 100644
--- a/spec/requests/api/internal_spec.rb
+++ b/spec/requests/api/internal_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:user) { create(:user) }
let(:key) { create(:key, user: user) }
let(:project) { create(:project) }
diff --git a/spec/requests/api/issues_spec.rb b/spec/requests/api/issues_spec.rb
index e62bc844352..dff7f20cb32 100644
--- a/spec/requests/api/issues_spec.rb
+++ b/spec/requests/api/issues_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let!(:issue) { create(:issue, author: user, assignee: user, project: project) }
diff --git a/spec/requests/api/merge_requests_spec.rb b/spec/requests/api/merge_requests_spec.rb
index 2fb3684fdf0..3611d9d6dc3 100644
--- a/spec/requests/api/merge_requests_spec.rb
+++ b/spec/requests/api/merge_requests_spec.rb
@@ -2,8 +2,6 @@ require "spec_helper"
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
let(:user) { create(:user) }
let!(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
let!(:merge_request) { create(:merge_request, :simple, author: user, assignee: user, source_project: project, target_project: project, title: "Test") }
diff --git a/spec/requests/api/milestones_spec.rb b/spec/requests/api/milestones_spec.rb
index 0d2740c5acf..f0619a1c801 100644
--- a/spec/requests/api/milestones_spec.rb
+++ b/spec/requests/api/milestones_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) {disable_observers}
-
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let!(:milestone) { create(:milestone, project: project) }
@@ -92,9 +89,6 @@ describe API::API, api: true do
end
describe "PUT /projects/:id/milestones/:milestone_id to test observer on close" do
- before { enable_observers }
- after { disable_observers }
-
it "should create an activity event when an milestone is closed" do
Event.should_receive(:create)
diff --git a/spec/requests/api/namespaces_spec.rb b/spec/requests/api/namespaces_spec.rb
index 2de7d1e23c3..d9d52468b15 100644
--- a/spec/requests/api/namespaces_spec.rb
+++ b/spec/requests/api/namespaces_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:admin) { create(:admin) }
let!(:group1) { create(:group) }
let!(:group2) { create(:group) }
diff --git a/spec/requests/api/notes_spec.rb b/spec/requests/api/notes_spec.rb
index 2875db04ee4..7aa53787aed 100644
--- a/spec/requests/api/notes_spec.rb
+++ b/spec/requests/api/notes_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:user) { create(:user) }
let!(:project) { create(:project, namespace: user.namespace ) }
let!(:issue) { create(:issue, project: project, author: user) }
@@ -128,14 +125,10 @@ describe API::API, api: true do
end
describe "POST /projects/:id/noteable/:noteable_id/notes to test observer on create" do
- before { enable_observers }
- after { disable_observers }
-
it "should create an activity event when an issue note is created" do
Event.should_receive(:create)
post api("/projects/#{project.id}/issues/#{issue.id}/notes", user), body: 'hi!'
end
end
-
end
diff --git a/spec/requests/api/project_hooks_spec.rb b/spec/requests/api/project_hooks_spec.rb
index 6e281f5a43e..cdb5e3d0612 100644
--- a/spec/requests/api/project_hooks_spec.rb
+++ b/spec/requests/api/project_hooks_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, 'ProjectHooks', api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
let(:user) { create(:user) }
let(:user3) { create(:user) }
let!(:project) { create(:project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/requests/api/project_members_spec.rb b/spec/requests/api/project_members_spec.rb
index 032f850010c..3c480c2ac4b 100644
--- a/spec/requests/api/project_members_spec.rb
+++ b/spec/requests/api/project_members_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb
index 415735091c3..41841e855fd 100644
--- a/spec/requests/api/projects_spec.rb
+++ b/spec/requests/api/projects_spec.rb
@@ -2,9 +2,6 @@ require 'spec_helper'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let(:user3) { create(:user) }
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 5afb3bddcb7..94850d0f1ae 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -3,9 +3,6 @@ require 'mime/types'
describe API::API, api: true do
include ApiHelpers
- before(:each) { enable_observers }
- after(:each) {disable_observers}
-
let(:user) { create(:user) }
let(:user2) { create(:user) }
let!(:project) { create(:project, creator_id: user.id) }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 684f8615999..f883c9e028a 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -2,9 +2,6 @@ require "spec_helper"
describe API::API, api: true do
include ApiHelpers
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:user) { create(:user) }
let(:project) {create(:project, creator_id: user.id, namespace: user.namespace) }
diff --git a/spec/services/issues/bulk_update_context_spec.rb b/spec/services/issues/bulk_update_context_spec.rb
index 548109a8450..f4c9148f1a3 100644
--- a/spec/services/issues/bulk_update_context_spec.rb
+++ b/spec/services/issues/bulk_update_context_spec.rb
@@ -1,12 +1,9 @@
require 'spec_helper'
describe Issues::BulkUpdateService do
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
let(:issue) {
create(:issue, project: @project)
- }
+ }
before do
@user = create :user
@@ -23,7 +20,7 @@ describe Issues::BulkUpdateService do
@issues = 5.times.collect do
create(:issue, project: @project)
end
- @params = {
+ @params = {
update: {
status: 'closed',
issues_ids: @issues.map(&:id)
@@ -48,7 +45,7 @@ describe Issues::BulkUpdateService do
@issues = 5.times.collect do
create(:closed_issue, project: @project)
end
- @params = {
+ @params = {
update: {
status: 'reopen',
issues_ids: @issues.map(&:id)
@@ -71,7 +68,7 @@ describe Issues::BulkUpdateService do
before do
@new_assignee = create :user
- @params = {
+ @params = {
update: {
issues_ids: [issue.id],
assignee_id: @new_assignee.id
@@ -93,7 +90,7 @@ describe Issues::BulkUpdateService do
before do
@milestone = create :milestone
- @params = {
+ @params = {
update: {
issues_ids: [issue.id],
milestone_id: @milestone.id
diff --git a/spec/services/notes/create_service_spec.rb b/spec/services/notes/create_service_spec.rb
new file mode 100644
index 00000000000..106c14bc015
--- /dev/null
+++ b/spec/services/notes/create_service_spec.rb
@@ -0,0 +1,27 @@
+require 'spec_helper'
+
+describe Notes::CreateService do
+ let(:project) { create(:empty_project) }
+ let(:issue) { create(:issue, project: project) }
+ let(:user) { create(:user) }
+
+ describe :execute do
+ context "valid params" do
+ before do
+ project.team << [user, :master]
+ opts = {
+ note: 'Awesome comment',
+ description: 'please fix',
+ noteable_type: 'Issue',
+ noteable_id: issue.id
+ }
+
+ @note = Notes::CreateService.new(project, user, opts).execute
+ end
+
+ it { @note.should be_valid }
+ it { @note.note.should == 'Awesome comment' }
+ end
+ end
+end
+
diff --git a/spec/services/notification_service_spec.rb b/spec/services/notification_service_spec.rb
index 57a4240f7a2..f82a14d482c 100644
--- a/spec/services/notification_service_spec.rb
+++ b/spec/services/notification_service_spec.rb
@@ -95,6 +95,49 @@ describe NotificationService do
end
end
+ context 'issue note mention' do
+ let(:issue) { create(:issue, assignee: create(:user)) }
+ let(:mentioned_issue) { create(:issue, assignee: issue.assignee) }
+ let(:note) { create(:note_on_issue, noteable: issue, project_id: issue.project_id, note: '@all mentioned') }
+
+ before do
+ build_team(note.project)
+ end
+
+ describe :new_note do
+ it do
+ # Notify all team members
+ note.project.team.members.each do |member|
+ # User with disabled notification should not be notified
+ next if member.id == @u_disabled.id
+ should_email(member.id)
+ end
+ should_email(note.noteable.author_id)
+ should_email(note.noteable.assignee_id)
+
+ should_not_email(note.author_id)
+ should_not_email(@u_disabled.id)
+ should_not_email(@u_not_mentioned.id)
+ notification.new_note(note)
+ end
+
+ it 'filters out "mentioned in" notes' do
+ mentioned_note = Note.create_cross_reference_note(mentioned_issue, issue, issue.author, issue.project)
+
+ Notify.should_not_receive(:note_issue_email)
+ notification.new_note(mentioned_note)
+ end
+ end
+
+ def should_email(user_id)
+ Notify.should_receive(:note_issue_email).with(user_id, note.id)
+ end
+
+ def should_not_email(user_id)
+ Notify.should_not_receive(:note_issue_email).with(user_id, note.id)
+ end
+ end
+
context 'commit note' do
let(:note) { create(:note_on_commit) }
@@ -312,6 +355,7 @@ describe NotificationService do
@u_disabled = create(:user, notification_level: Notification::N_DISABLED)
@u_mentioned = create(:user, username: 'mention', notification_level: Notification::N_PARTICIPATING)
@u_committer = create(:user, username: 'committer')
+ @u_not_mentioned = create(:user, username: 'regular', notification_level: Notification::N_PARTICIPATING)
project.team << [@u_watcher, :master]
project.team << [@u_participating, :master]
diff --git a/spec/services/projects/create_service_spec.rb b/spec/services/projects/create_service_spec.rb
index 0eac6bed74b..74c23418a28 100644
--- a/spec/services/projects/create_service_spec.rb
+++ b/spec/services/projects/create_service_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe Projects::CreateService do
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
describe :create_by_user do
before do
@user = create :user
@@ -66,11 +63,8 @@ describe Projects::CreateService do
@settings.stub(:merge_requests) { true }
@settings.stub(:wiki) { true }
@settings.stub(:snippets) { true }
- stub_const("Settings", Class.new)
- @restrictions = double("restrictions")
- @restrictions.stub(:restricted_visibility_levels) { [] }
- Settings.stub_chain(:gitlab).and_return(@restrictions)
- Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings)
+ Gitlab.config.gitlab.stub(restricted_visibility_levels: [])
+ Gitlab.config.gitlab.stub(:default_projects_features).and_return(@settings)
end
context 'should be public when setting is public' do
@@ -109,11 +103,9 @@ describe Projects::CreateService do
@settings.stub(:wiki) { true }
@settings.stub(:snippets) { true }
@settings.stub(:visibility_level) { Gitlab::VisibilityLevel::PRIVATE }
- stub_const("Settings", Class.new)
- @restrictions = double("restrictions")
- @restrictions.stub(:restricted_visibility_levels) { [ Gitlab::VisibilityLevel::PUBLIC ] }
- Settings.stub_chain(:gitlab).and_return(@restrictions)
- Settings.stub_chain(:gitlab, :default_projects_features).and_return(@settings)
+ @restrictions = [ Gitlab::VisibilityLevel::PUBLIC ]
+ Gitlab.config.gitlab.stub(restricted_visibility_levels: @restrictions)
+ Gitlab.config.gitlab.stub(:default_projects_features).and_return(@settings)
end
context 'should be private when option is public' do
@@ -158,4 +150,3 @@ describe Projects::CreateService do
Projects::CreateService.new(user, opts).execute
end
end
-
diff --git a/spec/services/projects/image_service_spec.rb b/spec/services/projects/image_service_spec.rb
index 070c21698cf..23c4e227ae3 100644
--- a/spec/services/projects/image_service_spec.rb
+++ b/spec/services/projects/image_service_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe Projects::ImageService do
- before(:each) { enable_observers }
- after(:each) { disable_observers }
-
describe 'Image service' do
before do
@user = create :user
diff --git a/spec/services/projects/transfer_service_spec.rb b/spec/services/projects/transfer_service_spec.rb
index 563a8b0c01c..2508dfc4565 100644
--- a/spec/services/projects/transfer_service_spec.rb
+++ b/spec/services/projects/transfer_service_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe Projects::TransferService do
- before(:each) { enable_observers }
- after(:each) {disable_observers}
-
let(:user) { create(:user) }
let(:group) { create(:group) }
let(:group2) { create(:group) }
diff --git a/spec/services/projects/update_service_spec.rb b/spec/services/projects/update_service_spec.rb
index 1854c0d8233..bb0470e3771 100644
--- a/spec/services/projects/update_service_spec.rb
+++ b/spec/services/projects/update_service_spec.rb
@@ -1,9 +1,6 @@
require 'spec_helper'
describe Projects::UpdateService do
- before(:each) { ActiveRecord::Base.observers.enable(:user_observer) }
- after(:each) { ActiveRecord::Base.observers.disable(:user_observer) }
-
describe :update_by_user do
before do
@user = create :user
diff --git a/spec/services/search_service_spec.rb b/spec/services/search_service_spec.rb
index b467282a5d6..daffe98a8ed 100644
--- a/spec/services/search_service_spec.rb
+++ b/spec/services/search_service_spec.rb
@@ -1,19 +1,18 @@
require 'spec_helper'
describe 'Search::GlobalService' do
- let(:user) { create(:user, namespace: found_namespace) }
- let(:public_user) { create(:user, namespace: public_namespace) }
- let(:internal_user) { create(:user, namespace: internal_namespace) }
+ let(:user) { create(:user) }
+ let(:public_user) { create(:user) }
+ let(:internal_user) { create(:user) }
- let(:found_namespace) { create(:namespace, name: 'searchable namespace', path:'another_thing') }
- let(:unfound_namespace) { create(:namespace, name: 'unfound namespace', path: 'yet_something_else') }
- let(:internal_namespace) { create(:namespace, name: 'searchable internal namespace', path: 'something_internal') }
- let(:public_namespace) { create(:namespace, name: 'searchable public namespace', path: 'something_public') }
+ let!(:found_project) { create(:empty_project, :private, name: 'searchable_project') }
+ let!(:unfound_project) { create(:empty_project, :private, name: 'unfound_project') }
+ let!(:internal_project) { create(:empty_project, :internal, name: 'searchable_internal_project') }
+ let!(:public_project) { create(:empty_project, :public, name: 'searchable_public_project') }
- let!(:found_project) { create(:project, :private, name: 'searchable_project', creator_id: user.id, namespace: found_namespace) }
- let!(:unfound_project) { create(:project, :private, name: 'unfound_project', creator_id: user.id, namespace: unfound_namespace) }
- let!(:internal_project) { create(:project, :internal, name: 'searchable_internal_project', creator_id: internal_user.id, namespace: internal_namespace) }
- let!(:public_project) { create(:project, :public, name: 'searchable_public_project', creator_id: public_user.id, namespace: public_namespace) }
+ before do
+ found_project.team << [user, :master]
+ end
describe '#execute' do
context 'unauthenticated' do
@@ -38,7 +37,7 @@ describe 'Search::GlobalService' do
end
it 'namespace name should be searchable' do
- context = Search::GlobalService.new(user, search: "searchable namespace")
+ context = Search::GlobalService.new(user, search: found_project.namespace.path)
results = context.execute
results[:projects].should match_array [found_project]
end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 65a641bcf12..2181238ae9f 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -43,7 +43,7 @@ RSpec.configure do |config|
# instead of true.
config.before(:suite) do
- TestEnv.init(observers: false, init_repos: true, repos: false)
+ TestEnv.init(init_repos: true, repos: false)
end
config.before(:each) do
TestEnv.setup_stubs
diff --git a/spec/support/login_helpers.rb b/spec/support/login_helpers.rb
index cc0ec2f4e3d..7713e9f17d7 100644
--- a/spec/support/login_helpers.rb
+++ b/spec/support/login_helpers.rb
@@ -3,9 +3,7 @@ module LoginHelpers
#
# role - User role (e.g., :admin, :user)
def login_as(role)
- ActiveRecord::Base.observers.enable(:user_observer) do
- @user = create(role)
- end
+ @user = create(role)
login_with(@user)
end
diff --git a/spec/support/test_env.rb b/spec/support/test_env.rb
index b1bb65a836e..85059dfa9e9 100644
--- a/spec/support/test_env.rb
+++ b/spec/support/test_env.rb
@@ -17,14 +17,6 @@ module TestEnv
def init(opts = {})
RSpec::Mocks::setup(self)
- # Disable observers to improve test speed
- #
- # You can enable it in whole test case where needed by next string:
- #
- # before(:each) { enable_observers }
- #
- disable_observers if opts[:observers] == false
-
# Disable mailer for spinach tests
disable_mailer if opts[:mailer] == false
setup_stubs
@@ -33,14 +25,6 @@ module TestEnv
setup_test_repos(opts) if opts[:repos] == true
end
- def enable_observers
- ActiveRecord::Base.observers.enable(:all)
- end
-
- def disable_observers
- ActiveRecord::Base.observers.disable(:all)
- end
-
def disable_mailer
NotificationService.any_instance.stub(mailer: double.as_null_object)
end
@@ -89,10 +73,6 @@ module TestEnv
Repository.any_instance.stub(
size: 12.45
)
-
- BaseObserver.any_instance.stub(
- current_user: double("current_user", id: 1)
- )
end
def clear_repo_dir(namespace, name)