Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
844eb8879a
commit
1f3baf00bf
|
@ -46,7 +46,6 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
containerRepository: {},
|
containerRepository: {},
|
||||||
fetchTagsCount: false,
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
apollo: {
|
apollo: {
|
||||||
|
|
|
@ -9,6 +9,7 @@ query getContainerRepositoryTags(
|
||||||
) {
|
) {
|
||||||
containerRepository(id: $id) {
|
containerRepository(id: $id) {
|
||||||
id
|
id
|
||||||
|
tagsCount
|
||||||
tags(after: $after, before: $before, first: $first, last: $last) {
|
tags(after: $after, before: $before, first: $first, last: $last) {
|
||||||
nodes {
|
nodes {
|
||||||
digest
|
digest
|
||||||
|
|
|
@ -25,9 +25,11 @@ import {
|
||||||
UNFINISHED_STATUS,
|
UNFINISHED_STATUS,
|
||||||
MISSING_OR_DELETED_IMAGE_BREADCRUMB,
|
MISSING_OR_DELETED_IMAGE_BREADCRUMB,
|
||||||
ROOT_IMAGE_TEXT,
|
ROOT_IMAGE_TEXT,
|
||||||
|
GRAPHQL_PAGE_SIZE,
|
||||||
} from '../constants/index';
|
} from '../constants/index';
|
||||||
import deleteContainerRepositoryTagsMutation from '../graphql/mutations/delete_container_repository_tags.mutation.graphql';
|
import deleteContainerRepositoryTagsMutation from '../graphql/mutations/delete_container_repository_tags.mutation.graphql';
|
||||||
import getContainerRepositoryDetailsQuery from '../graphql/queries/get_container_repository_details.query.graphql';
|
import getContainerRepositoryDetailsQuery from '../graphql/queries/get_container_repository_details.query.graphql';
|
||||||
|
import getContainerRepositoryTagsQuery from '../graphql/queries/get_container_repository_tags.query.graphql';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'RegistryDetailsPage',
|
name: 'RegistryDetailsPage',
|
||||||
|
@ -133,8 +135,8 @@ export default {
|
||||||
awaitRefetchQueries: true,
|
awaitRefetchQueries: true,
|
||||||
refetchQueries: [
|
refetchQueries: [
|
||||||
{
|
{
|
||||||
query: getContainerRepositoryDetailsQuery,
|
query: getContainerRepositoryTagsQuery,
|
||||||
variables: this.queryVariables,
|
variables: { ...this.queryVariables, first: GRAPHQL_PAGE_SIZE },
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
|
@ -64,7 +64,7 @@ export default {
|
||||||
<gl-button
|
<gl-button
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
:variant="user.attention_requested ? 'warning' : 'default'"
|
:variant="user.attention_requested ? 'warning' : 'default'"
|
||||||
:icon="user.attention_requested ? 'star' : 'star-o'"
|
:icon="user.attention_requested ? 'attention-solid' : 'attention'"
|
||||||
:aria-label="tooltipTitle"
|
:aria-label="tooltipTitle"
|
||||||
size="small"
|
size="small"
|
||||||
category="tertiary"
|
category="tertiary"
|
||||||
|
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/338350
|
||||||
milestone: '14.3'
|
milestone: '14.3'
|
||||||
type: development
|
type: development
|
||||||
group: group::memory
|
group: group::memory
|
||||||
default_enabled: false
|
default_enabled: true
|
||||||
|
|
|
@ -9,6 +9,8 @@ Rails.application.configure do
|
||||||
config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
|
config.action_cable.worker_pool_size = Gitlab::ActionCable::Config.worker_pool_size
|
||||||
end
|
end
|
||||||
|
|
||||||
|
ActionCable::SubscriptionAdapter::Base.prepend(Gitlab::Patch::ActionCableSubscriptionAdapterIdentifier)
|
||||||
|
|
||||||
# https://github.com/rails/rails/blob/bb5ac1623e8de08c1b7b62b1368758f0d3bb6379/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
|
# https://github.com/rails/rails/blob/bb5ac1623e8de08c1b7b62b1368758f0d3bb6379/actioncable/lib/action_cable/subscription_adapter/redis.rb#L18
|
||||||
ActionCable::SubscriptionAdapter::Redis.redis_connector = lambda do |config|
|
ActionCable::SubscriptionAdapter::Redis.redis_connector = lambda do |config|
|
||||||
args = config.except(:adapter, :channel_prefix)
|
args = config.except(:adapter, :channel_prefix)
|
||||||
|
|
|
@ -1354,7 +1354,7 @@ PUT /projects/:id
|
||||||
```
|
```
|
||||||
|
|
||||||
For example, to toggle the setting for
|
For example, to toggle the setting for
|
||||||
[shared runners on a GitLab.com project](../user/gitlab_com/index.md#shared-runner-cloud-runners):
|
[shared runners on a GitLab.com project](../ci/runners/index.md):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl --request PUT --header "PRIVATE-TOKEN: <your-token>" \
|
curl --request PUT --header "PRIVATE-TOKEN: <your-token>" \
|
||||||
|
|
|
@ -1623,6 +1623,7 @@ Returns:
|
||||||
- `201 Created` on success.
|
- `201 Created` on success.
|
||||||
- `404 User Not Found` if user cannot be found.
|
- `404 User Not Found` if user cannot be found.
|
||||||
- `403 Forbidden` if the user cannot be approved because they are blocked by an administrator or by LDAP synchronization.
|
- `403 Forbidden` if the user cannot be approved because they are blocked by an administrator or by LDAP synchronization.
|
||||||
|
- `409 Conflict` if the user has been deactivated.
|
||||||
|
|
||||||
Example Responses:
|
Example Responses:
|
||||||
|
|
||||||
|
|
|
@ -259,5 +259,5 @@ For very active repositories with a large number of references and files, you ca
|
||||||
must be configured per-repository. The pack-objects cache also automatically works for forks. On GitLab.com, where the pack-objects cache is
|
must be configured per-repository. The pack-objects cache also automatically works for forks. On GitLab.com, where the pack-objects cache is
|
||||||
enabled on all Gitaly servers, we found that we no longer need a pre-clone step for `gitlab-org/gitlab` development.
|
enabled on all Gitaly servers, we found that we no longer need a pre-clone step for `gitlab-org/gitlab` development.
|
||||||
- Optimize your CI/CD jobs by seeding repository data in a pre-clone step with the
|
- Optimize your CI/CD jobs by seeding repository data in a pre-clone step with the
|
||||||
[`pre_clone_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) of GitLab Runner. See the
|
[`pre_clone_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section) of GitLab Runner. See
|
||||||
[Runner Cloud for Linux](../runners/runner_cloud/linux_runner_cloud.md#pre-clone-script) for more details.
|
[SaaS runners on Linux](../runners/runner_cloud/linux_runner_cloud.md#pre-clone-script) for details.
|
||||||
|
|
|
@ -5,12 +5,12 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
type: reference
|
type: reference
|
||||||
---
|
---
|
||||||
|
|
||||||
# GitLab Runner Cloud **(FREE)**
|
# Runner SaaS **(FREE SAAS)**
|
||||||
|
|
||||||
If you are using self-managed GitLab or you want to use your own runners on GitLab.com, you can
|
If you are using self-managed GitLab or you use GitLab.com but want to use your own runners, you can
|
||||||
[install and configure your own runners](https://docs.gitlab.com/runner/install/).
|
[install and configure your own runners](https://docs.gitlab.com/runner/install/).
|
||||||
|
|
||||||
If you are using GitLab SaaS (GitLab.com), your CI jobs automatically run on runners in the GitLab Runner Cloud.
|
If you are using GitLab SaaS (GitLab.com), your CI jobs automatically run on runners provided by GitLab.
|
||||||
No configuration is required. Your jobs can run on:
|
No configuration is required. Your jobs can run on:
|
||||||
|
|
||||||
- [Linux runners](build_cloud/linux_build_cloud.md).
|
- [Linux runners](build_cloud/linux_build_cloud.md).
|
||||||
|
|
|
@ -4,9 +4,9 @@ group: Runner
|
||||||
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/#assignments
|
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/#assignments
|
||||||
---
|
---
|
||||||
|
|
||||||
# Runner Cloud for Linux **(FREE)**
|
# SaaS runners on Linux **(FREE SAAS)**
|
||||||
|
|
||||||
Runner Cloud runners for Linux run in autoscale mode and are powered by Google Cloud Platform.
|
SaaS runners on Linux are autoscaled ephemeral Google Cloud Platform virtual machines.
|
||||||
|
|
||||||
Autoscaling means reduced queue times to spin up CI/CD jobs, and isolated VMs for each job, thus maximizing security. These shared runners are available on GitLab.com.
|
Autoscaling means reduced queue times to spin up CI/CD jobs, and isolated VMs for each job, thus maximizing security. These shared runners are available on GitLab.com.
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ These runners share a [distributed cache](https://docs.gitlab.com/runner/configu
|
||||||
|
|
||||||
## Pre-clone script
|
## Pre-clone script
|
||||||
|
|
||||||
Cloud runners for Linux provide a way to run commands in a CI
|
With SaaS runners on Linux, you can run commands in a CI
|
||||||
job before the runner attempts to run `git init` and `git fetch` to
|
job before the runner attempts to run `git init` and `git fetch` to
|
||||||
download a GitLab repository. The
|
download a GitLab repository. The
|
||||||
[`pre_clone_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
|
[`pre_clone_script`](https://docs.gitlab.com/runner/configuration/advanced-configuration.html#the-runners-section)
|
||||||
|
|
|
@ -4,9 +4,9 @@ group: Runner
|
||||||
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/#assignments
|
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/#assignments
|
||||||
---
|
---
|
||||||
|
|
||||||
# VM instances and images for Runner Cloud for macOS **(FREE)**
|
# VM instances and images for SaaS runners on macOS **(FREE SAAS)**
|
||||||
|
|
||||||
When you use the Runner Cloud for macOS:
|
When you use SaaS runners on macOS:
|
||||||
|
|
||||||
- Each of your jobs runs in a newly provisioned VM, which is dedicated to the specific job.
|
- Each of your jobs runs in a newly provisioned VM, which is dedicated to the specific job.
|
||||||
- The VM is active only for the duration of the job and immediately deleted.
|
- The VM is active only for the duration of the job and immediately deleted.
|
||||||
|
|
|
@ -4,19 +4,20 @@ group: Runner
|
||||||
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/#assignments
|
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/#assignments
|
||||||
---
|
---
|
||||||
|
|
||||||
# Runner Cloud for macOS (Beta) **(FREE SAAS)**
|
# SaaS runners on macOS (Beta) **(FREE SAAS)**
|
||||||
|
|
||||||
The Runner Cloud for macOS Beta provides on-demand runners integrated with GitLab SaaS [CI/CD](../../../ci/index.md).
|
SaaS runners on macOS provide an on-demand macOS build environment integrated with
|
||||||
|
GitLab SaaS [CI/CD](../../../ci/index.md).
|
||||||
Use these runners to build, test, and deploy apps for the Apple ecosystem (macOS, iOS, tvOS). You can take advantage
|
Use these runners to build, test, and deploy apps for the Apple ecosystem (macOS, iOS, tvOS). You can take advantage
|
||||||
of all the capabilities of the GitLab single DevOps platform and not have to manage or operate a
|
of all the capabilities of the GitLab single DevOps platform and not have to manage or operate a
|
||||||
build environment.
|
build environment.
|
||||||
|
|
||||||
Cloud runners for macOS are in [Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta)
|
SaaS runners on macOS are in [Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta)
|
||||||
and shouldn't be relied upon for mission-critical production jobs.
|
and shouldn't be relied upon for mission-critical production jobs.
|
||||||
|
|
||||||
## Quickstart
|
## Quickstart
|
||||||
|
|
||||||
To start using Runner Cloud for macOS Beta, you must submit an access request [issue](https://gitlab.com/gitlab-com/macos-buildcloud-runners-beta/-/issues/new?issuable_template=beta_access_request). After your
|
To start using SaaS runners on macOS, you must submit an access request [issue](https://gitlab.com/gitlab-com/macos-buildcloud-runners-beta/-/issues/new?issuable_template=beta_access_request). After your
|
||||||
access has been granted and your build environment configured, you must configure your
|
access has been granted and your build environment configured, you must configure your
|
||||||
`.gitlab-ci.yml` pipeline file:
|
`.gitlab-ci.yml` pipeline file:
|
||||||
|
|
||||||
|
@ -28,10 +29,10 @@ The runners automatically run your build.
|
||||||
|
|
||||||
## Example `.gitlab-ci.yml` file
|
## Example `.gitlab-ci.yml` file
|
||||||
|
|
||||||
The following sample `.gitlab-ci.yml` file shows how to start using the runners for macOS:
|
The following sample `.gitlab-ci.yml` file shows how to start using the SaaS runners on macOS:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
.macos_buildcloud_runners:
|
.macos_saas_runners:
|
||||||
tags:
|
tags:
|
||||||
- shared-macos-amd64
|
- shared-macos-amd64
|
||||||
image: macos-11-xcode-12
|
image: macos-11-xcode-12
|
||||||
|
@ -45,14 +46,14 @@ before_script:
|
||||||
|
|
||||||
build:
|
build:
|
||||||
extends:
|
extends:
|
||||||
- .macos_buildcloud_runners
|
- .macos_saas_runners
|
||||||
stage: build
|
stage: build
|
||||||
script:
|
script:
|
||||||
- echo "running scripts in the build job"
|
- echo "running scripts in the build job"
|
||||||
|
|
||||||
test:
|
test:
|
||||||
extends:
|
extends:
|
||||||
- .macos_buildcloud_runners
|
- .macos_saas_runners
|
||||||
stage: test
|
stage: test
|
||||||
script:
|
script:
|
||||||
- echo "running scripts in the test job"
|
- echo "running scripts in the test job"
|
||||||
|
|
|
@ -4,9 +4,9 @@ group: Runner
|
||||||
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/#assignments
|
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/#assignments
|
||||||
---
|
---
|
||||||
|
|
||||||
# Runner Cloud for Windows (beta) **(FREE)**
|
# SaaS runners on Windows (beta) **(FREE SAAS)**
|
||||||
|
|
||||||
Runner Cloud runners for Windows are in [beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta)
|
SaaS runners on Windows are in [beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#beta)
|
||||||
and shouldn't be used for production workloads.
|
and shouldn't be used for production workloads.
|
||||||
|
|
||||||
During this beta period, the [shared runner pipeline quota](../../../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota)
|
During this beta period, the [shared runner pipeline quota](../../../user/admin_area/settings/continuous_integration.md#shared-runners-pipeline-minutes-quota)
|
||||||
|
|
|
@ -139,8 +139,9 @@ In these cases, use the following workflow:
|
||||||
and approval from the VP of Development, the DRI for Development Guidelines,
|
and approval from the VP of Development, the DRI for Development Guidelines,
|
||||||
@clefelhocz1.
|
@clefelhocz1.
|
||||||
|
|
||||||
1. After all approvals are complete, assign the merge request to the
|
1. After all approvals are complete, review the page's metadata to
|
||||||
Technical Writer for [Development Guidelines](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments-to-development-guidelines)
|
[find a Technical Writer](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments)
|
||||||
|
who can help you merge the changes.
|
||||||
for final content review and merge. The Technical Writer may ask for
|
for final content review and merge. The Technical Writer may ask for
|
||||||
additional approvals as previously suggested before merging the MR.
|
additional approvals as previously suggested before merging the MR.
|
||||||
|
|
||||||
|
|
|
@ -342,6 +342,7 @@ end
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69372) in GitLab 14.3.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69372) in GitLab 14.3.
|
||||||
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/338350) in GitLab 14.4.
|
> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/338350) in GitLab 14.4.
|
||||||
|
> - [Enabled on self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/338350) in GitLab 14.6.
|
||||||
|
|
||||||
The deduplication always take into account the latest binary replication pointer, not the first one.
|
The deduplication always take into account the latest binary replication pointer, not the first one.
|
||||||
This happens because we drop the same job scheduled for the second time and the Write-Ahead Log (WAL) is lost.
|
This happens because we drop the same job scheduled for the second time and the Write-Ahead Log (WAL) is lost.
|
||||||
|
@ -353,15 +354,11 @@ This way we are always comparing the latest binary replication pointer,
|
||||||
making sure that we read from the replica that is fully caught up.
|
making sure that we read from the replica that is fully caught up.
|
||||||
|
|
||||||
FLAG:
|
FLAG:
|
||||||
On self-managed GitLab, by default this feature is not available.
|
On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to
|
||||||
To make it available,
|
[disable the feature flag](../administration/feature_flags.md) named preserve_latest_wal_locations_for_idempotent_jobs flag.
|
||||||
ask an administrator to [enable the preserve_latest_wal_locations_for_idempotent_jobs flag](../administration/feature_flags.md).
|
|
||||||
FLAG:
|
|
||||||
On self-managed GitLab, by default this feature is not available.
|
|
||||||
To make it available,
|
|
||||||
ask an administrator to [enable the `preserve_latest_wal_locations_for_idempotent_jobs` flag](../administration/feature_flags.md).
|
|
||||||
This feature flag is related to GitLab development and is not intended to be used by GitLab administrators, though.
|
This feature flag is related to GitLab development and is not intended to be used by GitLab administrators, though.
|
||||||
On GitLab.com, this feature is available but can be configured by GitLab.com administrators only.
|
On GitLab.com, this feature is available.
|
||||||
|
|
||||||
## Limited capacity worker
|
## Limited capacity worker
|
||||||
|
|
||||||
|
|
|
@ -302,7 +302,8 @@ The GitLab Runner server requirements depend on:
|
||||||
|
|
||||||
Since the nature of the jobs varies for each use case, you need to experiment by adjusting the job concurrency to get the optimum setting.
|
Since the nature of the jobs varies for each use case, you need to experiment by adjusting the job concurrency to get the optimum setting.
|
||||||
|
|
||||||
For reference, the GitLab.com Runner Cloud [auto-scaling runner for Linux](../ci/runners/build_cloud/linux_build_cloud.md) is configured so that a **single job** runs in a **single instance** with:
|
For reference, the [SaaS runners on Linux](../ci/runners/build_cloud/linux_build_cloud.md)
|
||||||
|
are configured so that a **single job** runs in a **single instance** with:
|
||||||
|
|
||||||
- 1 vCPU.
|
- 1 vCPU.
|
||||||
- 3.75 GB of RAM.
|
- 3.75 GB of RAM.
|
||||||
|
|
|
@ -42,5 +42,6 @@ Align your work across teams.
|
||||||
- [Epics](../user/group/epics/index.md)
|
- [Epics](../user/group/epics/index.md)
|
||||||
- [Multi-level epics](../user/group/epics/manage_epics.md#multi-level-child-epics)
|
- [Multi-level epics](../user/group/epics/manage_epics.md#multi-level-child-epics)
|
||||||
- [Epic boards](../user/group/epics/epic_boards.md)
|
- [Epic boards](../user/group/epics/epic_boards.md)
|
||||||
- [View heath status](../user/project/issues/managing_issues.md#health-status)
|
- [View health status](../user/project/issues/managing_issues.md#health-status)
|
||||||
- [Roadmaps](../user/group/roadmap/index.md)
|
- [Roadmaps](../user/group/roadmap/index.md)
|
||||||
|
- [Planning hierarchies](../user/group/planning_hierarchy/index.md)
|
||||||
|
|
|
@ -200,11 +200,11 @@ The following limits apply for [Webhooks](../project/integrations/webhooks.md):
|
||||||
| [Number of webhooks](../../administration/instance_limits.md#number-of-webhooks) | `100` per project, `50` per group | `100` per project, `50` per group |
|
| [Number of webhooks](../../administration/instance_limits.md#number-of-webhooks) | `100` per project, `50` per group | `100` per project, `50` per group |
|
||||||
| Maximum payload size | 25 MB | 25 MB |
|
| Maximum payload size | 25 MB | 25 MB |
|
||||||
|
|
||||||
## Shared Runner Cloud runners
|
## Runner SaaS
|
||||||
|
|
||||||
GitLab has shared runners on GitLab.com that you can use to run your CI jobs.
|
Runner SaaS is the hosted, secure, and managed build environment you can use to run CI/CD jobs for your GitLab.com hosted project.
|
||||||
|
|
||||||
For more information, see [GitLab Runner Cloud runners](../../ci/runners/index.md).
|
For more information, see [Runner SaaS](../../ci/runners/index.md).
|
||||||
|
|
||||||
## Sidekiq
|
## Sidekiq
|
||||||
|
|
||||||
|
|
|
@ -41,6 +41,8 @@ graph TD
|
||||||
Child_epic --> Issue2
|
Child_epic --> Issue2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Also, read more about possible [planning hierarchies](../planning_hierarchy/index.md).
|
||||||
|
|
||||||
## Roadmap in epics **(ULTIMATE)**
|
## Roadmap in epics **(ULTIMATE)**
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7327) in GitLab 11.10.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7327) in GitLab 11.10.
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
type: reference
|
||||||
|
stage: Plan
|
||||||
|
group: Product Planning
|
||||||
|
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/#assignments
|
||||||
|
---
|
||||||
|
|
||||||
|
# Planning hierarchies **(PREMIUM)**
|
||||||
|
|
||||||
|
Planning hierarchies are an integral part of breaking down your work in GitLab.
|
||||||
|
To understand how you can use epics and issues together in hierarchies, remember the following:
|
||||||
|
|
||||||
|
- [Epics](../epics/index.md) exist in groups.
|
||||||
|
- [Issues](../../project/issues/index.md) exist in projects.
|
||||||
|
|
||||||
|
GitLab is not opinionated on how you structure your work and the hierarchy you can build with multi-level
|
||||||
|
epics. For example, you can use the hierarchy as a folder of issues for bigger initiatives.
|
||||||
|
|
||||||
|
To learn about hierarchies in general, common frameworks, and using GitLab for
|
||||||
|
portfolio management, see
|
||||||
|
[How to use GitLab for Agile portfolio planning and project management](https://about.gitlab.com/blog/2020/11/11/gitlab-for-agile-portfolio-planning-project-management/).
|
||||||
|
|
||||||
|
## Hierarchies with epics
|
||||||
|
|
||||||
|
With epics, you can achieve the following hierarchy:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
Group_epic --> Project1_Issue1
|
||||||
|
Group_epic --> Project1_Issue2
|
||||||
|
Group_epic --> Project2_Issue1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Hierarchies with multi-level epics **(ULTIMATE)**
|
||||||
|
|
||||||
|
With the addition of [multi-level epics](../epics/manage_epics.md#multi-level-child-epics) and up to
|
||||||
|
seven levels of nested epics, you can achieve the following hierarchy:
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
classDiagram
|
||||||
|
direction TD
|
||||||
|
class Epic
|
||||||
|
class Issue
|
||||||
|
|
||||||
|
Epic *-- "0..7" Epic
|
||||||
|
Epic "1" *-- "0..*" Issue
|
||||||
|
```
|
||||||
|
|
||||||
|
## View ancestry of an epic
|
||||||
|
|
||||||
|
In an epic, you can view the ancestors as parents in the right sidebar under **Ancestors**.
|
||||||
|
|
||||||
|
![epics state dropdown](img/epic-view-ancestors-in-sidebar_v14_6.png)
|
||||||
|
|
||||||
|
## View ancestry of an issue
|
||||||
|
|
||||||
|
In an issue, you can view the parented epic above the issue in the right sidebar under **Epic**.
|
||||||
|
|
||||||
|
![epics state dropdown](img/issue-view-parent-epic-in-sidebar_v14_6.png)
|
|
@ -4,6 +4,7 @@ module Gitlab
|
||||||
module Database
|
module Database
|
||||||
module MigrationHelpers
|
module MigrationHelpers
|
||||||
include Migrations::BackgroundMigrationHelpers
|
include Migrations::BackgroundMigrationHelpers
|
||||||
|
include Migrations::BatchedBackgroundMigrationHelpers
|
||||||
include DynamicModelHelpers
|
include DynamicModelHelpers
|
||||||
include RenameTableHelpers
|
include RenameTableHelpers
|
||||||
include AsyncIndexes::MigrationHelpers
|
include AsyncIndexes::MigrationHelpers
|
||||||
|
|
|
@ -5,11 +5,7 @@ module Gitlab
|
||||||
module Migrations
|
module Migrations
|
||||||
module BackgroundMigrationHelpers
|
module BackgroundMigrationHelpers
|
||||||
BATCH_SIZE = 1_000 # Number of rows to process per job
|
BATCH_SIZE = 1_000 # Number of rows to process per job
|
||||||
SUB_BATCH_SIZE = 100 # Number of rows to process per sub-batch
|
|
||||||
JOB_BUFFER_SIZE = 1_000 # Number of jobs to bulk queue at a time
|
JOB_BUFFER_SIZE = 1_000 # Number of jobs to bulk queue at a time
|
||||||
BATCH_CLASS_NAME = 'PrimaryKeyBatchingStrategy' # Default batch class for batched migrations
|
|
||||||
BATCH_MIN_VALUE = 1 # Default minimum value for batched migrations
|
|
||||||
BATCH_MIN_DELAY = 2.minutes.freeze # Minimum delay between batched migrations
|
|
||||||
|
|
||||||
# Bulk queues background migration jobs for an entire table, batched by ID range.
|
# Bulk queues background migration jobs for an entire table, batched by ID range.
|
||||||
# "Bulk" meaning many jobs will be pushed at a time for efficiency.
|
# "Bulk" meaning many jobs will be pushed at a time for efficiency.
|
||||||
|
@ -170,102 +166,6 @@ module Gitlab
|
||||||
duration
|
duration
|
||||||
end
|
end
|
||||||
|
|
||||||
# Creates a batched background migration for the given table. A batched migration runs one job
|
|
||||||
# at a time, computing the bounds of the next batch based on the current migration settings and the previous
|
|
||||||
# batch bounds. Each job's execution status is tracked in the database as the migration runs. The given job
|
|
||||||
# class must be present in the Gitlab::BackgroundMigration module, and the batch class (if specified) must be
|
|
||||||
# present in the Gitlab::BackgroundMigration::BatchingStrategies module.
|
|
||||||
#
|
|
||||||
# If migration with same job_class_name, table_name, column_name, and job_aruments already exists, this helper
|
|
||||||
# will log an warning and not create a new one.
|
|
||||||
#
|
|
||||||
# job_class_name - The background migration job class as a string
|
|
||||||
# batch_table_name - The name of the table the migration will batch over
|
|
||||||
# batch_column_name - The name of the column the migration will batch over
|
|
||||||
# job_arguments - Extra arguments to pass to the job instance when the migration runs
|
|
||||||
# job_interval - The pause interval between each job's execution, minimum of 2 minutes
|
|
||||||
# batch_min_value - The value in the column the batching will begin at
|
|
||||||
# batch_max_value - The value in the column the batching will end at, defaults to `SELECT MAX(batch_column)`
|
|
||||||
# batch_class_name - The name of the class that will be called to find the range of each next batch
|
|
||||||
# batch_size - The maximum number of rows per job
|
|
||||||
# sub_batch_size - The maximum number of rows processed per "iteration" within the job
|
|
||||||
#
|
|
||||||
#
|
|
||||||
# *Returns the created BatchedMigration record*
|
|
||||||
#
|
|
||||||
# Example:
|
|
||||||
#
|
|
||||||
# queue_batched_background_migration(
|
|
||||||
# 'CopyColumnUsingBackgroundMigrationJob',
|
|
||||||
# :events,
|
|
||||||
# :id,
|
|
||||||
# job_interval: 2.minutes,
|
|
||||||
# other_job_arguments: ['column1', 'column2'])
|
|
||||||
#
|
|
||||||
# Where the the background migration exists:
|
|
||||||
#
|
|
||||||
# class Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob
|
|
||||||
# def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, *other_args)
|
|
||||||
# # do something
|
|
||||||
# end
|
|
||||||
# end
|
|
||||||
def queue_batched_background_migration( # rubocop:disable Metrics/ParameterLists
|
|
||||||
job_class_name,
|
|
||||||
batch_table_name,
|
|
||||||
batch_column_name,
|
|
||||||
*job_arguments,
|
|
||||||
job_interval:,
|
|
||||||
batch_min_value: BATCH_MIN_VALUE,
|
|
||||||
batch_max_value: nil,
|
|
||||||
batch_class_name: BATCH_CLASS_NAME,
|
|
||||||
batch_size: BATCH_SIZE,
|
|
||||||
sub_batch_size: SUB_BATCH_SIZE
|
|
||||||
)
|
|
||||||
|
|
||||||
if Gitlab::Database::BackgroundMigration::BatchedMigration.for_configuration(job_class_name, batch_table_name, batch_column_name, job_arguments).exists?
|
|
||||||
Gitlab::AppLogger.warn "Batched background migration not enqueued because it already exists: " \
|
|
||||||
"job_class_name: #{job_class_name}, table_name: #{batch_table_name}, column_name: #{batch_column_name}, " \
|
|
||||||
"job_arguments: #{job_arguments.inspect}"
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
job_interval = BATCH_MIN_DELAY if job_interval < BATCH_MIN_DELAY
|
|
||||||
|
|
||||||
batch_max_value ||= connection.select_value(<<~SQL)
|
|
||||||
SELECT MAX(#{connection.quote_column_name(batch_column_name)})
|
|
||||||
FROM #{connection.quote_table_name(batch_table_name)}
|
|
||||||
SQL
|
|
||||||
|
|
||||||
migration_status = batch_max_value.nil? ? :finished : :active
|
|
||||||
batch_max_value ||= batch_min_value
|
|
||||||
|
|
||||||
migration = Gitlab::Database::BackgroundMigration::BatchedMigration.create!(
|
|
||||||
job_class_name: job_class_name,
|
|
||||||
table_name: batch_table_name,
|
|
||||||
column_name: batch_column_name,
|
|
||||||
job_arguments: job_arguments,
|
|
||||||
interval: job_interval,
|
|
||||||
min_value: batch_min_value,
|
|
||||||
max_value: batch_max_value,
|
|
||||||
batch_class_name: batch_class_name,
|
|
||||||
batch_size: batch_size,
|
|
||||||
sub_batch_size: sub_batch_size,
|
|
||||||
status: migration_status)
|
|
||||||
|
|
||||||
# This guard is necessary since #total_tuple_count was only introduced schema-wise,
|
|
||||||
# after this migration helper had been used for the first time.
|
|
||||||
return migration unless migration.respond_to?(:total_tuple_count)
|
|
||||||
|
|
||||||
# We keep track of the estimated number of tuples to reason later
|
|
||||||
# about the overall progress of a migration.
|
|
||||||
migration.total_tuple_count = Gitlab::Database::SharedModel.using_connection(connection) do
|
|
||||||
Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate
|
|
||||||
end
|
|
||||||
migration.save!
|
|
||||||
|
|
||||||
migration
|
|
||||||
end
|
|
||||||
|
|
||||||
# Force a background migration to complete.
|
# Force a background migration to complete.
|
||||||
#
|
#
|
||||||
# WARNING: This method will block the caller and move the background migration from an
|
# WARNING: This method will block the caller and move the background migration from an
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module Database
|
||||||
|
module Migrations
|
||||||
|
# BatchedBackgroundMigrations are a new approach to scheduling and executing background migrations, which uses
|
||||||
|
# persistent state in the database to track each migration. This avoids having to batch over an entire table and
|
||||||
|
# schedule a large number of sidekiq jobs upfront. It also provides for more flexibility as the migration runs,
|
||||||
|
# as it can be paused and restarted, and have configuration values like the batch size updated dynamically as the
|
||||||
|
# migration runs.
|
||||||
|
#
|
||||||
|
# For now, these migrations are not considered ready for general use, for more information see the tracking epic:
|
||||||
|
# https://gitlab.com/groups/gitlab-org/-/epics/6751
|
||||||
|
module BatchedBackgroundMigrationHelpers
|
||||||
|
BATCH_SIZE = 1_000 # Number of rows to process per job
|
||||||
|
SUB_BATCH_SIZE = 100 # Number of rows to process per sub-batch
|
||||||
|
BATCH_CLASS_NAME = 'PrimaryKeyBatchingStrategy' # Default batch class for batched migrations
|
||||||
|
BATCH_MIN_VALUE = 1 # Default minimum value for batched migrations
|
||||||
|
BATCH_MIN_DELAY = 2.minutes.freeze # Minimum delay between batched migrations
|
||||||
|
|
||||||
|
# Creates a batched background migration for the given table. A batched migration runs one job
|
||||||
|
# at a time, computing the bounds of the next batch based on the current migration settings and the previous
|
||||||
|
# batch bounds. Each job's execution status is tracked in the database as the migration runs. The given job
|
||||||
|
# class must be present in the Gitlab::BackgroundMigration module, and the batch class (if specified) must be
|
||||||
|
# present in the Gitlab::BackgroundMigration::BatchingStrategies module.
|
||||||
|
#
|
||||||
|
# If migration with same job_class_name, table_name, column_name, and job_aruments already exists, this helper
|
||||||
|
# will log an warning and not create a new one.
|
||||||
|
#
|
||||||
|
# job_class_name - The background migration job class as a string
|
||||||
|
# batch_table_name - The name of the table the migration will batch over
|
||||||
|
# batch_column_name - The name of the column the migration will batch over
|
||||||
|
# job_arguments - Extra arguments to pass to the job instance when the migration runs
|
||||||
|
# job_interval - The pause interval between each job's execution, minimum of 2 minutes
|
||||||
|
# batch_min_value - The value in the column the batching will begin at
|
||||||
|
# batch_max_value - The value in the column the batching will end at, defaults to `SELECT MAX(batch_column)`
|
||||||
|
# batch_class_name - The name of the class that will be called to find the range of each next batch
|
||||||
|
# batch_size - The maximum number of rows per job
|
||||||
|
# sub_batch_size - The maximum number of rows processed per "iteration" within the job
|
||||||
|
#
|
||||||
|
# *Returns the created BatchedMigration record*
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
#
|
||||||
|
# queue_batched_background_migration(
|
||||||
|
# 'CopyColumnUsingBackgroundMigrationJob',
|
||||||
|
# :events,
|
||||||
|
# :id,
|
||||||
|
# job_interval: 2.minutes,
|
||||||
|
# other_job_arguments: ['column1', 'column2'])
|
||||||
|
#
|
||||||
|
# Where the the background migration exists:
|
||||||
|
#
|
||||||
|
# class Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob
|
||||||
|
# def perform(start_id, end_id, batch_table, batch_column, sub_batch_size, *other_args)
|
||||||
|
# # do something
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
def queue_batched_background_migration( # rubocop:disable Metrics/ParameterLists
|
||||||
|
job_class_name,
|
||||||
|
batch_table_name,
|
||||||
|
batch_column_name,
|
||||||
|
*job_arguments,
|
||||||
|
job_interval:,
|
||||||
|
batch_min_value: BATCH_MIN_VALUE,
|
||||||
|
batch_max_value: nil,
|
||||||
|
batch_class_name: BATCH_CLASS_NAME,
|
||||||
|
batch_size: BATCH_SIZE,
|
||||||
|
sub_batch_size: SUB_BATCH_SIZE
|
||||||
|
)
|
||||||
|
|
||||||
|
if Gitlab::Database::BackgroundMigration::BatchedMigration.for_configuration(job_class_name, batch_table_name, batch_column_name, job_arguments).exists?
|
||||||
|
Gitlab::AppLogger.warn "Batched background migration not enqueued because it already exists: " \
|
||||||
|
"job_class_name: #{job_class_name}, table_name: #{batch_table_name}, column_name: #{batch_column_name}, " \
|
||||||
|
"job_arguments: #{job_arguments.inspect}"
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
job_interval = BATCH_MIN_DELAY if job_interval < BATCH_MIN_DELAY
|
||||||
|
|
||||||
|
batch_max_value ||= connection.select_value(<<~SQL)
|
||||||
|
SELECT MAX(#{connection.quote_column_name(batch_column_name)})
|
||||||
|
FROM #{connection.quote_table_name(batch_table_name)}
|
||||||
|
SQL
|
||||||
|
|
||||||
|
migration_status = batch_max_value.nil? ? :finished : :active
|
||||||
|
batch_max_value ||= batch_min_value
|
||||||
|
|
||||||
|
migration = Gitlab::Database::BackgroundMigration::BatchedMigration.create!(
|
||||||
|
job_class_name: job_class_name,
|
||||||
|
table_name: batch_table_name,
|
||||||
|
column_name: batch_column_name,
|
||||||
|
job_arguments: job_arguments,
|
||||||
|
interval: job_interval,
|
||||||
|
min_value: batch_min_value,
|
||||||
|
max_value: batch_max_value,
|
||||||
|
batch_class_name: batch_class_name,
|
||||||
|
batch_size: batch_size,
|
||||||
|
sub_batch_size: sub_batch_size,
|
||||||
|
status: migration_status)
|
||||||
|
|
||||||
|
# This guard is necessary since #total_tuple_count was only introduced schema-wise,
|
||||||
|
# after this migration helper had been used for the first time.
|
||||||
|
return migration unless migration.respond_to?(:total_tuple_count)
|
||||||
|
|
||||||
|
# We keep track of the estimated number of tuples to reason later
|
||||||
|
# about the overall progress of a migration.
|
||||||
|
migration.total_tuple_count = Gitlab::Database::SharedModel.using_connection(connection) do
|
||||||
|
Gitlab::Database::PgClass.for_table(batch_table_name)&.cardinality_estimate
|
||||||
|
end
|
||||||
|
migration.save!
|
||||||
|
|
||||||
|
migration
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Modifies https://github.com/rails/rails/blob/v6.1.4.1/actioncable/lib/action_cable/subscription_adapter/base.rb so
|
||||||
|
# that we do not overwrite an id that was explicitly set to `nil` in cable.yml.
|
||||||
|
# This is needed to support GCP Memorystore. See https://github.com/rails/rails/issues/38244.
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module Patch
|
||||||
|
module ActionCableSubscriptionAdapterIdentifier
|
||||||
|
def identifier
|
||||||
|
@server.config.cable.has_key?(:id) ? @server.config.cable[:id] : super # rubocop:disable Gitlab/ModuleWithInstanceVariables
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -167,6 +167,7 @@ export const imageTagsMock = (nodes = tagsMock) => ({
|
||||||
data: {
|
data: {
|
||||||
containerRepository: {
|
containerRepository: {
|
||||||
id: containerRepositoryMock.id,
|
id: containerRepositoryMock.id,
|
||||||
|
tagsCount: nodes.length,
|
||||||
tags: {
|
tags: {
|
||||||
nodes,
|
nodes,
|
||||||
pageInfo: { ...tagsPageInfo },
|
pageInfo: { ...tagsPageInfo },
|
||||||
|
@ -191,7 +192,7 @@ export const graphQLImageDetailsMock = (override) => ({
|
||||||
data: {
|
data: {
|
||||||
containerRepository: {
|
containerRepository: {
|
||||||
...containerRepositoryMock,
|
...containerRepositoryMock,
|
||||||
|
tagsCount: tagsMock.length,
|
||||||
tags: {
|
tags: {
|
||||||
nodes: tagsMock,
|
nodes: tagsMock,
|
||||||
pageInfo: { ...tagsPageInfo },
|
pageInfo: { ...tagsPageInfo },
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import { GlKeysetPagination } from '@gitlab/ui';
|
import { GlKeysetPagination } from '@gitlab/ui';
|
||||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||||
import VueApollo from 'vue-apollo';
|
import VueApollo from 'vue-apollo';
|
||||||
|
import { nextTick } from 'vue';
|
||||||
import createMockApollo from 'helpers/mock_apollo_helper';
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
import axios from '~/lib/utils/axios_utils';
|
import axios from '~/lib/utils/axios_utils';
|
||||||
|
@ -22,6 +23,7 @@ import {
|
||||||
} from '~/packages_and_registries/container_registry/explorer/constants';
|
} from '~/packages_and_registries/container_registry/explorer/constants';
|
||||||
import deleteContainerRepositoryTagsMutation from '~/packages_and_registries/container_registry/explorer/graphql/mutations/delete_container_repository_tags.mutation.graphql';
|
import deleteContainerRepositoryTagsMutation from '~/packages_and_registries/container_registry/explorer/graphql/mutations/delete_container_repository_tags.mutation.graphql';
|
||||||
import getContainerRepositoryDetailsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql';
|
import getContainerRepositoryDetailsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_details.query.graphql';
|
||||||
|
import getContainerRepositoryTagsQuery from '~/packages_and_registries/container_registry/explorer/graphql/queries/get_container_repository_tags.query.graphql';
|
||||||
|
|
||||||
import component from '~/packages_and_registries/container_registry/explorer/pages/details.vue';
|
import component from '~/packages_and_registries/container_registry/explorer/pages/details.vue';
|
||||||
import Tracking from '~/tracking';
|
import Tracking from '~/tracking';
|
||||||
|
@ -32,6 +34,7 @@ import {
|
||||||
containerRepositoryMock,
|
containerRepositoryMock,
|
||||||
graphQLEmptyImageDetailsMock,
|
graphQLEmptyImageDetailsMock,
|
||||||
tagsMock,
|
tagsMock,
|
||||||
|
imageTagsMock,
|
||||||
} from '../mock_data';
|
} from '../mock_data';
|
||||||
import { DeleteModal } from '../stubs';
|
import { DeleteModal } from '../stubs';
|
||||||
|
|
||||||
|
@ -67,12 +70,13 @@ describe('Details Page', () => {
|
||||||
|
|
||||||
const waitForApolloRequestRender = async () => {
|
const waitForApolloRequestRender = async () => {
|
||||||
await waitForPromises();
|
await waitForPromises();
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
const mountComponent = ({
|
const mountComponent = ({
|
||||||
resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock()),
|
resolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock()),
|
||||||
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock),
|
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock),
|
||||||
|
tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock)),
|
||||||
options,
|
options,
|
||||||
config = {},
|
config = {},
|
||||||
} = {}) => {
|
} = {}) => {
|
||||||
|
@ -81,6 +85,7 @@ describe('Details Page', () => {
|
||||||
const requestHandlers = [
|
const requestHandlers = [
|
||||||
[getContainerRepositoryDetailsQuery, resolver],
|
[getContainerRepositoryDetailsQuery, resolver],
|
||||||
[deleteContainerRepositoryTagsMutation, mutationResolver],
|
[deleteContainerRepositoryTagsMutation, mutationResolver],
|
||||||
|
[getContainerRepositoryTagsQuery, tagsResolver],
|
||||||
];
|
];
|
||||||
|
|
||||||
apolloProvider = createMockApollo(requestHandlers);
|
apolloProvider = createMockApollo(requestHandlers);
|
||||||
|
@ -242,38 +247,49 @@ describe('Details Page', () => {
|
||||||
|
|
||||||
describe('confirmDelete event', () => {
|
describe('confirmDelete event', () => {
|
||||||
let mutationResolver;
|
let mutationResolver;
|
||||||
|
let tagsResolver;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock);
|
mutationResolver = jest.fn().mockResolvedValue(graphQLDeleteImageRepositoryTagsMock);
|
||||||
mountComponent({ mutationResolver });
|
tagsResolver = jest.fn().mockResolvedValue(graphQLImageDetailsMock(imageTagsMock));
|
||||||
|
mountComponent({ mutationResolver, tagsResolver });
|
||||||
|
|
||||||
return waitForApolloRequestRender();
|
return waitForApolloRequestRender();
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when one item is selected to be deleted', () => {
|
describe('when one item is selected to be deleted', () => {
|
||||||
it('calls apollo mutation with the right parameters', async () => {
|
it('calls apollo mutation with the right parameters and refetches the tags list query', async () => {
|
||||||
findTagsList().vm.$emit('delete', [cleanTags[0]]);
|
findTagsList().vm.$emit('delete', [cleanTags[0]]);
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
findDeleteModal().vm.$emit('confirmDelete');
|
findDeleteModal().vm.$emit('confirmDelete');
|
||||||
|
|
||||||
expect(mutationResolver).toHaveBeenCalledWith(
|
expect(mutationResolver).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ tagNames: [cleanTags[0].name] }),
|
expect.objectContaining({ tagNames: [cleanTags[0].name] }),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(tagsResolver).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('when more than one item is selected to be deleted', () => {
|
describe('when more than one item is selected to be deleted', () => {
|
||||||
it('calls apollo mutation with the right parameters', async () => {
|
it('calls apollo mutation with the right parameters and refetches the tags list query', async () => {
|
||||||
findTagsList().vm.$emit('delete', tagsMock);
|
findTagsList().vm.$emit('delete', tagsMock);
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
findDeleteModal().vm.$emit('confirmDelete');
|
findDeleteModal().vm.$emit('confirmDelete');
|
||||||
|
|
||||||
expect(mutationResolver).toHaveBeenCalledWith(
|
expect(mutationResolver).toHaveBeenCalledWith(
|
||||||
expect.objectContaining({ tagNames: tagsMock.map((t) => t.name) }),
|
expect.objectContaining({ tagNames: tagsMock.map((t) => t.name) }),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(tagsResolver).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -382,7 +398,7 @@ describe('Details Page', () => {
|
||||||
|
|
||||||
findPartialCleanupAlert().vm.$emit('dismiss');
|
findPartialCleanupAlert().vm.$emit('dismiss');
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(axios.post).toHaveBeenCalledWith(config.userCalloutsPath, {
|
expect(axios.post).toHaveBeenCalledWith(config.userCalloutsPath, {
|
||||||
feature_name: config.userCalloutId,
|
feature_name: config.userCalloutId,
|
||||||
|
@ -472,7 +488,7 @@ describe('Details Page', () => {
|
||||||
await waitForApolloRequestRender();
|
await waitForApolloRequestRender();
|
||||||
findDetailsHeader().vm.$emit('delete');
|
findDetailsHeader().vm.$emit('delete');
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
};
|
};
|
||||||
|
|
||||||
it('on delete event it deletes the image', async () => {
|
it('on delete event it deletes the image', async () => {
|
||||||
|
@ -497,13 +513,13 @@ describe('Details Page', () => {
|
||||||
|
|
||||||
findDeleteImage().vm.$emit('start');
|
findDeleteImage().vm.$emit('start');
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(findTagsLoader().exists()).toBe(true);
|
expect(findTagsLoader().exists()).toBe(true);
|
||||||
|
|
||||||
findDeleteImage().vm.$emit('end');
|
findDeleteImage().vm.$emit('end');
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(findTagsLoader().exists()).toBe(false);
|
expect(findTagsLoader().exists()).toBe(false);
|
||||||
});
|
});
|
||||||
|
@ -513,7 +529,7 @@ describe('Details Page', () => {
|
||||||
|
|
||||||
findDeleteImage().vm.$emit('error');
|
findDeleteImage().vm.$emit('error');
|
||||||
|
|
||||||
await wrapper.vm.$nextTick();
|
await nextTick();
|
||||||
|
|
||||||
expect(findDeleteAlert().props('deleteAlertType')).toBe(ALERT_DANGER_IMAGE);
|
expect(findDeleteAlert().props('deleteAlertType')).toBe(ALERT_DANGER_IMAGE);
|
||||||
});
|
});
|
||||||
|
|
|
@ -23,8 +23,8 @@ describe('Attention require toggle', () => {
|
||||||
|
|
||||||
it.each`
|
it.each`
|
||||||
attentionRequested | icon
|
attentionRequested | icon
|
||||||
${true} | ${'star'}
|
${true} | ${'attention-solid'}
|
||||||
${false} | ${'star-o'}
|
${false} | ${'attention'}
|
||||||
`(
|
`(
|
||||||
'renders $icon icon when attention_requested is $attentionRequested',
|
'renders $icon icon when attention_requested is $attentionRequested',
|
||||||
({ attentionRequested, icon }) => {
|
({ attentionRequested, icon }) => {
|
|
@ -0,0 +1,24 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe 'ActionCableSubscriptionAdapterIdentifier override' do
|
||||||
|
describe '#identifier' do
|
||||||
|
context 'when id key is nil on cable.yml' do
|
||||||
|
it 'does not override server config id with action cable pid' do
|
||||||
|
config = {
|
||||||
|
adapter: 'redis',
|
||||||
|
url: 'unix:/home/localuser/redis/redis.socket',
|
||||||
|
channel_prefix: 'test_',
|
||||||
|
id: nil
|
||||||
|
}
|
||||||
|
::ActionCable::Server::Base.config.cable = config
|
||||||
|
|
||||||
|
sub = ActionCable.server.pubsub.send(:redis_connection)
|
||||||
|
|
||||||
|
expect(sub.connection[:id]).to eq('redis:///home/localuser/redis/redis.socket/0')
|
||||||
|
expect(ActionCable.server.config.cable[:id]).to be_nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -354,161 +354,6 @@ RSpec.describe Gitlab::Database::Migrations::BackgroundMigrationHelpers do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#queue_batched_background_migration' do
|
|
||||||
let(:pgclass_info) { instance_double('Gitlab::Database::PgClass', cardinality_estimate: 42) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
allow(Gitlab::Database::PgClass).to receive(:for_table).and_call_original
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when such migration already exists' do
|
|
||||||
it 'does not create duplicate migration' do
|
|
||||||
create(
|
|
||||||
:batched_background_migration,
|
|
||||||
job_class_name: 'MyJobClass',
|
|
||||||
table_name: :projects,
|
|
||||||
column_name: :id,
|
|
||||||
interval: 10.minutes,
|
|
||||||
min_value: 5,
|
|
||||||
max_value: 1005,
|
|
||||||
batch_class_name: 'MyBatchClass',
|
|
||||||
batch_size: 200,
|
|
||||||
sub_batch_size: 20,
|
|
||||||
job_arguments: [[:id], [:id_convert_to_bigint]]
|
|
||||||
)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration(
|
|
||||||
'MyJobClass',
|
|
||||||
:projects,
|
|
||||||
:id,
|
|
||||||
[:id], [:id_convert_to_bigint],
|
|
||||||
job_interval: 5.minutes,
|
|
||||||
batch_min_value: 5,
|
|
||||||
batch_max_value: 1000,
|
|
||||||
batch_class_name: 'MyBatchClass',
|
|
||||||
batch_size: 100,
|
|
||||||
sub_batch_size: 10)
|
|
||||||
end.not_to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates the database record for the migration' do
|
|
||||||
expect(Gitlab::Database::PgClass).to receive(:for_table).with(:projects).and_return(pgclass_info)
|
|
||||||
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration(
|
|
||||||
'MyJobClass',
|
|
||||||
:projects,
|
|
||||||
:id,
|
|
||||||
job_interval: 5.minutes,
|
|
||||||
batch_min_value: 5,
|
|
||||||
batch_max_value: 1000,
|
|
||||||
batch_class_name: 'MyBatchClass',
|
|
||||||
batch_size: 100,
|
|
||||||
sub_batch_size: 10)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to have_attributes(
|
|
||||||
job_class_name: 'MyJobClass',
|
|
||||||
table_name: 'projects',
|
|
||||||
column_name: 'id',
|
|
||||||
interval: 300,
|
|
||||||
min_value: 5,
|
|
||||||
max_value: 1000,
|
|
||||||
batch_class_name: 'MyBatchClass',
|
|
||||||
batch_size: 100,
|
|
||||||
sub_batch_size: 10,
|
|
||||||
job_arguments: %w[],
|
|
||||||
status: 'active',
|
|
||||||
total_tuple_count: pgclass_info.cardinality_estimate)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the job interval is lower than the minimum' do
|
|
||||||
let(:minimum_delay) { described_class::BATCH_MIN_DELAY }
|
|
||||||
|
|
||||||
it 'sets the job interval to the minimum value' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: minimum_delay - 1.minute)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
|
||||||
|
|
||||||
expect(created_migration.interval).to eq(minimum_delay)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when additional arguments are passed to the method' do
|
|
||||||
it 'saves the arguments on the database record' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration(
|
|
||||||
'MyJobClass',
|
|
||||||
:projects,
|
|
||||||
:id,
|
|
||||||
'my',
|
|
||||||
'arguments',
|
|
||||||
job_interval: 5.minutes,
|
|
||||||
batch_max_value: 1000)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to have_attributes(
|
|
||||||
job_class_name: 'MyJobClass',
|
|
||||||
table_name: 'projects',
|
|
||||||
column_name: 'id',
|
|
||||||
interval: 300,
|
|
||||||
min_value: 1,
|
|
||||||
max_value: 1000,
|
|
||||||
job_arguments: %w[my arguments])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the max_value is not given' do
|
|
||||||
context 'when records exist in the database' do
|
|
||||||
let!(:event1) { create(:event) }
|
|
||||||
let!(:event2) { create(:event) }
|
|
||||||
let!(:event3) { create(:event) }
|
|
||||||
|
|
||||||
it 'creates the record with the current max value' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
|
||||||
|
|
||||||
expect(created_migration.max_value).to eq(event3.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates the record with an active status' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to be_active
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'when the database is empty' do
|
|
||||||
it 'sets the max value to the min value' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
|
||||||
|
|
||||||
expect(created_migration.max_value).to eq(created_migration.min_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'creates the record with a finished status' do
|
|
||||||
expect do
|
|
||||||
model.queue_batched_background_migration('MyJobClass', :projects, :id, job_interval: 5.minutes)
|
|
||||||
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
|
||||||
|
|
||||||
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to be_finished
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#migrate_async' do
|
describe '#migrate_async' do
|
||||||
it 'calls BackgroundMigrationWorker.perform_async' do
|
it 'calls BackgroundMigrationWorker.perform_async' do
|
||||||
expect(BackgroundMigrationWorker).to receive(:perform_async).with("Class", "hello", "world")
|
expect(BackgroundMigrationWorker).to receive(:perform_async).with("Class", "hello", "world")
|
||||||
|
|
|
@ -0,0 +1,164 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers do
|
||||||
|
let(:migration) do
|
||||||
|
ActiveRecord::Migration.new.extend(described_class)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#queue_batched_background_migration' do
|
||||||
|
let(:pgclass_info) { instance_double('Gitlab::Database::PgClass', cardinality_estimate: 42) }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(Gitlab::Database::PgClass).to receive(:for_table).and_call_original
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when such migration already exists' do
|
||||||
|
it 'does not create duplicate migration' do
|
||||||
|
create(
|
||||||
|
:batched_background_migration,
|
||||||
|
job_class_name: 'MyJobClass',
|
||||||
|
table_name: :projects,
|
||||||
|
column_name: :id,
|
||||||
|
interval: 10.minutes,
|
||||||
|
min_value: 5,
|
||||||
|
max_value: 1005,
|
||||||
|
batch_class_name: 'MyBatchClass',
|
||||||
|
batch_size: 200,
|
||||||
|
sub_batch_size: 20,
|
||||||
|
job_arguments: [[:id], [:id_convert_to_bigint]]
|
||||||
|
)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration(
|
||||||
|
'MyJobClass',
|
||||||
|
:projects,
|
||||||
|
:id,
|
||||||
|
[:id], [:id_convert_to_bigint],
|
||||||
|
job_interval: 5.minutes,
|
||||||
|
batch_min_value: 5,
|
||||||
|
batch_max_value: 1000,
|
||||||
|
batch_class_name: 'MyBatchClass',
|
||||||
|
batch_size: 100,
|
||||||
|
sub_batch_size: 10)
|
||||||
|
end.not_to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates the database record for the migration' do
|
||||||
|
expect(Gitlab::Database::PgClass).to receive(:for_table).with(:projects).and_return(pgclass_info)
|
||||||
|
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration(
|
||||||
|
'MyJobClass',
|
||||||
|
:projects,
|
||||||
|
:id,
|
||||||
|
job_interval: 5.minutes,
|
||||||
|
batch_min_value: 5,
|
||||||
|
batch_max_value: 1000,
|
||||||
|
batch_class_name: 'MyBatchClass',
|
||||||
|
batch_size: 100,
|
||||||
|
sub_batch_size: 10)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to have_attributes(
|
||||||
|
job_class_name: 'MyJobClass',
|
||||||
|
table_name: 'projects',
|
||||||
|
column_name: 'id',
|
||||||
|
interval: 300,
|
||||||
|
min_value: 5,
|
||||||
|
max_value: 1000,
|
||||||
|
batch_class_name: 'MyBatchClass',
|
||||||
|
batch_size: 100,
|
||||||
|
sub_batch_size: 10,
|
||||||
|
job_arguments: %w[],
|
||||||
|
status: 'active',
|
||||||
|
total_tuple_count: pgclass_info.cardinality_estimate)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the job interval is lower than the minimum' do
|
||||||
|
let(:minimum_delay) { described_class::BATCH_MIN_DELAY }
|
||||||
|
|
||||||
|
it 'sets the job interval to the minimum value' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: minimum_delay - 1.minute)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
||||||
|
|
||||||
|
expect(created_migration.interval).to eq(minimum_delay)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when additional arguments are passed to the method' do
|
||||||
|
it 'saves the arguments on the database record' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration(
|
||||||
|
'MyJobClass',
|
||||||
|
:projects,
|
||||||
|
:id,
|
||||||
|
'my',
|
||||||
|
'arguments',
|
||||||
|
job_interval: 5.minutes,
|
||||||
|
batch_max_value: 1000)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to have_attributes(
|
||||||
|
job_class_name: 'MyJobClass',
|
||||||
|
table_name: 'projects',
|
||||||
|
column_name: 'id',
|
||||||
|
interval: 300,
|
||||||
|
min_value: 1,
|
||||||
|
max_value: 1000,
|
||||||
|
job_arguments: %w[my arguments])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the max_value is not given' do
|
||||||
|
context 'when records exist in the database' do
|
||||||
|
let!(:event1) { create(:event) }
|
||||||
|
let!(:event2) { create(:event) }
|
||||||
|
let!(:event3) { create(:event) }
|
||||||
|
|
||||||
|
it 'creates the record with the current max value' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
||||||
|
|
||||||
|
expect(created_migration.max_value).to eq(event3.id)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates the record with an active status' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to be_active
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the database is empty' do
|
||||||
|
it 'sets the max value to the min value' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration('MyJobClass', :events, :id, job_interval: 5.minutes)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
created_migration = Gitlab::Database::BackgroundMigration::BatchedMigration.last
|
||||||
|
|
||||||
|
expect(created_migration.max_value).to eq(created_migration.min_value)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates the record with a finished status' do
|
||||||
|
expect do
|
||||||
|
migration.queue_batched_background_migration('MyJobClass', :projects, :id, job_interval: 5.minutes)
|
||||||
|
end.to change { Gitlab::Database::BackgroundMigration::BatchedMigration.count }.by(1)
|
||||||
|
|
||||||
|
expect(Gitlab::Database::BackgroundMigration::BatchedMigration.last).to be_finished
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue