diff options
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | Gemfile | 7 | ||||
-rw-r--r-- | Gemfile.lock | 26 | ||||
-rw-r--r-- | app/assets/stylesheets/pages/dashboard.scss | 2 | ||||
-rw-r--r-- | app/controllers/profiles_controller.rb | 3 | ||||
-rw-r--r-- | app/helpers/gitlab_routing_helper.rb | 1 | ||||
-rw-r--r-- | app/models/note.rb | 25 | ||||
-rw-r--r-- | app/services/notification_service.rb | 2 | ||||
-rw-r--r-- | app/views/projects/_commit_button.html.haml | 3 | ||||
-rw-r--r-- | app/views/projects/issues/_issue.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/merge_requests/_merge_request.html.haml | 2 | ||||
-rw-r--r-- | app/views/projects/new.html.haml | 103 | ||||
-rw-r--r-- | app/views/projects/show.html.haml | 2 | ||||
-rw-r--r-- | config/initializers/timeout.rb | 8 | ||||
-rw-r--r-- | config/unicorn.rb.example | 20 | ||||
-rw-r--r-- | doc/api/merge_requests.md | 2 | ||||
-rw-r--r-- | doc/api/notes.md | 2 | ||||
-rw-r--r-- | lib/gitlab/middleware/timeout.rb | 13 | ||||
-rw-r--r-- | lib/tasks/gitlab/cleanup.rake | 9 | ||||
-rw-r--r-- | public/503.html | 13 | ||||
-rw-r--r-- | spec/lib/gitlab/reference_extractor_spec.rb | 14 | ||||
-rw-r--r-- | spec/models/note_spec.rb | 153 |
22 files changed, 268 insertions, 148 deletions
diff --git a/CHANGELOG b/CHANGELOG index e0676b30ce8..f38a075fff5 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,8 @@ Please view this file on the master branch, on stable branches it's out of date. v 7.10.0 (unreleased) + - Update poltergeist to version 1.6.0 to support PhantomJS 2.0 (Zeger-Jan van de Weg) + - Fix cross references when usernames, milestones, or project names contain underscores (Stan Hu) - enable line wrapping per default and remove the checkbox to toggle it (Hannes Rosenögger) - extend the commit calendar to show the actual commits made on a date (Hannes Rosenögger) - Add a service to support external wikis (Hannes Rosenögger) @@ -9,6 +11,8 @@ v 7.10.0 (unreleased) - Improve diff UI - Fix alignment of navbar toggle button (Cody Mize) - Identical look of selectboxes in UI + - Move "Import existing repository by URL" option to button. + - Improve error message when save profile has error. v 7.9.0 (unreleased) - Add HipChat integration documentation (Stan Hu) @@ -31,7 +31,7 @@ gem 'omniauth-shibboleth' gem 'omniauth-kerberos' gem 'omniauth-gitlab' gem 'omniauth-bitbucket' -gem 'doorkeeper', '2.1.0' +gem 'doorkeeper', '2.1.3' gem "rack-oauth2", "~> 1.0.5" # Browser detection @@ -48,7 +48,7 @@ gem 'gitlab-grack', '~> 2.0.0.rc2', require: 'grack' gem 'gitlab_omniauth-ldap', '1.2.1', require: "omniauth-ldap" # Git Wiki -gem 'gollum-lib', '~> 4.0.0' +gem 'gollum-lib', '~> 4.0.2' # Language detection gem "gitlab-linguist", "~> 3.0.1", require: "linguist" @@ -180,9 +180,6 @@ gem 'mousetrap-rails' # Detect and convert string character encoding gem 'charlock_holmes' -# Shutting down requests that take too long -gem "slowpoke" - gem "sass-rails", '~> 4.0.2' gem "coffee-rails" gem "uglifier" diff --git a/Gemfile.lock b/Gemfile.lock index 71936584d6e..80eebc16e4c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -136,8 +136,8 @@ GEM diff-lcs (1.2.5) diffy (3.0.3) docile (1.1.5) - doorkeeper (2.1.0) - railties (>= 3.1) + doorkeeper (2.1.3) + railties (>= 3.2) dotenv (0.9.0) dropzonejs-rails (0.4.14) rails (> 3.1) @@ -147,7 +147,6 @@ GEM enumerize (0.7.0) activesupport (>= 3.2) equalizer (0.0.8) - errbase (0.0.2) erubis (2.7.0) escape_utils (0.2.4) eventmachine (1.0.4) @@ -224,11 +223,11 @@ GEM omniauth (~> 1.0) pyu-ruby-sasl (~> 0.0.3.1) rubyntlm (~> 0.3) - gollum-grit_adapter (0.1.0) - gitlab-grit (~> 2.7.1) - gollum-lib (4.0.0) + gollum-grit_adapter (0.1.3) + gitlab-grit (~> 2.7, >= 2.7.1) + gollum-lib (4.0.2) github-markup (~> 1.3.1) - gollum-grit_adapter (~> 0.1.0) + gollum-grit_adapter (~> 0.1, >= 0.1.1) nokogiri (~> 1.6.4) rouge (~> 1.7.4) sanitize (~> 2.1.0) @@ -429,7 +428,6 @@ GEM rack rack-test (0.6.3) rack (>= 1.0) - rack-timeout (0.2.0) rails (4.1.9) actionmailer (= 4.1.9) actionpack (= 4.1.9) @@ -482,9 +480,7 @@ GEM rest-client (1.6.7) mime-types (>= 1.16) rinku (1.7.3) - robustly (0.0.3) - errbase - rouge (1.7.4) + rouge (1.7.7) rspec (2.99.0) rspec-core (~> 2.99.0) rspec-expectations (~> 2.99.0) @@ -566,9 +562,6 @@ GEM temple (~> 0.6.6) tilt (>= 1.3.3, < 2.1) slop (3.6.0) - slowpoke (0.0.5) - rack-timeout (>= 0.1.0) - robustly spinach (0.8.7) colorize (= 0.5.8) gherkin-ruby (>= 0.3.1) @@ -690,7 +683,7 @@ DEPENDENCIES devise (= 3.2.4) devise-async (= 0.9.0) diffy (~> 3.0.3) - doorkeeper (= 2.1.0) + doorkeeper (= 2.1.3) dropzonejs-rails email_spec enumerize @@ -708,7 +701,7 @@ DEPENDENCIES gitlab_git (~> 7.1.2) gitlab_meta (= 7.0) gitlab_omniauth-ldap (= 1.2.1) - gollum-lib (~> 4.0.0) + gollum-lib (~> 4.0.2) gon (~> 5.0.0) grape (~> 0.6.1) grape-entity (~> 0.4.2) @@ -776,7 +769,6 @@ DEPENDENCIES six slack-notifier (~> 1.0.0) slim - slowpoke spinach-rails spring (~> 1.3.1) spring-commands-rspec (= 1.0.4) diff --git a/app/assets/stylesheets/pages/dashboard.scss b/app/assets/stylesheets/pages/dashboard.scss index e408211fc7d..af9c83e5dc8 100644 --- a/app/assets/stylesheets/pages/dashboard.scss +++ b/app/assets/stylesheets/pages/dashboard.scss @@ -29,7 +29,7 @@ line-height: 24px; .str-truncated { - max-width: 75%; + max-width: 72%; } a { diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 1b9a86ee42c..3c7f45d559b 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -25,7 +25,8 @@ class ProfilesController < ApplicationController if @user.update_attributes(user_params) flash[:notice] = "Profile was successfully updated" else - flash[:alert] = "Failed to update profile" + messages = @user.errors.full_messages.uniq.join('. ') + flash[:alert] = "Failed to update profile. #{messages}" end respond_to do |format| diff --git a/app/helpers/gitlab_routing_helper.rb b/app/helpers/gitlab_routing_helper.rb index b005cb8e417..3386fac8657 100644 --- a/app/helpers/gitlab_routing_helper.rb +++ b/app/helpers/gitlab_routing_helper.rb @@ -47,6 +47,5 @@ module GitlabRoutingHelper def project_snippet_url(entity, *args) namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args) - end end diff --git a/app/models/note.rb b/app/models/note.rb index 649e9b4e852..27b583a869a 100644 --- a/app/models/note.rb +++ b/app/models/note.rb @@ -59,7 +59,7 @@ class Note < ActiveRecord::Base class << self def create_status_change_note(noteable, project, author, status, source) - body = "_Status changed to #{status}#{' by ' + source.gfm_reference if source}_" + body = "Status changed to #{status}#{' by ' + source.gfm_reference if source}" create( noteable: noteable, @@ -95,9 +95,9 @@ class Note < ActiveRecord::Base def create_milestone_change_note(noteable, project, author, milestone) body = if milestone.nil? - '_Milestone removed_' + 'Milestone removed' else - "_Milestone changed to #{milestone.title}_" + "Milestone changed to #{milestone.title}" end create( @@ -110,7 +110,7 @@ class Note < ActiveRecord::Base end def create_assignee_change_note(noteable, project, author, assignee) - body = assignee.nil? ? '_Assignee removed_' : "_Reassigned to @#{assignee.username}_" + body = assignee.nil? ? 'Assignee removed' : "Reassigned to @#{assignee.username}" create({ noteable: noteable, @@ -140,7 +140,7 @@ class Note < ActiveRecord::Base end message << ' ' << 'label'.pluralize(labels_count) - body = "_#{message.capitalize}_" + body = "#{message.capitalize}" create( noteable: noteable, @@ -170,14 +170,14 @@ class Note < ActiveRecord::Base commits_text = ActionController::Base.helpers.pluralize(existing_commits.length, 'commit') - branch = + branch = if merge_request.for_fork? "#{merge_request.target_project_namespace}:#{merge_request.target_branch}" else merge_request.target_branch end - message = "* #{commit_ids} - _#{commits_text} from branch `#{branch}`_" + message = "* #{commit_ids} - #{commits_text} from branch `#{branch}`" body << message body << "\n" end @@ -240,7 +240,7 @@ class Note < ActiveRecord::Base where(noteable_id: noteable.id) end - notes.where('note like ?', cross_reference_note_content(gfm_reference)). + notes.where('note like ?', cross_reference_note_pattern(gfm_reference)). system.any? end @@ -249,13 +249,18 @@ class Note < ActiveRecord::Base end def cross_reference_note_prefix - '_mentioned in ' + 'mentioned in ' end private def cross_reference_note_content(gfm_reference) - cross_reference_note_prefix + "#{gfm_reference}_" + cross_reference_note_prefix + "#{gfm_reference}" + end + + def cross_reference_note_pattern(gfm_reference) + # Older cross reference notes contained underscores for emphasis + "%" + cross_reference_note_content(gfm_reference) + "%" end # Prepend the mentioner's namespaced project path to the GFM reference for diff --git a/app/services/notification_service.rb b/app/services/notification_service.rb index 848ed77ebf8..cc5853144c5 100644 --- a/app/services/notification_service.rb +++ b/app/services/notification_service.rb @@ -120,7 +120,7 @@ class NotificationService return true unless note.noteable_type.present? # ignore gitlab service messages - return true if note.note.start_with?('_Status changed to closed_') + return true if note.note.start_with?('Status changed to closed') return true if note.cross_reference? && note.system == true opts = { noteable_type: note.noteable_type, project_id: note.project_id } diff --git a/app/views/projects/_commit_button.html.haml b/app/views/projects/_commit_button.html.haml index fd8320adb8d..35f7e7bb34b 100644 --- a/app/views/projects/_commit_button.html.haml +++ b/app/views/projects/_commit_button.html.haml @@ -2,8 +2,5 @@ .commit-button-annotation = button_tag 'Commit Changes', class: 'btn commit-btn js-commit-button btn-create' - .message - to branch - %strong= ref = link_to 'Cancel', cancel_path, class: 'btn btn-cancel', data: {confirm: leave_edit_message} diff --git a/app/views/projects/issues/_issue.html.haml b/app/views/projects/issues/_issue.html.haml index 3b50ce01351..7b06fe72882 100644 --- a/app/views/projects/issues/_issue.html.haml +++ b/app/views/projects/issues/_issue.html.haml @@ -17,7 +17,7 @@ = issue.notes.count .issue-info - %span.light= "##{issue.iid}" + = link_to "##{issue.iid}", issue_path(issue), class: "light" - if issue.assignee assigned to #{link_to_member(@project, issue.assignee)} - if issue.votes_count > 0 diff --git a/app/views/projects/merge_requests/_merge_request.html.haml b/app/views/projects/merge_requests/_merge_request.html.haml index 1eba1a96b7b..ecbff722b42 100644 --- a/app/views/projects/merge_requests/_merge_request.html.haml +++ b/app/views/projects/merge_requests/_merge_request.html.haml @@ -22,7 +22,7 @@ %i.fa.fa-comments = merge_request.mr_and_commit_notes.count .merge-request-info - %span.light= "##{merge_request.iid}" + = link_to "##{merge_request.iid}", merge_request_path(merge_request), class: "light" - if merge_request.assignee assigned to #{link_to_member(merge_request.source_project, merge_request.assignee)} - else diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 7fc612c0c7d..173a3080b31 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -21,64 +21,65 @@ = f.select :namespace_id, namespaces_options(params[:namespace_id] || :current_user), {}, {class: 'select2', tabindex: 2} %hr - .js-toggle-container + + .project-import.js-toggle-container .form-group - .col-sm-2 + %label.control-label Import project from .col-sm-10 - = link_to "#", class: 'js-toggle-button' do - %i.fa.fa-upload - %span Import existing repository by URL - .js-toggle-content.hide - .form-group.import-url-data - = f.label :import_url, class: 'control-label' do - %span Import existing git repo - .col-sm-10 - = f.text_field :import_url, class: 'form-control', placeholder: 'https://github.com/randx/six.git' - .alert.alert-info.prepend-top-10 - This URL must be publicly accessible or you can add a username and password like this: https://username:password@gitlab.com/company/project.git. - %br - The import will time out after 4 minutes. For big repositories, use a clone/push combination. - For SVN repositories, check #{link_to "this migrating from SVN doc.", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"} + - if github_import_enabled? + = link_to status_import_github_path, class: 'btn' do + %i.fa.fa-github + GitHub + - else + = link_to '#', class: 'how_to_import_link light btn' do + %i.fa.fa-github + GitHub + = render 'github_import_modal' - .project-import.form-group - %label.control-label Import projects from - .col-sm-10 - - if github_import_enabled? - = link_to status_import_github_path, class: 'btn' do - %i.fa.fa-github - GitHub - - else - = link_to '#', class: 'how_to_import_link light btn' do - %i.fa.fa-github - GitHub - = render 'github_import_modal' - - - - if bitbucket_import_enabled? - = link_to status_import_bitbucket_path, class: 'btn' do - %i.fa.fa-bitbucket - Bitbucket - - else - = link_to '#', class: 'how_to_import_link light btn' do - %i.fa.fa-bitbucket - Bitbucket - = render 'bitbucket_import_modal' - - - unless request.host == 'gitlab.com' - - if gitlab_import_enabled? - = link_to status_import_gitlab_path, class: 'btn' do - %i.fa.fa-heart - GitLab.com + - if bitbucket_import_enabled? + = link_to status_import_bitbucket_path, class: 'btn' do + %i.fa.fa-bitbucket + Bitbucket - else = link_to '#', class: 'how_to_import_link light btn' do - %i.fa.fa-heart - GitLab.com - = render 'gitlab_import_modal' + %i.fa.fa-bitbucket + Bitbucket + = render 'bitbucket_import_modal' - = link_to new_import_gitorious_path, class: 'btn' do - %i.icon-gitorious.icon-gitorious-small - Gitorious.org + - unless request.host == 'gitlab.com' + - if gitlab_import_enabled? + = link_to status_import_gitlab_path, class: 'btn' do + %i.fa.fa-heart + GitLab.com + - else + = link_to '#', class: 'how_to_import_link light btn' do + %i.fa.fa-heart + GitLab.com + = render 'gitlab_import_modal' + + = link_to new_import_gitorious_path, class: 'btn' do + %i.icon-gitorious.icon-gitorious-small + Gitorious.org + + = link_to "#", class: 'btn js-toggle-button' do + %i.fa.fa-git + %span Any repo by URL + + .js-toggle-content.hide + .form-group.import-url-data + = f.label :import_url, class: 'control-label' do + %span Git repository URL + .col-sm-10 + = f.text_field :import_url, class: 'form-control', placeholder: 'https://username:password@gitlab.company.com/group/project.git' + .alert.alert-info.prepend-top-10 + %ul + %li + The repository must be accessible over HTTP(S). If it is not publicly accessible, you can add authentication information to the URL: <code>https://username:password@gitlab.company.com/group/project.git</code>. + %li + The import will time out after 4 minutes. For big repositories, use a clone/push combination. + %li + To migrate an SVN repository, check out #{link_to "this document", "http://doc.gitlab.com/ce/workflow/migrating_from_svn.html"}. %hr.prepend-botton-10 diff --git a/app/views/projects/show.html.haml b/app/views/projects/show.html.haml index cfa6cda0466..cfa6f558dd6 100644 --- a/app/views/projects/show.html.haml +++ b/app/views/projects/show.html.haml @@ -73,7 +73,7 @@ %span.light Created on #{@project.created_at.stamp('Aug 22, 2013')} %p - %span.light Owned by + %span.light Owned by #{@project.group ? "the" : nil} - if @project.group #{link_to @project.group.name, @project.group} group - else diff --git a/config/initializers/timeout.rb b/config/initializers/timeout.rb deleted file mode 100644 index bc88595cf26..00000000000 --- a/config/initializers/timeout.rb +++ /dev/null @@ -1,8 +0,0 @@ -# Slowpoke extends Rack::Timeout to gracefully kill Unicorn workers so they can clean up state. -Slowpoke.timeout = 60 - -# The `Rack::Timeout` middleware kills requests after 60 seconds (as set above). -# We're replacing it with our `Gitlab::Middleware::Timeout` that does the same, -# except ignoring Git-over-HTTP requests, letting those take as long as they need. - -Rails.application.config.middleware.swap(Rack::Timeout, Gitlab::Middleware::Timeout) diff --git a/config/unicorn.rb.example b/config/unicorn.rb.example index 3aee718097f..86a5512e761 100644 --- a/config/unicorn.rb.example +++ b/config/unicorn.rb.example @@ -35,10 +35,22 @@ working_directory "/home/git/gitlab" # available in 0.94.0+ listen "/home/git/gitlab/tmp/sockets/gitlab.socket", :backlog => 1024 listen "127.0.0.1:8080", :tcp_nopush => true -# Kill workers after 1 hour. -# A shorter timeout of 60 seconds is enforced by rack-timeout for web requests. -# Git-over-HTTP only has the below timeout since large pulls/pushes can take a long time. -timeout 60 * 60 +# nuke workers after 30 seconds instead of 60 seconds (the default) +# +# NOTICE: git push over http depends on this value. +# If you want be able to push huge amount of data to git repository over http +# you will have to increase this value too. +# +# Example of output if you try to push 1GB repo to GitLab over http. +# -> git push http://gitlab.... master +# +# error: RPC failed; result=18, HTTP code = 200 +# fatal: The remote end hung up unexpectedly +# fatal: The remote end hung up unexpectedly +# +# For more information see http://stackoverflow.com/a/21682112/752049 +# +timeout 60 # feel free to point this anywhere accessible on the filesystem pid "/home/git/gitlab/tmp/pids/unicorn.pid" diff --git a/doc/api/merge_requests.md b/doc/api/merge_requests.md index 1f3fd26a241..6a272539e45 100644 --- a/doc/api/merge_requests.md +++ b/doc/api/merge_requests.md @@ -375,7 +375,7 @@ Parameters: } }, { - "note": "_Status changed to closed_", + "note": "Status changed to closed", "author": { "id": 11, "username": "admin", diff --git a/doc/api/notes.md b/doc/api/notes.md index c22e493562a..ee2f9fa0eac 100644 --- a/doc/api/notes.md +++ b/doc/api/notes.md @@ -21,7 +21,7 @@ Parameters: [ { "id": 302, - "body": "_Status changed to closed_", + "body": "Status changed to closed", "attachment": null, "author": { "id": 1, diff --git a/lib/gitlab/middleware/timeout.rb b/lib/gitlab/middleware/timeout.rb deleted file mode 100644 index 015600392b9..00000000000 --- a/lib/gitlab/middleware/timeout.rb +++ /dev/null @@ -1,13 +0,0 @@ -module Gitlab - module Middleware - class Timeout < Rack::Timeout - GRACK_REGEX = /[-\/\w\.]+\.git\//.freeze - - def call(env) - return @app.call(env) if env['PATH_INFO'] =~ GRACK_REGEX - - super - end - end - end -end diff --git a/lib/tasks/gitlab/cleanup.rake b/lib/tasks/gitlab/cleanup.rake index 189ad6090a4..3c9802a0be4 100644 --- a/lib/tasks/gitlab/cleanup.rake +++ b/lib/tasks/gitlab/cleanup.rake @@ -90,13 +90,14 @@ namespace :gitlab do warn_user_is_not_gitlab block_flag = ENV['BLOCK'] - User.ldap.each do |ldap_user| - print "#{ldap_user.name} (#{ldap_user.extern_uid}) ..." - if Gitlab::LDAP::Access.allowed?(ldap_user) + User.find_each do |user| + next unless user.ldap_user? + print "#{user.name} (#{user.ldap_identity.extern_uid}) ..." + if Gitlab::LDAP::Access.allowed?(user) puts " [OK]".green else if block_flag - ldap_user.block! unless ldap_user.blocked? + user.block! unless user.blocked? puts " [BLOCKED]".red else puts " [NOT IN LDAP]".yellow diff --git a/public/503.html b/public/503.html deleted file mode 100644 index efdae0f512d..00000000000 --- a/public/503.html +++ /dev/null @@ -1,13 +0,0 @@ -<!DOCTYPE html> -<html> -<head> - <title>Page took too long to load (503)</title> - <link href="/static.css" media="screen" rel="stylesheet" type="text/css" /> -</head> -<body> - <h1>503</h1> - <h3>Page took too long to load.</h3> - <hr/> - <p>Please contact your GitLab administrator if this problem persists.</p> -</body> -</html> diff --git a/spec/lib/gitlab/reference_extractor_spec.rb b/spec/lib/gitlab/reference_extractor_spec.rb index 034f8ee7c45..5ebe44f6fb7 100644 --- a/spec/lib/gitlab/reference_extractor_spec.rb +++ b/spec/lib/gitlab/reference_extractor_spec.rb @@ -120,4 +120,18 @@ describe Gitlab::ReferenceExtractor do expect(extracted[0][1].message).to eq(commit.message) end end + + context 'with a project with an underscore' do + let(:project) { create(:project, path: 'test_project') } + let(:issue) { create(:issue, project: project) } + + it 'handles project issue references' do + subject.analyze("this refers issue #{project.path_with_namespace}##{issue.iid}", + project) + extracted = subject.issues_for(project) + expect(extracted.size).to eq(1) + expect(extracted).to eq([issue]) + end + + end end diff --git a/spec/models/note_spec.rb b/spec/models/note_spec.rb index 17cb439c90e..a7bf5081d5b 100644 --- a/spec/models/note_spec.rb +++ b/spec/models/note_spec.rb @@ -182,14 +182,14 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to match(/Status changed to #{status}/) } + it { is_expected.to eq("Status changed to #{status}") } end it 'appends a back-reference if a closing mentionable is supplied' do commit = double('commit', gfm_reference: 'commit 123456') n = Note.create_status_change_note(thing, project, author, status, commit) - expect(n.note).to match(/Status changed to #{status} by commit 123456/) + expect(n.note).to eq("Status changed to #{status} by commit 123456") end end @@ -197,7 +197,7 @@ describe Note do let(:project) { create(:project) } let(:thing) { create(:issue, project: project) } let(:author) { create(:user) } - let(:assignee) { create(:user) } + let(:assignee) { create(:user, username: "assigned_user") } subject { Note.create_assignee_change_note(thing, project, author, assignee) } @@ -227,7 +227,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to match(/Reassigned to @#{assignee.username}/) } + it { is_expected.to eq('Reassigned to @assigned_user') } end context 'assignee is removed' do @@ -235,11 +235,95 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to match(/Assignee removed/) } + it { is_expected.to eq('Assignee removed') } end end end + describe '#create_labels_change_note' do + let(:project) { create(:project) } + let(:thing) { create(:issue, project: project) } + let(:author) { create(:user) } + let(:label1) { create(:label) } + let(:label2) { create(:label) } + let(:added_labels) { [label1, label2] } + let(:removed_labels) { [] } + + subject { Note.create_labels_change_note(thing, project, author, added_labels, removed_labels) } + + context 'creates and saves a Note' do + it { is_expected.to be_a Note } + + describe '#id' do + subject { super().id } + it { is_expected.not_to be_nil } + end + end + + describe '#noteable' do + subject { super().noteable } + it { is_expected.to eq(thing) } + end + + describe '#project' do + subject { super().project } + it { is_expected.to eq(thing.project) } + end + + describe '#author' do + subject { super().author } + it { is_expected.to eq(author) } + end + + describe '#note' do + subject { super().note } + it { is_expected.to eq("Added ~#{label1.id} ~#{label2.id} labels") } + end + + context 'label is removed' do + let(:added_labels) { [label1] } + let(:removed_labels) { [label2] } + + describe '#note' do + subject { super().note } + it { is_expected.to eq("Added ~#{label1.id} and removed ~#{label2.id} labels") } + end + end + end + + describe '#create_milestone_change_note' do + let(:project) { create(:project) } + let(:thing) { create(:issue, project: project) } + let(:milestone) { create(:milestone, project: project, title: "first_milestone") } + let(:author) { create(:user) } + + subject { Note.create_milestone_change_note(thing, project, author, milestone) } + + context 'creates and saves a Note' do + it { is_expected.to be_a Note } + + describe '#id' do + subject { super().id } + it { is_expected.not_to be_nil } + end + end + + describe '#project' do + subject { super().project } + it { is_expected.to eq(thing.project) } + end + + describe '#author' do + subject { super().author } + it { is_expected.to eq(author) } + end + + describe '#note' do + subject { super().note } + it { is_expected.to eq("Milestone changed to first_milestone") } + end + end + describe '#create_cross_reference_note' do let(:project) { create(:project) } let(:author) { create(:user) } @@ -272,7 +356,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in merge request !#{mergereq.iid}_") } + it { is_expected.to eq("mentioned in merge request !#{mergereq.iid}") } end end @@ -288,7 +372,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in commit #{commit.sha}_") } + it { is_expected.to eq("mentioned in commit #{commit.sha}") } end end @@ -309,7 +393,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in issue ##{issue.iid}_") } + it { is_expected.to eq("mentioned in issue ##{issue.iid}") } end end @@ -330,7 +414,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in merge request !#{mergereq.iid}_") } + it { is_expected.to eq("mentioned in merge request !#{mergereq.iid}") } end end @@ -362,7 +446,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in issue ##{issue.iid}_") } + it { is_expected.to eq("mentioned in issue ##{issue.iid}") } end end @@ -389,7 +473,7 @@ describe Note do describe '#note' do subject { super().note } - it { is_expected.to eq("_mentioned in commit #{parent_commit.id}_") } + it { is_expected.to eq("mentioned in commit #{parent_commit.id}") } end end end @@ -421,6 +505,41 @@ describe Note do it { expect(Note.cross_reference_exists?(commit0, commit1)).to be_truthy } it { expect(Note.cross_reference_exists?(commit1, commit0)).to be_falsey } end + + context 'legacy note with Markdown emphasis' do + let(:issue2) { create :issue, project: project } + let!(:note) do + create :note, system: true, noteable_id: issue2.id, + noteable_type: "Issue", note: "_mentioned in issue " \ + "#{issue.project.path_with_namespace}##{issue.iid}_" + end + + it 'detects if a mentionable with emphasis has been mentioned' do + expect(Note.cross_reference_exists?(issue2, issue)).to be_truthy + end + end + end + + describe '#cross_references_with_underscores?' do + let(:project) { create :project, path: "first_project" } + let(:second_project) { create :project, path: "second_project" } + + let(:author) { create :user } + let(:issue0) { create :issue, project: project } + let(:issue1) { create :issue, project: second_project } + let!(:note) { Note.create_cross_reference_note(issue0, issue1, author, project) } + + it 'detects if a mentionable has already been mentioned' do + expect(Note.cross_reference_exists?(issue0, issue1)).to be_truthy + end + + it 'detects if a mentionable has not already been mentioned' do + expect(Note.cross_reference_exists?(issue1, issue0)).to be_falsey + end + + it 'detects that text has underscores' do + expect(note.note).to eq("mentioned in issue #{second_project.path_with_namespace}##{issue1.iid}") + end end describe '#system?' do @@ -429,6 +548,8 @@ describe Note do let(:other) { create(:issue, project: project) } let(:author) { create(:user) } let(:assignee) { create(:user) } + let(:label) { create(:label) } + let(:milestone) { create(:milestone) } it 'should recognize user-supplied notes as non-system' do @note = create(:note_on_issue) @@ -449,6 +570,16 @@ describe Note do @note = Note.create_assignee_change_note(issue, project, author, assignee) expect(@note).to be_system end + + it 'should identify label-change notes as system notes' do + @note = Note.create_labels_change_note(issue, project, author, [label], []) + expect(@note).to be_system + end + + it 'should identify milestone-change notes as system notes' do + @note = Note.create_milestone_change_note(issue, project, author, milestone) + expect(@note).to be_system + end end describe :authorization do |