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'
gem 'unf', '~> 0.1.4'
# 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
gem 'elasticsearch-model', '~> 0.1.9'
......
......@@ -844,7 +844,7 @@ GEM
rake (>= 0.9, < 13)
sass (~> 3.4.20)
securecompare (1.0.0)
seed-fu (2.3.7)
seed-fu (2.3.6)
activerecord (>= 3.1)
activesupport (>= 3.1)
select2-rails (3.5.9.3)
......@@ -1191,7 +1191,7 @@ DEPENDENCIES
sanitize (~> 2.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.54.0)
seed-fu (~> 2.3.7)
seed-fu (= 2.3.6)
select2-rails (~> 3.5.9)
selenium-webdriver (~> 3.5)
sentry-raven (~> 2.5.3)
......
......@@ -44,8 +44,6 @@ import './commits';
import './compare';
import './compare_autocomplete';
import './confirm_danger_modal';
import './diff';
import './files_comment_button';
import Flash, { removeFlashClickListener } from './flash';
import './gl_dropdown';
import './gl_field_error';
......
......@@ -252,6 +252,10 @@
background: $white-light;
}
.login-page-broadcast {
margin-top: 50px;
}
.navless-container {
padding: 65px 15px; // height of footer + bottom padding of email confirmation link
......
......@@ -925,7 +925,8 @@ class MergeRequest < ActiveRecord::Base
def compute_diverged_commits_count
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
private :compute_diverged_commits_count
......
......@@ -11,7 +11,9 @@ class ProtectedBranch < ActiveRecord::Base
def self.protected?(project, ref_name)
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
def self.default_branch_protected?
......
......@@ -6,6 +6,8 @@ class ProtectedTag < ActiveRecord::Base
protected_ref_access_levels :create
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
.flash-container.flash-container-page
-# We currently only support `alert`, `notice`, `success`
- flash.each do |key, value|
%div{ class: "flash-#{key}" }
%div{ class: (container_class) }
%span= value
-# Don't show a flash message if the message is nil
- if value
%div{ class: "flash-#{key}" }
%div{ class: (container_class) }
%span= value
......@@ -4,7 +4,8 @@
%body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } }
.page-wrap
= render "layouts/header/empty"
= render "layouts/broadcast"
.login-page-broadcast
= render "layouts/broadcast"
.container.navless-container
.content
= 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 @@
%h5.prepend-top-0.append-bottom-0.prepend-left-default.append-right-default
Click to fork the project
- @namespaces.each do |namespace|
- avatar = namespace_icon(namespace, 100)
- 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
= render 'fork_button', namespace: namespace
- else
%strong
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'
Plan.create!(name: EE::Namespace::FREE_PLAN,
Plan.seed(name: EE::Namespace::FREE_PLAN,
title: EE::Namespace::FREE_PLAN.titleize)
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
......@@ -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?sort=asc&order_by=updated_at
```
Parameters:
- `id` (required) - 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
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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` | 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
[
......@@ -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?sort=asc&order_by=updated_at
```
Parameters:
- `id` (required) - 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
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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` | 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
......@@ -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?sort=asc&order_by=updated_at
```
Parameters:
- `id` (required) - 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
| Attribute | Type | Required | Description |
| ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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` | 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
......
......@@ -367,6 +367,9 @@ sudo usermod -aG redis git
# Enable packfile bitmaps
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
sudo -u git -H cp config/resque.yml.example config/resque.yml
......
......@@ -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
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:
......
......@@ -18,6 +18,10 @@ module API
end
params do
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
end
get ":id/#{noteables_str}/:noteable_id/notes" do
......@@ -29,11 +33,12 @@ module API
# at the DB query level (which we cannot in that case), the current
# page can have less elements than :per_page even if
# there's more than one page.
raw_notes = noteable.notes.with_metadata.reorder(params[:order_by] => params[:sort])
notes =
# paginate() only works with a relation. This could lead to a
# mismatch between the pagination headers info and the actual notes
# 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) }
present notes, with: Entities::Note
else
......
......@@ -49,6 +49,7 @@ module Gitlab
# 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.
#
# Gitaly migration issue: https://gitlab.com/gitlab-org/gitaly/issues/798
def batch(repository, blob_references, blob_size_limit: nil)
blob_size_limit ||= MAX_DATA_DISPLAY_SIZE
blob_references.map do |sha, path|
......
......@@ -506,7 +506,7 @@ module Gitlab
# Counts the amount of commits between `from` and `to`.
def count_commits_between(from, to)
Commit.between(self, from, to).size
count_commits(ref: "#{from}..#{to}")
end
# Returns the SHA of the most recent common ancestor of +from+ and +to+
......
......@@ -47,8 +47,11 @@ module Gitlab
startline = 0
result.each_line.each_with_index do |line, index|
if line =~ /^.*:.*:\d+:/
ref, filename, startline = line.split(':')
matches = line.match(/^(?<ref>[^:]*):(?<filename>.*):(?<startline>\d+):/)
if matches
ref = matches[:ref]
filename = matches[:filename]
startline = matches[:startline]
startline = startline.to_i - index
extname = Regexp.escape(File.extname(filename))
basename = filename.sub(/#{extname}$/, '')
......
......@@ -8,7 +8,8 @@ end
module Gitlab
class Seeder
def self.quiet
mute_mailer
mute_mailer unless Rails.env.test?
SeedFu.quiet = true
yield
......
#!/usr/bin/env ruby
gitaly_dir = 'tmp/tests/gitaly'
env = { 'HOME' => File.expand_path('tmp/tests') }
args = %W[#{gitaly_dir}/gitaly #{gitaly_dir}/config.toml]
# 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'
describe 'Project fork' do
include ProjectForksHelper
let(:user) { create(:user) }
let(:project) { create(:project, :public, :repository) }
......@@ -24,8 +26,9 @@ describe 'Project fork' do
end
context 'master in group' do
let(:group) { create(:group) }
before do
group = create(:group)
group.add_master(user)
end
......@@ -53,5 +56,17 @@ describe 'Project fork' do
expect(page).to have_css('.fork-thumbnail', count: 2)
expect(page).to have_css('.fork-thumbnail.disabled')
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
......@@ -92,34 +92,6 @@ describe('Multi-file editor library', () => {
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', () => {
......
......@@ -70,6 +70,15 @@ describe Gitlab::ProjectSearchResults do
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
is_expected.to be_an Gitlab::SearchResults::FoundBlob
expect(subject.id).to be_nil
......
......@@ -34,6 +34,48 @@ describe API::Notes do
describe "GET /projects/:id/noteable/:noteable_id/notes" 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
get api("/projects/#{project.id}/issues/#{issue.iid}/notes", user)
......@@ -85,6 +127,47 @@ describe API::Notes do
end
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
get api("/projects/#{project.id}/snippets/#{snippet.id}/notes", user)
......@@ -108,6 +191,47 @@ describe API::Notes do
end
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
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/notes", user)
......
......@@ -225,3 +225,6 @@ Shoulda::Matchers.configure do |config|
with.library :rails
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