Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-11-17 03:08:08 +00:00
parent cc626f1411
commit 4d528bfd73
22 changed files with 280 additions and 41 deletions

View File

@ -1,8 +1,10 @@
<script>
import { GlAlert } from '@gitlab/ui';
import { breakpoints } from '@gitlab/ui/dist/utils';
import { sortBy, throttle } from 'lodash';
import Draggable from 'vuedraggable';
import { mapState, mapGetters, mapActions } from 'vuex';
import { contentTop } from '~/lib/utils/common_utils';
import { s__ } from '~/locale';
import { formatBoardLists } from 'ee_else_ce/boards/boards_util';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
@ -142,7 +144,11 @@ export default {
el.scrollTo({ left: el.scrollWidth, behavior: 'smooth' });
},
setBoardHeight() {
this.boardHeight = `${window.innerHeight - this.$el.getBoundingClientRect().top}px`;
if (window.innerWidth < breakpoints.md) {
this.boardHeight = `${window.innerHeight - contentTop()}px`;
} else {
this.boardHeight = `${window.innerHeight - this.$el.getBoundingClientRect().top}px`;
}
},
},
};

View File

@ -41,7 +41,13 @@ module Environments
def by_search(environments)
if params[:search].present?
environments.for_name_like(params[:search], limit: nil)
if Feature.enabled?(:enable_environments_search_within_folder, project)
Environment.from_union(
environments.for_name_like(params[:search], limit: nil),
environments.for_name_like_within_folder(params[:search], limit: nil))
else
environments.for_name_like(params[:search], limit: nil)
end
else
environments
end

View File

@ -6,6 +6,7 @@ class Environment < ApplicationRecord
include FastDestroyAll::Helpers
include Presentable
include NullifyIfBlank
include FromUnion
self.reactive_cache_refresh_interval = 1.minute
self.reactive_cache_lifetime = 55.seconds
@ -96,7 +97,16 @@ class Environment < ApplicationRecord
# Search environments which have names like the given query.
# Do not set a large limit unless you've confirmed that it works on gitlab.com scale.
scope :for_name_like, -> (query, limit: 5) do
where('LOWER(environments.name) LIKE LOWER(?) || \'%\'', sanitize_sql_like(query)).limit(limit)
top_level = 'LOWER(environments.name) LIKE LOWER(?) || \'%\''
where(top_level, sanitize_sql_like(query)).limit(limit)
end
scope :for_name_like_within_folder, -> (query, limit: 5) do
within_folder = 'LOWER(ltrim(environments.name, environments.environment_type'\
' || \'/\')) LIKE LOWER(?) || \'%\''
where(within_folder, sanitize_sql_like(query)).limit(limit)
end
scope :for_project, -> (project) { where(project_id: project) }

View File

@ -0,0 +1,8 @@
---
name: enable_environments_search_within_folder
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/102227/diffs
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382108
milestone: '15.6'
type: development
group: group::release
default_enabled: false

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class IndexEnvironmentsForNameSearchWithinFolder < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
INDEX_NAME = 'index_environments_for_name_search_within_folder'
def up
add_concurrent_index :environments,
"project_id, lower(ltrim(name, environment_type || '/')) varchar_pattern_ops, state", name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :environments, INDEX_NAME
end
end

View File

@ -0,0 +1 @@
600e0c6bd79850846c38de38f175889cee731b5619dfbd084e1bd4438d13d387

View File

@ -28967,6 +28967,8 @@ CREATE INDEX index_emails_on_user_id ON emails USING btree (user_id);
CREATE INDEX index_enabled_clusters_on_id ON clusters USING btree (id) WHERE (enabled = true);
CREATE INDEX index_environments_for_name_search_within_folder ON environments USING btree (project_id, lower(ltrim((name)::text, ((environment_type)::text || '/'::text))) varchar_pattern_ops, state);
CREATE INDEX index_environments_on_merge_request_id ON environments USING btree (merge_request_id);
CREATE INDEX index_environments_on_name_varchar_pattern_ops ON environments USING btree (name varchar_pattern_ops);

View File

