Skip to content
Snippets Groups Projects
Commit 17ab40ca authored by GitLab Bot's avatar GitLab Bot
Browse files

Add latest changes from gitlab-org/gitlab@master

parent 66d42037
No related branches found
No related tags found
No related merge requests found
Showing
with 328 additions and 100 deletions
---
title: Return 503 to the Runner when the object storage is unavailable
merge_request: 25822
author:
type: fixed
---
title: Fixed repository browsing for folders with non-ascii characters
merge_request: 25877
author:
type: fixed
---
title: Remove special chars from previous and next items in pagination
merge_request: 25891
author:
type: other
Loading
@@ -252,7 +252,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
Loading
@@ -252,7 +252,11 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end end
   
namespace :performance_monitoring do namespace :performance_monitoring do
resources :dashboards, only: [:create] resources :dashboards, only: [:create] do
collection do
put '/:file_name', to: 'dashboards#update', constraints: { file_name: /.+\.yml/ }
end
end
end end
   
namespace :error_tracking do namespace :error_tracking do
Loading
Loading
Loading
@@ -85,13 +85,27 @@ the following feature flags are enabled on your GitLab instance:
Loading
@@ -85,13 +85,27 @@ the following feature flags are enabled on your GitLab instance:
- `:ci_use_merge_request_ref` - `:ci_use_merge_request_ref`
- `:merge_ref_auto_sync` - `:merge_ref_auto_sync`
   
To check these feature flag values, please ask administrator to execute the following commands: To check and set these feature flag values, please ask an administrator to:
   
```shell 1. Log into the Rails console of the GitLab instance:
> sudo gitlab-rails console # Login to Rails console of GitLab instance.
> Feature.enabled?(:ci_use_merge_request_ref) # Check if it's enabled or not. ```shell
> Feature.enable(:ci_use_merge_request_ref) # Enable the feature flag. sudo gitlab-rails console
``` ```
1. Check if the flags are enabled or not:
```ruby
Feature.enabled?(:ci_use_merge_request_ref)
Feature.enabled?(:merge_ref_auto_sync)
```
1. If needed, enable the feature flags:
```ruby
Feature.enable(:ci_use_merge_request_ref)
Feature.enable(:merge_ref_auto_sync)
```
   
### Intermittently pipelines fail by `fatal: reference is not a tree:` error ### Intermittently pipelines fail by `fatal: reference is not a tree:` error
   
Loading
Loading
Loading
@@ -283,10 +283,12 @@ module API
Loading
@@ -283,10 +283,12 @@ module API
bad_request!('Missing artifacts file!') unless artifacts bad_request!('Missing artifacts file!') unless artifacts
file_too_large! unless artifacts.size < max_artifacts_size(job) file_too_large! unless artifacts.size < max_artifacts_size(job)
   
if Ci::CreateJobArtifactsService.new.execute(job, artifacts, params, metadata_file: metadata) result = Ci::CreateJobArtifactsService.new(job.project).execute(job, artifacts, params, metadata_file: metadata)
if result[:status] == :success
status :created status :created
else else
render_validation_error!(job) render_api_error!(result[:message], result[:http_status])
end end
end end
   
Loading
Loading
Loading
@@ -3,7 +3,7 @@
Loading
@@ -3,7 +3,7 @@
module Gitlab module Gitlab
module MarkdownCache module MarkdownCache
# Increment this number every time the renderer changes its output # Increment this number every time the renderer changes its output
CACHE_COMMONMARK_VERSION = 19 CACHE_COMMONMARK_VERSION = 20
CACHE_COMMONMARK_VERSION_START = 10 CACHE_COMMONMARK_VERSION_START = 10
   
BaseError = Class.new(StandardError) BaseError = Class.new(StandardError)
Loading
Loading
Loading
@@ -10,9 +10,13 @@ module Gitlab
Loading
@@ -10,9 +10,13 @@ module Gitlab
@expires_in = expires_in @expires_in = expires_in
end end
   
def cache_key(key)
"#{cache_type}:#{key}:set"
end
def clear_cache!(key) def clear_cache!(key)
with do |redis| with do |redis|
keys = read(key).map { |value| "#{cache_type}#{value}" } keys = read(key).map { |value| "#{cache_type}:#{value}" }
keys << cache_key(key) keys << cache_key(key)
   
redis.pipelined do redis.pipelined do
Loading
@@ -24,7 +28,7 @@ module Gitlab
Loading
@@ -24,7 +28,7 @@ module Gitlab
private private
   
def cache_type def cache_type
"#{Gitlab::Redis::Cache::CACHE_NAMESPACE}:" Gitlab::Redis::Cache::CACHE_NAMESPACE
end end
end end
end end
Loading
@@ -69,7 +69,7 @@ module Gitlab
Loading
@@ -69,7 +69,7 @@ module Gitlab
end end
   
def entry_path(entry) def entry_path(entry)
File.join(*[path, entry[:file_name]].compact) File.join(*[path, entry[:file_name]].compact).force_encoding(Encoding::ASCII_8BIT)
end end
   
def build_entry(entry) def build_entry(entry)
Loading
Loading
Loading
@@ -13658,18 +13658,12 @@ msgstr ""
Loading
@@ -13658,18 +13658,12 @@ msgstr ""
msgid "Pagination|Next" msgid "Pagination|Next"
msgstr "" msgstr ""
   
msgid "Pagination|Next ›"
msgstr ""
msgid "Pagination|Prev" msgid "Pagination|Prev"
msgstr "" msgstr ""
   
msgid "Pagination|« First" msgid "Pagination|« First"
msgstr "" msgstr ""
   
msgid "Pagination|‹ Prev"
msgstr ""
msgid "Parameter" msgid "Parameter"
msgstr "" msgstr ""
   
Loading
@@ -18615,6 +18609,9 @@ msgstr ""
Loading
@@ -18615,6 +18609,9 @@ msgstr ""
msgid "Subscription deletion failed." msgid "Subscription deletion failed."
msgstr "" msgstr ""
   
msgid "Subscription successfully applied to \"%{group_name}\""
msgstr ""
msgid "Subscription successfully created." msgid "Subscription successfully created."
msgstr "" msgstr ""
   
Loading
@@ -19633,6 +19630,12 @@ msgstr ""
Loading
@@ -19633,6 +19630,12 @@ msgstr ""
msgid "There was an error trying to validate your query" msgid "There was an error trying to validate your query"
msgstr "" msgstr ""
   
msgid "There was an error updating the dashboard, branch name is invalid."
msgstr ""
msgid "There was an error updating the dashboard, branch named: %{branch} already exists."
msgstr ""
msgid "There was an error when reseting email token." msgid "There was an error when reseting email token."
msgstr "" msgstr ""
   
Loading
@@ -22692,6 +22695,9 @@ msgstr ""
Loading
@@ -22692,6 +22695,9 @@ msgstr ""
msgid "Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}." msgid "Your dashboard has been copied. You can %{web_ide_link_start}edit it here%{web_ide_link_end}."
msgstr "" msgstr ""
   
msgid "Your dashboard has been updated. You can %{web_ide_link_start}edit it here%{web_ide_link_end}."
msgstr ""
msgid "Your deployment services will be broken, you will need to manually fix the services after renaming." msgid "Your deployment services will be broken, you will need to manually fix the services after renaming."
msgstr "" msgstr ""
   
