Skip to content
Snippets Groups Projects
Commit 48c3a57e authored by 🤖 GitLab Bot 🤖's avatar 🤖 GitLab Bot 🤖
Browse files

Add latest changes from gitlab-org/gitlab@master

parent a85d15fd
No related branches found
No related tags found
No related merge requests found
Showing
with 383 additions and 256 deletions
<script>
import { GlIcon, GlBadge, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import Visibility from 'visibilityjs';
import { createAlert } from '~/alert';
import {
issuableStatusText,
STATUS_CLOSED,
TYPE_EPIC,
TYPE_INCIDENT,
TYPE_ISSUE,
WORKSPACE_PROJECT,
} from '~/issues/constants';
import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import updateDescription from '~/issues/show/utils/update_description';
import { sanitize } from '~/lib/dompurify';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
......@@ -17,7 +9,6 @@ import Poll from '~/lib/utils/poll';
import { containsSensitiveToken, confirmSensitiveAction, i18n } from '~/lib/utils/secret_detection';
import { visitUrl } from '~/lib/utils/url_utility';
import { __, sprintf } from '~/locale';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
import { ISSUE_TYPE_PATH, INCIDENT_TYPE_PATH, POLLING_DELAY } from '../constants';
import eventHub from '../event_hub';
import getIssueStateQuery from '../queries/get_issue_state.query.graphql';
......@@ -28,24 +19,18 @@ import FormComponent from './form.vue';
import HeaderActions from './header_actions.vue';
import IssueHeader from './issue_header.vue';
import PinnedLinks from './pinned_links.vue';
import StickyHeader from './sticky_header.vue';
import TitleComponent from './title.vue';
export default {
WORKSPACE_PROJECT,
components: {
GlIcon,
GlBadge,
GlIntersectionObserver,
HeaderActions,
IssueHeader,
TitleComponent,
EditedComponent,
FormComponent,
PinnedLinks,
ConfidentialityBadge,
},
directives: {
GlTooltip: GlTooltipDirective,
StickyHeader,
},
props: {
author: {
......@@ -291,26 +276,13 @@ export default {
defaultErrorMessage() {
return sprintf(__('Error updating %{issuableType}'), { issuableType: this.issuableType });
},
isClosed() {
return this.issuableStatus === STATUS_CLOSED;
},
pinnedLinkClasses() {
return this.showTitleBorder
? 'gl-border-b-1 gl-border-b-gray-100 gl-border-b-solid gl-mb-6'
: '';
},
statusIcon() {
if (this.issuableType === TYPE_EPIC) {
return this.isClosed ? 'epic-closed' : 'epic';
}
return this.isClosed ? 'issue-closed' : 'issues';
},
statusVariant() {
return this.isClosed ? 'info' : 'success';
},
statusText() {
return issuableStatusText[this.issuableStatus];
},
shouldShowStickyHeader() {
return [TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC].includes(this.issuableType);
},
......@@ -569,60 +541,18 @@ export default {
</template>
</title-component>
<gl-intersection-observer
<sticky-header
v-if="shouldShowStickyHeader"
@appear="hideStickyHeader"
@disappear="showStickyHeader"
>
<transition name="issuable-header-slide">
<div
v-if="isStickyHeaderShowing"
class="issue-sticky-header gl-fixed gl-z-index-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
data-testid="issue-sticky-header"
>
<div
class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-gap-2 gl-mx-auto gl-px-5"
>
<gl-badge :variant="statusVariant">
<gl-icon :name="statusIcon" />
<span class="gl-display-none gl-sm-display-block gl-ml-2">{{
statusText
}}</span></gl-badge
>
<span
v-if="isLocked"
v-gl-tooltip.bottom
data-testid="locked"
class="issuable-warning-icon"
:title="__('This issue is locked. Only project members can comment.')"
>
<gl-icon name="lock" :aria-label="__('Locked')" />
</span>
<confidentiality-badge
v-if="isConfidential"
:issuable-type="issuableType"
:workspace-type="$options.WORKSPACE_PROJECT"
/>
<span
v-if="isHidden"
v-gl-tooltip.bottom
:title="__('This issue is hidden because its author has been banned')"
data-testid="hidden"
class="issuable-warning-icon"
>
<gl-icon name="spam" />
</span>
<a
href="#top"
class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-text-black-normal"
:title="state.titleText"
>
{{ state.titleText }}
</a>
</div>
</div>
</transition>
</gl-intersection-observer>
:is-confidential="isConfidential"
:is-hidden="isHidden"
:is-locked="isLocked"
:issuable-status="issuableStatus"
:issuable-type="issuableType"
:show="isStickyHeaderShowing"
:title="state.titleText"
@hide="hideStickyHeader"
@show="showStickyHeader"
/>
<slot name="header">
<issue-header
......
<script>
import { GlBadge, GlIcon, GlIntersectionObserver, GlTooltipDirective } from '@gitlab/ui';
import {
issuableStatusText,
STATUS_CLOSED,
TYPE_EPIC,
WORKSPACE_PROJECT,
} from '~/issues/constants';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
export default {
WORKSPACE_PROJECT,
components: {
ConfidentialityBadge,
GlBadge,
GlIcon,
GlIntersectionObserver,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
isConfidential: {
type: Boolean,
required: false,
default: false,
},
isHidden: {
type: Boolean,
required: false,
default: false,
},
isLocked: {
type: Boolean,
required: false,
default: false,
},
issuableStatus: {
type: String,
required: true,
},
issuableType: {
type: String,
required: true,
},
show: {
type: Boolean,
required: false,
default: false,
},
title: {
type: String,
required: true,
},
},
computed: {
isClosed() {
return this.issuableStatus === STATUS_CLOSED;
},
statusIcon() {
if (this.issuableType === TYPE_EPIC) {
return this.isClosed ? 'epic-closed' : 'epic';
}
return this.isClosed ? 'issue-closed' : 'issues';
},
statusText() {
return issuableStatusText[this.issuableStatus];
},
statusVariant() {
return this.isClosed ? 'info' : 'success';
},
},
};
</script>
<template>
<gl-intersection-observer @appear="$emit('hide')" @disappear="$emit('show')">
<transition name="issuable-header-slide">
<div
v-if="show"
class="issue-sticky-header gl-fixed gl-z-index-3 gl-bg-white gl-border-1 gl-border-b-solid gl-border-b-gray-100 gl-py-3"
data-testid="issue-sticky-header"
>
<div
class="issue-sticky-header-text gl-display-flex gl-align-items-center gl-gap-2 gl-mx-auto gl-px-5"
>
<gl-badge :variant="statusVariant">
<gl-icon :name="statusIcon" />
<span class="gl-display-none gl-sm-display-block gl-ml-2">{{ statusText }}</span>
</gl-badge>
<span
v-if="isLocked"
v-gl-tooltip.bottom
data-testid="locked"
class="issuable-warning-icon"
:title="__('This issue is locked. Only project members can comment.')"
>
<gl-icon name="lock" :aria-label="__('Locked')" />
</span>
<confidentiality-badge
v-if="isConfidential"
:issuable-type="issuableType"
:workspace-type="$options.WORKSPACE_PROJECT"
/>
<span
v-if="isHidden"
v-gl-tooltip.bottom
:title="__('This issue is hidden because its author has been banned')"
data-testid="hidden"
class="issuable-warning-icon"
>
<gl-icon name="spam" />
</span>
<a
href="#top"
class="gl-font-weight-bold gl-overflow-hidden gl-white-space-nowrap gl-text-overflow-ellipsis gl-my-0 gl-text-black-normal"
:title="title"
>
{{ title }}
</a>
</div>
</div>
</transition>
</gl-intersection-observer>
</template>
......@@ -60,7 +60,7 @@ def track!
def target_tag?
# There is no clear indication in the event structure when we delete a top-level manifest
# except existance of "tag" key
# except existence of "tag" key
event['target'].has_key?('tag')
end
......
......@@ -1654,6 +1654,7 @@ def predefined_variables
variables.append(key: 'CI_MERGE_REQUEST_ASSIGNEES', value: assignee_username_list) if assignees.present?
variables.append(key: 'CI_MERGE_REQUEST_MILESTONE', value: milestone.title) if milestone
variables.append(key: 'CI_MERGE_REQUEST_LABELS', value: label_names.join(',')) if labels.present?
variables.append(key: 'CI_MERGE_REQUEST_SQUASH_ON_MERGE', value: squash_on_merge?.to_s)
variables.concat(source_project_variables)
end
end
......@@ -2141,6 +2142,7 @@ def source_project_variables
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_PROJECT_PATH', value: source_project.full_path)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_PROJECT_URL', value: source_project.web_url)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME', value: source_branch.to_s)
variables.append(key: 'CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED', value: ProtectedBranch.protected?(source_project, source_branch).to_s)
end
end
......
......@@ -39,7 +39,7 @@ When onboarding, you must also specify your preference for the weekly four-hour
Available scheduled maintenance windows, performed outside standard working hours:
- APAC: Wednesday 1 AM - 5 AM UTC
- APAC: Wednesday 1 PM - 5 PM UTC
- EU: Tuesday 1 AM - 5 AM UTC
- AMER Option 1: Tuesday 7 AM - 11 AM UTC
- AMER Option 2: Sunday 9 PM - Monday 1 AM UTC
......@@ -261,9 +261,9 @@ To activate SAML for your GitLab Dedicated instance:
"admin_groups": [
// optional
],
"idp_cert_fingerprint": "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
"idp_cert_fingerprint": "43:51:43:a1:b5:fc:8b:b7:0a:3a:a9:b1:0f:66:73:a8",
"idp_sso_target_url": "https://login.example.com/idp",
"label": "IDP Name",
"label": "IDP Name",
"name_identifier_format": "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent",
"security": {
// optional
......
......@@ -195,7 +195,10 @@ This list of limitations only reflects the latest version of GitLab. If you are
- Pushing directly to a **secondary** site redirects (for HTTP) or proxies (for SSH) the request to the **primary** site instead of [handling it directly](https://gitlab.com/gitlab-org/gitlab/-/issues/1381). The limitation is that you cannot use Git over HTTP with credentials embedded in the URI, for example, `https://user:personal-access-token@secondary.tld`. For more information, see how to [use a Geo Site](replication/usage.md).
- The **primary** site has to be online for OAuth login to happen. Existing sessions and Git are not affected. Support for the **secondary** site to use an OAuth provider independent from the primary is [being planned](https://gitlab.com/gitlab-org/gitlab/-/issues/208465).
- The installation takes multiple manual steps that together can take about an hour depending on circumstances. Consider using [the GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to deploy and operate production GitLab instances based on our [Reference Architectures](../reference_architectures/index.md), including automation of common daily tasks. We are planning to [improve Geo's installation even further](https://gitlab.com/groups/gitlab-org/-/epics/1465).
- The installation takes multiple manual steps that together can take about an hour depending on circumstances. Consider using the
[GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) Terraform and Ansible scripts to deploy and operate production
GitLab instances based on our [Reference Architectures](../reference_architectures/index.md), including automation of common daily tasks.
[Epic 1465](https://gitlab.com/groups/gitlab-org/-/epics/1465) proposes to improve Geo installation even more.
- Real-time updates of issues/merge requests (for example, via long polling) doesn't work on the **secondary** site.
- Using Geo secondary sites to accelerate runners is not officially supported. Support for this functionality is planned and can be tracked in [epic 9779](https://gitlab.com/groups/gitlab-org/-/epics/9779). If a replication lag occurs between the primary and secondary site, and the pipeline ref is not available on the secondary site when the job is executed, the job will fail.
- GitLab Runners cannot register with a **secondary** site. Support for this is [planned for the future](https://gitlab.com/gitlab-org/gitlab/-/issues/3294).
......
......@@ -413,7 +413,7 @@ For more information, see our [handbook page](https://about.gitlab.com/handbook/
Testing occurs against all reference architectures and cloud providers in an automated and ad-hoc fashion. This is done by two tools:
- The [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) for building the environments.
- The [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) Terraform and Ansible scripts for building the environments.
- The [GitLab Performance Tool](https://gitlab.com/gitlab-org/quality/performance) for performance testing.
Network latency on the test environments between components on all Cloud Providers were measured at <5 ms. This is shared as an observation and not as an implicit recommendation.
......
......@@ -165,13 +165,15 @@ These variables are available when:
| `CI_MERGE_REQUEST_PROJECT_PATH` | 11.6 | all | The path of the project of the merge request. For example `namespace/awesome-project`. |
| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request. For example, `http://192.168.10.15:3000/namespace/awesome-project`. |
| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request. For example, `refs/merge-requests/1/head`. |
| `CI_MERGE_REQUEST_SQUASH_ON_MERGE` | 16.3 | all | `true` when the [squash on merge](../../user/project/merge_requests/squash_and_merge.md) option is set. |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED` | 16.3 | all | `true` when the source branch of the merge request is [protected](../../user/project/protected_branches.md). |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../pipelines/merged_results_pipelines.md). |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED` | 15.2 | all | The protection status for the target branch of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED` | 15.2 | all | `true` when the target branch of the merge request is [protected](../../user/project/protected_branches.md). |
| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../pipelines/merged_results_pipelines.md). |
| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request. |
| `CI_MERGE_REQUEST_EVENT_TYPE` | 12.3 | all | The event type of the merge request. Can be `detached`, `merged_result` or `merge_train`. |
......
......@@ -666,6 +666,37 @@ In this example:
- `user` has a value of `test-user`, because that is the default when not specified.
- `flags` has no value, because it is optional and has no default when not specified.
### Use `include:inputs` with multiple files
`inputs` must be specified separately for each included file. For example:
```yaml
include:
- component: gitlab.com/org/my-component@1.0
inputs:
stage: my-stage
- local: path/to/file.yml
inputs:
stage: my-stage
```
You can also include the same file multiple times, with different inputs.
For example:
```yaml
include:
- local: path/to/my-super-linter.yml
inputs:
type: docs
job-name: lint-docs
lint-path: "doc/"
- local: path/to/my-super-linter.yml
inputs:
type: yaml
job-name: lint-yaml
lint-path: "data/yaml/"
```
## Troubleshooting
### `Maximum of 150 nested includes are allowed!` error
......
......@@ -23,7 +23,7 @@ The following outline re-uses the [maturity metric](https://about.gitlab.com/dir
- [Release management](#release-management)
- [Enabled on GitLab.com](feature_flags/controls.md#enabling-a-feature-for-gitlabcom)
- Complete
- [Configurable by the GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit)
- [Validated by the Reference Architecture group and scaled out recommendations made](https://about.gitlab.com/handbook/engineering/quality/quality-engineering/self-managed-excellence/#reference-architectures)
- Lovable
- Enabled by default for the majority of users
......
......@@ -32,38 +32,12 @@ Amazon provides a managed Kubernetes service offering known as [Amazon Elastic K
## Available Infrastructure as Code for GitLab Cloud Native Hybrid
The [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) is an effort made by GitLab to create a multi-cloud, multi-GitLab (Linux package installation + Cloud Native Hybrid) toolkit to provision GitLab. GET is developed by GitLab developers and is open to community contributions. GET is where GitLab is investing its resources as the primary option for Infrastructure as Code, and is being actively used in production as a part of [GitLab Dedicated](../../subscriptions/gitlab_dedicated/index.md).
The [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) is a set of opinionated Terraform
and Ansible scripts. These scripts help with the deployment of Linux package or Cloud Native Hybrid environments on selected cloud providers and are used
by GitLab developers for [GitLab Dedicated](../../subscriptions/gitlab_dedicated/index.md) (for example).
For more information about the project, see [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md).
The [AWS Quick Start for GitLab Cloud Native Hybrid on EKS](https://aws-quickstart.github.io/quickstart-eks-gitlab/) is developed by AWS, GitLab, and the community that contributes to AWS Quick Starts, whether directly to the GitLab Quick Start or to the underlying Quick Start dependencies GitLab inherits (for example, EKS Quick Start).
GET is recommended for most deployments. The AWS Quick Start can be used if the IaC language of choice is CloudFormation, integration with AWS services like Control Tower is desired, or preference for a UI-driven configuration experience or when any aspect in the below table is an overriding concern.
NOTE:
This automation is in **[Open Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#open-beta)**. GitLab is working with AWS on resolving [the outstanding issues](https://github.com/aws-quickstart/quickstart-eks-gitlab/issues?q=is%3Aissue+is%3Aopen+%5BHL%5D) before it is fully released. You can subscribe to this issue to be notified of progress and release announcements: [AWS Quick Start for GitLab Cloud Native Hybrid on EKS Status: Beta](https://gitlab.com/gitlab-com/alliances/aws/public-tracker/-/issues/11).<br><br>
The Beta version deploys Aurora PostgreSQL, but the release version will deploy Amazon RDS PostgreSQL due to [known issues](https://gitlab.com/gitlab-com/alliances/aws/public-tracker/-/issues?label_name%5B%5D=AWS+Known+Issue) with Aurora. All performance testing results will also be redone after this change has been made.
| | [AWS Quick Start for GitLab Cloud Native Hybrid on EKS](https://aws-quickstart.github.io/quickstart-eks-gitlab/) | [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) |
| ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ |
| Overview and Vision | [AWS Quick Start](https://aws.amazon.com/solutions/implementations/amazon-eks/) | [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md) |
| Licensing | [Open Source (Apache 2.0)](https://github.com/aws-quickstart/quickstart-eks-gitlab/blob/main/LICENSE.txt) | [GitLab Enterprise Edition license](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/LICENSE) ([GitLab Premium tier](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/README.md)) |
| GitLab Support | [GitLab Beta Support](../../policy/experiment-beta-support.md#beta) | [GitLab GA Support](../../policy/experiment-beta-support.md#generally-available-ga) |
| GitLab Reference Architecture Compliant | Yes | Yes |
| GitLab Performance Tool (GPT) Tested | Yes | Yes |
| Amazon Well Architected Compliant | Yes<br />(via Quick Start program) | Critical portions <br />reviewed by AWS |
| Target Cloud Platforms | AWS | AWS, Google, Azure |
| IaC Languages | CloudFormation (Quick Starts) | Terraform, Ansible |
| Community Contributions and Participation (EcoSystem) | <u>GitLab QSG</u>: Getting Started<br /><u>For QSG Dependencies (for example, EKS)</u>: Substantial | Getting Started |
| Compatible with AWS Meta-Automation Services (via CloudFormation) | - [AWS Service Catalog](https://aws.amazon.com/servicecatalog/) (Direct Import)<br>- [ServiceNow via an AWS Service Catalog Connector](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/integrations-servicenow.html#integrations-servicenow)<br>- [Jira Service Manager via an AWS Service Catalog Connector](https://docs.aws.amazon.com/servicecatalog/latest/adminguide/integrations-jiraservicedesk.html#integrations-jiraservicedesk)<br>- [AWS Control Tower](https://docs.aws.amazon.com/controltower/) ([Integration](https://aws.amazon.com/blogs/infrastructure-and-automation/deploy-aws-quick-start-to-multiple-accounts-using-aws-control-tower/))<br>- Quick Starts<br>- [AWS SaaS Factory](https://aws.amazon.com/partners/programs/saas-factory/) | No |
| Results in a Ready-to-Use instance | Yes | Manual Actions or <br />Supplemental IaC Required |
| **<u>Configuration Features</u>** | | |
| Can deploy Linux package (non-Kubernetes) | No | Yes |
| Can deploy a single instance by using the Linux package (non-Kubernetes) | No | Yes |
| Complete Internal Encryption | 85%, Targeting 100% | Manual |
| AWS GovCloud Support | Yes | TBD |
| No Code Form-Based Deployment User Experience Available | Yes | No |
| Full IaC User Experience Available | Yes | Yes |
You can use the GitLab Environment Toolkit to deploy a Cloud Native Hybrid environment on AWS. However, it's not required and may not support every valid
permutation. That said, the scripts are presented as-is and you can adapt them accordingly.
### Two and Three Zone High Availability
......
......@@ -17,7 +17,7 @@ or use one of the following methods.
| [Helm chart](https://docs.gitlab.com/charts/) | A chart for installing a cloud-native version of GitLab and its components on Kubernetes. | Use if your infrastructure is on Kubernetes and you're familiar with how it works. Management, observability, and some concepts are different than traditional deployments.<br/>- Administration and troubleshooting requires Kubernetes knowledge.<br/>- It can be more expensive for smaller installations. The default installation requires more resources than a single node Linux package deployment, because most services are deployed in a redundant fashion.<br/><br/> |
| [Docker](docker.md) | The GitLab packages in a Docker container. | Use if you're familiar with Docker. |
| [Source](installation.md) | GitLab and its components from scratch. | Use if none of the previous methods are available for your platform. Can use for unsupported systems like \*BSD.|
| [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#documentation) | A set of automation tools. | Use to deploy a [reference architecture](../administration/reference_architectures/index.md) on most major cloud providers. Has some [limitations](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#missing-features-to-be-aware-of) and manual setup for production environments. |
| [GitLab Environment Toolkit (GET)](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#documentation) | A set of opinionated Terraform and Ansible scripts. | Use to deploy a [reference architecture](../administration/reference_architectures/index.md) on selected major cloud providers. Has some [limitations](https://gitlab.com/gitlab-org/gitlab-environment-toolkit#missing-features-to-be-aware-of) and manual setup for production environments. |
| [GitLab Operator](https://docs.gitlab.com/operator/) | An installation and management method that follows the [Kubernetes Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/). | Use to run GitLab in an [OpenShift](openshift_and_gitlab/index.md) environment. |
## Unsupported Linux distributions and Unix-like operating systems
......
......@@ -37,7 +37,12 @@ def error_message
def interpolate!
return @errors.push(config.error) unless config.valid?
return @errors.push('unknown input arguments') if inputs_without_header?
if inputs_without_header?
return @errors.push(
_('Given inputs not defined in the `spec` section of the included configuration file'))
end
return @result ||= config.content unless config.has_header?
return @errors.concat(header.errors) unless header.valid?
......
......@@ -21727,6 +21727,9 @@ msgstr ""
msgid "Given epic is already related to this epic."
msgstr ""
 
msgid "Given inputs not defined in the `spec` section of the included configuration file"
msgstr ""
msgid "Global SAML group membership lock"
msgstr ""
 
import { GlIcon, GlIntersectionObserver } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import { createAlert } from '~/alert';
import {
issuableStatusText,
STATUS_CLOSED,
STATUS_OPEN,
STATUS_REOPENED,
TYPE_EPIC,
TYPE_INCIDENT,
TYPE_ISSUE,
} from '~/issues/constants';
import { TYPE_EPIC, TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import IssuableApp from '~/issues/show/components/app.vue';
import DescriptionComponent from '~/issues/show/components/description.vue';
import EditedComponent from '~/issues/show/components/edited.vue';
import FormComponent from '~/issues/show/components/form.vue';
import StickyHeader from '~/issues/show/components/sticky_header.vue';
import TitleComponent from '~/issues/show/components/title.vue';
import IncidentTabs from '~/issues/show/components/incidents/incident_tabs.vue';
import PinnedLinks from '~/issues/show/components/pinned_links.vue';
......@@ -25,7 +16,6 @@ import eventHub from '~/issues/show/event_hub';
import axios from '~/lib/utils/axios_utils';
import { HTTP_STATUS_OK, HTTP_STATUS_UNAUTHORIZED } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
import {
appProps,
initialRequest,
......@@ -45,22 +35,15 @@ describe('Issuable output', () => {
let axiosMock;
let wrapper;
const findStickyHeader = () => wrapper.findByTestId('issue-sticky-header');
const findLockedBadge = () => wrapper.findByTestId('locked');
const findHiddenBadge = () => wrapper.findByTestId('hidden');
const findConfidentialBadge = () => wrapper.findComponent(ConfidentialityBadge);
const findStickyHeader = () => wrapper.findComponent(StickyHeader);
const findTitle = () => wrapper.findComponent(TitleComponent);
const findDescription = () => wrapper.findComponent(DescriptionComponent);
const findEdited = () => wrapper.findComponent(EditedComponent);
const findForm = () => wrapper.findComponent(FormComponent);
const findPinnedLinks = () => wrapper.findComponent(PinnedLinks);
const createComponent = ({ props = {}, options = {}, data = {} } = {}) => {
wrapper = shallowMountExtended(IssuableApp, {
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
const createComponent = ({ props = {}, options = {} } = {}) => {
wrapper = shallowMount(IssuableApp, {
propsData: { ...appProps, ...props },
provide: {
fullPath: 'gitlab-org/incidents',
......@@ -70,11 +53,6 @@ describe('Issuable output', () => {
HighlightBar: true,
IncidentTabs: true,
},
data() {
return {
...data,
};
},
...options,
});
......@@ -82,13 +60,6 @@ describe('Issuable output', () => {
return waitForPromises();
};
const createComponentAndScroll = async (props) => {
await createComponent({ props });
global.pageYOffset = 100;
wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
await nextTick();
};
const emitHubEvent = (event) => {
eventHub.$emit(event);
return waitForPromises();
......@@ -333,104 +304,36 @@ describe('Issuable output', () => {
describe('when title is in view', () => {
it('is not shown', async () => {
await createComponent();
wrapper.findComponent(GlIntersectionObserver).vm.$emit('disappear');
expect(findStickyHeader().exists()).toBe(false);
wrapper.findComponent(StickyHeader).vm.$emit('show');
expect(findStickyHeader().props('show')).toBe(false);
});
});
describe('when title is not in view', () => {
it.each([TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC])(
'shows with title when issuableType="%s"',
async (issuableType) => {
await createComponentAndScroll({ issuableType });
expect(findStickyHeader().text()).toContain('this is a title');
},
);
it.each`
issuableType | issuableStatus | statusIcon
${TYPE_INCIDENT} | ${STATUS_OPEN} | ${'issues'}
${TYPE_INCIDENT} | ${STATUS_CLOSED} | ${'issue-closed'}
${TYPE_ISSUE} | ${STATUS_OPEN} | ${'issues'}
${TYPE_ISSUE} | ${STATUS_CLOSED} | ${'issue-closed'}
${TYPE_EPIC} | ${STATUS_OPEN} | ${'epic'}
${TYPE_EPIC} | ${STATUS_CLOSED} | ${'epic-closed'}
`(
'shows with state icon "$statusIcon" for $issuableType when status is $issuableStatus',
async ({ issuableType, issuableStatus, statusIcon }) => {
await createComponentAndScroll({ issuableType, issuableStatus });
expect(findStickyHeader().findComponent(GlIcon).props('name')).toBe(statusIcon);
},
);
it.each`
title | issuableStatus
${'shows with Open when status is opened'} | ${STATUS_OPEN}
${'shows with Closed when status is closed'} | ${STATUS_CLOSED}
${'shows with Open when status is reopened'} | ${STATUS_REOPENED}
`('$title', async ({ issuableStatus }) => {
await createComponentAndScroll({ issuableStatus });
expect(findStickyHeader().text()).toContain(issuableStatusText[issuableStatus]);
});
describe.each([TYPE_INCIDENT, TYPE_ISSUE, TYPE_EPIC])(
'when title is not in view',
(issuableType) => {
beforeEach(async () => {
await createComponent({ props: { issuableType } });
it.each`
title | isConfidential
${'does not show confidential badge when issue is not confidential'} | ${false}
${'shows confidential badge when issue is confidential'} | ${true}
`('$title', async ({ isConfidential }) => {
await createComponentAndScroll({ isConfidential });
const confidentialEl = findConfidentialBadge();
expect(confidentialEl.exists()).toBe(isConfidential);
if (isConfidential) {
expect(confidentialEl.props()).toMatchObject({
workspaceType: 'project',
issuableType: 'issue',
});
}
});
global.pageYOffset = 100;
wrapper.findComponent(StickyHeader).vm.$emit('show');
await nextTick();
});
it.each`
title | isLocked
${'does not show locked badge when issue is not locked'} | ${false}
${'shows locked badge when issue is locked'} | ${true}
`('$title', async ({ isLocked }) => {
await createComponentAndScroll({ isLocked });
const lockedBadge = findLockedBadge();
expect(lockedBadge.exists()).toBe(isLocked);
if (isLocked) {
expect(lockedBadge.attributes('title')).toBe(
'This issue is locked. Only project members can comment.',
);
expect(getBinding(lockedBadge.element, 'gl-tooltip')).not.toBeUndefined();
}
});
it(`shows when issuableType=${issuableType}`, () => {
expect(findStickyHeader().props('show')).toBe(true);
});
it.each`
title | isHidden
${'does not show hidden badge when issue is not hidden'} | ${false}
${'shows hidden badge when issue is hidden'} | ${true}
`('$title', async ({ isHidden }) => {
await createComponentAndScroll({ isHidden });
const hiddenBadge = findHiddenBadge();
expect(hiddenBadge.exists()).toBe(isHidden);
if (isHidden) {
expect(hiddenBadge.attributes('title')).toBe(
'This issue is hidden because its author has been banned',
);
expect(getBinding(hiddenBadge.element, 'gl-tooltip')).not.toBeUndefined();
}
});
});
it('hides again when title is back in view', async () => {
wrapper.findComponent(StickyHeader).vm.$emit('hide');
await nextTick();
expect(findStickyHeader().props('show')).toBe(false);
});
},
);
});
describe('Composable description component', () => {
......
import { GlIcon } from '@gitlab/ui';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import {
issuableStatusText,
STATUS_CLOSED,
STATUS_OPEN,
STATUS_REOPENED,
TYPE_EPIC,
TYPE_INCIDENT,
TYPE_ISSUE,
} from '~/issues/constants';
import StickyHeader from '~/issues/show/components/sticky_header.vue';
import ConfidentialityBadge from '~/vue_shared/components/confidentiality_badge.vue';
describe('StickyHeader component', () => {
let wrapper;
const findConfidentialBadge = () => wrapper.findComponent(ConfidentialityBadge);
const findHiddenBadge = () => wrapper.findByTestId('hidden');
const findLockedBadge = () => wrapper.findByTestId('locked');
const createComponent = (props = {}) => {
wrapper = shallowMountExtended(StickyHeader, {
directives: {
GlTooltip: createMockDirective('gl-tooltip'),
},
propsData: {
issuableStatus: STATUS_OPEN,
issuableType: TYPE_ISSUE,
show: true,
title: 'A sticky issue',
...props,
},
});
};
it.each`
issuableType | issuableStatus | statusIcon
${TYPE_INCIDENT} | ${STATUS_OPEN} | ${'issues'}
${TYPE_INCIDENT} | ${STATUS_CLOSED} | ${'issue-closed'}
${TYPE_ISSUE} | ${STATUS_OPEN} | ${'issues'}
${TYPE_ISSUE} | ${STATUS_CLOSED} | ${'issue-closed'}
${TYPE_EPIC} | ${STATUS_OPEN} | ${'epic'}
${TYPE_EPIC} | ${STATUS_CLOSED} | ${'epic-closed'}
`(
'shows with state icon "$statusIcon" for $issuableType when status is $issuableStatus',
({ issuableType, issuableStatus, statusIcon }) => {
createComponent({ issuableType, issuableStatus });
expect(wrapper.findComponent(GlIcon).props('name')).toBe(statusIcon);
},
);
it.each`
title | issuableStatus
${'shows with Open when status is opened'} | ${STATUS_OPEN}
${'shows with Closed when status is closed'} | ${STATUS_CLOSED}
${'shows with Open when status is reopened'} | ${STATUS_REOPENED}
`('$title', ({ issuableStatus }) => {
createComponent({ issuableStatus });
expect(wrapper.text()).toContain(issuableStatusText[issuableStatus]);
});
it.each`
title | isConfidential
${'does not show confidential badge when issue is not confidential'} | ${false}
${'shows confidential badge when issue is confidential'} | ${true}
`('$title', ({ isConfidential }) => {
createComponent({ isConfidential });
const confidentialBadge = findConfidentialBadge();
expect(confidentialBadge.exists()).toBe(isConfidential);
if (isConfidential) {
expect(confidentialBadge.props()).toMatchObject({
workspaceType: 'project',
issuableType: 'issue',
});
}
});
it.each`
title | isLocked
${'does not show locked badge when issue is not locked'} | ${false}
${'shows locked badge when issue is locked'} | ${true}
`('$title', ({ isLocked }) => {
createComponent({ isLocked });
const lockedBadge = findLockedBadge();
expect(lockedBadge.exists()).toBe(isLocked);
if (isLocked) {
expect(lockedBadge.attributes('title')).toBe(
'This issue is locked. Only project members can comment.',
);
expect(getBinding(lockedBadge.element, 'gl-tooltip')).not.toBeUndefined();
}
});
it.each`
title | isHidden
${'does not show hidden badge when issue is not hidden'} | ${false}
${'shows hidden badge when issue is hidden'} | ${true}
`('$title', ({ isHidden }) => {
createComponent({ isHidden });
const hiddenBadge = findHiddenBadge();
expect(hiddenBadge.exists()).toBe(isHidden);
if (isHidden) {
expect(hiddenBadge.attributes('title')).toBe(
'This issue is hidden because its author has been banned',
);
expect(getBinding(hiddenBadge.element, 'gl-tooltip')).not.toBeUndefined();
}
});
it('shows with title', () => {
createComponent();
const title = wrapper.find('a');
expect(title.text()).toContain('A sticky issue');
expect(title.attributes('href')).toBe('#top');
});
});
......@@ -57,7 +57,8 @@
expect(subject).not_to be_valid
expect(subject.error_message).to eq subject.errors.first
expect(subject.errors).to include('unknown input arguments')
expect(subject.errors).to include('Given inputs not defined in the `spec` section of the included ' \
'configuration file')
end
end
......
......@@ -108,12 +108,17 @@
'CI_MERGE_REQUEST_SOURCE_PROJECT_URL' => merge_request.source_project.web_url,
'CI_MERGE_REQUEST_SOURCE_BRANCH_NAME' => merge_request.source_branch.to_s,
'CI_MERGE_REQUEST_SOURCE_BRANCH_SHA' => '',
'CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED' => ProtectedBranch.protected?(
merge_request.source_project,
merge_request.source_branch
).to_s,
'CI_MERGE_REQUEST_TITLE' => merge_request.title,
'CI_MERGE_REQUEST_ASSIGNEES' => merge_request.assignee_username_list,
'CI_MERGE_REQUEST_MILESTONE' => milestone.title,
'CI_MERGE_REQUEST_LABELS' => labels.map(&:title).sort.join(','),
'CI_MERGE_REQUEST_EVENT_TYPE' => 'detached',
'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true))
'CI_OPEN_MERGE_REQUESTS' => merge_request.to_reference(full: true)),
'CI_MERGE_REQUEST_SQUASH_ON_MERGE' => merge_request.squash_on_merge?.to_s
end
it 'exposes diff variables' do
......
......@@ -57,10 +57,26 @@ def self.name
it 'enqueues jobs' do
expect(worker_class)
.to receive(:bulk_perform_async)
.with([[:arg], [:arg], [:arg]])
.with([[:arg], [:arg], [:arg]]).and_call_original
expect(Sidekiq::Client).to receive(:push_bulk)
perform_with_capacity
end
context 'when max_running_jobs is 0' do
let(:max_running_jobs) { 0 }
it 'does not enqueue jobs' do
expect(worker_class)
.to receive(:bulk_perform_async)
.with([]).and_call_original
expect(Sidekiq::Client).not_to receive(:push_bulk)
perform_with_capacity
end
end
end
describe '#perform' do
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment