Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-05-02 18:10:57 +00:00
parent f62efc3864
commit 63fbe648bb
30 changed files with 400 additions and 100 deletions

View File

@ -122,6 +122,9 @@ export default {
showDeleteDropdown() {
return this.group.dependencyProxyManifests?.nodes.length > 0;
},
showDependencyProxyImagePrefix() {
return this.group.dependencyProxyImagePrefix?.length > 0;
},
},
methods: {
fetchNextPage() {
@ -186,6 +189,31 @@ export default {
</gl-dropdown>
</template>
</title-area>
<gl-form-group v-if="showDependencyProxyImagePrefix" :label="$options.i18n.proxyImagePrefix">
<gl-form-input-group
readonly
:value="group.dependencyProxyImagePrefix"
class="gl-layout-w-limited"
data-testid="proxy-url"
>
<template #append>
<clipboard-button
:text="group.dependencyProxyImagePrefix"
:title="$options.i18n.copyImagePrefixText"
/>
</template>
</gl-form-input-group>
<template #description>
<span data-qa-selector="dependency_proxy_count" data-testid="proxy-count">
<gl-sprintf :message="$options.i18n.blobCountAndSize">
<template #count>{{ group.dependencyProxyBlobCount }}</template>
<template #size>{{ group.dependencyProxyTotalSize }}</template>
</gl-sprintf>
</span>
</template>
</gl-form-group>
<gl-alert
v-if="!dependencyProxyAvailable"
:dismissible="false"
@ -197,30 +225,6 @@ export default {
<gl-skeleton-loader v-else-if="$apollo.queries.group.loading" />
<div v-else data-testid="main-area">
<gl-form-group :label="$options.i18n.proxyImagePrefix">
<gl-form-input-group
readonly
:value="group.dependencyProxyImagePrefix"
class="gl-layout-w-limited"
data-testid="proxy-url"
>
<template #append>
<clipboard-button
:text="group.dependencyProxyImagePrefix"
:title="$options.i18n.copyImagePrefixText"
/>
</template>
</gl-form-input-group>
<template #description>
<span data-qa-selector="dependency_proxy_count" data-testid="proxy-count">
<gl-sprintf :message="$options.i18n.blobCountAndSize">
<template #count>{{ group.dependencyProxyBlobCount }}</template>
<template #size>{{ group.dependencyProxyTotalSize }}</template>
</gl-sprintf>
</span>
</template>
</gl-form-group>
<manifests-list
v-if="manifests && manifests.length"
:manifests="manifests"

View File

@ -346,6 +346,14 @@
}
}
&:last-child {
> a {
font-weight: 600;
line-height: 16px;
color: $gl-text-color;
}
}
> a {
font-size: 12px;
color: currentColor;
@ -383,17 +391,6 @@
margin-left: auto;
}
.breadcrumbs-sub-title {
margin: 0;
font-size: 12px;
font-weight: 600;
line-height: 16px;
a {
color: $gl-text-color;
}
}
.btn-sign-in {
background-color: $indigo-100;
color: $indigo-900;

View File

@ -17,9 +17,24 @@ module Types
def current_user_todos(state: nil)
state ||= %i[done pending] # TodosFinder treats a `nil` state param as `pending`
klass = unpresented.class
key = [state, unpresented.class.name]
TodosFinder.new(current_user, state: state, type: klass.name, target_id: object.id).execute
BatchLoader::GraphQL.for(unpresented).batch(default_value: [], key: key) do |targets, loader, args|
state, klass_name = args[:key]
targets_by_id = targets.index_by(&:id)
ids = targets_by_id.keys
results = TodosFinder.new(current_user, state: state, type: klass_name, target_id: ids).execute
by_target_id = results.group_by(&:target_id)
by_target_id.each do |target_id, todos|
target = targets_by_id[target_id]
todos.each { _1.target = target } # prevent extra loads
loader.call(target, todos)
end
end
end
end
end

View File

@ -18,9 +18,8 @@
= breadcrumb_list_item link_to(extra[:text], extra[:link])
= render "layouts/nav/breadcrumbs/collapsed_inline_list", location: :after
- unless @skip_current_level_breadcrumb
%li
%h2.breadcrumbs-sub-title{ data: { qa_selector: 'breadcrumb_sub_title_content' } }
= link_to @breadcrumb_title, breadcrumb_title_link
%li{ data: { testid: 'breadcrumb-current-link', qa_selector: 'breadcrumb_current_link' } }
= link_to @breadcrumb_title, breadcrumb_title_link
-# haml-lint:disable InlineJavaScript
%script{ type: 'application/ld+json' }
:plain

View File

@ -1123,25 +1123,36 @@ postgresql['trust_auth_cidr_addresses'] = %w(123.123.123.123/32 <other_cidrs>)
### Reinitialize a replica
If replication is not occurring, it may be necessary to reinitialize a replica.
If a replica cannot start or rejoin the cluster, or when it lags behind and can not catch up, it might be necessary to reinitialize the replica:
1. On any server in the cluster, determine the Cluster and Member names,
and check the replication lag by running `gitlab-ctl patroni members`. Here is an example:
1. [Check the replication status](#check-replication-status) to confirm which server
needs to be reinitialized. For example:
```plaintext
+ Cluster: postgresql-ha (6970678148837286213) ------+---------+---------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+-------------------------------------+--------------+---------+---------+----+-----------+
| gitlab-database-1.example.com | 172.18.0.111 | Replica | running | 5 | 0 |
| gitlab-database-2.example.com | 172.18.0.112 | Replica | running | 5 | 100 |
| gitlab-database-3.example.com | 172.18.0.113 | Leader | running | 5 | |
+-------------------------------------+--------------+---------+---------+----+-----------+
+ Cluster: postgresql-ha (6970678148837286213) ------+---------+--------------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+-------------------------------------+--------------+---------+--------------+----+-----------+
| gitlab-database-1.example.com | 172.18.0.111 | Replica | running | 55 | 0 |
| gitlab-database-2.example.com | 172.18.0.112 | Replica | start failed | | unknown |
| gitlab-database-3.example.com | 172.18.0.113 | Leader | running | 55 | |
+-------------------------------------+--------------+---------+--------------+----+-----------+
```
1. Reinitialize the affected replica server:
1. Sign in to the broken server and reinitialize the database and replication. Patroni will shut
down PostgreSQL on that server, remove the data directory, and reinitialize it from scratch:
```plaintext
gitlab-ctl patroni reinitialize-replica postgresql-ha gitlab-database-2.example.com
```shell
sudo gitlab-ctl patroni reinitialize-replica --member gitlab-database-2.example.com
```
This can be run on any Patroni node, but be aware that `sudo gitlab-ctl patroni
reinitialize-replica` without `--member` will reinitialize the server it is run on.
It is recommended to run it locally on the broken server to reduce the risk of
unintended data loss.
1. Monitor the logs:
```shell
sudo gitlab-ctl tail patroni
```
### Reset the Patroni state in Consul

View File

@ -192,12 +192,8 @@ To configure the metrics server:
## Configure health checks
If you use health check probes to observe Sidekiq,
you can set a separate port for health checks.
Configuring health checks is only necessary if there is something that actually probes them.
For more information about health checks, see the [Sidekiq health check page](sidekiq_health_check.md).
To enable health checks for Sidekiq:
If you use health check probes to observe Sidekiq, enable the Sidekiq health check server.
To make health checks available from `localhost:8092`:
1. Edit `/etc/gitlab/gitlab.rb`:
@ -207,16 +203,14 @@ To enable health checks for Sidekiq:
sidekiq['health_checks_listen_port'] = "8092"
```
NOTE:
If health check settings are not set, they default to the metrics exporter settings.
This default is deprecated and is set to be removed in [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/347509).
1. Reconfigure GitLab:
```shell
sudo gitlab-ctl reconfigure
```
For more information about health checks, see the [Sidekiq health check page](sidekiq_health_check.md).
## Configure LDAP and user or group synchronization
If you use LDAP for user and group management, you must add the LDAP configuration to your Sidekiq node as well as the LDAP

View File

@ -21,8 +21,7 @@ The readiness probe checks whether the Sidekiq workers are ready to process jobs
GET /readiness
```
If you set Sidekiq's address as `localhost` and port as `8092`,
here's an example request:
If the server is bound to `localhost:8092`, the process cluster can be probed for readiness as follows:
```shell
curl "http://localhost:8092/readiness"
@ -44,8 +43,7 @@ Checks whether the Sidekiq cluster is running.
GET /liveness
```
If you set Sidekiq's address as `localhost` and port as `8092`,
here's an example request:
If the server is bound to `localhost:8092`, the process cluster can be probed for liveness as follows:
```shell
curl "http://localhost:8092/liveness"

View File

@ -601,6 +601,7 @@ Input type: `AdminSidekiqQueuesDeleteJobsInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationadminsidekiqqueuesdeletejobsartifactsize"></a>`artifactSize` | [`String`](#string) | Delete jobs matching artifact_size in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobscallerid"></a>`callerId` | [`String`](#string) | Delete jobs matching caller_id in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobsclientid"></a>`clientId` | [`String`](#string) | Delete jobs matching client_id in the context metadata. |
| <a id="mutationadminsidekiqqueuesdeletejobsclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |

View File

@ -135,7 +135,7 @@ happened. See [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/342123)
GitLab doesn't skip jobs scheduled in the future, as we assume that
the state has changed by the time the job is scheduled to
execute. Deduplication of jobs scheduled in the feature is possible
execute. Deduplication of jobs scheduled in the future is possible
for both `until_executed` and `until_executing` strategies.
If you do want to deduplicate jobs scheduled in the future,

View File

@ -111,6 +111,10 @@ module API
# noop: overridden in EE
end
def log_artifact_size(artifact)
Gitlab::ApplicationContext.push(artifact: artifact)
end
private
def get_runner_config_from_request

View File

@ -305,6 +305,7 @@ module API
result = ::Ci::JobArtifacts::CreateService.new(job).execute(artifacts, params, metadata_file: metadata)
if result[:status] == :success
log_artifact_size(artifacts)
status :created
body "201"
else

View File

@ -565,6 +565,8 @@ module API
def present_carrierwave_file!(file, supports_direct_download: true)
return not_found! unless file&.exists?
log_artifact_size(file) if file.is_a?(JobArtifactUploader)
if file.file_storage?
present_disk_file!(file.path, file.filename)
elsif supports_direct_download && file.class.direct_download_enabled?
@ -718,6 +720,7 @@ module API
# Deprecated. Use `send_artifacts_entry` instead.
def legacy_send_artifacts_entry(file, entry)
header(*Gitlab::Workhorse.send_artifacts_entry(file, entry))
log_artifact_size(file)
body ''
end
@ -725,10 +728,15 @@ module API
def send_artifacts_entry(file, entry)
header(*Gitlab::Workhorse.send_artifacts_entry(file, entry))
header(*Gitlab::Workhorse.detect_content_type)
log_artifact_size(file)
body ''
end
def log_artifact_size(file)
Gitlab::ApplicationContext.push(artifact: file.model)
end
# The Grape Error Middleware only has access to `env` but not `params` nor
# `request`. We workaround this by defining methods that returns the right
# values.

View File

@ -19,7 +19,8 @@ module Gitlab
:job_id,
:pipeline_id,
:related_class,
:feature_category
:feature_category,
:artifact_size
].freeze
private_constant :KNOWN_KEYS
@ -32,7 +33,8 @@ module Gitlab
Attribute.new(:remote_ip, String),
Attribute.new(:job, ::Ci::Build),
Attribute.new(:related_class, String),
Attribute.new(:feature_category, String)
Attribute.new(:feature_category, String),
Attribute.new(:artifact, ::Ci::JobArtifact)
].freeze
def self.known_keys
@ -74,6 +76,8 @@ module Gitlab
assign_attributes(args)
end
# rubocop: disable Metrics/CyclomaticComplexity
# rubocop: disable Metrics/PerceivedComplexity
def to_lazy_hash
{}.tap do |hash|
hash[:user] = -> { username } if include_user?
@ -86,8 +90,11 @@ module Gitlab
hash[:feature_category] = feature_category if set_values.include?(:feature_category)
hash[:pipeline_id] = -> { job&.pipeline_id } if set_values.include?(:job)
hash[:job_id] = -> { job&.id } if set_values.include?(:job)
hash[:artifact_size] = -> { artifact&.size } if set_values.include?(:artifact)
end
end
# rubocop: enable Metrics/CyclomaticComplexity
# rubocop: enable Metrics/PerceivedComplexity
def use
Labkit::Context.with_context(to_lazy_hash) { yield }

View File

@ -240,6 +240,9 @@ module Gitlab
end
end
# TODO: some queries live under app/graphql/queries - we should look there if/when we add fragments there
# See: https://gitlab.com/gitlab-org/gitlab/-/issues/361079
# for fragments too.
class Fragments
def initialize(root, dir = 'app/assets/javascripts')
@root = root
@ -278,7 +281,7 @@ module Gitlab
def self.all
['.', 'ee'].flat_map do |prefix|
find(Rails.root / prefix / 'app/assets/javascripts')
find(Rails.root / prefix / 'app/assets/javascripts') + find(Rails.root / prefix / 'app/graphql/queries')
end
end

View File

@ -109,7 +109,7 @@
"codesandbox-api": "0.0.23",
"compression-webpack-plugin": "^5.0.2",
"copy-webpack-plugin": "^6.4.1",
"core-js": "^3.22.2",
"core-js": "^3.22.3",
"cron-validator": "^1.1.1",
"cronstrue": "^1.122.0",
"cropper": "^2.3.0",

View File

@ -82,7 +82,7 @@ module QA
base.view 'app/views/layouts/nav/_breadcrumbs.html.haml' do
element :breadcrumb_links_content
element :breadcrumb_sub_title_content
element :breadcrumb_current_link
end
end
@ -257,7 +257,7 @@ module QA
def snippet_id
within_element(:breadcrumb_links_content) do
find_element(:breadcrumb_sub_title_content).text.delete_prefix('$')
find_element(:breadcrumb_current_link).text.delete_prefix('$')
end
end
end

View File

@ -468,7 +468,7 @@ RSpec.describe "Admin Runners" do
describe 'runner show page breadcrumbs' do
it 'contains the current runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
expect(page.find('h2')).to have_link("##{runner.id} (#{runner.short_sha})")
expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_link("##{runner.id} (#{runner.short_sha})")
end
end
end
@ -519,7 +519,7 @@ RSpec.describe "Admin Runners" do
it 'contains the current runner id and token' do
page.within '[data-testid="breadcrumb-links"]' do
expect(page).to have_link("##{runner.id} (#{runner.short_sha})")
expect(page.find('h2')).to have_content("Edit")
expect(page.find('[data-testid="breadcrumb-current-link"]')).to have_content("Edit")
end
end
end

View File

@ -548,7 +548,7 @@ RSpec.describe 'Admin::Users' do
end
def check_breadcrumb(content)
expect(find('.breadcrumbs-sub-title')).to have_content(content)
expect(find('[data-testid="breadcrumb-current-link"]')).to have_content(content)
end
end

View File

@ -26,7 +26,7 @@ RSpec.describe 'New issue breadcrumb' do
visit project_issue_path(project, issue)
expect(find('.breadcrumbs-sub-title a')[:href]).to end_with(issue_path(issue))
expect(find('[data-testid="breadcrumb-current-link"] a')[:href]).to end_with(issue_path(issue))
end
it 'excludes award_emoji from comment count', :js do

View File

@ -29,7 +29,7 @@ RSpec.describe 'Profile > SSH Keys' do
expect(page).to have_content("Title: #{attrs[:title]}")
expect(page).to have_content(attrs[:key])
expect(find('.breadcrumbs-sub-title')).to have_link(attrs[:title])
expect(find('[data-testid="breadcrumb-current-link"]')).to have_link(attrs[:title])
end
it 'shows a confirmable warning if the key begins with an algorithm name that is unsupported' do

View File

@ -16,7 +16,7 @@ RSpec.describe 'Profile > Applications' do
visit oauth_application_path(application)
expect(page).to have_content("Application: #{application.name}")
expect(find('.breadcrumbs-sub-title')).to have_link(application.name)
expect(find('[data-testid="breadcrumb-current-link"]')).to have_link(application.name)
end
it 'deletes an application' do

View File

@ -10,9 +10,6 @@ RSpec.describe 'User uploads new design', :js do
let(:issue) { create(:issue, project: project) }
before do
# Cause of raising query limiting threshold https://gitlab.com/gitlab-org/gitlab/-/issues/358845
stub_const("Gitlab::QueryLimiting::Transaction::THRESHOLD", 106)
sign_in(user)
enable_design_management(feature_enabled)
visit project_issue_path(project, issue)

View File

@ -9,7 +9,7 @@ import {
GlSprintf,
GlEmptyState,
} from '@gitlab/ui';
import Vue from 'vue';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import MockAdapter from 'axios-mock-adapter';
import createMockApollo from 'helpers/mock_apollo_helper';
@ -140,21 +140,23 @@ describe('DependencyProxyApp', () => {
describe('when the dependency proxy is available', () => {
describe('when is loading', () => {
it('renders the skeleton loader', () => {
beforeEach(() => {
createComponent();
});
it('renders the skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(true);
});
it('does not show the main section', () => {
createComponent();
it('does not render a form group with label', () => {
expect(findFormGroup().exists()).toBe(false);
});
it('does not show the main section', () => {
expect(findMainArea().exists()).toBe(false);
});
it('does not render the info alert', () => {
createComponent();
expect(findProxyNotAvailableAlert().exists()).toBe(false);
});
});
@ -193,7 +195,7 @@ describe('DependencyProxyApp', () => {
});
});
it('from group has a description with proxy count', () => {
it('form group has a description with proxy count', () => {
expect(findProxyCountText().text()).toBe('Contains 2 blobs of images (1024 Bytes)');
});
@ -257,6 +259,28 @@ describe('DependencyProxyApp', () => {
});
});
describe('triggering page event on list', () => {
beforeEach(async () => {
findManifestList().vm.$emit('next-page');
await nextTick();
});
it('re-renders the skeleton loader', () => {
expect(findSkeletonLoader().exists()).toBe(true);
});
it('renders form group with label', () => {
expect(findFormGroup().attributes('label')).toEqual(
expect.stringMatching(DependencyProxyApp.i18n.proxyImagePrefix),
);
});
it('does not show the main section', () => {
expect(findMainArea().exists()).toBe(false);
});
});
it('shows the clear cache dropdown list', () => {
expect(findClearCacheDropdownList().exists()).toBe(true);

View File

@ -3,7 +3,214 @@
require 'spec_helper'
RSpec.describe GitlabSchema.types['CurrentUserTodos'] do
include GraphqlHelpers
specify { expect(described_class.graphql_name).to eq('CurrentUserTodos') }
specify { expect(described_class).to have_graphql_fields(:current_user_todos).only }
# Request store is necessary to prevent duplicate max-member-access lookups
describe '.current_user_todos', :request_store, :aggregate_failures do
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project, :repository) }
let_it_be(:issue_a) { create(:issue, project: project) }
let_it_be(:issue_b) { create(:issue, project: project) }
let_it_be(:todo_a) { create(:todo, :pending, user: user, project: project, target: issue_a) }
let_it_be(:todo_b) { create(:todo, :done, user: user, project: project, target: issue_a) }
let_it_be(:todo_c) { create(:todo, :pending, user: user, project: project, target: issue_b) }
let_it_be(:todo_d) { create(:todo, :done, user: user, project: project, target: issue_b) }
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
let_it_be(:todo_e) { create(:todo, :pending, user: user, project: project, target: merge_request) }
let(:object_type) do
fresh_object_type('HasTodos').tap { _1.implements(Types::CurrentUserTodos) }
end
let(:id_enum) do
Class.new(Types::BaseEnum) do
graphql_name 'AorB'
value 'A'
value 'B'
end
end
let(:query_type) do
i_a = issue_a
i_b = issue_b
issue_id = id_enum
mr = merge_request
q = fresh_object_type('Query')
q.field :issue, null: false, type: object_type do
argument :id, type: issue_id, required: true
end
q.field :mr, null: false, type: object_type
q.define_method(:issue) do |id:|
case id
when 'A'
i_a
when 'B'
i_b
end
end
q.define_method(:mr) { mr }
q
end
let(:todo_fragment) do
<<-GQL
fragment todos on HasTodos {
todos: currentUserTodos {
nodes { id }
}
}
GQL
end
let(:base_query) do
<<-GQL
query {
issue(id: A) { ... todos }
}
#{todo_fragment}
GQL
end
let(:query_without_state_arguments) do
<<-GQL
query {
a: issue(id: A) {
... todos
}
b: issue(id: B) {
... todos
}
c: mr {
... todos
}
d: mr {
... todos
}
e: issue(id: A) {
... todos
}
}
#{todo_fragment}
GQL
end
let(:with_state_arguments) do
<<-GQL
query {
a: issue(id: A) {
todos: currentUserTodos(state: pending) { nodes { id } }
}
b: issue(id: B) {
todos: currentUserTodos(state: done) { nodes { id } }
}
c: mr {
... todos
}
}
#{todo_fragment}
GQL
end
before_all do
project.add_developer(user)
end
it 'batches todo lookups, linear in the number of target types/state arguments' do
# The baseline is 4 queries:
#
# When we batch queries, we see the following three groups of queries:
# # user authorization
# 1. SELECT "users".* FROM "users"
# INNER JOIN "project_authorizations"
# ON "users"."id" = "project_authorizations"."user_id"
# WHERE "project_authorizations"."project_id" = project_id
# AND "project_authorizations"."access_level" = 50
# 2. SELECT MAX("project_authorizations"."access_level") AS maximum_access_level,
# "project_authorizations"."user_id" AS project_authorizations_user_id
# FROM "project_authorizations"
# WHERE "project_authorizations"."project_id" = project_id
# AND "project_authorizations"."user_id" = user_id
# GROUP BY "project_authorizations"."user_id"
#
# # find todos for issues
# 1. SELECT "todos".* FROM "todos"
# WHERE "todos"."user_id" = user_id
# AND ("todos"."state" IN ('done','pending'))
# AND "todos"."target_id" IN (issue_a, issue_b)
# AND "todos"."target_type" = 'Issue' ORDER BY "todos"."id" DESC
#
# # find todos for merge_requests
# 1. SELECT "todos".* FROM "todos" WHERE "todos"."user_id" = user_id
# AND ("todos"."state" IN ('done','pending'))
# AND "todos"."target_id" = merge_request
# AND "todos"."target_type" = 'MergeRequest' ORDER BY "todos"."id" DESC
baseline = ActiveRecord::QueryRecorder.new do
execute_query(query_type, graphql: base_query)
end
expect do
execute_query(query_type, graphql: query_without_state_arguments)
end.not_to exceed_query_limit(baseline) # at present this is 3
expect do
execute_query(query_type, graphql: with_state_arguments)
end.not_to exceed_query_limit(baseline.count + 1)
end
it 'returns correct data' do
result = execute_query(query_type,
graphql: query_without_state_arguments,
raise_on_error: true).to_h
expect(result.dig('data', 'a', 'todos', 'nodes')).to contain_exactly(
{ "id" => global_id_of(todo_a) },
{ "id" => global_id_of(todo_b) }
)
expect(result.dig('data', 'b', 'todos', 'nodes')).to contain_exactly(
{ "id" => global_id_of(todo_c) },
{ "id" => global_id_of(todo_d) }
)
expect(result.dig('data', 'c', 'todos', 'nodes')).to contain_exactly(
{ "id" => global_id_of(todo_e) }
)
expect(result.dig('data', 'd', 'todos', 'nodes')).to contain_exactly(
{ "id" => global_id_of(todo_e) }
)
expect(result.dig('data', 'e', 'todos', 'nodes')).to contain_exactly(
{ "id" => global_id_of(todo_a) },
{ "id" => global_id_of(todo_b) }
)
end
it 'returns correct data, when state arguments are supplied' do
result = execute_query(query_type,
raise_on_error: true,
graphql: with_state_arguments).to_h
expect(result.dig('data', 'a', 'todos', 'nodes')).to contain_exactly(
include("id" => global_id_of(todo_a))
)
expect(result.dig('data', 'b', 'todos', 'nodes')).to contain_exactly(
include("id" => global_id_of(todo_d))
)
expect(result.dig('data', 'c', 'todos', 'nodes')).to contain_exactly(
include("id" => global_id_of(todo_e))
)
end
end
end

View File

@ -70,5 +70,17 @@ RSpec.describe API::Ci::Helpers::Runner do
expect(details['ip_address']).to eq(ip_address)
end
end
describe '#log_artifact_size' do
subject { runner_helper.log_artifact_size(artifact) }
let(:runner_params) { {} }
let(:artifact) { create(:ci_job_artifact, size: 42) }
let(:expected_params) { { artifact_size: artifact.size } }
let(:subject_proc) { proc { subject } }
it_behaves_like 'storing arguments in the application context'
it_behaves_like 'not executing any extra queries for the application context'
end
end
end

View File

@ -91,6 +91,7 @@ RSpec.describe Gitlab::ApplicationContext do
let_it_be(:project) { create(:project) }
let_it_be(:namespace) { create(:group) }
let_it_be(:subgroup) { create(:group, parent: namespace) }
let_it_be(:artifact) { create(:ci_job_artifact, size: 42) }
def result(context)
context.to_lazy_hash.transform_values { |v| v.respond_to?(:call) ? v.call : v }

View File

@ -85,11 +85,15 @@ RSpec.describe Gitlab::Graphql::Queries do
describe '.all' do
it 'is the combination of finding queries in CE and EE' do
expect(described_class)
.to receive(:find).with(Rails.root / 'app/assets/javascripts').and_return([:ce])
.to receive(:find).with(Rails.root / 'app/assets/javascripts').and_return([:ce_assets])
expect(described_class)
.to receive(:find).with(Rails.root / 'ee/app/assets/javascripts').and_return([:ee])
.to receive(:find).with(Rails.root / 'ee/app/assets/javascripts').and_return([:ee_assets])
expect(described_class)
.to receive(:find).with(Rails.root / 'app/graphql/queries').and_return([:ce_gql])
expect(described_class)
.to receive(:find).with(Rails.root / 'ee/app/graphql/queries').and_return([:ee_gql])
expect(described_class.all).to eq([:ce, :ee])
expect(described_class.all).to contain_exactly(:ce_assets, :ee_assets, :ce_gql, :ee_gql)
end
end

View File

@ -263,6 +263,9 @@ RSpec.describe API::Ci::JobArtifacts do
'Content-Disposition' => %q(attachment; filename="ci_build_artifacts.zip"; filename*=UTF-8''ci_build_artifacts.zip) }
end
let(:expected_params) { { artifact_size: job.artifacts_file.size } }
let(:subject_proc) { proc { subject } }
it 'returns specific job artifacts' do
subject
@ -270,6 +273,9 @@ RSpec.describe API::Ci::JobArtifacts do
expect(response.headers.to_h).to include(download_headers)
expect(response.body).to match_file(job.artifacts_file.file.file)
end
it_behaves_like 'storing arguments in the application context'
it_behaves_like 'not executing any extra queries for the application context'
end
context 'normal authentication' do

View File

@ -687,21 +687,28 @@ module GraphqlHelpers
end
end
# assumes query_string to be let-bound in the current context
def execute_query(query_type, schema: empty_schema, graphql: query_string)
# assumes query_string and user to be let-bound in the current context
def execute_query(query_type, schema: empty_schema, graphql: query_string, raise_on_error: false)
schema.query(query_type)
schema.execute(
r = schema.execute(
graphql,
context: { current_user: user },
variables: {}
)
if raise_on_error && r.to_h['errors'].present?
raise NoData, r.to_h['errors']
end
r
end
def empty_schema
Class.new(GraphQL::Schema) do
use GraphQL::Pagination::Connections
use Gitlab::Graphql::Pagination::Connections
use BatchLoader::GraphQL
lazy_resolve ::Gitlab::Graphql::Lazy, :force
end

View File

@ -3900,10 +3900,10 @@ core-js-pure@^3.0.0:
resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.6.5.tgz#c79e75f5e38dbc85a662d91eea52b8256d53b813"
integrity sha512-lacdXOimsiD0QyNf9BC/mxivNJ/ybBGJXQFKzRekp1WTHoVUWsUHEn+2T8GJAzzIhyOuXA+gOxCVN3l+5PLPUA==
core-js@^3.22.2:
version "3.22.2"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.2.tgz#3ea0a245b0895fa39d1faa15fe75d91ade504a01"
integrity sha512-Z5I2vzDnEIqO2YhELVMFcL1An2CIsFe9Q7byZhs8c/QxummxZlAHw33TUHbIte987LkisOgL0LwQ1P9D6VISnA==
core-js@^3.22.3:
version "3.22.3"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.3.tgz#498c41d997654cb00e81c7a54b44f0ab21ab01d5"
integrity sha512-1t+2a/d2lppW1gkLXx3pKPVGbBdxXAkqztvWb1EJ8oF8O2gIGiytzflNiFEehYwVK/t2ryUsGBoOFFvNx95mbg==
core-js@~2.3.0:
version "2.3.0"