Loading
Loading
Loading
@@ -129,4 +129,130 @@ describe Projects::PerformanceMonitoring::DashboardsController do
Loading
@@ -129,4 +129,130 @@ describe Projects::PerformanceMonitoring::DashboardsController do
end end
end end
end end
describe 'PUT #update' do
context 'authenticated user' do
before do
sign_in(user)
end
let(:file_content) do
{
"dashboard" => "Dashboard Title",
"panel_groups" => [{
"group" => "Group Title",
"panels" => [{
"type" => "area-chart",
"title" => "Chart Title",
"y_label" => "Y-Axis",
"metrics" => [{
"id" => "metric_of_ages",
"unit" => "count",
"label" => "Metric of Ages",
"query_range" => "http_requests_total"
}]
}]
}]
}
end
let(:params) do
{
namespace_id: namespace,
project_id: project,
dashboard: dashboard,
file_name: file_name,
file_content: file_content,
commit_message: commit_message,
branch: branch_name,
format: :json
}
end
context 'project with repository feature' do
context 'with rights to push to the repository' do
before do
project.add_maintainer(user)
end
context 'valid parameters' do
context 'request format json' do
let(:update_dashboard_service_params) { params.except(:namespace_id, :project_id, :format) }
let(:update_dashboard_service_results) do
{
status: :success,
http_status: :created,
dashboard: {
path: ".gitlab/dashboards/custom_dashboard.yml",
display_name: "custom_dashboard.yml",
default: false,
system_dashboard: false
}
}
end
let(:update_dashboard_service) { instance_double(::Metrics::Dashboard::UpdateDashboardService, execute: update_dashboard_service_results) }
it 'returns path to new file' do
allow(controller).to receive(:repository).and_return(repository)
allow(repository).to receive(:find_branch).and_return(branch)
allow(::Metrics::Dashboard::UpdateDashboardService).to receive(:new).with(project, user, update_dashboard_service_params).and_return(update_dashboard_service)
put :update, params: params
expect(response).to have_gitlab_http_status :created
expect(response).to set_flash[:notice].to eq("Your dashboard has been updated. You can <a href=\"/-/ide/project/#{namespace.path}/#{project.name}/edit/#{branch_name}/-/.gitlab/dashboards/#{file_name}\">edit it here</a>.")
expect(json_response).to eq('status' => 'success', 'dashboard' => { 'default' => false, 'display_name' => "custom_dashboard.yml", 'path' => ".gitlab/dashboards/#{file_name}", 'system_dashboard' => false })
end
context 'UpdateDashboardService failure' do
it 'returns json with failure message' do
allow(::Metrics::Dashboard::UpdateDashboardService).to receive(:new).and_return(double(execute: { status: :error, message: 'something went wrong', http_status: :bad_request }))
put :update, params: params
expect(response).to have_gitlab_http_status :bad_request
expect(json_response).to eq('error' => 'something went wrong')
end
end
end
end
context 'missing branch' do
let(:branch_name) { nil }
it 'raises responds with :bad_request status code and error message' do
put :update, params: params
expect(response).to have_gitlab_http_status :bad_request
expect(json_response).to eq('error' => "Request parameter branch is missing.")
end
end
end
context 'without rights to push to repository' do
before do
project.add_guest(user)
end
it 'responds with :forbidden status code' do
put :update, params: params
expect(response).to have_gitlab_http_status :forbidden
end
end
end
context 'project without repository feature' do
let!(:project) { create(:project, name: 'dashboard-project', namespace: namespace) }
it 'responds with :not_found status code' do
put :update, params: params
expect(response).to have_gitlab_http_status :not_found
end
end
end
end
end end
Loading
@@ -24,7 +24,7 @@ describe 'Thread Comments Commit', :js do
Loading
@@ -24,7 +24,7 @@ describe 'Thread Comments Commit', :js do
expect(page).to have_css('.js-note-emoji') expect(page).to have_css('.js-note-emoji')
end end
   
it 'adds award to the correct note' do it 'adds award to the correct note', quarantine: 'https://gitlab.com/gitlab-org/gitlab/issues/207973' do
find("#note_#{commit_discussion_note2.id} .js-note-emoji").click find("#note_#{commit_discussion_note2.id} .js-note-emoji").click
first('.emoji-menu .js-emoji-btn').click first('.emoji-menu .js-emoji-btn').click
   
Loading
Loading
Loading
@@ -37,6 +37,16 @@ describe 'Projects tree', :js do
Loading
@@ -37,6 +37,16 @@ describe 'Projects tree', :js do
expect(page).not_to have_selector('.flash-alert') expect(page).not_to have_selector('.flash-alert')
end end
   
it 'renders tree table with non-ASCII filenames without errors' do
visit project_tree_path(project, File.join(test_sha, 'encoding'))
wait_for_requests
expect(page).to have_selector('.tree-item')
expect(page).to have_content('Files, encoding and much more')
expect(page).to have_content('テスト.txt')
expect(page).not_to have_selector('.flash-alert')
end
context 'gravatar disabled' do context 'gravatar disabled' do
let(:gravatar_enabled) { false } let(:gravatar_enabled) { false }
   
