Commit e160f89a authored by Rémy Coutable's avatar Rémy Coutable

Merge branch 'ce-to-ee-2017-11-30' into 'master'

CE upstream - Thursday

Closes gitlab-ce#40671

See merge request gitlab-org/gitlab-ee!3593
parents fc57c9eb 42df7dcd
...@@ -114,7 +114,7 @@ gem 'google-api-client', '~> 0.13.6' ...@@ -114,7 +114,7 @@ gem 'google-api-client', '~> 0.13.6'
gem 'unf', '~> 0.1.4' gem 'unf', '~> 0.1.4'
# Seed data # Seed data
gem 'seed-fu', '~> 2.3.7' gem 'seed-fu', '2.3.6' # Upgrade to > 2.3.7 once https://github.com/mbleigh/seed-fu/issues/123 is solved
# Search # Search
gem 'elasticsearch-model', '~> 0.1.9' gem 'elasticsearch-model', '~> 0.1.9'
......
...@@ -844,7 +844,7 @@ GEM ...@@ -844,7 +844,7 @@ GEM
rake (>= 0.9, < 13) rake (>= 0.9, < 13)
sass (~> 3.4.20) sass (~> 3.4.20)
securecompare (1.0.0) securecompare (1.0.0)
seed-fu (2.3.7) seed-fu (2.3.6)
activerecord (>= 3.1) activerecord (>= 3.1)
activesupport (>= 3.1) activesupport (>= 3.1)
select2-rails (3.5.9.3) select2-rails (3.5.9.3)
...@@ -1191,7 +1191,7 @@ DEPENDENCIES ...@@ -1191,7 +1191,7 @@ DEPENDENCIES
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.54.0) scss_lint (~> 0.54.0)
seed-fu (~> 2.3.7) seed-fu (= 2.3.6)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5) selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3) sentry-raven (~> 2.5.3)
......
...@@ -44,8 +44,6 @@ import './commits'; ...@@ -44,8 +44,6 @@ import './commits';
import './compare'; import './compare';
import './compare_autocomplete'; import './compare_autocomplete';
import './confirm_danger_modal'; import './confirm_danger_modal';
import './diff';
import './files_comment_button';
import Flash, { removeFlashClickListener } from './flash'; import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown'; import './gl_dropdown';
import './gl_field_error'; import './gl_field_error';
......
...@@ -252,6 +252,10 @@ ...@@ -252,6 +252,10 @@
background: $white-light; background: $white-light;
} }
.login-page-broadcast {
margin-top: 50px;
}
.navless-container { .navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link padding: 65px 15px; // height of footer + bottom padding of email confirmation link
......
...@@ -925,7 +925,8 @@ class MergeRequest < ActiveRecord::Base ...@@ -925,7 +925,8 @@ class MergeRequest < ActiveRecord::Base
def compute_diverged_commits_count def compute_diverged_commits_count
return 0 unless source_branch_sha && target_branch_sha return 0 unless source_branch_sha && target_branch_sha
Gitlab::Git::Commit.between(target_project.repository.raw_repository, source_branch_sha, target_branch_sha).size target_project.repository
.count_commits_between(source_branch_sha, target_branch_sha)
end end
private :compute_diverged_commits_count private :compute_diverged_commits_count
......
...@@ -11,7 +11,9 @@ class ProtectedBranch < ActiveRecord::Base ...@@ -11,7 +11,9 @@ class ProtectedBranch < ActiveRecord::Base
def self.protected?(project, ref_name) def self.protected?(project, ref_name)
return true if project.empty_repo? && default_branch_protected? return true if project.empty_repo? && default_branch_protected?
self.matching(ref_name, protected_refs: project.protected_branches).present? refs = project.protected_branches.select(:name)
self.matching(ref_name, protected_refs: refs).present?
end end
def self.default_branch_protected? def self.default_branch_protected?
......
...@@ -6,6 +6,8 @@ class ProtectedTag < ActiveRecord::Base ...@@ -6,6 +6,8 @@ class ProtectedTag < ActiveRecord::Base
protected_ref_access_levels :create protected_ref_access_levels :create
def self.protected?(project, ref_name) def self.protected?(project, ref_name)
self.matching(ref_name, protected_refs: project.protected_tags).present? refs = project.protected_tags.select(:name)
self.matching(ref_name, protected_refs: refs).present?
end end
end end
.flash-container.flash-container-page .flash-container.flash-container-page
-# We currently only support `alert`, `notice`, `success` -# We currently only support `alert`, `notice`, `success`
- flash.each do |key, value| - flash.each do |key, value|
%div{ class: "flash-#{key}" } -# Don't show a flash message if the message is nil
%div{ class: (container_class) } - if value
%span= value %div{ class: "flash-#{key}" }
%div{ class: (container_class) }
%span= value
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
%body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } } %body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } }
.page-wrap .page-wrap
= render "layouts/header/empty" = render "layouts/header/empty"
= render "layouts/broadcast" .login-page-broadcast
= render "layouts/broadcast"
.container.navless-container .container.navless-container
.content .content
= render "layouts/flash" = render "layouts/flash"
......
- avatar = namespace_icon(namespace, 100)
- can_create_project = current_user.can?(:create_projects, namespace)
- if forked_project = namespace.find_fork_of(@project)
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default.forked
= link_to project_path(forked_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
- else
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: ("disabled" unless can_create_project) }
= link_to project_forks_path(@project, namespace_key: namespace.id),
method: "POST",
class: ("disabled has-tooltip" unless can_create_project),
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
...@@ -14,22 +14,7 @@ ...@@ -14,22 +14,7 @@
%h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default %h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default
Click to fork the project Click to fork the project
- @namespaces.each do |namespace| - @namespaces.each do |namespace|
- avatar = namespace_icon(namespace, 100) = render 'fork_button', namespace: namespace
- can_create_project = current_user.can?(:create_projects, namespace)
- forked_project = namespace.find_fork_of(@project)
- fork_path = forked_project ? project_path(forked_project) : project_forks_path(@project, namespace_key: namespace.id)
.bordered-box.fork-thumbnail.text-center.prepend-left-default.append-right-default.prepend-top-default.append-bottom-default{ class: [("disabled" unless can_create_project), ("forked" if forked_project)] }
= link_to fork_path,
method: "POST",
class: [("js-fork-thumbnail" unless forked_project), ("disabled has-tooltip" unless can_create_project)],
title: (_('You have reached your project limit') unless can_create_project) do
- if /no_((\w*)_)*avatar/.match(avatar)
= project_identicon(namespace, class: "avatar s100 identicon")
- else
.avatar-container.s100
= image_tag(avatar, class: "avatar s100")
%h5.prepend-top-default
= namespace.human_name
- else - else
%strong %strong
No available namespaces to fork the project. No available namespaces to fork the project.
......
---
title: Fix broadcast message not showing up on login page
merge_request: 15578
author:
type: fixed
---
title: added support for ordering and sorting in notes api
merge_request: 15342
author: haseebeqx
type: added
---
title: Fix search results when a filename would contain a special character.
merge_request: 15606
author: haseebeqx
type: fixed
---
title: Correctly link to a forked project from the new fork page.
merge_request: 15653
author:
type: fixed
---
title: Only load branch names for protected branch checks
merge_request:
author:
type: performance
---
title: Improve the performance for counting commits
merge_request: 15628
author:
type: performance
require './spec/support/sidekiq' require './spec/support/sidekiq'
Plan.create!(name: EE::Namespace::FREE_PLAN, Plan.seed(name: EE::Namespace::FREE_PLAN,
title: EE::Namespace::FREE_PLAN.titleize) title: EE::Namespace::FREE_PLAN.titleize)
EE::Namespace::NAMESPACE_PLANS_TO_LICENSE_PLANS.each_key do |plan| EE::Namespace::NAMESPACE_PLANS_TO_LICENSE_PLANS.each_key do |plan|
Plan.create!(name: plan, title: plan.titleize) Plan.seed(name: plan, title: plan.titleize)
end end
...@@ -10,12 +10,15 @@ Gets a list of all notes for a single issue. ...@@ -10,12 +10,15 @@ Gets a list of all notes for a single issue.
``` ```
GET /projects/:id/issues/:issue_iid/notes GET /projects/:id/issues/:issue_iid/notes
GET /projects/:id/issues/:issue_iid/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `issue_iid` (required) - The IID of an issue | `issue_iid` | integer | yes | The IID of an issue
| `sort` | string | no | Return issue notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return issue notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
```json ```json
[ [
...@@ -133,12 +136,15 @@ Gets a list of all notes for a single snippet. Snippet notes are comments users ...@@ -133,12 +136,15 @@ Gets a list of all notes for a single snippet. Snippet notes are comments users
``` ```
GET /projects/:id/snippets/:snippet_id/notes GET /projects/:id/snippets/:snippet_id/notes
GET /projects/:id/snippets/:snippet_id/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `snippet_id` (required) - The ID of a project snippet | `snippet_id` | integer | yes | The ID of a project snippet
| `sort` | string | no | Return snippet notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return snippet notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
### Get single snippet note ### Get single snippet note
...@@ -231,12 +237,15 @@ Gets a list of all notes for a single merge request. ...@@ -231,12 +237,15 @@ Gets a list of all notes for a single merge request.
``` ```
GET /projects/:id/merge_requests/:merge_request_iid/notes GET /projects/:id/merge_requests/:merge_request_iid/notes
GET /projects/:id/merge_requests/:merge_request_iid/notes?sort=asc&order_by=updated_at
``` ```
Parameters: | Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
- `id` (required) - The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) owned by the authenticated user
- `merge_request_iid` (required) - The IID of a project merge request | `merge_request_iid` | integer | yes | The IID of a project merge request
| `sort` | string | no | Return merge request notes sorted in `asc` or `desc` order. Default is `desc`
| `order_by` | string | no | Return merge request notes ordered by `created_at` or `updated_at` fields. Default is `created_at`
### Get single merge request note ### Get single merge request note
......
...@@ -367,6 +367,9 @@ sudo usermod -aG redis git ...@@ -367,6 +367,9 @@ sudo usermod -aG redis git
# Enable packfile bitmaps # Enable packfile bitmaps
sudo -u git -H git config --global repack.writeBitmaps true sudo -u git -H git config --global repack.writeBitmaps true
# Enable push options
sudo -u git -H git config --global receive.advertisePushOptions true
# Configure Redis connection settings # Configure Redis connection settings
sudo -u git -H cp config/resque.yml.example config/resque.yml sudo -u git -H cp config/resque.yml.example config/resque.yml
......
...@@ -35,7 +35,7 @@ In Google's side: ...@@ -35,7 +35,7 @@ In Google's side:
1. You should now be able to see a Client ID and Client secret. Note them down 1. You should now be able to see a Client ID and Client secret. Note them down
or keep this page open as you will need them later. or keep this page open as you will need them later.
1. From the **Dashboard** select **ENABLE APIS AND SERVICES > Google Cloud APIs > Container Engine API > Enable** 1. From the **Dashboard** select **ENABLE APIS AND SERVICES > Compute > Google Container Engine API > Enable**
On your GitLab server: On your GitLab server:
......
...@@ -18,6 +18,10 @@ module API ...@@ -18,6 +18,10 @@ module API
end end
params do params do
requires :noteable_id, type: Integer, desc: 'The ID of the noteable' requires :noteable_id, type: Integer, desc: 'The ID of the noteable'
optional :order_by, type: String, values: %w[created_at updated_at], default: 'created_at',
desc: 'Return notes ordered by `created_at` or `updated_at` fields.'
optional :sort, type: String, values: %w[asc desc], default: 'desc',
desc: 'Return notes sorted in `asc` or `desc` order.'
use :pagination use :pagination
end end
get ":id/#{noteables_str}/:noteable_id/notes" do get ":id/#{noteables_str}/:noteable_id/notes" do
...@@ -29,11 +33,12 @@ module API ...@@ -29,11 +33,12 @@ module API
# at the DB query level (which we cannot in that case), the current # at the DB query level (which we cannot in that case), the current
# page can have less elements than :per_page even if # page can have less elements than :per_page even if
# there's more than one page. # there's more than one page.
raw_notes = noteable.notes.with_metadata.reorder(params[:order_by] => params[:sort])
notes = notes =
# paginate() only works with a relation. This could lead to a # paginate() only works with a relation. This could lead to a
# mismatch between the pagination headers info and the actual notes # mismatch between the pagination headers info and the actual notes
# array returned, but this is really a edge-case. # array returned, but this is really a edge-case.
paginate(noteable.notes.with_metadata) paginate(raw_notes)
.reject { |n| n.cross_reference_not_visible_for?(current_user) } .reject { |n| n.cross_reference_not_visible_for?(current_user) }
present notes, with: Entities::Note present notes, with: Entities::Note
else else
......
...@@ -49,6 +49,7 @@ module Gitlab ...@@ -49,6 +49,7 @@ module Gitlab
# Keep in mind that this method may allocate a lot of memory. It is up # Keep in mind that this method may allocate a lot of memory. It is up
# to the caller to limit the number of blobs and blob_size_limit. # to the caller to limit the number of blobs and blob_size_limit.
# #
# Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/798
def batch(repository, blob_references, blob_size_limit: nil) def batch(repository, blob_references, blob_size_limit: nil)
blob_size_limit ||= MAX_DATA_DISPLAY_SIZE blob_size_limit ||= MAX_DATA_DISPLAY_SIZE
blob_references.map do |sha, path| blob_references.map do |sha, path|
......
...@@ -506,7 +506,7 @@ module Gitlab ...@@ -506,7 +506,7 @@ module Gitlab
# Counts the amount of commits between `from` and `to`. # Counts the amount of commits between `from` and `to`.
def count_commits_between(from, to) def count_commits_between(from, to)
Commit.between(self, from, to).size count_commits(ref: "#{from}..#{to}")
end end
# Returns the SHA of the most recent common ancestor of +from+ and +to+ # Returns the SHA of the most recent common ancestor of +from+ and +to+
......
...@@ -47,8 +47,11 @@ module Gitlab ...@@ -47,8 +47,11 @@ module Gitlab
startline = 0 startline = 0
result.each_line.each_with_index do |line, index| result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/ matches = line.match(/^(?<ref>[^:]*):(?<filename>.*):(?<startline>\d+):/)
ref, filename, startline = line.split(':') if matches
ref = matches[:ref]
filename = matches[:filename]
startline = matches[:startline]
startline = startline.to_i - index startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename)) extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '') basename = filename.sub(/#{extname}$/, '')
......
...@@ -8,7 +8,8 @@ end ...@@ -8,7 +8,8 @@ end
module Gitlab module Gitlab
class Seeder class Seeder
def self.quiet def self.quiet
mute_mailer mute_mailer unless Rails.env.test?
SeedFu.quiet = true SeedFu.quiet = true
yield yield
......
#!/usr/bin/env ruby #!/usr/bin/env ruby
gitaly_dir = 'tmp/tests/gitaly' gitaly_dir = 'tmp/tests/gitaly'
env = { 'HOME' => File.expand_path('tmp/tests') }
args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml] args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml]
# Print the PID of the spawned process # Print the PID of the spawned process
puts spawn(*args, [:out, :err] => 'log/gitaly-test.log') puts spawn(env, *args, [:out, :err] => 'log/gitaly-test.log')
require 'spec_helper'
describe 'Logout/Sign out', :js do
let(:user) { create(:user) }
before do
sign_in(user)
visit root_path
end
it 'sign out redirects to sign in page' do
gitlab_sign_out
expect(current_path).to eq new_user_session_path
end
it 'sign out does not show signed out flash notice' do
gitlab_sign_out
expect(page).not_to have_selector('.flash-notice')
end
end
require 'spec_helper' require 'spec_helper'
describe 'Project fork' do describe 'Project fork' do
include ProjectForksHelper
let(:user) { create(:user) } let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
...@@ -24,8 +26,9 @@ describe 'Project fork' do ...@@ -24,8 +26,9 @@ describe 'Project fork' do
end end
context 'master in group' do context 'master in group' do
let(:group) { create(:group) }
before do before do
group = create(:group)
group.add_master(user) group.add_master(user)
end end
...@@ -53,5 +56,17 @@ describe 'Project fork' do ...@@ -53,5 +56,17 @@ describe 'Project fork' do
expect(page).to have_css('.fork-thumbnail', count: 2) expect(page).to have_css('.fork-thumbnail', count: 2)
expect(page).to have_css('.fork-thumbnail.disabled') expect(page).to have_css('.fork-thumbnail.disabled')
end end
it 'links to the fork if the project was already forked within that namespace' do
forked_project = fork_project(project, user, namespace: group, repository: true)
visit new_project_fork_path(project)
expect(page).to have_css('div.forked', text: group.full_name)
click_link group.full_name
expect(current_path).to eq(project_path(forked_project))
end
end end
end end
...@@ -92,34 +92,6 @@ describe('Multi-file editor library', () => { ...@@ -92,34 +92,6 @@ describe('Multi-file editor library', () => {
expect(instance.dirtyDiffController.reDecorate).toHaveBeenCalledWith(model); expect(instance.dirtyDiffController.reDecorate).toHaveBeenCalledWith(model);
}); });
describe('updateOptions', () => {
it('defaults readOnly to false', () => {
spyOn(instance.instance, 'updateOptions');
instance.attachModel(model);
expect(instance.instance.updateOptions).toHaveBeenCalledWith({
readOnly: false,
});
});
it('puts editor into readOnly mode when file is locked', () => {
spyOn(instance.instance, 'updateOptions');
Object.assign(model.file, {
file_lock: {
name: 'test',
},
});
instance.attachModel(model);
expect(instance.instance.updateOptions).toHaveBeenCalledWith({
readOnly: true,
});
});
});
}); });
describe('clearEditor', () => { describe('clearEditor', () => {
......
...@@ -70,6 +70,15 @@ describe Gitlab::ProjectSearchResults do ...@@ -70,6 +70,15 @@ describe Gitlab::ProjectSearchResults do
subject { described_class.parse_search_result(search_result) } subject { described_class.parse_search_result(search_result) }
it 'can correctly parse filenames including ":"' do
special_char_result = "\nmaster:testdata/project::function1.yaml-1----\nmaster:testdata/project::function1.yaml:2:test: data1\n"
blob = described_class.parse_search_result(special_char_result)
expect(blob.ref).to eq('master')
expect(blob.filename).to eq('testdata/project::function1.yaml')
end
it "returns a valid FoundBlob" do it "returns a valid FoundBlob" do
is_expected.to be_an Gitlab::SearchResults::FoundBlob is_expected.to be_an Gitlab::SearchResults::FoundBlob
expect(subject.id).to be_nil expect(subject.id).to be_nil
......
...@@ -34,6 +34,48 @@ describe API::Notes do ...@@ -34,6 +34,48 @@ describe API::Notes do
describe "GET /projects/:id/noteable/:noteable_id/notes" do describe "GET /projects/:id/noteable/:noteable_id/notes" do
context "when noteable is an Issue" do context "when noteable is an Issue" do
context 'sorting' do
before do
create_list(:note, 3, noteable: issue, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of issue notes" do it "returns an array of issue notes" do
get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user) get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
...@@ -85,6 +127,47 @@ describe API::Notes do ...@@ -85,6 +127,47 @@ describe API::Notes do
end end
context "when noteable is a Snippet" do context "when noteable is a Snippet" do
context 'sorting' do
before do
create_list(:note, 3, noteable: snippet, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of snippet notes" do it "returns an array of snippet notes" do
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user) get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
...@@ -108,6 +191,47 @@ describe API::Notes do ...@@ -108,6 +191,47 @@ describe API::Notes do
end end
context "when noteable is a Merge Request" do context "when noteable is a Merge Request" do
context 'sorting' do
before do
create_list(:note, 3, noteable: merge_request, project: project, author: user)
end
it 'sorts by created_at in descending order by default' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by ascending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?sort=asc", user)
response_dates = json_response.map { |noteable| noteable['created_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
it 'sorts by updated_at in descending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes?order_by=updated_at", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort.reverse)
end
it 'sorts by updated_at in ascending order when requested' do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes??order_by=updated_at&sort=asc", user)
response_dates = json_response.map { |noteable| noteable['updated_at'] }
expect(json_response.length).to eq(4)
expect(response_dates).to eq(response_dates.sort)
end
end
it "returns an array of merge_requests notes" do it "returns an array of merge_requests notes" do
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user) get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
......
...@@ -225,3 +225,6 @@ Shoulda::Matchers.configure do |config| ...@@ -225,3 +225,6 @@ Shoulda::Matchers.configure do |config|
with.library :rails with.library :rails
end end
end end
# Prevent Rugged from picking up local developer gitconfig.
Rugged::Settings['search_path_global'] = Rails.root.join('tmp/tests').to_s
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment