Commit b677925e authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents a8145ff5 8a4c87fe
...@@ -32,7 +32,7 @@ export default { ...@@ -32,7 +32,7 @@ export default {
</script> </script>
<template> <template>
<nav class="ide-activity-bar"> <nav class="ide-activity-bar" data-testid="left-sidebar">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li> <li>
<button <button
......
...@@ -44,7 +44,7 @@ export default { ...@@ -44,7 +44,7 @@ export default {
<nav-dropdown /> <nav-dropdown />
<slot name="header"></slot> <slot name="header"></slot>
</header> </header>
<div class="ide-tree-body h-100"> <div class="ide-tree-body h-100" data-testid="ide-tree-body">
<template v-if="currentTree.tree.length"> <template v-if="currentTree.tree.length">
<file-tree <file-tree
v-for="file in currentTree.tree" v-for="file in currentTree.tree"
......
...@@ -152,6 +152,7 @@ export default { ...@@ -152,6 +152,7 @@ export default {
v-model.trim="entryName" v-model.trim="entryName"
type="text" type="text"
class="form-control" class="form-control"
data-testid="file-name-field"
data-qa-selector="file_name_field" data-qa-selector="file_name_field"
:placeholder="placeholder" :placeholder="placeholder"
/> />
......
<script>
import { n__ } from '~/locale';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '../constants';
export default {
name: 'PackageTitle',
components: {
TitleArea,
MetadataItem,
},
props: {
packagesCount: {
type: Number,
required: false,
default: null,
},
packageHelpUrl: {
type: String,
required: true,
},
},
computed: {
showPackageCount() {
return Number.isInteger(this.packagesCount);
},
packageAmountText() {
return n__(`%d Package`, `%d Packages`, this.packagesCount);
},
infoMessages() {
return [{ text: LIST_INTRO_TEXT, link: this.packageHelpUrl }];
},
},
i18n: {
LIST_TITLE_TEXT,
},
};
</script>
<template>
<title-area :title="$options.i18n.LIST_TITLE_TEXT" :info-messages="infoMessages">
<template #metadata_amount>
<metadata-item v-if="showPackageCount" icon="package" :text="packageAmountText" />
</template>
</title-area>
</template>
...@@ -3,13 +3,14 @@ import { mapActions, mapState } from 'vuex'; ...@@ -3,13 +3,14 @@ import { mapActions, mapState } from 'vuex';
import { GlEmptyState, GlTab, GlTabs, GlLink, GlSprintf } from '@gitlab/ui'; import { GlEmptyState, GlTab, GlTabs, GlLink, GlSprintf } from '@gitlab/ui';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import createFlash from '~/flash'; import createFlash from '~/flash';
import { historyReplaceState } from '~/lib/utils/common_utils';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants';
import PackageFilter from './packages_filter.vue'; import PackageFilter from './packages_filter.vue';
import PackageList from './packages_list.vue'; import PackageList from './packages_list.vue';
import PackageSort from './packages_sort.vue'; import PackageSort from './packages_sort.vue';
import { PACKAGE_REGISTRY_TABS, DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants'; import { PACKAGE_REGISTRY_TABS, DELETE_PACKAGE_SUCCESS_MESSAGE } from '../constants';
import PackagesComingSoon from '../coming_soon/packages_coming_soon.vue'; import PackagesComingSoon from '../coming_soon/packages_coming_soon.vue';
import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages/shared/constants'; import PackageTitle from './package_title.vue';
import { historyReplaceState } from '~/lib/utils/common_utils';
export default { export default {
components: { components: {
...@@ -22,6 +23,7 @@ export default { ...@@ -22,6 +23,7 @@ export default {
PackageList, PackageList,
PackageSort, PackageSort,
PackagesComingSoon, PackagesComingSoon,
PackageTitle,
}, },
computed: { computed: {
...mapState({ ...mapState({
...@@ -30,6 +32,8 @@ export default { ...@@ -30,6 +32,8 @@ export default {
comingSoon: state => state.config.comingSoon, comingSoon: state => state.config.comingSoon,
filterQuery: state => state.filterQuery, filterQuery: state => state.filterQuery,
selectedType: state => state.selectedType, selectedType: state => state.selectedType,
packageHelpUrl: state => state.config.packageHelpUrl,
packagesCount: state => state.pagination?.total,
}), }),
tabsToRender() { tabsToRender() {
return PACKAGE_REGISTRY_TABS; return PACKAGE_REGISTRY_TABS;
...@@ -89,12 +93,15 @@ export default { ...@@ -89,12 +93,15 @@ export default {
</script> </script>
<template> <template>
<div>
<package-title :package-help-url="packageHelpUrl" :packages-count="packagesCount" />
<gl-tabs @input="tabChanged"> <gl-tabs @input="tabChanged">
<template #tabs-end> <template #tabs-end>
<div <div
class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
> >
<package-filter class="mr-1" @filter="requestPackagesList" /> <package-filter class="gl-mr-2" @filter="requestPackagesList" />
<package-sort @sort:changed="requestPackagesList" /> <package-sort @sort:changed="requestPackagesList" />
</div> </div>
</template> </template>
...@@ -124,4 +131,5 @@ export default { ...@@ -124,4 +131,5 @@ export default {
/> />
</gl-tab> </gl-tab>
</gl-tabs> </gl-tabs>
</div>
</template> </template>
...@@ -86,3 +86,9 @@ export const PACKAGE_REGISTRY_TABS = [ ...@@ -86,3 +86,9 @@ export const PACKAGE_REGISTRY_TABS = [
type: PackageType.PYPI, type: PackageType.PYPI,
}, },
]; ];
export const LIST_TITLE_TEXT = s__('PackageRegistry|Package Registry');
export const LIST_INTRO_TEXT = s__(
'PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}',
);
...@@ -53,7 +53,8 @@ module PackagesHelper ...@@ -53,7 +53,8 @@ module PackagesHelper
page_type: type, page_type: type,
empty_list_help_url: help_page_path('user/packages/package_registry/index'), empty_list_help_url: help_page_path('user/packages/package_registry/index'),
empty_list_illustration: image_path('illustrations/no-packages.svg'), empty_list_illustration: image_path('illustrations/no-packages.svg'),
coming_soon_json: packages_coming_soon_data(resource).to_json coming_soon_json: packages_coming_soon_data(resource).to_json,
package_help_url: help_page_path('user/packages/index')
} }
end end
end end
...@@ -82,8 +82,7 @@ module Ci ...@@ -82,8 +82,7 @@ module Ci
schedule_head_pipeline_update if pipeline.persisted? schedule_head_pipeline_update if pipeline.persisted?
# If pipeline is not persisted, try to recover IID # If pipeline is not persisted, try to recover IID
pipeline.reset_project_iid unless pipeline.persisted? || pipeline.reset_project_iid unless pipeline.persisted?
Feature.disabled?(:ci_pipeline_rewind_iid, project, default_enabled: true)
pipeline pipeline
end end
......
---
title: Add a title section to the Package Registry UI
merge_request: 42963
author:
type: changed
---
name: ci_pipeline_rewind_iid
introduced_by_url:
rollout_issue_url:
group:
type: development
default_enabled: true
--- ---
name: settings_operations_prometheus_service name: settings_operations_prometheus_service
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24727 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24296
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258560 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/258560
group: group::health group: group::health
type: development type: development
......
...@@ -24,7 +24,6 @@ GET /projects/:id/registry/repositories ...@@ -24,7 +24,6 @@ GET /projects/:id/registry/repositories
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. | | `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. | | `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). | | `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell ```shell
...@@ -68,7 +67,6 @@ GET /groups/:id/registry/repositories ...@@ -68,7 +67,6 @@ GET /groups/:id/registry/repositories
| --------- | ---- | -------- | ----------- | | --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. | | `id` | integer/string | yes | The ID or [URL-encoded path of the group](README.md#namespaced-path-encoding) accessible by the authenticated user. |
| `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. | | `tags` | boolean | no | If the parameter is included as true, each repository will include an array of `"tags"` in the response. |
| `name` | string | no | Returns a list of repositories with a name that matches the value. ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/29763) in GitLab 13.0). |
| `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). | | `tags_count` | boolean | no | If the parameter is included as true, each repository will include `"tags_count"` in the response ([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/32141) in GitLab 13.1). |
```shell ```shell
......
...@@ -332,7 +332,7 @@ applications. ...@@ -332,7 +332,7 @@ applications.
| `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From GitLab 11.11, used to set a username to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. | | `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME` | From GitLab 11.11, used to set a username to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD`. |
| `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From GitLab 11.11, used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. | | `AUTO_DEVOPS_CHART_REPOSITORY_PASSWORD` | From GitLab 11.11, used to set a password to connect to the Helm repository. Defaults to no credentials. Also set `AUTO_DEVOPS_CHART_REPOSITORY_USERNAME`. |
| `AUTO_DEVOPS_DEPLOY_DEBUG` | From GitLab 13.1, if this variable is present, Helm will output debug logs. | | `AUTO_DEVOPS_DEPLOY_DEBUG` | From GitLab 13.1, if this variable is present, Helm will output debug logs. |
| `AUTO_DEVOPS_ALLOW_TO_FORCE_DEPLOY_V<N>` | From [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) v1.0.0, if this variable is present, a new major version of chart is forcibly deployed. [More details](upgrading_chart.md#ignore-warning-and-continue-deploying) | | `AUTO_DEVOPS_ALLOW_TO_FORCE_DEPLOY_V<N>` | From [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) v1.0.0, if this variable is present, a new major version of chart is forcibly deployed. For more information, see [Ignore warnings and continue deploying](upgrading_auto_deploy_dependencies.md#ignore-warnings-and-continue-deploying). |
| `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` | From GitLab 12.5, used in combination with [ModSecurity feature flag](../../user/clusters/applications.md#web-application-firewall-modsecurity) to toggle [ModSecurity's `SecRuleEngine`](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecRuleEngine) behavior. Defaults to `DetectionOnly`. | | `AUTO_DEVOPS_MODSECURITY_SEC_RULE_ENGINE` | From GitLab 12.5, used in combination with [ModSecurity feature flag](../../user/clusters/applications.md#web-application-firewall-modsecurity) to toggle [ModSecurity's `SecRuleEngine`](https://github.com/SpiderLabs/ModSecurity/wiki/Reference-Manual-(v2.x)#SecRuleEngine) behavior. Defaults to `DetectionOnly`. |
| `BUILDPACK_URL` | Buildpack's full URL. Can point to either [a Git repository URL or a tarball URL](#custom-buildpacks). | | `BUILDPACK_URL` | Buildpack's full URL. Can point to either [a Git repository URL or a tarball URL](#custom-buildpacks). |
| `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments). | | `CANARY_ENABLED` | From GitLab 11.0, used to define a [deploy policy for canary environments](#deploy-policy-for-canary-environments). |
......
...@@ -466,7 +466,7 @@ application runs. ...@@ -466,7 +466,7 @@ application runs.
### Upgrade auto-deploy-app Chart ### Upgrade auto-deploy-app Chart
You can upgrade auto-deploy-app chart by following the [upgrade guide](upgrading_chart.md). You can upgrade the auto-deploy-app chart by following the [upgrade guide](upgrading_auto_deploy_dependencies.md).
### Workers ### Workers
......
---
stage: Release
group: Progressive Delivery
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
type: reference
---
# Upgrading deployments for newer Auto Deploy dependencies (Auto Deploy template, auto-deploy-image and auto-deploy-app chart)
[Auto Deploy](stages.md#auto-deploy) is a feature that deploys your application to a Kubernetes cluster.
It consists of several dependencies:
- [Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml) is a set of pipeline jobs and scripts that makes use of `auto-deploy-image`.
- [`auto-deploy-image`](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) is the executable image that communicates with the Kubernetes cluster.
- [`auto-deploy-app chart`](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app) is the Helm chart for deploying your application.
The `auto-deploy-image` and `auto-deploy-app` charts use [Semantic Versioning](https://semver.org/).
By default, your Auto DevOps project keeps using the stable and non-breaking version.
However, these dependencies could be upgraded in a major version release of GitLab
with breaking changes requiring you to upgrade your deployments.
This guide explains how to upgrade your deployments with newer or different major versions of Auto Deploy dependencies.
## Verify dependency versions
The process to check the current versions differs depending on which template you
are using. First verify which template is in use:
- For self-managed instances, the [stable Auto Deploy template bundled with the GitLab package](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
is being used.
- [The GitLab.com stable Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml)
is being used if **one** of the following is true:
- Your Auto DevOps project doesn't have a `.gitlab-ci.yml` file.
- Your Auto DevOps project has a `.gitlab-ci.yml` and [includes](../../ci/yaml/README.md#includetemplate)
the `Auto-DevOps.gitlab-ci.yml` template.
- [The latest Auto Deploy template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml)
is being used if **both** of the following is true:
- Your Auto DevOps project has a `.gitlab-ci.yml` file and [includes](../../ci/yaml/README.md#includetemplate)
the `Auto-DevOps.gitlab-ci.yml` template.
- It also includes [the latest Auto Deploy template](#early-adopters)
If you know what template is being used:
- The `auto-deploy-image` version is in the template (for example `auto-deploy-image:v1.0.3`).
- The `auto-deploy-app` chart version is [in the auto-deploy-image repository](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/blob/v1.0.3/assets/auto-deploy-app/Chart.yaml)
(for example `version: 1.0.3`).
## Compatibility
The following table explains the version compatibility between GitLab and Auto Deploy dependencies:
| GitLab version | `auto-deploy-image` version | Notes |
|------------------|-----------------------------|-------|
| v10.0 to v14.0 | v0.1.0 to v2.0.0 | v0 and v1 auto-deploy-image are backwards compatible. |
| v13.4 and higher | v2.0.0 and higher | v2 auto-deploy-image contains breaking changes, as explained in the [upgrade guide](#upgrade-deployments-to-the-v2-auto-deploy-image). |
You can find the current stable version of auto-deploy-image in the [Auto Deploy stable template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml).
## Upgrade Guide
Projects using Auto DevOps must use the unmodified chart managed by GitLab.
[Customized charts](customize.md#custom-helm-chart) are unsupported.
### Upgrade deployments to the v1 `auto-deploy-image`
The v1 chart is backward compatible with the v0 chart, so no configuration changes are needed.
### Upgrade deployments to the v2 `auto-deploy-image`
The v2 auto-deploy-image contains multiple dependency and architectural changes.
If your Auto DevOps project has an active environment deployed with the v1 `auto-deploy-image`,
please proceed with the following upgrade guide. Otherwise, you can skip this process.
#### Helm 3
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/228609) in GitLab 13.4.
The `auto-deploy-image` uses the Helm binary to manipulate the releases.
Previously, `auto-deploy-image` used Helm v2, which used Tiller in a cluster.
In the v2 `auto-deploy-image`, it uses Helm v3 that doesn't require Tiller anymore.
If your Auto DevOps project has an active environment that was deployed with the v1
`auto-deploy-image`, use the following steps to upgrade to v2, which uses Helm 3:
1. Modify your `.gitlab-ci.yml` with:
```yaml
include:
- template: Auto-DevOps.gitlab-ci.yml
- remote: https://gitlab.com/hfyngvason/ci-templates/-/raw/master/Helm-2to3.gitlab-ci.yml
variables:
# If this variable is not present, the migration jobs will not show up
MIGRATE_HELM_2TO3: "true"
.auto-deploy:
image: registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v2.0.0-beta.1
variables:
AUTO_DEVOPS_FORCE_DEPLOY_V2: 1
```
1. Run the `<environment-name>:helm-2to3:migrate` job.
1. Deploy your environment as usual. This deployment uses Helm 3.
1. If the deployment succeeds, you can safely run `environment:helm-2to3:cleanup`.
This deletes all Helm 2 release data from the namespace.
If you accidentally delete the Helm 2 releases before you are ready, the `<environment-name>:helm2to3:migrate`
job saves a backup for 1 week in a job artifact called `helm-2-release-backups`.
The backup is in a Kubernetes manifest file that can be restored using
`kubectl apply -f $backup`.
1. Remove the `MIGRATE_HELM_2TO3` variable.
#### Traffic routing change for canary deployments and incremental rollouts
> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/merge_requests/109) in GitLab 13.4.
Auto Deploy supports advanced deployment strategies such as [canary deployments](customize.md#deploy-policy-for-canary-environments)
and [incremental rollouts](../../ci/environments/incremental_rollouts.md).
Previously, `auto-deploy-image` created one service to balance the traffic between
unstable and stable tracks by changing the replica ratio. In the v2 `auto-deploy-image`,
it controls the traffic with [Canary Ingress](https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary).
For more details, see the [v2 `auto-deploy-app` chart resource architecture](#v2-chart-resource-architecture).
If your Auto DevOps project has active `canary` or `rollout` track releases in the
`production` environment deployed with the v1 `auto-deploy-image`, use the following
steps to upgrade to v2:
1. Verify your project is [using the v1 `auto-deploy-image`](#verify-dependency-versions).
If not, [specify the version](#use-a-specific-version-of-auto-deploy-dependencies).
1. If you're in the process of deploying `canary` or `rollout` deployments, promote
them to `production` first to delete the unstable tracks.
1. Verify your project is [using the v2 `auto-deploy-image`](#verify-dependency-versions).
If not, [specify the version](#use-a-specific-version-of-auto-deploy-dependencies).
1. Add an `AUTO_DEVOPS_FORCE_DEPLOY_V2` environment variable with a value of `true`
in the GitLab CI/CD settings.
1. Create a new pipeline and run the `production` job to renew the resource architecture
with the v2 `auto-deploy-app chart`.
1. Remove the `AUTO_DEVOPS_FORCE_DEPLOY_V2` environment variable.
### Use a specific version of Auto Deploy dependencies
To use a specifc version of Auto Deploy dependencies, specify the previous Auto Deploy
stable template that contains the [desired version of `auto-deploy-image` and `auto-deploy-app`](#verify-dependency-versions).
For example, if the template is bundled in GitLab v13.3, change your `.gitlab-ci.yml` to:
```yaml
include:
- template: Auto-DevOps.gitlab-ci.yml
- remote: https://gitlab.com/gitlab-org/gitlab/-/blob/v13.3.0-ee/lib/gitlab/ci/templates/Jobs/Deploy.gitlab-ci.yml
```
### Ignore warnings and continue deploying
If you are certain that the new chart version is safe to be deployed, you can add
the `AUTO_DEVOPS_FORCE_DEPLOY_V<major-version-number>` [environment variable](customize.md#build-and-deployment)
to force the deployment to continue.
For example, if you want to deploy the `v2.0.0` chart on a deployment that previously
used the `v0.17.0` chart, add `AUTO_DEVOPS_FORCE_DEPLOY_V2`.
## Early adopters
If you want to use the latest beta or unstable version of `auto-deploy-image`, include
the latest Auto Deploy template into your `.gitlab-ci.yml`:
```yaml
include:
- template: Auto-DevOps.gitlab-ci.yml
- remote: https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Jobs/Deploy.latest.gitlab-ci.yml
```
CAUTION: **Warning:**
Using a beta or unstable `auto-deploy-image` could cause unrecoverable damage to
your environments. Do not test it with important projects or environments.
The next stable template update is [planned for GitLab v14.0](https://gitlab.com/gitlab-org/gitlab/-/issues/232788).
## Resource Architectures of the `auto-deploy-app` chart
### v0 and v1 chart resource architecture
```mermaid
graph TD;
subgraph gl-managed-app
Z[Nginx Ingress]
end
Z[Nginx Ingress] --> A(Ingress);
Z[Nginx Ingress] --> B(Ingress);
subgraph stg namespace
B[Ingress] --> H(...);
end
subgraph prd namespace
A[Ingress] --> D(Service);
D[Service] --> E(Deployment:Pods:app:stable);
D[Service] --> F(Deployment:Pods:app:canary);
D[Service] --> I(Deployment:Pods:app:rollout);
E(Deployment:Pods:app:stable)---id1[(Pods:Postgres)]
F(Deployment:Pods:app:canary)---id1[(Pods:Postgres)]
I(Deployment:Pods:app:rollout)---id1[(Pods:Postgres)]
end
```
### v2 chart resource architecture
```mermaid
graph TD;
subgraph gl-managed-app
Z[Nginx Ingress]
end
Z[Nginx Ingress] --> A(Ingress);
Z[Nginx Ingress] --> B(Ingress);
Z[Nginx Ingress] --> |If canary is present or incremental rollout/|J(Canary Ingress);
subgraph stg namespace
B[Ingress] --> H(...);
end
subgraph prd namespace
subgraph stable track
A[Ingress] --> D[Service];
D[Service] --> E(Deployment:Pods:app:stable);
end
subgraph canary track
J(Canary Ingress) --> K[Service]
K[Service] --> F(Deployment:Pods:app:canary);
end
E(Deployment:Pods:app:stable)---id1[(Pods:Postgres)]
F(Deployment:Pods:app:canary)---id1[(Pods:Postgres)]
end
```
## Troubleshooting
### Major version mismatch warning
If deploying a chart that has a major version that is different from the previous one,
the new chart might not be correctly deployed. This could be due to an architectural
change. If that happens, the deployment job fails with a message similar to:
```plaintext
*************************************************************************************
[WARNING]
Detected a major version difference between the the chart that is currently deploying (auto-deploy-app-v0.7.0), and the previously deployed chart (auto-deploy-app-v1.0.0).
A new major version might not be backward compatible with the current release (production). The deployment could fail or be stuck in an unrecoverable status.
...
```
To clear this error message and resume deployments, you must do one of the following:
- Manually [upgrade the chart version](#upgrade-guide).
- [Use a specific chart version](#use-a-specific-version-of-auto-deploy-dependencies).
### Error: `missing key "app.kubernetes.io/managed-by": must be set to "Helm"`
If your cluster has a deployment that was deployed with the v1 `auto-deploy-image`,
you might encounter the following error:
- `Error: rendered manifests contain a resource that already exists. Unable to continue with install: Secret "production-postgresql" in namespace "<project-name>-production" exists and cannot be imported into the current release: invalid ownership metadata; label validation error: missing key "app.kubernetes.io/managed-by": must be set to "Helm"; annotation validation error: missing key "meta.helm.sh/release-name": must be set to "production-postgresql"; annotation validation error: missing key "meta.helm.sh/release-namespace": must be set to "<project-name>-production"`
This is because the previous deployment was deployed with Helm2, which is not compatible with Helm3.
To resolve the problem, please follow the [upgrade guide](#upgrade-deployments-to-the-v2-auto-deploy-image).
# Upgrading auto-deploy-app chart for Auto DevOps ---
redirect_to: 'upgrading_auto_deploy_dependencies.md'
---
Auto DevOps provides the auto-deploy-app chart for deploying your application to the This document was moved to [another location](upgrading_auto_deploy_dependencies.md).
Kubernetes cluster with Helm/Tiller. Major version changes of this chart could have
a significantly different resource architecture, and may not be backwards compatible.
This guide provides instructions on how to upgrade your deployments to use the latest
chart and resource architecture.
## Compatibility
The following table lists the version compatibility between GitLab and [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) (with the [auto-deploy-app chart](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/tree/master/assets/auto-deploy-app)).
| GitLab version | auto-deploy-image version | Notes |
|------------------|---------------------------|--------------------------------------------|
| v10.0 and higher | v0.1.0 and higher | v0 and v1 charts are backwards compatible. |
## Upgrade Guide
The Auto DevOps project must use the unmodified chart managed by GitLab.
[Customized charts](customize.md#custom-helm-chart) are unsupported.
### v1 chart
The v1 chart is backward compatible with the v0 chart, so no configuration changes are needed.
## Troubleshooting
### Major version mismatch warning
If deploying a chart that has a major version that is different from the previous one,
the new chart might not be correctly deployed. This could be due to an architectural
change. If that happens, the deployment job fails with a message similar to:
```plaintext
*************************************************************************************
[WARNING]
Detected a major version difference between the the chart that is currently deploying (auto-deploy-app-v0.7.0), and the previously deployed chart (auto-deploy-app-v1.0.0).
A new major version might not be backward compatible with the current release (production). The deployment could fail or be stuck in an unrecoverable status.
...
```
To clear this error message and resume deployments, you must do one of the following:
- Manually [upgrade the chart version](#upgrade-guide).
- [Use a specific chart version](#use-a-specific-chart-version).
#### Use a specific chart version
To use a specific chart version, you must specify a corresponding version of [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image).
Do this by [customizing the image in your `.gitlab-ci.yml`](customize.md#customizing-gitlab-ciyml).
For example, create the following `.gitlab-ci.yml` file in the project. It configures Auto DevOps
to use [auto-deploy-image](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image) version `v0.17.0`
for deployment jobs. It will download the chart from [chart repository](https://charts.gitlab.io/):
```yaml
include:
- template: Auto-DevOps.gitlab-ci.yml
.auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v0.17.0"
```
#### Ignore warning and continue deploying
If you are certain that the new chart version is safe to be deployed,
you can add the `AUTO_DEVOPS_FORCE_DEPLOY_V<N>` [environment variable](customize.md#build-and-deployment)
to force the deployment to continue, where `<N>` is the major version.
For example, if you want to deploy the v2.0.0 chart on a deployment that previously
used the v0.17.0 chart, add `AUTO_DEVOPS_FORCE_DEPLOY_V2`.
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
import produce from 'immer'; import produce from 'immer';
import { GlAlert, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui'; import { GlAlert, GlLoadingIcon, GlIntersectionObserver } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import VulnerabilityList from './vulnerability_list.vue'; import VulnerabilityList from './vulnerability_list.vue';
import vulnerabilitiesQuery from '../graphql/project_vulnerabilities.graphql'; import vulnerabilitiesQuery from '../graphql/project_vulnerabilities.graphql';
import securityScannersQuery from '../graphql/project_security_scanners.graphql'; import securityScannersQuery from '../graphql/project_security_scanners.graphql';
...@@ -17,7 +16,6 @@ export default { ...@@ -17,7 +16,6 @@ export default {
GlIntersectionObserver, GlIntersectionObserver,
VulnerabilityList, VulnerabilityList,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
projectFullPath: { projectFullPath: {
type: String, type: String,
...@@ -78,9 +76,6 @@ export default { ...@@ -78,9 +76,6 @@ export default {
pipelineRun: pipelineRun.map(translateScannerName), pipelineRun: pipelineRun.map(translateScannerName),
}; };
}, },
skip() {
return !this.glFeatures.scannerAlerts;
},
}, },
}, },
computed: { computed: {
......
...@@ -144,13 +144,13 @@ export default { ...@@ -144,13 +144,13 @@ export default {
</div> </div>
<div class="ci-table" role="grid"> <div class="ci-table" role="grid">
<div <div
class="gl-responsive-table-row table-row-header bg-gray-light pl-2 border-top mt-3 lh-100" class="gl-responsive-table-row table-row-header gl-pl-3 gl-border-t-solid gl-border-t-1 gl-border-gray-100 gl-mt-5 gl-line-height-normal gl-text-black-normal gl-font-base"
role="row" role="row"
> >
<div class="table-section section-70 font-weight-bold" role="columnheader"> <div class="table-section section-70 gl-font-weight-bold" role="columnheader">
{{ __('Project') }} {{ __('Project') }}
</div> </div>
<div class="table-section section-30 font-weight-bold" role="columnheader"> <div class="table-section section-30 gl-font-weight-bold" role="columnheader">
{{ __('Usage') }} {{ __('Usage') }}
</div> </div>
</div> </div>
......
<script> <script>
import { GlButton, GlLink, GlIcon } from '@gitlab/ui'; import { GlLink, GlIcon } from '@gitlab/ui';
import ProjectAvatar from '~/vue_shared/components/project_avatar/default.vue'; import ProjectAvatar from '~/vue_shared/components/project_avatar/default.vue';
import { numberToHumanSize, isOdd } from '~/lib/utils/number_utils'; import { numberToHumanSize, isOdd } from '~/lib/utils/number_utils';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import StorageRow from './storage_row.vue'; import StorageRow from './storage_row.vue';
export default { export default {
components: { components: {
GlIcon, GlIcon,
GlButton,
GlLink, GlLink,
ProjectAvatar, ProjectAvatar,
StorageRow, StorageRow,
...@@ -29,7 +29,7 @@ export default { ...@@ -29,7 +29,7 @@ export default {
const { name, id, avatarUrl, webUrl } = this.project; const { name, id, avatarUrl, webUrl } = this.project;
return { return {
name, name,
id: Number(id), id: Number(getIdFromGraphQLId(id)),
avatar_url: avatarUrl, avatar_url: avatarUrl,
path: webUrl, path: webUrl,
}; };
...@@ -54,7 +54,13 @@ export default { ...@@ -54,7 +54,13 @@ export default {
}, },
}, },
methods: { methods: {
toggleProject() { toggleProject(e) {
const NO_EXPAND_CLS = 'js-project-link';
const targetClasses = e.target.classList;
if (targetClasses.contains(NO_EXPAND_CLS)) {
return;
}
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
}, },
getFormattedName(name) { getFormattedName(name) {
...@@ -83,27 +89,42 @@ export default { ...@@ -83,27 +89,42 @@ export default {
</script> </script>
<template> <template>
<div> <div>
<div class="gl-responsive-table-row border-bottom" role="row"> <div
<div class="table-section section-wrap section-70 text-truncate" role="gridcell"> class="gl-responsive-table-row gl-border-solid gl-border-b-1 gl-pt-3 gl-pb-3 gl-border-b-gray-100 gl-hover-bg-blue-50 gl-hover-border-blue-200 gl-hover-cursor-pointer"
<div class="table-mobile-header font-weight-bold" role="rowheader">{{ __('Project') }}</div> role="row"
<div class="table-mobile-content"> data-testid="projectTableRow"
<gl-button
class="btn-transparent float-left p-0 mr-2"
:aria-label="__('Toggle project')"
category="tertiary"
@click="toggleProject" @click="toggleProject"
> >
<gl-icon :name="iconName" class="folder-icon" /> <div
</gl-button> class="table-section gl-white-space-normal! gl-flex-sm-wrap section-70 gl-text-truncate"
role="gridcell"
<project-avatar :project="projectAvatar" :size="20" /> >
<div class="table-mobile-header gl-font-weight-bold" role="rowheader">
<gl-link :href="project.webUrl" class="font-weight-bold">{{ name }}</gl-link> {{ __('Project') }}
</div>
<div class="table-mobile-content gl-display-flex gl-align-items-center">
<div class="gl-display-flex gl-mr-3 gl-align-items-center">
<gl-icon :size="10" :name="iconName" class="gl-mr-2" />
<gl-icon name="bookmark" />
</div> </div>
<div>
<project-avatar :project="projectAvatar" :size="32" />
</div>
<gl-link
:href="project.webUrl"
class="js-project-link gl-font-weight-bold gl-text-gray-900!"
>{{ name }}</gl-link
>
</div>
</div>
<div
class="table-section gl-white-space-normal! gl-flex-sm-wrap section-30 gl-text-truncate"
role="gridcell"
>
<div class="table-mobile-header gl-font-weight-bold" role="rowheader">
{{ __('Usage') }}
</div> </div>
<div class="table-section section-wrap section-30 text-truncate" role="gridcell"> <div class="table-mobile-content gl-text-gray-900">{{ storageSize }}</div>
<div class="table-mobile-header font-weight-bold" role="rowheader">{{ __('Usage') }}</div>
<div class="table-mobile-content">{{ storageSize }}</div>
</div> </div>
</div> </div>
...@@ -113,7 +134,7 @@ export default { ...@@ -113,7 +134,7 @@ export default {
:key="index" :key="index"
:name="getFormattedName(statisticsName)" :name="getFormattedName(statisticsName)"
:value="getValue(value)" :value="getValue(value)"
:class="{ 'bg-gray-light': isOdd(index) }" :class="{ 'gl-bg-gray-10': isOdd(index) }"
/> />
</template> </template>
</div> </div>
......
...@@ -9,7 +9,6 @@ module Projects ...@@ -9,7 +9,6 @@ module Projects
before_action only: [:index] do before_action only: [:index] do
push_frontend_feature_flag(:hide_dismissed_vulnerabilities) push_frontend_feature_flag(:hide_dismissed_vulnerabilities)
push_frontend_feature_flag(:scanner_alerts, default_enabled: true)
end end
end end
end end
......
---
title: Improve projects table in Usage quotas page
merge_request: 43080
author:
type: changed
---
name: scanner_alerts
introduced_by_url:
rollout_issue_url:
group:
type: development
default_enabled: true
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { GlButton } from '@gitlab/ui';
import Project from 'ee/storage_counter/components/project.vue'; import Project from 'ee/storage_counter/components/project.vue';
import StorageRow from 'ee/storage_counter/components/storage_row.vue';
import ProjectAvatar from '~/vue_shared/components/project_avatar/default.vue'; import ProjectAvatar from '~/vue_shared/components/project_avatar/default.vue';
import { numberToHumanSize } from '~/lib/utils/number_utils'; import { numberToHumanSize } from '~/lib/utils/number_utils';
...@@ -32,6 +32,9 @@ function factory(project) { ...@@ -32,6 +32,9 @@ function factory(project) {
}); });
} }
const findTableRow = () => wrapper.find('[data-testid="projectTableRow"]');
const findStorageRow = () => wrapper.find(StorageRow);
describe('Storage Counter project component', () => { describe('Storage Counter project component', () => {
beforeEach(() => { beforeEach(() => {
factory(data); factory(data);
...@@ -52,15 +55,18 @@ describe('Storage Counter project component', () => { ...@@ -52,15 +55,18 @@ describe('Storage Counter project component', () => {
describe('toggle row', () => { describe('toggle row', () => {
describe('on click', () => { describe('on click', () => {
it('toggles isOpen', () => { it('toggles isOpen', () => {
expect(wrapper.vm.isOpen).toEqual(false); expect(findStorageRow().exists()).toBe(false);
wrapper.find(GlButton).vm.$emit('click');
expect(wrapper.vm.isOpen).toEqual(true); findTableRow().trigger('click');
wrapper.find(GlButton).vm.$emit('click'); wrapper.vm.$nextTick(() => {
expect(findStorageRow().exists()).toBe(true);
findTableRow().trigger('click');
expect(wrapper.vm.isOpen).toEqual(false); wrapper.vm.$nextTick(() => {
expect(findStorageRow().exists()).toBe(false);
});
});
}); });
}); });
}); });
......
.auto-deploy: .auto-deploy:
image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v1.0.3" image: "registry.gitlab.com/gitlab-org/cluster-integration/auto-deploy-image:v2.0.0-beta.2"
dependencies: [] dependencies: []
review: review:
...@@ -91,7 +91,7 @@ canary: ...@@ -91,7 +91,7 @@ canary:
- auto-deploy ensure_namespace - auto-deploy ensure_namespace
- auto-deploy initialize_tiller - auto-deploy initialize_tiller
- auto-deploy create_secret - auto-deploy create_secret
- auto-deploy deploy canary - auto-deploy deploy canary 50
environment: environment:
name: production name: production
url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN url: http://$CI_PROJECT_PATH_SLUG.$KUBE_INGRESS_BASE_DOMAIN
...@@ -114,7 +114,6 @@ canary: ...@@ -114,7 +114,6 @@ canary:
- auto-deploy create_secret - auto-deploy create_secret
- auto-deploy deploy - auto-deploy deploy
- auto-deploy delete canary - auto-deploy delete canary
- auto-deploy delete rollout
- auto-deploy persist_environment_url - auto-deploy persist_environment_url
environment: environment:
name: production name: production
...@@ -163,9 +162,7 @@ production_manual: ...@@ -163,9 +162,7 @@ production_manual:
- auto-deploy ensure_namespace - auto-deploy ensure_namespace
- auto-deploy initialize_tiller - auto-deploy initialize_tiller
- auto-deploy create_secret - auto-deploy create_secret
- auto-deploy deploy rollout $ROLLOUT_PERCENTAGE - auto-deploy deploy canary $ROLLOUT_PERCENTAGE
- auto-deploy scale stable $((100-ROLLOUT_PERCENTAGE))
- auto-deploy delete canary
- auto-deploy persist_environment_url - auto-deploy persist_environment_url
environment: environment:
name: production name: production
......
...@@ -137,6 +137,7 @@ module Gitlab ...@@ -137,6 +137,7 @@ module Gitlab
# TODO this class is meant to replace Handler when the feature flag # TODO this class is meant to replace Handler when the feature flag
# upload_middleware_jwt_params_handler is removed # upload_middleware_jwt_params_handler is removed
# See https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
class HandlerForJWTParams < Handler class HandlerForJWTParams < Handler
def with_open_files def with_open_files
@rewritten_fields.keys.each do |field| @rewritten_fields.keys.each do |field|
......
...@@ -42,6 +42,9 @@ class UploadedFile ...@@ -42,6 +42,9 @@ class UploadedFile
@remote_id = remote_id @remote_id = remote_id
end end
# TODO this function is meant to replace .from_params when the feature flag
# upload_middleware_jwt_params_handler is removed
# See https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
def self.from_params_without_field(params, upload_paths) def self.from_params_without_field(params, upload_paths)
path = params['path'] path = params['path']
remote_id = params['remote_id'] remote_id = params['remote_id']
...@@ -68,6 +71,10 @@ class UploadedFile ...@@ -68,6 +71,10 @@ class UploadedFile
) )
end end
# Deprecated. Don't use it.
# .from_params_without_field will replace this one
# See .from_params_without_field and
# https://gitlab.com/gitlab-org/gitlab/-/issues/233895#roll-out-steps
def self.from_params(params, field, upload_paths, path_override = nil) def self.from_params(params, field, upload_paths, path_override = nil)
path = path_override || params["#{field}.path"] path = path_override || params["#{field}.path"]
remote_id = params["#{field}.remote_id"] remote_id = params["#{field}.remote_id"]
......
...@@ -84,6 +84,11 @@ msgid_plural "%d Approvals" ...@@ -84,6 +84,11 @@ msgid_plural "%d Approvals"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "%d Package"
msgid_plural "%d Packages"
msgstr[0] ""
msgstr[1] ""
msgid "%d Scanned URL" msgid "%d Scanned URL"
msgid_plural "%d Scanned URLs" msgid_plural "%d Scanned URLs"
msgstr[0] "" msgstr[0] ""
...@@ -18185,12 +18190,18 @@ msgstr "" ...@@ -18185,12 +18190,18 @@ msgstr ""
msgid "PackageRegistry|NuGet Command" msgid "PackageRegistry|NuGet Command"
msgstr "" msgstr ""
msgid "PackageRegistry|Package Registry"
msgstr ""
msgid "PackageRegistry|Pip Command" msgid "PackageRegistry|Pip Command"
msgstr "" msgstr ""
msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}" msgid "PackageRegistry|Pipeline %{link} triggered %{datetime} by %{author}"
msgstr "" msgstr ""
msgid "PackageRegistry|Publish and share packages for a variety of common package managers. %{docLinkStart}More information%{docLinkEnd}"
msgstr ""
msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}" msgid "PackageRegistry|Published to the %{project} Package Registry %{datetime}"
msgstr "" msgstr ""
...@@ -26911,9 +26922,6 @@ msgstr "" ...@@ -26911,9 +26922,6 @@ msgstr ""
msgid "Toggle navigation" msgid "Toggle navigation"
msgstr "" msgstr ""
msgid "Toggle project"
msgstr ""
msgid "Toggle sidebar" msgid "Toggle sidebar"
msgstr "" msgstr ""
......
import { findByText } from '@testing-library/dom';
export const waitForText = async (text, container = document) => findByText(container, text);
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`packages_list_app renders 1`] = ` exports[`packages_list_app renders 1`] = `
<b-tabs-stub <div>
<package-title-stub
packagehelpurl="foo"
/>
<b-tabs-stub
activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo" activenavitemclass="gl-tab-nav-item-active gl-tab-nav-item-active-indigo"
class="gl-tabs" class="gl-tabs"
contentclass=",gl-tab-content" contentclass=",gl-tab-content"
...@@ -9,7 +14,7 @@ exports[`packages_list_app renders 1`] = ` ...@@ -9,7 +14,7 @@ exports[`packages_list_app renders 1`] = `
nofade="true" nofade="true"
nonavstyle="true" nonavstyle="true"
tag="div" tag="div"
> >
<template> <template>
<b-tab-stub <b-tab-stub
...@@ -447,11 +452,12 @@ exports[`packages_list_app renders 1`] = ` ...@@ -447,11 +452,12 @@ exports[`packages_list_app renders 1`] = `
class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end" class="gl-display-flex gl-align-self-center gl-py-2 gl-flex-grow-1 gl-justify-content-end"
> >
<package-filter-stub <package-filter-stub
class="mr-1" class="gl-mr-2"
/> />
<package-sort-stub /> <package-sort-stub />
</div> </div>
</template> </template>
</b-tabs-stub> </b-tabs-stub>
</div>
`; `;
...@@ -36,6 +36,7 @@ describe('packages_list_app', () => { ...@@ -36,6 +36,7 @@ describe('packages_list_app', () => {
resourceId: 'project_id', resourceId: 'project_id',
emptyListIllustration: 'helpSvg', emptyListIllustration: 'helpSvg',
emptyListHelpUrl, emptyListHelpUrl,
packageHelpUrl: 'foo',
}, },
filterQuery, filterQuery,
}, },
......
import { shallowMount } from '@vue/test-utils';
import PackageTitle from '~/packages/list/components/package_title.vue';
import TitleArea from '~/vue_shared/components/registry/title_area.vue';
import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue';
import { LIST_INTRO_TEXT, LIST_TITLE_TEXT } from '~/packages/list//constants';
describe('PackageTitle', () => {
let wrapper;
let store;
const findTitleArea = () => wrapper.find(TitleArea);
const findMetadataItem = () => wrapper.find(MetadataItem);
const mountComponent = (propsData = { packageHelpUrl: 'foo' }) => {
wrapper = shallowMount(PackageTitle, {
store,
propsData,
stubs: {
TitleArea,
},
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('title area', () => {
it('exists', () => {
mountComponent();
expect(findTitleArea().exists()).toBe(true);
});
it('has the correct props', () => {
mountComponent();
expect(findTitleArea().props()).toMatchObject({
title: LIST_TITLE_TEXT,
infoMessages: [{ text: LIST_INTRO_TEXT, link: 'foo' }],
});
});
});
describe.each`
packagesCount | exist | text
${null} | ${false} | ${''}
${undefined} | ${false} | ${''}
${0} | ${true} | ${'0 Packages'}
${1} | ${true} | ${'1 Package'}
${2} | ${true} | ${'2 Packages'}
`('when packagesCount is $packagesCount metadata item', ({ packagesCount, exist, text }) => {
beforeEach(() => {
mountComponent({ packagesCount, packageHelpUrl: 'foo' });
});
it(`is ${exist} that it exists`, () => {
expect(findMetadataItem().exists()).toBe(exist);
});
if (exist) {
it('has the correct props', () => {
expect(findMetadataItem().props()).toMatchObject({
icon: 'package',
text,
});
});
}
});
});
...@@ -4,3 +4,5 @@ settings: ...@@ -4,3 +4,5 @@ settings:
import/resolver: import/resolver:
jest: jest:
jestConfigFile: 'jest.config.integration.js' jestConfigFile: 'jest.config.integration.js'
globals:
mockServer: false
import { findAllByText, fireEvent, getByLabelText, screen } from '@testing-library/dom';
const isFileRowOpen = row => row.matches('.is-open');
const getLeftSidebar = () => screen.getByTestId('left-sidebar');
const clickOnLeftSidebarTab = name => {
const sidebar = getLeftSidebar();
const button = getByLabelText(sidebar, name);
button.click();
};
const findMonacoEditor = () =>
screen.findByLabelText(/Editor content;/).then(x => x.closest('.monaco-editor'));
const findAndSetEditorValue = async value => {
const editor = await findMonacoEditor();
const uri = editor.getAttribute('data-uri');
window.monaco.editor.getModel(uri).setValue(value);
};
const findTreeBody = () => screen.findByTestId('ide-tree-body', {}, { timeout: 5000 });
const findFileRowContainer = (row = null) =>
row ? Promise.resolve(row.parentElement) : findTreeBody();
const findFileChild = async (row, name, index = 0) => {
const container = await findFileRowContainer(row);
const children = await findAllByText(container, name, { selector: '.file-row-name' });
return children.map(x => x.closest('.file-row')).find(x => x.dataset.level === index.toString());
};
const openFileRow = row => {
if (!row || isFileRowOpen(row)) {
return;
}
row.click();
};
const findAndTraverseToPath = async (path, index = 0, row = null) => {
if (!path) {
return row;
}
const [name, ...restOfPath] = path.split('/');
openFileRow(row);
const child = await findFileChild(row, name, index);
return findAndTraverseToPath(restOfPath.join('/'), index + 1, child);
};
const clickFileRowAction = (row, name) => {
fireEvent.mouseOver(row);
const dropdownButton = getByLabelText(row, 'Create new file or directory');
dropdownButton.click();
const dropdownAction = getByLabelText(dropdownButton.parentNode, name);
dropdownAction.click();
};
const findAndSetFileName = async value => {
const nameField = await screen.findByTestId('file-name-field');
fireEvent.input(nameField, { target: { value } });
const createButton = screen.getByText('Create file');
createButton.click();
};
export const createFile = async (path, content) => {
const parentPath = path
.split('/')
.slice(0, -1)
.join('/');
const parentRow = await findAndTraverseToPath(parentPath);
clickFileRowAction(parentRow, 'New file');
await findAndSetFileName(path);
await findAndSetEditorValue(content);
};
export const deleteFile = async path => {
const row = await findAndTraverseToPath(path);
clickFileRowAction(row, 'Delete');
};
export const commit = async () => {
clickOnLeftSidebarTab('Commit');
screen.getByTestId('begin-commit-button').click();
await screen.findByLabelText(/Commit to .+ branch/).then(x => x.click());
screen.getByText('Commit').click();
};
/**
* WARNING: WIP
*
* Please do not copy from this spec or use it as an example for anything.
*
* This is in place to iteratively set up the frontend integration testing environment
* and will be improved upon in a later iteration.
*
* See https://gitlab.com/gitlab-org/gitlab/-/issues/208800 for more information.
*/
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { waitForText } from 'helpers/wait_for_text';
import { useOverclockTimers } from 'test_helpers/utils/overclock_timers'; import { useOverclockTimers } from 'test_helpers/utils/overclock_timers';
import { createCommitId } from 'test_helpers/factories/commit_id';
import { initIde } from '~/ide'; import { initIde } from '~/ide';
import extendStore from '~/ide/stores/extend'; import extendStore from '~/ide/stores/extend';
import * as ideHelper from './ide_helper';
const TEST_DATASET = { const TEST_DATASET = {
emptyStateSvgPath: '/test/empty_state.svg', emptyStateSvgPath: '/test/empty_state.svg',
...@@ -59,4 +52,38 @@ describe('WebIDE', () => { ...@@ -59,4 +52,38 @@ describe('WebIDE', () => {
expect(root).toMatchSnapshot(); expect(root).toMatchSnapshot();
}); });
it('user commits changes', async () => {
createComponent();
await ideHelper.createFile('foo/bar/test.txt', 'Lorem ipsum dolar sit');
await ideHelper.deleteFile('foo/bar/.gitkeep');
await ideHelper.commit();
const commitId = createCommitId(1);
const commitShortId = commitId.slice(0, 8);
await waitForText('All changes are committed');
await waitForText(commitShortId);
expect(mockServer.db.branches.findBy({ name: 'master' }).commit).toMatchObject({
short_id: commitShortId,
id: commitId,
message: 'Update foo/bar/test.txt\nDeleted foo/bar/.gitkeep',
__actions: [
{
action: 'create',
content: 'Lorem ipsum dolar sit\n',
encoding: 'text',
file_path: 'foo/bar/test.txt',
last_commit_id: '',
},
{
action: 'delete',
encoding: 'text',
file_path: 'foo/bar/.gitkeep',
},
],
});
});
}); });
import { createMockServer } from '../mock_server'; import { createMockServer } from '../mock_server';
beforeEach(() => { beforeEach(() => {
if (global.mockServer) {
global.mockServer.shutdown();
}
const server = createMockServer(); const server = createMockServer();
server.logging = false; server.logging = false;
global.mockServer = server; global.mockServer = server;
}); });
afterEach(() => {
global.mockServer.shutdown();
global.mockServer = null;
});
...@@ -731,11 +731,6 @@ RSpec.describe Ci::CreatePipelineService do ...@@ -731,11 +731,6 @@ RSpec.describe Ci::CreatePipelineService do
.and_call_original .and_call_original
end end
context 'when ci_pipeline_rewind_iid is enabled' do
before do
stub_feature_flags(ci_pipeline_rewind_iid: true)
end
it 'rewinds iid' do it 'rewinds iid' do
result = execute_service result = execute_service
...@@ -743,20 +738,6 @@ RSpec.describe Ci::CreatePipelineService do ...@@ -743,20 +738,6 @@ RSpec.describe Ci::CreatePipelineService do
expect(internal_id.last_value).to eq(0) expect(internal_id.last_value).to eq(0)
end end
end end
context 'when ci_pipeline_rewind_iid is disabled' do
before do
stub_feature_flags(ci_pipeline_rewind_iid: false)
end
it 'does not rewind iid' do
result = execute_service
expect(result).not_to be_persisted
expect(internal_id.last_value).to eq(1)
end
end
end
end end
context 'with manual actions' do context 'with manual actions' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment