Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-07-14 00:09:46 +00:00
parent 0698388e65
commit b941629bbf
32 changed files with 336 additions and 52 deletions

View file

@ -1 +1 @@
a75309cec88ed34f594a4f6514bb0bb2aef7fcd5 fdd1fe70085c1a20b10553680d88a967a4cfbfae

View file

@ -0,0 +1,34 @@
<script>
import { GlLink, GlSprintf } from '@gitlab/ui';
import { mapState } from 'vuex';
export default {
components: {
GlLink,
GlSprintf,
},
computed: {
...mapState(['ancestorHelperPath', 'hasAncestorClusters']),
},
};
</script>
<template>
<div v-if="hasAncestorClusters" class="bs-callout bs-callout-info">
<p>
<gl-sprintf
:message="
s__(
'ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}',
)
"
>
<template #link="{ content }">
<gl-link :href="ancestorHelperPath">
<strong>{{ content }}</strong>
</gl-link>
</template>
</gl-sprintf>
</p>
</div>
</template>

View file

@ -9,6 +9,7 @@ import {
GlSprintf, GlSprintf,
GlTable, GlTable,
} from '@gitlab/ui'; } from '@gitlab/ui';
import AncestorNotice from './ancestor_notice.vue';
import tooltip from '~/vue_shared/directives/tooltip'; import tooltip from '~/vue_shared/directives/tooltip';
import { CLUSTER_TYPES, STATUSES } from '../constants'; import { CLUSTER_TYPES, STATUSES } from '../constants';
import { __, sprintf } from '~/locale'; import { __, sprintf } from '~/locale';
@ -17,6 +18,7 @@ export default {
nodeMemoryText: __('%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)'), nodeMemoryText: __('%{totalMemory} (%{freeSpacePercentage}%{percentSymbol} free)'),
nodeCpuText: __('%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)'), nodeCpuText: __('%{totalCpu} (%{freeSpacePercentage}%{percentSymbol} free)'),
components: { components: {
AncestorNotice,
GlBadge, GlBadge,
GlLink, GlLink,
GlLoadingIcon, GlLoadingIcon,
@ -195,6 +197,8 @@ export default {
<gl-loading-icon v-if="loadingClusters" size="md" class="gl-mt-3" /> <gl-loading-icon v-if="loadingClusters" size="md" class="gl-mt-3" />
<section v-else> <section v-else>
<ancestor-notice />
<gl-table :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table"> <gl-table :items="clusters" :fields="fields" stacked="md" class="qa-clusters-table">
<template #cell(name)="{ item }"> <template #cell(name)="{ item }">
<div :class="[contentAlignClasses, 'js-status']"> <div :class="[contentAlignClasses, 'js-status']">

View file

@ -1,4 +1,5 @@
export default (initialState = {}) => ({ export default (initialState = {}) => ({
ancestorHelperPath: initialState.ancestorHelpPath,
endpoint: initialState.endpoint, endpoint: initialState.endpoint,
hasAncestorClusters: false, hasAncestorClusters: false,
clusters: [], clusters: [],

View file

@ -13,7 +13,11 @@ module Types
field :jira_email, GraphQL::STRING_TYPE, null: true, field :jira_email, GraphQL::STRING_TYPE, null: true,
description: 'Email of the Jira user, returned only for users with public emails' description: 'Email of the Jira user, returned only for users with public emails'
field :gitlab_id, GraphQL::INT_TYPE, null: true, field :gitlab_id, GraphQL::INT_TYPE, null: true,
description: 'Id of the matched GitLab user' description: 'ID of the matched GitLab user'
field :gitlab_username, GraphQL::STRING_TYPE, null: true,
description: 'Username of the matched GitLab user'
field :gitlab_name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the matched GitLab user'
end end
# rubocop: enable Graphql/AuthorizeTypes # rubocop: enable Graphql/AuthorizeTypes
end end

View file

@ -18,6 +18,7 @@ module ClustersHelper
def js_clusters_list_data(path = nil) def js_clusters_list_data(path = nil)
{ {
ancestor_help_path: help_page_path('user/group/clusters/index', anchor: 'cluster-precedence'),
endpoint: path, endpoint: path,
img_tags: { img_tags: {
aws: { path: image_path('illustrations/logos/amazon_eks.svg'), text: s_('ClusterIntegration|Amazon EKS') }, aws: { path: image_path('illustrations/logos/amazon_eks.svg'), text: s_('ClusterIntegration|Amazon EKS') },

View file

@ -11,7 +11,7 @@ module Ci
METRICS_SHARD_TAG_PREFIX = 'metrics_shard::'.freeze METRICS_SHARD_TAG_PREFIX = 'metrics_shard::'.freeze
DEFAULT_METRICS_SHARD = 'default'.freeze DEFAULT_METRICS_SHARD = 'default'.freeze
Result = Struct.new(:build, :valid?) Result = Struct.new(:build, :build_json, :valid?)
def initialize(runner) def initialize(runner)
@runner = runner @runner = runner
@ -59,7 +59,7 @@ module Ci
end end
register_failure register_failure
Result.new(nil, valid) Result.new(nil, nil, valid)
end end
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
@ -71,7 +71,7 @@ module Ci
# In case when 2 runners try to assign the same build, second runner will be declined # In case when 2 runners try to assign the same build, second runner will be declined
# with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method. # with StateMachines::InvalidTransition or StaleObjectError when doing run! or save method.
if assign_runner!(build, params) if assign_runner!(build, params)
Result.new(build, true) present_build!(build)
end end
rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError rescue StateMachines::InvalidTransition, ActiveRecord::StaleObjectError
# We are looping to find another build that is not conflicting # We are looping to find another build that is not conflicting
@ -83,8 +83,10 @@ module Ci
# In case we hit the concurrency-access lock, # In case we hit the concurrency-access lock,
# we still have to return 409 in the end, # we still have to return 409 in the end,
# to make sure that this is properly handled by runner. # to make sure that this is properly handled by runner.
Result.new(nil, false) Result.new(nil, nil, false)
rescue => ex rescue => ex
# If an error (e.g. GRPC::DeadlineExceeded) occurred constructing
# the result, consider this as a failure to be retried.
scheduler_failure!(build) scheduler_failure!(build)
track_exception_for_build(ex, build) track_exception_for_build(ex, build)
@ -92,6 +94,15 @@ module Ci
nil nil
end end
# Force variables evaluation to occur now
def present_build!(build)
# We need to use the presenter here because Gitaly calls in the presenter
# may fail, and we need to ensure the response has been generated.
presented_build = ::Ci::BuildRunnerPresenter.new(build) # rubocop:disable CodeReuse/Presenter
build_json = ::API::Entities::JobRequest::Response.new(presented_build).to_json
Result.new(build, build_json, true)
end
def assign_runner!(build, params) def assign_runner!(build, params)
build.runner_id = runner.id build.runner_id = runner.id
build.runner_session_attributes = params[:session] if params[:session].present? build.runner_session_attributes = params[:session] if params[:session].present?

View file

@ -14,9 +14,8 @@ module JiraImport
{ {
jira_account_id: jira_user['accountId'], jira_account_id: jira_user['accountId'],
jira_display_name: jira_user['displayName'], jira_display_name: jira_user['displayName'],
jira_email: jira_user['emailAddress'], jira_email: jira_user['emailAddress']
gitlab_id: match_user(jira_user) }.merge(match_user(jira_user))
}
end end
end end
@ -25,7 +24,7 @@ module JiraImport
# TODO: Matching user by email and displayName will be done as the part # TODO: Matching user by email and displayName will be done as the part
# of follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/219023 # of follow-up issue: https://gitlab.com/gitlab-org/gitlab/-/issues/219023
def match_user(jira_user) def match_user(jira_user)
nil { gitlab_id: nil, gitlab_username: nil, gitlab_name: nil }
end end
end end
end end

View file

@ -12,15 +12,14 @@
= s_('ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project') = s_('ClusterIntegration|Kubernetes clusters can be used to deploy applications and to provide Review Apps for this project')
= render 'clusters/clusters/buttons' = render 'clusters/clusters/buttons'
- if @has_ancestor_clusters
.bs-callout.bs-callout-info
= s_('ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.')
%strong
= link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
- if Feature.enabled?(:clusters_list_redesign) - if Feature.enabled?(:clusters_list_redesign)
#js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) } #js-clusters-list-app{ data: js_clusters_list_data(clusterable.index_path(format: :json)) }
- else - else
- if @has_ancestor_clusters
.bs-callout.bs-callout-info
= s_('ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.')
%strong
= link_to _('More information'), help_page_path('user/group/clusters/index', anchor: 'cluster-precedence')
.clusters-table.js-clusters-list .clusters-table.js-clusters-list
.gl-responsive-table-row.table-row-header{ role: "row" } .gl-responsive-table-row.table-row-header{ role: "row" }
.table-section.section-60{ role: "rowheader" } .table-section.section-60{ role: "rowheader" }

View file

@ -60,8 +60,6 @@ module Reenqueuer
5.seconds 5.seconds
end end
# We intend to get rid of sleep:
# https://gitlab.com/gitlab-org/gitlab/issues/121697
module ReenqueuerSleeper module ReenqueuerSleeper
# The block will run, and then sleep until the minimum duration. Returns the # The block will run, and then sleep until the minimum duration. Returns the
# block's return value. # block's return value.

View file

@ -0,0 +1,5 @@
---
title: Add GitLab username and name to the import users from Jira mutation response
merge_request: 35542
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: Change PrometheusMetrics identifier index
merge_request: 35912
author:
type: fixed

View file

@ -0,0 +1,5 @@
---
title: Fail jobs that fail to render registration response
merge_request: 36274
author:
type: fixed

View file

@ -0,0 +1,22 @@
# frozen_string_literal: true
class ChangePrometheusMetricsIdentifierIndex < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
NEW_INDEX = :index_prometheus_metrics_on_identifier_and_null_project
OLD_INDEX = :index_prometheus_metrics_on_identifier
disable_ddl_transaction!
def up
add_concurrent_index :prometheus_metrics, :identifier, name: NEW_INDEX, unique: true, where: 'project_id IS NULL'
remove_concurrent_index_by_name :prometheus_metrics, OLD_INDEX
end
def down
add_concurrent_index :prometheus_metrics, :identifier, name: OLD_INDEX, unique: true
remove_concurrent_index_by_name :prometheus_metrics, NEW_INDEX
end
end

View file

@ -20025,7 +20025,7 @@ CREATE INDEX index_prometheus_metrics_on_common ON public.prometheus_metrics USI
CREATE INDEX index_prometheus_metrics_on_group ON public.prometheus_metrics USING btree ("group"); CREATE INDEX index_prometheus_metrics_on_group ON public.prometheus_metrics USING btree ("group");
CREATE UNIQUE INDEX index_prometheus_metrics_on_identifier ON public.prometheus_metrics USING btree (identifier); CREATE UNIQUE INDEX index_prometheus_metrics_on_identifier_and_null_project ON public.prometheus_metrics USING btree (identifier) WHERE (project_id IS NULL);
CREATE UNIQUE INDEX index_prometheus_metrics_on_identifier_and_project_id ON public.prometheus_metrics USING btree (identifier, project_id); CREATE UNIQUE INDEX index_prometheus_metrics_on_identifier_and_project_id ON public.prometheus_metrics USING btree (identifier, project_id);
@ -23718,6 +23718,7 @@ COPY "schema_migrations" (version) FROM STDIN;
20200701093859 20200701093859
20200701205710 20200701205710
20200702123805 20200702123805
20200702201039
20200703064117 20200703064117
20200703121557 20200703121557
20200703154822 20200703154822

View file

@ -35,7 +35,8 @@ The availability objectives for Gitaly clusters are:
Writes are replicated asynchronously. Any writes that have not been replicated Writes are replicated asynchronously. Any writes that have not been replicated
to the newly promoted primary are lost. to the newly promoted primary are lost.
[Strong consistency](#strong-consistency) can be used to improve this to "no loss". [Strong consistency](#strong-consistency) can be used to avoid loss in some
circumstances.
- **Recovery Time Objective (RTO):** Less than 10 seconds. - **Recovery Time Objective (RTO):** Less than 10 seconds.
@ -886,8 +887,8 @@ after the write to the primary Gitaly node has happened.
Praefect can instead provide strong consistency by creating a transaction and writing Praefect can instead provide strong consistency by creating a transaction and writing
changes to all Gitaly nodes at once. Strong consistency is currently in changes to all Gitaly nodes at once. Strong consistency is currently in
[alpha](https://about.gitlab.com/handbook/product/#alpha-beta-ga) and not enabled by [alpha](https://about.gitlab.com/handbook/product/#alpha-beta-ga) and not enabled by
default. For more information, see the default. If enabled, transactions are only available for a subset of RPCs. For more
[strong consistency epic](https://gitlab.com/groups/gitlab-org/-/epics/1189). information, see the [strong consistency epic](https://gitlab.com/groups/gitlab-org/-/epics/1189).
To enable strong consistency: To enable strong consistency:

View file

@ -119,6 +119,49 @@ For `<project>.git` you'll need to
[translate your project name into the hashed storage format](repository_storage_types.md#translating-hashed-storage-paths) [translate your project name into the hashed storage format](repository_storage_types.md#translating-hashed-storage-paths)
that GitLab uses. that GitLab uses.
## Environment Variables
The following set of environment variables are available to server hooks.
### GitLab Environment Variables
| Envirnment Variable | purpose |
|---------------------|---------------------------------------------------------|
| GL_ID | GitLab identifier eg: user-2234 that initiated the push |
| GL_PROJECT_PATH (available starting 13.2) | GitLab project path |
| GL_PROTOCOL (available starting 13.2) | Protocol used with push |
| GL_REPOSITORY | project-<id> where id of the project |
| GL_USERNAME | GitLab username that initiated the push |
Pre-receive and post-receive server hooks can also access the following Git environment variables.
| Environment variable | Description |
|:-----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `GIT_ALTERNATE_OBJECT_DIRECTORIES` | Alternate object directories in the quarantine environment. See [Git `receive-pack` documentation](https://git-scm.com/docs/git-receive-pack#_quarantine_environment). |
| `GIT_OBJECT_DIRECTORY` | GitLab project path in the quarantine environment. See [Git `receive-pack` documentation](https://git-scm.com/docs/git-receive-pack#_quarantine_environment). |
| `GIT_PUSH_OPTION_COUNT` | Number of push options. See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
| `GIT_PUSH_OPTION_<i>` | Value of push options where `i` is from `0` to `GIT_PUSH_OPTION_COUNT - 1`. See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
NOTE: **Note:**
While other environment variables can be passed to server hooks, your application
should not rely on them as they can change.
## Transition to Go
> Introduced in GitLab 13.2 using feature flags.
The following server hooks have been reimplemented in Go:
- `pre-receive`, with the Go implementation used by default. To use the Ruby
implementation instead, [disable](../operations/feature_flags.md#enable-or-disable-feature-flag-strategies)
the `:gitaly_go_preceive_hook` feature flag.
- `update`, with the Go implementation used by default. To use the Ruby implementation
instead, [disable](../operations/feature_flags.md#enable-or-disable-feature-flag-strategies)
the `:gitaly_go_update_hook` feature flag.
- `post-receive`, however the Ruby implementation is used by default. To use the Go
implementation instead, [enabled](../operations/feature_flags.md#enable-or-disable-feature-flag-strategies)
the `:gitaly_go_postreceive_hook` feature flag.
## Custom error messages ## Custom error messages
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5073) in GitLab 8.10. > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/5073) in GitLab 8.10.

View file

@ -423,7 +423,7 @@ Status: 200 OK
``` ```
CAUTION: **Deprecation:** CAUTION: **Deprecation:**
The `Links` Header will be removed in GitLab 14.0 to be aligned with the [W3C specification](https://www.w3.org/wiki/LinkHeader) The `Links` Header will be removed in GitLab 14.0 to be aligned with the [W3C `Link` specification](https://www.w3.org/wiki/LinkHeader)
The link to the next page contains an additional filter `id_after=42` which excludes records we have retrieved already. The link to the next page contains an additional filter `id_after=42` which excludes records we have retrieved already.
Note the type of filter depends on the `order_by` option used and we may have more than one additional filter. Note the type of filter depends on the `order_by` option used and we may have more than one additional filter.

View file

@ -6656,10 +6656,20 @@ type JiraService implements Service {
type JiraUser { type JiraUser {
""" """
Id of the matched GitLab user ID of the matched GitLab user
""" """
gitlabId: Int gitlabId: Int
"""
Name of the matched GitLab user
"""
gitlabName: String
"""
Username of the matched GitLab user
"""
gitlabUsername: String
""" """
Account id of the Jira user Account id of the Jira user
""" """

View file

@ -18439,7 +18439,7 @@
"fields": [ "fields": [
{ {
"name": "gitlabId", "name": "gitlabId",
"description": "Id of the matched GitLab user", "description": "ID of the matched GitLab user",
"args": [ "args": [
], ],
@ -18451,6 +18451,34 @@
"isDeprecated": false, "isDeprecated": false,
"deprecationReason": null "deprecationReason": null
}, },
{
"name": "gitlabName",
"description": "Name of the matched GitLab user",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "gitlabUsername",
"description": "Username of the matched GitLab user",
"args": [
],
"type": {
"kind": "SCALAR",
"name": "String",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{ {
"name": "jiraAccountId", "name": "jiraAccountId",
"description": "Account id of the Jira user", "description": "Account id of the Jira user",

View file

@ -1007,7 +1007,9 @@ Autogenerated return type of JiraImportUsers
| Name | Type | Description | | Name | Type | Description |
| --- | ---- | ---------- | | --- | ---- | ---------- |
| `gitlabId` | Int | Id of the matched GitLab user | | `gitlabId` | Int | ID of the matched GitLab user |
| `gitlabName` | String | Name of the matched GitLab user |
| `gitlabUsername` | String | Username of the matched GitLab user |
| `jiraAccountId` | String! | Account id of the Jira user | | `jiraAccountId` | String! | Account id of the Jira user |
| `jiraDisplayName` | String! | Display name of the Jira user | | `jiraDisplayName` | String! | Display name of the Jira user |
| `jiraEmail` | String | Email of the Jira user, returned only for users with public emails | | `jiraEmail` | String | Email of the Jira user, returned only for users with public emails |

View file

@ -48,7 +48,7 @@ Example response:
"sign_in_text" : null, "sign_in_text" : null,
"container_expiration_policies_enable_historic_entries": true, "container_expiration_policies_enable_historic_entries": true,
"container_registry_token_expire_delay": 5, "container_registry_token_expire_delay": 5,
"repository_storages": ["default"], "repository_storages_weighted": {"default": 100},
"plantuml_enabled": false, "plantuml_enabled": false,
"plantuml_url": null, "plantuml_url": null,
"terminal_max_session_time": 0, "terminal_max_session_time": 0,
@ -314,7 +314,8 @@ are listed in the descriptions of the relevant settings.
| `receive_max_input_size` | integer | no | Maximum push size (MB). | | `receive_max_input_size` | integer | no | Maximum push size (MB). |
| `repository_checks_enabled` | boolean | no | GitLab will periodically run `git fsck` in all project and wiki repositories to look for silent disk corruption issues. | | `repository_checks_enabled` | boolean | no | GitLab will periodically run `git fsck` in all project and wiki repositories to look for silent disk corruption issues. |
| `repository_size_limit` | integer | no | **(PREMIUM)** Size limit per repository (MB) | | `repository_size_limit` | integer | no | **(PREMIUM)** Size limit per repository (MB) |
| `repository_storages` | array of strings | no | A list of names of enabled storage paths, taken from `gitlab.yml`. New projects will be created in one of these stores, chosen at random. | | `repository_storages` | array of strings | no | (GitLab 13.0 and earlier) List of names of enabled storage paths, taken from `gitlab.yml`. New projects are created in one of these stores, chosen at random. |
| `repository_storages_weighted` | hash of strings to integers | no | (GitLab 13.1 and later) Hash of names of taken from `gitlab.yml` to weights. New projects are created in one of these stores, chosen by a weighted random selection. |
| `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. | | `require_two_factor_authentication` | boolean | no | (**If enabled, requires:** `two_factor_grace_period`) Require all users to set up Two-factor authentication. |
| `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-admin users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. | | `restricted_visibility_levels` | array of strings | no | Selected levels cannot be used by non-admin users for groups, projects or snippets. Can take `private`, `internal` and `public` as a parameter. Default is `null` which means there is no restriction. |
| `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. | | `rsa_key_restriction` | integer | no | The minimum allowed bit length of an uploaded RSA key. Default is `0` (no restriction). `-1` disables RSA keys. |

View file

@ -111,7 +111,8 @@ Patterns:
- `'"((?:\\"|[^"]|\\")*)"'`: captures terms inside quotes, removing the quotes - `'"((?:\\"|[^"]|\\")*)"'`: captures terms inside quotes, removing the quotes
- `"'((?:\\'|[^']|\\')*)'"`: same as above, for single-quotes - `"'((?:\\'|[^']|\\')*)'"`: same as above, for single-quotes
- `'\.([^.]+)(?=\.|\s|\Z)'`: separate terms with periods in-between - `'\.([^.]+)(?=\.|\s|\Z)'`: separate terms with periods in-between
- `'([\p{L}_.-]+)'` : some common chars in file names to keep the whole filename intact (eg. `my_file-ñame.txt`) - `'([\p{L}_.-]+)'`: some common chars in file names to keep the whole filename intact (eg. `my_file-ñame.txt`)
- `'([\p{L}\d_]+)'`: letters, numbers and underscores are the most common tokens in programming. Always capture them greedily regardless of context.
## Gotchas ## Gotchas

View file

@ -53,14 +53,14 @@ Be sure to read about [page-specific JavaScript](./performance.md#page-specific-
#### Providing data from HAML to JavaScript #### Providing data from HAML to JavaScript
While mounting a Vue application may be a need to provide data from Rails to JavaScript. While mounting a Vue application, you might need to provide data from Rails to JavaScript.
To do that, provide the data through `data` attributes in the HTML element and query them while mounting the application. To do that, you can use the `data` attributes in the HTML element and query them while mounting the application.
_Note:_ You should only do this while initializing the application, because the mounted element will be replaced with Vue-generated DOM. _Note:_ You should only do this while initializing the application, because the mounted element will be replaced with Vue-generated DOM.
The advantage of providing data from the DOM to the Vue instance through `props` in the `render` function The advantage of providing data from the DOM to the Vue instance through `props` in the `render` function
instead of querying the DOM inside the main Vue component is that makes tests easier by avoiding the need to instead of querying the DOM inside the main Vue component is avoiding the need to create a fixture or an HTML element in the unit test,
create a fixture or an HTML element in the unit test. See the following example: which will make the tests easier. See the following example:
```javascript ```javascript
// haml // haml
@ -134,7 +134,7 @@ This approach has a few benefits:
intermediate components being aware of it (c.f. passing the flag down via intermediate components being aware of it (c.f. passing the flag down via
props). props).
- Good testability, since the flag can be provided to `mount`/`shallowMount` - Good testability, since the flag can be provided to `mount`/`shallowMount`
from `vue-test-utils` as easily as a prop. from `vue-test-utils` simply as a prop.
```javascript ```javascript
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
@ -155,7 +155,7 @@ This folder holds all components that are specific of this new feature.
If you need to use or create a component that will probably be used somewhere If you need to use or create a component that will probably be used somewhere
else, please refer to `vue_shared/components`. else, please refer to `vue_shared/components`.
A good thumb rule to know when you should create a component is to think if A good rule of thumb to know when you should create a component is to think if
it will be reusable elsewhere. it will be reusable elsewhere.
For example, tables are used in a quite amount of places across GitLab, a table For example, tables are used in a quite amount of places across GitLab, a table
@ -321,7 +321,7 @@ We should verify an event has been fired by asserting against the result of the
## Vue.js Expert Role ## Vue.js Expert Role
One should apply to be a Vue.js expert by opening an MR when the Merge Request's they create and review show: You should only apply to be a Vue.js expert when your own merge requests and your reviews show:
- Deep understanding of Vue and Vuex reactivity - Deep understanding of Vue and Vuex reactivity
- Vue and Vuex code are structured according to both official and our guidelines - Vue and Vuex code are structured according to both official and our guidelines

View file

@ -108,6 +108,20 @@ module API
end end
optional :job_age, type: Integer, desc: %q(Job should be older than passed age in seconds to be ran on runner) optional :job_age, type: Integer, desc: %q(Job should be older than passed age in seconds to be ran on runner)
end end
# Since we serialize the build output ourselves to ensure Gitaly
# gRPC calls succeed, we need a custom Grape format to handle
# this:
# 1. Grape will ordinarily call `JSON.dump` when Content-Type is set
# to application/json. To avoid this, we need to define a custom type in
# `content_type` and a custom formatter to go with it.
# 2. Grape will parse the request input with the parser defined for
# `content_type`. If no such parser exists, it will be treated as text. We
# reuse the existing JSON parser to preserve the previous behavior.
content_type :build_json, 'application/json'
formatter :build_json, ->(object, _) { object }
parser :build_json, ::Grape::Parser::Json
post '/request' do post '/request' do
authenticate_runner! authenticate_runner!
@ -128,9 +142,10 @@ module API
result = ::Ci::RegisterJobService.new(current_runner).execute(runner_params) result = ::Ci::RegisterJobService.new(current_runner).execute(runner_params)
if result.valid? if result.valid?
if result.build if result.build_json
Gitlab::Metrics.add_event(:build_found) Gitlab::Metrics.add_event(:build_found)
present ::Ci::BuildRunnerPresenter.new(result.build), with: Entities::JobRequest::Response env['api.format'] = :build_json
body result.build_json
else else
Gitlab::Metrics.add_event(:build_not_found) Gitlab::Metrics.add_event(:build_not_found)
header 'X-GitLab-Last-Update', new_update header 'X-GitLab-Last-Update', new_update

View file

@ -5054,6 +5054,9 @@ msgstr ""
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters." msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters."
msgstr "" msgstr ""
msgid "ClusterIntegration|Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters. %{linkStart}More information%{linkEnd}"
msgstr ""
msgid "ClusterIntegration|Copy API URL" msgid "ClusterIntegration|Copy API URL"
msgstr "" msgstr ""

View file

@ -0,0 +1,51 @@
import AncestorNotice from '~/clusters_list/components/ancestor_notice.vue';
import ClusterStore from '~/clusters_list/store';
import { shallowMount } from '@vue/test-utils';
import { GlLink, GlSprintf } from '@gitlab/ui';
describe('ClustersAncestorNotice', () => {
let store;
let wrapper;
const createWrapper = () => {
store = ClusterStore({ ancestorHelperPath: '/some/ancestor/path' });
wrapper = shallowMount(AncestorNotice, { store, stubs: { GlSprintf } });
return wrapper.vm.$nextTick();
};
beforeEach(() => {
return createWrapper();
});
afterEach(() => {
wrapper.destroy();
});
describe('when cluster does not have ancestors', () => {
beforeEach(() => {
store.state.hasAncestorClusters = false;
return wrapper.vm.$nextTick();
});
it('displays no notice', () => {
expect(wrapper.isEmpty()).toBe(true);
});
});
describe('when cluster has ancestors', () => {
beforeEach(() => {
store.state.hasAncestorClusters = true;
return wrapper.vm.$nextTick();
});
it('displays notice text', () => {
expect(wrapper.text()).toContain(
'Clusters are utilized by selecting the nearest ancestor with a matching environment scope. For example, project clusters will override group clusters.',
);
});
it('displays link', () => {
expect(wrapper.contains(GlLink)).toBe(true);
});
});
});

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['JiraUser'] do
specify { expect(described_class.graphql_name).to eq('JiraUser') }
it 'has the expected fields' do
expect(described_class).to have_graphql_fields(
:jira_account_id, :jira_display_name, :jira_email, :gitlab_id, :gitlab_username, :gitlab_name
)
end
end

View file

@ -60,18 +60,24 @@ RSpec.describe ClustersHelper do
end end
describe '#js_clusters_list_data' do describe '#js_clusters_list_data' do
it 'displays endpoint path and images' do subject { helper.js_clusters_list_data('/path') }
js_data = helper.js_clusters_list_data('/path')
expect(js_data[:endpoint]).to eq('/path') it 'displays endpoint path' do
expect(subject[:endpoint]).to eq('/path')
end
expect(js_data.dig(:img_tags, :aws, :path)).to match(%r(/illustrations/logos/amazon_eks|svg)) it 'generates svg image data', :aggregate_failures do
expect(js_data.dig(:img_tags, :default, :path)).to match(%r(/illustrations/logos/kubernetes|svg)) expect(subject.dig(:img_tags, :aws, :path)).to match(%r(/illustrations/logos/amazon_eks|svg))
expect(js_data.dig(:img_tags, :gcp, :path)).to match(%r(/illustrations/logos/google_gke|svg)) expect(subject.dig(:img_tags, :default, :path)).to match(%r(/illustrations/logos/kubernetes|svg))
expect(subject.dig(:img_tags, :gcp, :path)).to match(%r(/illustrations/logos/google_gke|svg))
expect(js_data.dig(:img_tags, :aws, :text)).to eq('Amazon EKS') expect(subject.dig(:img_tags, :aws, :text)).to eq('Amazon EKS')
expect(js_data.dig(:img_tags, :default, :text)).to eq('Kubernetes Cluster') expect(subject.dig(:img_tags, :default, :text)).to eq('Kubernetes Cluster')
expect(js_data.dig(:img_tags, :gcp, :text)).to eq('Google GKE') expect(subject.dig(:img_tags, :gcp, :text)).to eq('Google GKE')
end
it 'displays and ancestor_help_path' do
expect(subject[:ancestor_help_path]).to eq('/help/user/group/clusters/index#cluster-precedence')
end end
end end

View file

@ -518,6 +518,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
request_job info: { platform: :darwin } request_job info: { platform: :darwin }
expect(response).to have_gitlab_http_status(:created) expect(response).to have_gitlab_http_status(:created)
expect(response.headers['Content-Type']).to eq('application/json')
expect(response.headers).not_to have_key('X-GitLab-Last-Update') expect(response.headers).not_to have_key('X-GitLab-Last-Update')
expect(runner.reload.platform).to eq('darwin') expect(runner.reload.platform).to eq('darwin')
expect(json_response['id']).to eq(job.id) expect(json_response['id']).to eq(job.id)
@ -569,6 +570,24 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end end
end end
context 'when a Gitaly exception is thrown during response' do
before do
allow_next_instance_of(Ci::BuildRunnerPresenter) do |instance|
allow(instance).to receive(:artifacts).and_raise(GRPC::DeadlineExceeded)
end
end
it 'fails the job as a scheduler failure' do
request_job
expect(response).to have_gitlab_http_status(:no_content)
expect(job.reload.failed?).to be_truthy
expect(job.failure_reason).to eq('scheduler_failure')
expect(job.runner_id).to eq(runner.id)
expect(job.runner_session).to be_nil
end
end
context 'when GIT_DEPTH is not specified and there is no default git depth for the project' do context 'when GIT_DEPTH is not specified and there is no default git depth for the project' do
before do before do
project.update!(ci_default_git_depth: nil) project.update!(ci_default_git_depth: nil)
@ -1090,7 +1109,7 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
def request_job(token = runner.token, **params) def request_job(token = runner.token, **params)
new_params = params.merge(token: token, last_update: last_update) new_params = params.merge(token: token, last_update: last_update)
post api('/jobs/request'), params: new_params, headers: { 'User-Agent' => user_agent } post api('/jobs/request'), params: new_params.to_json, headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' }
end end
end end

View file

@ -109,12 +109,14 @@ module Ci
end end
context 'shared runner' do context 'shared runner' do
let(:build) { execute(shared_runner) } let(:response) { described_class.new(shared_runner).execute }
let(:build) { response.build }
it { expect(build).to be_kind_of(Build) } it { expect(build).to be_kind_of(Build) }
it { expect(build).to be_valid } it { expect(build).to be_valid }
it { expect(build).to be_running } it { expect(build).to be_running }
it { expect(build.runner).to eq(shared_runner) } it { expect(build.runner).to eq(shared_runner) }
it { expect(Gitlab::Json.parse(response.build_json)['id']).to eq(build.id) }
end end
context 'specific runner' do context 'specific runner' do

View file

@ -29,9 +29,9 @@ RSpec.describe JiraImport::UsersMapper do
# mapping is tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/219023 # mapping is tracked in https://gitlab.com/gitlab-org/gitlab/-/issues/219023
let(:mapped_users) do let(:mapped_users) do
[ [
{ jira_account_id: 'abcd', jira_display_name: 'user1', jira_email: nil, gitlab_id: nil }, { jira_account_id: 'abcd', jira_display_name: 'user1', jira_email: nil, gitlab_id: nil, gitlab_username: nil, gitlab_name: nil },
{ jira_account_id: 'efg', jira_display_name: nil, jira_email: nil, gitlab_id: nil }, { jira_account_id: 'efg', jira_display_name: nil, jira_email: nil, gitlab_id: nil, gitlab_username: nil, gitlab_name: nil },
{ jira_account_id: 'hij', jira_display_name: 'user3', jira_email: 'user3@example.com', gitlab_id: nil } { jira_account_id: 'hij', jira_display_name: 'user3', jira_email: 'user3@example.com', gitlab_id: nil, gitlab_username: nil, gitlab_name: nil }
] ]
end end