Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-11 00:10:18 +00:00
parent fba0e44e08
commit 1a3d7fe0b6
29 changed files with 363 additions and 82 deletions

View File

@ -9,6 +9,8 @@ import {
GlSprintf,
GlAlert,
} from '@gitlab/ui';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
import { timeRanges } from '~/vue_shared/constants';
import DashboardPanel from './dashboard_panel.vue';
const initialYml = `title: Go heap size
@ -30,6 +32,7 @@ export default {
GlSprintf,
GlAlert,
DashboardPanel,
DateTimePicker,
},
data() {
return {
@ -41,20 +44,35 @@ export default {
'panelPreviewIsLoading',
'panelPreviewError',
'panelPreviewGraphData',
'panelPreviewTimeRange',
'panelPreviewIsShown',
'projectPath',
'addDashboardDocumentationPath',
]),
},
methods: {
...mapActions('monitoringDashboard', ['fetchPanelPreview']),
...mapActions('monitoringDashboard', [
'fetchPanelPreview',
'fetchPanelPreviewMetrics',
'setPanelPreviewTimeRange',
]),
onSubmit() {
this.fetchPanelPreview(this.yml);
},
onDateTimePickerInput(timeRange) {
this.setPanelPreviewTimeRange(timeRange);
// refetch data only if preview has been clicked
// and there are no errors
if (this.panelPreviewIsShown && !this.panelPreviewError) {
this.fetchPanelPreviewMetrics();
}
},
},
timeRanges,
};
</script>
<template>
<div>
<div class="prometheus-panel-builder">
<div class="gl-xs-flex-direction-column gl-display-flex gl-mx-n3">
<gl-card class="gl-flex-grow-1 gl-flex-basis-0 gl-mx-3">
<template #header>
@ -151,7 +169,13 @@ export default {
<gl-alert v-if="panelPreviewError" variant="warning" :dismissible="false">
{{ panelPreviewError }}
</gl-alert>
<date-time-picker
ref="dateTimePicker"
class="gl-flex-grow-1 preview-date-time-picker"
:value="panelPreviewTimeRange"
:options="$options.timeRanges"
@input="onDateTimePickerInput"
/>
<dashboard-panel :graph-data="panelPreviewGraphData" />
</div>
</template>

View File

@ -3,7 +3,7 @@ import statusCodes from '~/lib/utils/http_status';
import { backOff } from '~/lib/utils/common_utils';
import { PROMETHEUS_TIMEOUT } from '../constants';
const backOffRequest = makeRequestCallback =>
const cancellableBackOffRequest = makeRequestCallback =>
backOff((next, stop) => {
makeRequestCallback()
.then(resp => {
@ -13,16 +13,19 @@ const backOffRequest = makeRequestCallback =>
stop(resp);
}
})
.catch(stop);
// If the request is cancelled by axios
// then consider it as noop so that its not
// caught by subsequent catches
.catch(thrown => (axios.isCancel(thrown) ? undefined : stop(thrown)));
}, PROMETHEUS_TIMEOUT);
export const getDashboard = (dashboardEndpoint, params) =>
backOffRequest(() => axios.get(dashboardEndpoint, { params })).then(
cancellableBackOffRequest(() => axios.get(dashboardEndpoint, { params })).then(
axiosResponse => axiosResponse.data,
);
export const getPrometheusQueryData = (prometheusEndpoint, params) =>
backOffRequest(() => axios.get(prometheusEndpoint, { params }))
export const getPrometheusQueryData = (prometheusEndpoint, params, opts) =>
cancellableBackOffRequest(() => axios.get(prometheusEndpoint, { params, ...opts }))
.then(axiosResponse => axiosResponse.data)
.then(prometheusResponse => prometheusResponse.data)
.catch(error => {

View File

@ -16,10 +16,12 @@ import getDashboardValidationWarnings from '../queries/getDashboardValidationWar
import { convertObjectPropsToCamelCase } from '../../lib/utils/common_utils';
import { s__, sprintf } from '../../locale';
import { getDashboard, getPrometheusQueryData } from '../requests';
import { defaultTimeRange } from '~/vue_shared/constants';
import { ENVIRONMENT_AVAILABLE_STATE, OVERVIEW_DASHBOARD_PATH, VARIABLE_TYPES } from '../constants';
const axiosCancelToken = axios.CancelToken;
let cancelTokenSource;
function prometheusMetricQueryParams(timeRange) {
const { start, end } = convertToFixedRange(timeRange);
@ -491,12 +493,18 @@ export const fetchVariableMetricLabelValues = ({ state, commit }, { defaultQuery
// Panel Builder
export const setPanelPreviewTimeRange = ({ commit }, timeRange) => {
commit(types.SET_PANEL_PREVIEW_TIME_RANGE, timeRange);
};
export const fetchPanelPreview = ({ state, commit, dispatch }, panelPreviewYml) => {
if (!panelPreviewYml) {
return null;
}
commit(types.SET_PANEL_PREVIEW_IS_SHOWN, true);
commit(types.REQUEST_PANEL_PREVIEW, panelPreviewYml);
return axios
.post(state.panelPreviewEndpoint, { panel_yaml: panelPreviewYml })
.then(({ data }) => {
@ -510,7 +518,12 @@ export const fetchPanelPreview = ({ state, commit, dispatch }, panelPreviewYml)
};
export const fetchPanelPreviewMetrics = ({ state, commit }) => {
const defaultQueryParams = prometheusMetricQueryParams(defaultTimeRange);
if (cancelTokenSource) {
cancelTokenSource.cancel();
}
cancelTokenSource = axiosCancelToken.source();
const defaultQueryParams = prometheusMetricQueryParams(state.panelPreviewTimeRange);
state.panelPreviewGraphData.metrics.forEach((metric, index) => {
commit(types.REQUEST_PANEL_PREVIEW_METRIC_RESULT, { index });
@ -519,7 +532,9 @@ export const fetchPanelPreviewMetrics = ({ state, commit }) => {
if (metric.step) {
params.step = metric.step;
}
return getPrometheusQueryData(metric.prometheusEndpointPath, params)
return getPrometheusQueryData(metric.prometheusEndpointPath, params, {
cancelToken: cancelTokenSource.token,
})
.then(data => {
commit(types.RECEIVE_PANEL_PREVIEW_METRIC_RESULT_SUCCESS, { index, data });
})

View File

@ -57,3 +57,6 @@ export const RECEIVE_PANEL_PREVIEW_METRIC_RESULT_SUCCESS =
'RECEIVE_PANEL_PREVIEW_METRIC_RESULT_SUCCESS';
export const RECEIVE_PANEL_PREVIEW_METRIC_RESULT_FAILURE =
'RECEIVE_PANEL_PREVIEW_METRIC_RESULT_FAILURE';
export const SET_PANEL_PREVIEW_TIME_RANGE = 'SET_PANEL_PREVIEW_TIME_RANGE';
export const SET_PANEL_PREVIEW_IS_SHOWN = 'SET_PANEL_PREVIEW_IS_SHOWN';

View File

@ -264,4 +264,10 @@ export default {
metric.state = emptyStateFromError(error);
metric.result = null;
},
[types.SET_PANEL_PREVIEW_TIME_RANGE](state, timeRange) {
state.panelPreviewTimeRange = timeRange;
},
[types.SET_PANEL_PREVIEW_IS_SHOWN](state, isPreviewShown) {
state.panelPreviewIsShown = isPreviewShown;
},
};

View File

@ -1,6 +1,7 @@
import invalidUrl from '~/lib/utils/invalid_url';
import { timezones } from '../format_date';
import { dashboardEmptyStates } from '../constants';
import { defaultTimeRange } from '~/vue_shared/constants';
export default () => ({
// API endpoints
@ -66,6 +67,8 @@ export default () => ({
panelPreviewIsLoading: false,
panelPreviewGraphData: null,
panelPreviewError: null,
panelPreviewTimeRange: defaultTimeRange,
panelPreviewIsShown: false,
// Other project data
dashboardTimezone: timezones.LOCAL,

View File

@ -340,3 +340,11 @@
opacity: 0;
pointer-events: all;
}
.prometheus-panel-builder {
.preview-date-time-picker {
// same as in .dropdown-menu-toggle
// see app/assets/stylesheets/framework/dropdowns.scss
width: 160px;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -59,6 +59,38 @@ Follow the [HA Gitaly epic](https://gitlab.com/groups/gitlab-org/-/epics/1489)
for improvements including
[horizontally distributing reads](https://gitlab.com/groups/gitlab-org/-/epics/2013).
## Cluster or shard
Gitaly supports multiple models of scaling:
- Clustering using Gitaly Cluster, where each repository is stored on multiple Gitaly nodes in the
cluster. Read requests are distributed between repository replicas and write requests are
broadcast to repository replicas.
- Sharding using [repository storage paths](../repository_storage_paths.md), where each repository
is stored on the assigned Gitaly node. All requests are routed to this node.
| Cluster | Shard |
|---|---|
| ![Cluster example](img/cluster_example_v13_3.png) | ![Shard example](img/shard_example_v13_3.png) |
Generally, Gitaly Cluster can replace sharded configurations, at the expense of additional storage
needed to store each repository on multiple Gitaly nodes. The benefit of using Gitaly Cluster over
sharding is:
- Improved fault tolerance, because each Gitaly node has a copy of every repository.
- Improved resource utilization, reducing the need for over-provisioning for shard-specific peak
loads, because read loads are distributed across replicas.
- Manual rebalancing for performance is not required, because read loads are distributed across
replicas.
- Simpler management, because all Gitaly nodes are identical.
Under some workloads, CPU and memory requirements may require a large fleet of Gitaly nodes and it
can be uneconomical to have one to one replication factor.
A hybrid approach can be used in these instances, where each shard is configured as a smaller
cluster. [Variable replication factor](https://gitlab.com/groups/gitlab-org/-/epics/3372) is planned
to provide greater flexibility for extremely large GitLab instances.
## Requirements for configuring a Gitaly Cluster
The minimum recommended configuration for a Gitaly Cluster requires:
@ -142,6 +174,16 @@ database on the same PostgreSQL server if using
[Geo](../geo/replication/index.md). The replication state is internal to each instance
of GitLab and should not be replicated.
These instructions help set up a single PostgreSQL database, which creates a single point of
failure. For greater fault tolerance, the following options are available:
- For non-Geo installations, use one of the fault-tolerant
[PostgreSQL setups](../postgresql/index.md).
- For Geo instances, either:
- Set up a separate [PostgreSQL instance](https://www.postgresql.org/docs/11/high-availability.html).
- Use a cloud-managed PostgreSQL service. AWS
[Relational Database Service](https://aws.amazon.com/rds/)) is recommended.
To complete this section you will need:
- 1 Praefect node

View File

@ -449,8 +449,9 @@ you can pull from the Container Registry, but you cannot push.
1. This example uses the `aws` CLI. If you haven't configured the
CLI before, you have to configure your credentials by running `sudo aws configure`.
Because a non-admin user likely can't access the Container Registry folder,
ensure you use `sudo`. To check your credential configuration, run [`ls`]
to list all buckets.
ensure you use `sudo`. To check your credential configuration, run
[`ls`](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3/ls.html) to list
all buckets.
```shell
sudo aws --endpoint-url https://your-object-storage-backend.com s3 ls