Loading
Loading
import Vue from 'vue'; import { shallowMount } from '@vue/test-utils';
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import GkeZoneDropdown from '~/create_cluster/gke_cluster/components/gke_zone_dropdown.vue'; import GkeZoneDropdown from '~/create_cluster/gke_cluster/components/gke_zone_dropdown.vue';
import DropdownHiddenInput from '~/vue_shared/components/dropdown/dropdown_hidden_input.vue';
import DropdownButton from '~/vue_shared/components/dropdown/dropdown_button.vue';
import { createStore } from '~/create_cluster/gke_cluster/store'; import { createStore } from '~/create_cluster/gke_cluster/store';
import { import {
SET_PROJECT, SET_PROJECT,
Loading
@@ -9,7 +10,7 @@ import {
Loading
@@ -9,7 +10,7 @@ import {
} from '~/create_cluster/gke_cluster/store/mutation_types'; } from '~/create_cluster/gke_cluster/store/mutation_types';
import { selectedZoneMock, selectedProjectMock, gapiZonesResponseMock } from '../mock_data'; import { selectedZoneMock, selectedProjectMock, gapiZonesResponseMock } from '../mock_data';
   
const componentConfig = { const propsData = {
fieldId: 'cluster_provider_gcp_attributes_gcp_zone', fieldId: 'cluster_provider_gcp_attributes_gcp_zone',
fieldName: 'cluster[provider_gcp_attributes][gcp_zone]', fieldName: 'cluster[provider_gcp_attributes][gcp_zone]',
}; };
Loading
@@ -20,75 +21,81 @@ const LABELS = {
Loading
@@ -20,75 +21,81 @@ const LABELS = {
DEFAULT: 'Select zone', DEFAULT: 'Select zone',
}; };
   
const createComponent = (store, props = componentConfig) => {
const Component = Vue.extend(GkeZoneDropdown);
return mountComponentWithStore(Component, {
el: null,
props,
store,
});
};
describe('GkeZoneDropdown', () => { describe('GkeZoneDropdown', () => {
let vm;
let store; let store;
let wrapper;
   
beforeEach(() => { beforeEach(() => {
store = createStore(); store = createStore();
vm = createComponent(store); wrapper = shallowMount(GkeZoneDropdown, { propsData, store });
}); });
   
afterEach(() => { afterEach(() => {
vm.$destroy(); wrapper.destroy();
}); });
   
describe('toggleText', () => { describe('toggleText', () => {
let dropdownButton;
beforeEach(() => {
dropdownButton = wrapper.find(DropdownButton);
});
it('returns disabled state toggle text', () => { it('returns disabled state toggle text', () => {
expect(vm.toggleText).toBe(LABELS.DISABLED); expect(dropdownButton.props('toggleText')).toBe(LABELS.DISABLED);
}); });
   
it('returns loading toggle text', () => { describe('isLoading', () => {
vm.isLoading = true; beforeEach(() => {
wrapper.setData({ isLoading: true });
return wrapper.vm.$nextTick();
});
   
expect(vm.toggleText).toBe(LABELS.LOADING); it('returns loading toggle text', () => {
expect(dropdownButton.props('toggleText')).toBe(LABELS.LOADING);
});
}); });
   
it('returns default toggle text', () => { describe('project is set', () => {
expect(vm.toggleText).toBe(LABELS.DISABLED); beforeEach(() => {
wrapper.vm.$store.commit(SET_PROJECT, selectedProjectMock);
wrapper.vm.$store.commit(SET_PROJECT_BILLING_STATUS, true);
return wrapper.vm.$nextTick();
});
   
vm.$store.commit(SET_PROJECT, selectedProjectMock); it('returns default toggle text', () => {
vm.$store.commit(SET_PROJECT_BILLING_STATUS, true); expect(dropdownButton.props('toggleText')).toBe(LABELS.DEFAULT);
});
expect(vm.toggleText).toBe(LABELS.DEFAULT);
}); });
   
it('returns project name if project selected', () => { describe('project is selected', () => {
vm.setItem(selectedZoneMock); beforeEach(() => {
wrapper.vm.setItem(selectedZoneMock);
return wrapper.vm.$nextTick();
});
   
expect(vm.toggleText).toBe(selectedZoneMock); it('returns project name if project selected', () => {
expect(dropdownButton.props('toggleText')).toBe(selectedZoneMock);
});
}); });
}); });
   
describe('selectItem', () => { describe('selectItem', () => {
it('reflects new value when dropdown item is clicked', done => { beforeEach(() => {
expect(vm.$el.querySelector('input').value).toBe(''); wrapper.vm.$store.commit(SET_ZONES, gapiZonesResponseMock.items);
vm.$store.commit(SET_ZONES, gapiZonesResponseMock.items); return wrapper.vm.$nextTick();
});
return vm
.$nextTick() it('reflects new value when dropdown item is clicked', () => {
.then(() => { const dropdown = wrapper.find(DropdownHiddenInput);
vm.$el.querySelector('.dropdown-content button').click();
expect(dropdown.attributes('value')).toBe('');
return vm
.$nextTick() wrapper.find('.dropdown-content button').trigger('click');
.then(() => {
expect(vm.$el.querySelector('input').value).toBe(selectedZoneMock); return wrapper.vm.$nextTick().then(() => {
done(); expect(dropdown.attributes('value')).toBe(selectedZoneMock);
}) });
.catch(done.fail);
})
.catch(done.fail);
}); });
}); });
}); });
Loading
@@ -41,7 +41,7 @@ describe('Repository breadcrumbs component', () => {
Loading
@@ -41,7 +41,7 @@ describe('Repository breadcrumbs component', () => {
.findAll(RouterLinkStub) .findAll(RouterLinkStub)
.at(3) .at(3)
.props('to'), .props('to'),
).toEqual('/-/tree//app/assets/javascripts%23'); ).toEqual('/-/tree/app/assets/javascripts%23');
}); });
   