@ -49,6 +49,9 @@ NOTE:
When configured to run on their own servers, Gitaly servers must be
[upgraded](../../update/package/index.md) before Gitaly clients in your cluster.
NOTE:
[Disk requirements](index.md#disk-requirements) apply to Gitaly nodes.
The process for setting up Gitaly on its own server is:
1. [Install Gitaly](#install-gitaly).

View File

@ -90,6 +90,50 @@ If you are unable to use either method, contact customer support for restoration
Contact customer support for immediate help in restoration or recovery.
## Disk requirements
Gitaly and Gitaly Cluster require fast local storage to perform effectively because they are heavy I/O-based processes. Therefore,
we strongly recommend that all Gitaly nodes use solid-state drives (SSDs).
These SSDs should have a throughput of at least:
- 8,000 input/output operations per second (IOPS) for read operations.
- 2,000 IOPS for write operations.
These IOPS values are initial recommendations, and may be adjusted to greater or lesser values
depending on the scale of your environment's workload. If youre running the environment on a
cloud provider, refer to their documentation about how to configure IOPS correctly.
For repository data, only local storage is supported for Gitaly and Gitaly Cluster for performance and consistency reasons. Alternatives such as
[NFS](#moving-beyond-nfs) or [cloud-based systems](../nfs.md#avoid-using-cloud-based-file-systems) are not supported.
### Moving beyond NFS
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be unavailable starting
November 22, 2022. See our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
for more details.
[Network File System (NFS)](https://en.wikipedia.org/wiki/Network_File_System)
is not well suited to Git workloads which are CPU and IOPS sensitive.
Specifically:
- Git is sensitive to file system latency. Some operations require many
read operations. Operations that are fast on block storage can become an order of
magnitude slower. This significantly impacts GitLab application performance.
- NFS performance optimizations that prevent the performance gap between
block storage and NFS being even wider are vulnerable to race conditions. We have observed
[data inconsistencies](https://gitlab.com/gitlab-org/gitaly/-/issues/2589)
in production environments caused by simultaneous writes to different NFS
clients. Data corruption is not an acceptable risk.
Gitaly Cluster is purpose built to provide reliable, high performance, fault
tolerant Git storage.
Further reading:
- Blog post: [The road to Gitaly v1.0 (aka, why GitLab doesn't require NFS for storing Git data anymore)](https://about.gitlab.com/blog/2018/09/12/the-road-to-gitaly-1-0/)
- Blog post: [How we spent two weeks hunting an NFS bug in the Linux kernel](https://about.gitlab.com/blog/2018/11/14/how-we-spent-two-weeks-hunting-an-nfs-bug/)
## Directly accessing repositories
GitLab doesn't advise directly accessing Gitaly repositories stored on disk with a Git client or any other tool,
@ -405,33 +449,6 @@ The leftover state is eventually cleaned up.
Unlike Gitaly, Gitaly Cluster doesn't move the repositories in the storages but only virtually moves the repository by updating the
relative path of the repository in the metadata store.
### Moving beyond NFS
Engineering support for NFS for Git repositories is deprecated. Technical support is planned to be unavailable starting
November 22, 2022. See our [statement of support](https://about.gitlab.com/support/statement-of-support/#gitaly-and-nfs)
for more details.
[Network File System (NFS)](https://en.wikipedia.org/wiki/Network_File_System)
is not well suited to Git workloads which are CPU and IOPS sensitive.
Specifically:
- Git is sensitive to file system latency. Some operations require many
read operations. Operations that are fast on block storage can become an order of
magnitude slower. This significantly impacts GitLab application performance.
- NFS performance optimizations that prevent the performance gap between
block storage and NFS being even wider are vulnerable to race conditions. We have observed
[data inconsistencies](https://gitlab.com/gitlab-org/gitaly/-/issues/2589)
in production environments caused by simultaneous writes to different NFS
clients. Data corruption is not an acceptable risk.
Gitaly Cluster is purpose built to provide reliable, high performance, fault
tolerant Git storage.
Further reading:
- Blog post: [The road to Gitaly v1.0 (aka, why GitLab doesn't require NFS for storing Git data anymore)](https://about.gitlab.com/blog/2018/09/12/the-road-to-gitaly-1-0/)
- Blog post: [How we spent two weeks hunting an NFS bug in the Linux kernel](https://about.gitlab.com/blog/2018/11/14/how-we-spent-two-weeks-hunting-an-nfs-bug/)
### Components
Gitaly Cluster consists of multiple components:

View File

@ -28,6 +28,9 @@ The minimum recommended configuration for a Gitaly Cluster requires:
- 3 Praefect nodes
- 3 Gitaly nodes (1 primary, 2 secondary)
NOTE:
[Disk requirements](index.md#disk-requirements) apply to Gitaly nodes.
You should configure an odd number of Gitaly nodes so that transactions have a tie-breaker in case one of the
Gitaly nodes fails in a mutating RPC call.

View File

@ -188,6 +188,31 @@ In this example:
- `DEPLOY_ENVIRONMENT` is listed in the **Run pipeline** page, but with no value set.
The user is expected to define the value each time the pipeline is run manually.
##### Configure a list of selectable values for a prefilled variable
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363660) in GitLab 15.5 [with a flag](../../administration/feature_flags.md) named `run_pipeline_graphql`. Disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available,
ask an administrator to [enable the feature flag](../../administration/feature_flags.md) named `run_pipeline_graphql`.
The feature is not ready for production use.
You can define an array of CI/CD variable values the user can select from when running a pipeline manually.
These values are in a dropdown list in the **Run pipeline** page. The first value
in the array is the value selected by default.
For example:
```yaml
variables:
DEPLOY_ENVIRONMENT:
value:
- "production"
- "staging"
- "canary"
description: "The deployment target. Set to 'production' by default."
```
### Run a pipeline by using a URL query string
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/24146) in GitLab 12.5.

View File

@ -4228,7 +4228,8 @@ deploy_review_job:
#### `variables:description`
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30101) in GitLab 13.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30101) in GitLab 13.7.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/363660) in GitLab 15.5, `variables:value` can contain an array of values.
Use the `description` keyword to define a [pipeline-level (global) variable that is prefilled](../pipelines/index.md#prefill-variables-in-manual-pipelines)
when [running a pipeline manually](../pipelines/index.md#run-a-pipeline-manually).
@ -4240,6 +4241,7 @@ If used with `value`, the variable value is also prefilled when running a pipeli
**Possible inputs**:
- A string.
- An array of strings.
**Example of `variables:description`**:
@ -4254,6 +4256,7 @@ variables:
- A global variable defined with `value` but no `description` behaves the same as
[`variables`](#variables).
- `variables:value` can [contain an array of selectable values](../pipelines/index.md#configure-a-list-of-selectable-values-for-a-prefilled-variable).
#### `variables:expand`

View File

@ -16,7 +16,7 @@ variables:
COVFUZZ_VERSION: v3
# This is for users who have an offline environment and will have to replicate gitlab-cov-fuzz release binaries
# to their own servers
COVFUZZ_URL_PREFIX: "https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw"
COVFUZZ_URL_PREFIX: "https://gitlab.com/security-products/gitlab-cov-fuzz/-/raw"
coverage_fuzzing_unlicensed:

View File

@ -16,7 +16,7 @@ variables:
COVFUZZ_VERSION: v3
# This is for users who have an offline environment and will have to replicate gitlab-cov-fuzz release binaries
# to their own servers
COVFUZZ_URL_PREFIX: "https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-cov-fuzz/-/raw"
COVFUZZ_URL_PREFIX: "https://gitlab.com/security-products/gitlab-cov-fuzz/-/raw"
coverage_fuzzing_unlicensed:

View File

@ -161,7 +161,7 @@ module Gitlab
def validate_url!
return if Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
Gitlab::UrlBlocker.validate!(api_prefix, allow_local_network: false)
Gitlab::UrlBlocker.validate!(api_prefix, allow_local_network: false, schemes: %w[http https])
end
def service_account_exists?(resource)

View File

@ -67,7 +67,7 @@ module Gitlab
(delegator_class.instance_methods - allowlist).each do |method_name|
target_classes.each do |target_class|
next unless target_class.instance_methods.include?(method_name)
next unless target_class.method_defined?(method_name)
errors << generate_error(method_name, target_class, delegator_class)
end

View File

@ -67,8 +67,8 @@ module Gitlab
private
def instance_method_defined?(klass, name)
klass.instance_methods(false).include?(name) ||
klass.private_instance_methods(false).include?(name)
klass.method_defined?(name, false) ||
klass.private_method_defined?(name, false)
end
def find_direct_method(klass, name)

View File

@ -91,6 +91,34 @@ RSpec.describe Projects::EnvironmentsController do
expect(json_response['stopped_count']).to eq 1
end
it 'supports search within environment folder name' do
create(:environment, project: project, name: 'review-app', state: :available)
get :index, params: environment_params(format: :json, search: 'review')
expect(environments.map { |env| env['name'] }).to contain_exactly('review-app',
'staging/review-1',
'staging/review-2')
expect(json_response['available_count']).to eq 3
expect(json_response['stopped_count']).to eq 1
end
context 'when enable_environments_search_within_folder FF is disabled' do
before do
stub_feature_flags(enable_environments_search_within_folder: false)
end
it 'ignores name inside folder' do
create(:environment, project: project, name: 'review-app', state: :available)
get :index, params: environment_params(format: :json, search: 'review')
expect(environments.map { |env| env['name'] }).to contain_exactly('review-app')
expect(json_response['available_count']).to eq 1
expect(json_response['stopped_count']).to eq 0
end
end
it 'sets the polling interval header' do
subject

View File

@ -51,15 +51,35 @@ RSpec.describe Environments::EnvironmentsFinder do
end
context 'with search and states' do
let_it_be(:environment_available_b) { create(:environment, :available, name: 'test/foldered-env', project: project) }
it 'searches environments by name and state' do
result = described_class.new(project, user, search: 'test', states: :available).execute
expect(result).to contain_exactly(environment_available)
expect(result).to contain_exactly(environment_available, environment_available_b)
end
it 'searches environments by name inside folder and state' do
result = described_class.new(project, user, search: 'folder', states: :available).execute
expect(result).to contain_exactly(environment_available_b)
end
context 'when enable_environments_search_within_folder FF is disabled' do
before do
stub_feature_flags(enable_environments_search_within_folder: false)
end
it 'ignores name inside folder' do
result = described_class.new(project, user, search: 'folder', states: :available).execute
expect(result).to be_empty
end
end
end
context 'with id' do
it 'searches environments by name and state' do
it 'searches environments by name and id' do
result = described_class.new(project, user, search: 'test', environment_ids: [environment_available.id]).execute
expect(result).to contain_exactly(environment_available)

View File

@ -123,15 +123,32 @@ describe('BoardContent', () => {
expect(wrapper.findComponent(GlAlert).exists()).toBe(false);
});
it('resizes the list on resize', async () => {
it('on small screens, sets board container height to full height', async () => {
window.innerHeight = 1000;
window.innerWidth = 767;
jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ top: 100 });
wrapper.vm.resizeObserver.trigger();
await nextTick();
expect(wrapper.findComponent({ ref: 'list' }).attributes('style')).toBe('height: 900px;');
const style = wrapper.findComponent({ ref: 'list' }).attributes('style');
expect(style).toBe('height: 1000px;');
});
it('on large screens, sets board container height fill area below filters', async () => {
window.innerHeight = 1000;
window.innerWidth = 768;
jest.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ top: 100 });
wrapper.vm.resizeObserver.trigger();
await nextTick();
const style = wrapper.findComponent({ ref: 'list' }).attributes('style');
expect(style).toBe('height: 900px;');
});
});

View File

@ -132,6 +132,14 @@ RSpec.describe Gitlab::Kubernetes::KubeClient do
it_behaves_like 'local address'
end
context 'when a non HTTP/HTTPS URL is provided' do
let(:api_url) { 'ssh://192.168.1.2' }
it 'raises an error' do
expect { client }.to raise_error(Gitlab::UrlBlocker::BlockedUrlError)
end
end
it 'falls back to default options, but allows overriding' do
client = described_class.new(api_url)
defaults = Gitlab::Kubernetes::KubeClient::DEFAULT_KUBECLIENT_OPTIONS

View File

@ -282,6 +282,72 @@ RSpec.describe Environment, :use_clean_rails_memory_store_caching do
end
end
describe '.for_name_like_within_folder' do
subject { project.environments.for_name_like_within_folder(query, limit: limit) }
let!(:environment) { create(:environment, name: 'review/test-app', project: project) }
let!(:environment_a) { create(:environment, name: 'test-app', project: project) }
let(:query) { 'test' }
let(:limit) { 5 }
it 'returns a found name' do
is_expected.to contain_exactly(environment)
end
it 'does not return environment without folder' do
is_expected.not_to include(environment_a)
end
context 'when query is test-app' do
let(:query) { 'test-app' }
it 'returns a found name' do
is_expected.to include(environment)
end
end
context 'when query is test-app-a' do
let(:query) { 'test-app-a' }
it 'returns empty array' do
is_expected.to be_empty
end
end
context 'when query is empty string' do
let(:query) { '' }
let!(:environment_b) { create(:environment, name: 'review/test-app-1', project: project) }
it 'returns only the foldered environments' do
is_expected.to contain_exactly(environment, environment_b)
end
end
context 'when query is nil' do
let(:query) {}
it 'raises an error' do
expect { subject }.to raise_error(NoMethodError)
end
end
context 'when query is partially matched in the middle of environment name' do
let(:query) { 'app' }
it 'returns empty array' do
is_expected.to be_empty
end
end
context 'when query contains a wildcard character' do
let(:query) { 'test%' }
it 'prevents wildcard injection' do
is_expected.to be_empty
end
end
end
describe '.auto_stoppable' do
subject { described_class.auto_stoppable(limit) }