View File

@ -8,8 +8,8 @@ guidance on getting started from the [command line](getting_started.md#command-l
The [example users query](#set-up-the-graphiql-explorer) looks for a subset of users in
a GitLab instance either by username or
[global ID](../../development/api_graphql_styleguide.md#exposing-global-ids). The query
includes:
[Global ID](../../development/api_graphql_styleguide.md#global-ids).
The query includes:
- [`pageInfo`](#pageinfo)
- [`nodes`](#nodes)

View File

@ -59,8 +59,9 @@ The GitLab GraphQL API can be used to perform:
- [Mutations](#mutations) for creating, updating, and deleting data.
NOTE: **Note:**
In the GitLab GraphQL API, `id` generally refers to a global ID,
which is an object identifier in the format of `gid://gitlab/Issue/123`.
In the GitLab GraphQL API, `id` refers to a
[Global ID](https://graphql.org/learn/global-object-identification/),
which is an object identifier in the format of `"gid://gitlab/Issue/123"`.
[GitLab's GraphQL Schema](reference/index.md) outlines which objects and fields are
available for clients to query and their corresponding data types.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

@ -79,7 +79,7 @@ POST /admin/ci/variables
| Attribute | Type | required | Description |
|-----------------|---------|----------|-----------------------|
| `key` | string | yes | The `key` of a variable. Max 255 characters, only `A-Z`, `a-z`, `0-9`, and `_` are allowed. |
| `value` | string | yes | The `value` of a variable. 10,000 characters allowed. [Since GitLab 13.3] |
| `value` | string | yes | The `value` of a variable. 10,000 characters allowed. [Since GitLab 13.3](https://gitlab.com/gitlab-org/gitlab/-/issues/220028) |
| `variable_type` | string | no | The type of a variable. Available types are: `env_var` (default) and `file`. |
| `protected` | boolean | no | Whether the variable is protected. |
| `masked` | boolean | no | Whether the variable is masked. |

View File

@ -104,33 +104,33 @@ The following table lists available parameters for jobs:
| Keyword | Description |
|:---------------------------------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [`script`](#script) | Shell script which is executed by Runner. |
| [`image`](#image) | Use Docker images. Also available: `image:name` and `image:entrypoint`. |
| [`services`](#services) | Use Docker services images. Also available: `services:name`, `services:alias`, `services:entrypoint`, and `services:command`. |
| [`before_script`](#before_script-and-after_script) | Override a set of commands that are executed before job. |
| [`after_script`](#before_script-and-after_script) | Override a set of commands that are executed after job. |
| [`stage`](#stage) | Defines a job stage (default: `test`). |
| [`only`](#onlyexcept-basic) | Limit when jobs are created. Also available: [`only:refs`, `only:kubernetes`, `only:variables`, and `only:changes`](#onlyexcept-advanced). |
| [`except`](#onlyexcept-basic) | Limit when jobs are not created. Also available: [`except:refs`, `except:kubernetes`, `except:variables`, and `except:changes`](#onlyexcept-advanced). |
| [`rules`](#rules) | List of conditions to evaluate and determine selected attributes of a job, and whether or not it's created. May not be used alongside `only`/`except`. |
| [`tags`](#tags) | List of tags which are used to select Runner. |
| [`allow_failure`](#allow_failure) | Allow job to fail. Failed job does not contribute to commit status. |
| [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. |
| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in` and `environment:action`. |
| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. |
| [`artifacts`](#artifacts) | List of files and directories to attach to a job on success. Also available: `artifacts:paths`, `artifacts:exclude`, `artifacts:expose_as`, `artifacts:name`, `artifacts:untracked`, `artifacts:when`, `artifacts:expire_in`, `artifacts:reports`, `artifacts:reports:codequality`, `artifacts:reports:junit`, `artifacts:reports:cobertura`, and `artifacts:reports:terraform`.<br><br>In GitLab [Enterprise Edition](https://about.gitlab.com/pricing/), these are available: `artifacts:reports:sast`, `artifacts:reports:dependency_scanning`, `artifacts:reports:container_scanning`, `artifacts:reports:dast`, `artifacts:reports:license_scanning`, `artifacts:reports:license_management` (removed in GitLab 13.0), `artifacts:reports:performance`, `artifacts:reports:load_performance`, and `artifacts:reports:metrics`. |
| [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. |
| [`before_script`](#before_script-and-after_script) | Override a set of commands that are executed before job. |
| [`cache`](#cache) | List of files that should be cached between subsequent runs. Also available: `cache:paths`, `cache:key`, `cache:untracked`, and `cache:policy`. |
| [`coverage`](#coverage) | Code coverage settings for a given job. |
| [`retry`](#retry) | When and how many times a job can be auto-retried in case of a failure. |
| [`timeout`](#timeout) | Define a custom job-level timeout that takes precedence over the project-wide setting. |
| [`parallel`](#parallel) | How many instances of a job should be run in parallel. |
| [`trigger`](#trigger) | Defines a downstream pipeline trigger. |
| [`include`](#include) | Allows this job to include external YAML files. Also available: `include:local`, `include:file`, `include:template`, and `include:remote`. |
| [`dependencies`](#dependencies) | Restrict which artifacts are passed to a specific job by providing a list of jobs to fetch artifacts from. |
| [`environment`](#environment) | Name of an environment to which the job deploys. Also available: `environment:name`, `environment:url`, `environment:on_stop`, `environment:auto_stop_in` and `environment:action`. |
| [`except`](#onlyexcept-basic) | Limit when jobs are not created. Also available: [`except:refs`, `except:kubernetes`, `except:variables`, and `except:changes`](#onlyexcept-advanced). |
| [`extends`](#extends) | Configuration entries that this job is going to inherit from. |
| [`pages`](#pages) | Upload the result of a job to use with GitLab Pages. |
| [`variables`](#variables) | Define job variables on a job level. |
| [`image`](#image) | Use Docker images. Also available: `image:name` and `image:entrypoint`. |
| [`include`](#include) | Allows this job to include external YAML files. Also available: `include:local`, `include:file`, `include:template`, and `include:remote`. |
| [`interruptible`](#interruptible) | Defines if a job can be canceled when made redundant by a newer run. |
| [`resource_group`](#resource_group) | Limit job concurrency. |
| [`only`](#onlyexcept-basic) | Limit when jobs are created. Also available: [`only:refs`, `only:kubernetes`, `only:variables`, and `only:changes`](#onlyexcept-advanced). |
| [`pages`](#pages) | Upload the result of a job to use with GitLab Pages. |
| [`parallel`](#parallel) | How many instances of a job should be run in parallel. |
| [`release`](#release) | Instructs the Runner to generate a [Release](../../user/project/releases/index.md) object. |
| [`resource_group`](#resource_group) | Limit job concurrency. |
| [`retry`](#retry) | When and how many times a job can be auto-retried in case of a failure. |
| [`rules`](#rules) | List of conditions to evaluate and determine selected attributes of a job, and whether or not it's created. May not be used alongside `only`/`except`. |
| [`services`](#services) | Use Docker services images. Also available: `services:name`, `services:alias`, `services:entrypoint`, and `services:command`. |
| [`stage`](#stage) | Defines a job stage (default: `test`). |
| [`tags`](#tags) | List of tags which are used to select Runner. |
| [`timeout`](#timeout) | Define a custom job-level timeout that takes precedence over the project-wide setting. |
| [`trigger`](#trigger) | Defines a downstream pipeline trigger. |
| [`variables`](#variables) | Define job variables on a job level. |
| [`when`](#when) | When to run job. Also available: `when:manual` and `when:delayed`. |
NOTE: **Note:**
Parameters `types` and `type` are [deprecated](#deprecated-parameters).

View File

@ -36,6 +36,19 @@ can be shared.
It is also possible to add a `private_token` to the querystring, or
add a `HTTP_PRIVATE_TOKEN` header.
## Global IDs
GitLab's GraphQL API uses Global IDs (i.e: `"gid://gitlab/MyObject/123"`)
and never database primary key IDs.
Global ID is [a standard](https://graphql.org/learn/global-object-identification/)
used for caching and fetching in client-side libraries.
See also:
- [Exposing Global IDs](#exposing-global-ids).
- [Mutation arguments](#object-identifier-arguments).
## Types
We use a code-first schema, and we declare what type everything is in Ruby.
@ -106,18 +119,28 @@ Further reading:
### Exposing Global IDs
When exposing an `ID` field on a type, we will by default try to
expose a global ID by calling `to_global_id` on the resource being
rendered.
In keeping with GitLab's use of [Global IDs](#global-ids), always convert
database primary key IDs into Global IDs when you expose them.
To override this behavior, you can implement an `id` method on the
type for which you are exposing an ID. Please make sure that when
exposing a `GraphQL::ID_TYPE` using a custom method that it is
globally unique.
All fields named `id` are
[converted automatically](https://gitlab.com/gitlab-org/gitlab/-/blob/b0f56e7/app/graphql/types/base_object.rb#L11-14)
into the object's Global ID.
The records that are exposing a `full_path` as an `ID_TYPE` are one of
these exceptions. Since the full path is a unique identifier for a
`Project` or `Namespace`.
Fields that are not named `id` need to be manually converted. We can do this using
[`Gitlab::GlobalID.build`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/global_id.rb),
or by calling `#to_global_id` on an object that has mixed in the
`GlobalID::Identification` module.
Using an example from
[`Types::Notes::DiscussionType`](https://gitlab.com/gitlab-org/gitlab/-/blob/3c95bd9/app/graphql/types/notes/discussion_type.rb#L24-26):
```ruby
field :reply_id, GraphQL::ID_TYPE
def reply_id
::Gitlab::GlobalId.build(object, id: object.reply_id)
end
```
### Connection Types
@ -654,15 +677,8 @@ the objects in question.
To find objects to display in a field, we can add resolvers to
`app/graphql/resolvers`.
Arguments can be defined within the resolver, those arguments will be
made available to the fields using the resolver. When exposing a model
that had an internal ID (`iid`), prefer using that in combination with
the namespace path as arguments in a resolver over a database
ID. Otherwise use a [globally unique ID](#exposing-global-ids).
We already have a `FullPathLoader` that can be included in other
resolvers to quickly find Projects and Namespaces which will have a
lot of dependent objects.
Arguments can be defined within the resolver in the same way as in a mutation.
See the [Mutation arguments](#object-identifier-arguments) section.
To limit the amount of queries performed, we can use `BatchLoader`.
@ -751,10 +767,6 @@ actions. In the same way a GET-request should not modify data, we
cannot modify data in a regular GraphQL-query. We can however in a
mutation.
To find objects for a mutation, arguments need to be specified. As with
[resolvers](#resolvers), prefer using internal ID or, if needed, a
global ID rather than the database ID.
### Building Mutations
Mutations live in `app/graphql/mutations` ideally grouped per
@ -809,10 +821,34 @@ If you need advice for mutation naming, canvass the Slack `#graphql` channel for
### Arguments
Arguments required by the mutation can be defined as arguments
required for a field. These will be wrapped up in an input type for
the mutation. For example, the `Mutations::MergeRequests::SetWip`
with GraphQL-name `MergeRequestSetWip` defines these arguments:
Arguments for a mutation are defined using `argument`.
Example:
```ruby
argument :my_arg, GraphQL::STRING_TYPE,
required: true,
description: "A description of the argument"
```
Each GraphQL `argument` defined will be passed to the `#resolve` method
of a mutation as keyword arguments.
Example:
```ruby
def resolve(my_arg:)
# Perform mutation ...
end
```
`graphql-ruby` will automatically wrap up arguments into an
[input type](https://graphql.org/learn/schema/#input-types).
For example, the
[`mergeRequestSetWip` mutation](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/merge_requests/set_wip.rb)
defines these arguments (some
[through inheritance](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/graphql/mutations/merge_requests/base.rb)):
```ruby
argument :project_path, GraphQL::ID_TYPE,
@ -832,12 +868,19 @@ argument :wip,
DESC
```
This would automatically generate an input type called
These arguments automatically generate an input type called
`MergeRequestSetWipInput` with the 3 arguments we specified and the
`clientMutationId`.
These arguments are then passed to the `resolve` method of a mutation
as keyword arguments.
### Object identifier arguments
In keeping with GitLab's use of [Global IDs](#global-ids), mutation
arguments should use Global IDs to identify an object and never database
primary key IDs.
Where an object has an `iid`, prefer to use the `full_path` or `group_path`
of its parent in combination with its `iid` as arguments to identify an
object rather than its `id`.
### Fields

View File

@ -136,7 +136,7 @@ at GitLab so far:
- Their availability:
- No "OOO"/"PTO"/"Parental Leave" in their GitLab or Slack status.
- No `:red_circle:`/`:palm_tree:`/`:beach:`/`:beach_umbrella:`/`:beach_with_umbrella:` emojis in GitLab or Slack status.
- [Experimental] Their timezone: people for which the local hour is between
- (Experimental) Their timezone: people for which the local hour is between
6 AM and 2 PM are eligible to be picked. This is to ensure they have a good
chance to get to perform a review during their current work day. The experimentation is tracked in
[this issue](https://gitlab.com/gitlab-org/quality/team-tasks/-/issues/563)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -194,6 +194,103 @@ The output from the above `terraform` commands should be viewable in the job log
See [this reference project](https://gitlab.com/nicholasklick/gitlab-terraform-aws) using GitLab and Terraform to deploy a basic AWS EC2 within a custom VPC.
## Copy Terraform state between backends
Terraform supports copying the state when the backend is changed or
reconfigured. This can be useful if you need to migrate from another backend to
GitLab managed Terraform state. It's also useful if you need to change the state
name as in the following example:
```shell
PROJECT_ID="<gitlab-project-id>"
TF_USERNAME="<gitlab-username>"
TF_PASSWORD="<gitlab-personal-access-token>"
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/old-state-name"
terraform init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
```
```plaintext
Initializing the backend...
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```
Now that `terraform init` has created a `.terraform/` directory that knows where
the old state is, you can tell it about the new location:
```shell
TF_ADDRESS="https://gitlab.com/api/v4/projects/${PROJECT_ID}/terraform/state/new-state-name"
terraform init \
-backend-config=address=${TF_ADDRESS} \
-backend-config=lock_address=${TF_ADDRESS}/lock \
-backend-config=unlock_address=${TF_ADDRESS}/lock \
-backend-config=username=${TF_USERNAME} \
-backend-config=password=${TF_PASSWORD} \
-backend-config=lock_method=POST \
-backend-config=unlock_method=DELETE \
-backend-config=retry_wait_min=5
```
```plaintext
Initializing the backend...
Backend configuration changed!
Terraform has detected that the configuration specified for the backend
has changed. Terraform will now check for existing state in the backends.
Acquiring state lock. This may take a few moments...
Do you want to copy existing state to the new backend?
Pre-existing state was found while migrating the previous "http" backend to the
newly configured "http" backend. No existing state was found in the newly
configured "http" backend. Do you want to copy this state to the new "http"
backend? Enter "yes" to copy and "no" to start with an empty state.
Enter a value: yes
Successfully configured the backend "http"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
```
If you type `yes`, it will copy your state from the old location to the new
location. You can then go back to running it from within GitLab CI.
## Output Terraform Plan information into a merge request
Using the [GitLab Terraform Report artifact](../../ci/pipelines/job_artifacts.md#artifactsreportsterraform),

View File

@ -16,13 +16,11 @@ RSpec.describe 'Projects > Settings > Packages', :js do
allow(Gitlab.config.packages).to receive(:enabled).and_return(true)
end
context 'without the need for a license' do
it 'displays the packages toggle button' do
visit edit_project_path(project)
it 'displays the packages toggle button' do
visit edit_project_path(project)
expect(page).to have_content('Packages')
expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true)
end
expect(page).to have_content('Packages')
expect(page).to have_selector('input[name="project[packages_enabled]"] + button', visible: true)
end
end

View File

@ -4,8 +4,10 @@ import { createStore } from '~/monitoring/stores';
import DashboardPanel from '~/monitoring/components/dashboard_panel.vue';
import * as types from '~/monitoring/stores/mutation_types';
import { metricsDashboardResponse } from '../fixture_data';
import { mockTimeRange } from '../mock_data';
import DashboardPanelBuilder from '~/monitoring/components/dashboard_panel_builder.vue';
import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_picker.vue';
const mockPanel = metricsDashboardResponse.dashboard.panel_groups[0].panels[0];
@ -37,6 +39,7 @@ describe('dashboard invalid url parameters', () => {
const findViewDocumentationBtn = () => wrapper.find({ ref: 'viewDocumentationBtn' });
const findOpenRepositoryBtn = () => wrapper.find({ ref: 'openRepositoryBtn' });
const findPanel = () => wrapper.find(DashboardPanel);
const findTimeRangePicker = () => wrapper.find(DateTimePicker);
beforeEach(() => {
mockShowToast = jest.fn();
@ -110,6 +113,31 @@ describe('dashboard invalid url parameters', () => {
});
});
describe('time range picker', () => {
it('is visible by default', () => {
expect(findTimeRangePicker().exists()).toBe(true);
});
it('when changed does not trigger data fetch unless preview panel button is clicked', () => {
// mimic initial state where SET_PANEL_PREVIEW_IS_SHOWN is set to false
store.commit(`monitoringDashboard/${types.SET_PANEL_PREVIEW_IS_SHOWN}`, false);
return wrapper.vm.$nextTick(() => {
expect(store.dispatch).not.toHaveBeenCalled();
});
});
it('when changed triggers data fetch if preview panel button is clicked', () => {
findForm().vm.$emit('submit', new Event('submit'));
store.commit(`monitoringDashboard/${types.SET_PANEL_PREVIEW_TIME_RANGE}`, mockTimeRange);
return wrapper.vm.$nextTick(() => {
expect(store.dispatch).toHaveBeenCalled();
});
});
});
describe('instructions card', () => {
const mockDocsPath = '/docs-path';
const mockProjectPath = '/project-path';
@ -146,6 +174,14 @@ describe('dashboard invalid url parameters', () => {
it('displays an empty dashboard panel', () => {
expect(findPanel().props('graphData')).toBe(null);
});
it('changing time range should not refetch data', () => {
store.commit(`monitoringDashboard/${types.SET_PANEL_PREVIEW_TIME_RANGE}`, mockTimeRange);
return wrapper.vm.$nextTick(() => {
expect(store.dispatch).not.toHaveBeenCalled();
});
});
});
describe('when panel data is available', () => {

View File

@ -1183,6 +1183,7 @@ describe('Monitoring store actions', () => {
mockYmlContent,
state,
[
{ type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true },
{ type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent },
{ type: types.RECEIVE_PANEL_PREVIEW_SUCCESS, payload: mockPanel },
],
@ -1200,6 +1201,7 @@ describe('Monitoring store actions', () => {
});
testAction(fetchPanelPreview, mockYmlContent, state, [
{ type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true },
{ type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent },
{ type: types.RECEIVE_PANEL_PREVIEW_FAILURE, payload: mockErrorMsg },
]);
@ -1209,6 +1211,7 @@ describe('Monitoring store actions', () => {
mock.onPost(panelPreviewEndpoint, { panel_yaml: mockYmlContent }).reply(500);
testAction(fetchPanelPreview, mockYmlContent, state, [
{ type: types.SET_PANEL_PREVIEW_IS_SHOWN, payload: true },
{ type: types.REQUEST_PANEL_PREVIEW, payload: mockYmlContent },
{
type: types.RECEIVE_PANEL_PREVIEW_FAILURE,

View File

@ -2361,14 +2361,12 @@ RSpec.describe API::Projects do
expect(project.packages_enabled).to be true
end
context 'without the need for a license' do
it 'disables project packages feature' do
put(api("/projects/#{project.id}", user), params: { packages_enabled: false })
it 'disables project packages feature' do
put(api("/projects/#{project.id}", user), params: { packages_enabled: false })
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.packages_enabled).to be false
expect(json_response['packages_enabled']).to eq(false)
end
expect(response).to have_gitlab_http_status(:ok)
expect(project.reload.packages_enabled).to be false
expect(json_response['packages_enabled']).to eq(false)
end
end