it('renders last link as active', () => { it('renders last link as active', () => {
Loading
Loading
Loading
@@ -109,6 +109,26 @@ describe('Repository table row component', () => {
Loading
@@ -109,6 +109,26 @@ describe('Repository table row component', () => {
}); });
}); });
   
it.each`
path
${'test#'}
${'Änderungen'}
`('renders link for $path', ({ path }) => {
factory({
id: '1',
sha: '123',
path,
type: 'tree',
currentPath: '/',
});
return vm.vm.$nextTick().then(() => {
expect(vm.find({ ref: 'link' }).props('to')).toEqual({
path: `/-/tree/master/${encodeURIComponent(path)}`,
});
});
});
it('pushes new route for directory with hash', () => { it('pushes new route for directory with hash', () => {
factory({ factory({
id: '1', id: '1',
Loading
Loading
rules:
# https://gitlab.com/gitlab-org/gitlab/issues/33025
promise/no-nesting: off
export const emptyProjectMock = {
projectId: '',
name: '',
};
export const selectedProjectMock = {
projectId: 'gcp-project-123',
name: 'gcp-project',
};
export const selectedZoneMock = 'us-central1-a';
export const selectedMachineTypeMock = 'n1-standard-2';
export const gapiProjectsResponseMock = {
projects: [
{
projectNumber: '1234',
projectId: 'gcp-project-123',
lifecycleState: 'ACTIVE',
name: 'gcp-project',
createTime: '2017-12-16T01:48:29.129Z',
parent: {
type: 'organization',
id: '12345',
},
},
],
};
export const gapiZonesResponseMock = {
kind: 'compute#zoneList',
id: 'projects/gitlab-internal-153318/zones',
items: [
{
kind: 'compute#zone',
id: '2000',
creationTimestamp: '1969-12-31T16:00:00.000-08:00',
name: 'us-central1-a',
description: 'us-central1-a',
status: 'UP',
region:
'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/regions/us-central1',
selfLink:
'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a',
availableCpuPlatforms: ['Intel Skylake', 'Intel Broadwell', 'Intel Sandy Bridge'],
},
],
selfLink: 'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones',
};
export const gapiMachineTypesResponseMock = {
kind: 'compute#machineTypeList',
id: 'projects/gitlab-internal-153318/zones/us-central1-a/machineTypes',
items: [
{
kind: 'compute#machineType',
id: '3002',
creationTimestamp: '1969-12-31T16:00:00.000-08:00',
name: 'n1-standard-2',
description: '2 vCPUs, 7.5 GB RAM',
guestCpus: 2,
memoryMb: 7680,
imageSpaceGb: 10,
maximumPersistentDisks: 64,
maximumPersistentDisksSizeGb: '65536',
zone: 'us-central1-a',
selfLink:
'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a/machineTypes/n1-standard-2',
isSharedCpu: false,
},
],
selfLink:
'https://www.googleapis.com/compute/v1/projects/gitlab-internal-153318/zones/us-central1-a/machineTypes',
};
Loading
@@ -41,7 +41,9 @@ describe('diffs/components/commit_item', () => {
Loading
@@ -41,7 +41,9 @@ describe('diffs/components/commit_item', () => {
expect(titleElement).toHaveText(commit.title_html); expect(titleElement).toHaveText(commit.title_html);
}); });
   
it('renders commit description', () => { // https://gitlab.com/gitlab-org/gitlab/issues/197139
// eslint-disable-next-line jasmine/no-disabled-tests
xit('renders commit description', () => {
const descElement = getDescElement(vm); const descElement = getDescElement(vm);
const descExpandElement = getDescExpandElement(vm); const descExpandElement = getDescExpandElement(vm);
   
Loading
Loading
Loading
@@ -14,6 +14,8 @@ export const issuable1 = {
Loading
@@ -14,6 +14,8 @@ export const issuable1 = {
path: '/foo/bar/issues/123', path: '/foo/bar/issues/123',
state: 'opened', state: 'opened',
linkType: 'relates_to', linkType: 'relates_to',
dueDate: '2010-11-22',
weight: 5,
}; };
   
export const issuable2 = { export const issuable2 = {
Loading
Loading
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment