Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d2091d1e92
commit
bac259ea8b
61 changed files with 786 additions and 184 deletions
|
@ -192,7 +192,7 @@ export default {
|
|||
<gl-button
|
||||
v-if="canRenderPipelineButton"
|
||||
block
|
||||
class="gl-mt-3 gl-mb-0 gl-md-display-none"
|
||||
class="gl-mt-3 gl-mb-3 gl-md-display-none"
|
||||
variant="success"
|
||||
data-testid="run_pipeline_button_mobile"
|
||||
:loading="state.isRunningMergeRequestPipeline"
|
||||
|
|
|
@ -85,7 +85,7 @@ export default {
|
|||
this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', showLoader);
|
||||
|
||||
this.service
|
||||
.getFolderContent(folder.folder_path)
|
||||
.getFolderContent(folder.folder_path, folder.state)
|
||||
.then((response) => this.store.setfolderContent(folder, response.data.environments))
|
||||
.then(() => this.store.updateEnvironmentProp(folder, 'isLoadingFolderContent', false))
|
||||
.catch(() => {
|
||||
|
|
|
@ -21,7 +21,7 @@ export default class EnvironmentsService {
|
|||
return axios.delete(endpoint, {});
|
||||
}
|
||||
|
||||
getFolderContent(folderUrl) {
|
||||
return axios.get(`${folderUrl}.json?per_page=${this.folderResults}`);
|
||||
getFolderContent(folderUrl, scope) {
|
||||
return axios.get(`${folderUrl}.json?per_page=${this.folderResults}&scope=${scope}`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,7 +292,7 @@ export default {
|
|||
failure.text
|
||||
}}</gl-alert>
|
||||
<div class="gl-mb-3">
|
||||
<h3>{{ s__('PipelineCharts|CI / CD Analytics') }}</h3>
|
||||
<h3>{{ s__('PipelineCharts|CI/CD Analytics') }}</h3>
|
||||
</div>
|
||||
<h4 class="gl-my-4">{{ s__('PipelineCharts|Overall statistics') }}</h4>
|
||||
<div class="row">
|
||||
|
|
|
@ -6,8 +6,8 @@ module Types
|
|||
graphql_name 'DiffPositionType'
|
||||
description 'Type of file the position refers to'
|
||||
|
||||
value 'text'
|
||||
value 'image'
|
||||
value 'text', description: "A text file"
|
||||
value 'image', description: "An image"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -58,7 +58,7 @@ module Analytics
|
|||
return unless project.feature_available?(:builds, current_user) || !project.empty_repo?
|
||||
|
||||
navbar_sub_item(
|
||||
title: _('CI / CD'),
|
||||
title: _('CI/CD'),
|
||||
path: 'pipelines#charts',
|
||||
link: charts_project_pipelines_path(project)
|
||||
)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- breadcrumb_title _("CI / CD Settings")
|
||||
- page_title _("CI / CD")
|
||||
- breadcrumb_title _("CI/CD Settings")
|
||||
- page_title _("CI/CD")
|
||||
|
||||
- expanded = expanded_by_default?
|
||||
- general_expanded = @group.errors.empty? ? expanded : true
|
||||
|
|
|
@ -171,9 +171,9 @@
|
|||
= _('Repository')
|
||||
|
||||
= nav_link(controller: :ci_cd) do
|
||||
= link_to group_settings_ci_cd_path(@group), title: _('CI / CD') do
|
||||
= link_to group_settings_ci_cd_path(@group), title: _('CI/CD') do
|
||||
%span
|
||||
= _('CI / CD')
|
||||
= _('CI/CD')
|
||||
|
||||
= render 'groups/sidebar/packages_settings'
|
||||
|
||||
|
|
|
@ -179,13 +179,13 @@
|
|||
.nav-icon-container
|
||||
= sprite_icon('rocket')
|
||||
%span.nav-item-name#js-onboarding-pipelines-link
|
||||
= _('CI / CD')
|
||||
= _('CI/CD')
|
||||
|
||||
%ul.sidebar-sub-level-items
|
||||
= nav_link(controller: [:pipelines, :builds, :jobs, :pipeline_schedules, :artifacts, :test_cases, :pipeline_editor], html_options: { class: "fly-out-top-item" }) do
|
||||
= link_to project_pipelines_path(@project) do
|
||||
%strong.fly-out-top-item-name
|
||||
= _('CI / CD')
|
||||
= _('CI/CD')
|
||||
%li.divider.fly-out-top-item
|
||||
- if project_nav_tab? :pipelines
|
||||
= nav_link(path: ['pipelines#index', 'pipelines#show']) do
|
||||
|
@ -418,9 +418,9 @@
|
|||
= _('Repository')
|
||||
- if !@project.archived? && @project.feature_available?(:builds, current_user)
|
||||
= nav_link(controller: :ci_cd) do
|
||||
= link_to project_settings_ci_cd_path(@project), title: _('CI / CD') do
|
||||
= link_to project_settings_ci_cd_path(@project), title: _('CI/CD') do
|
||||
%span
|
||||
= _('CI / CD')
|
||||
= _('CI/CD')
|
||||
- if settings_operations_available?
|
||||
= nav_link(controller: [:operations]) do
|
||||
= link_to project_settings_operations_path(@project), title: _('Operations'), data: { qa_selector: 'operations_settings_link' } do
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
- page_title _('CI / CD Analytics')
|
||||
- page_title _('CI/CD Analytics')
|
||||
|
||||
#js-project-pipelines-charts-app{ data: { project_path: @project.full_path,
|
||||
should_render_deployment_frequency_charts: should_render_deployment_frequency_charts.to_s } }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- @content_class = "limit-container-width" unless fluid_layout
|
||||
- page_title _("CI / CD Settings")
|
||||
- page_title _("CI / CD")
|
||||
- page_title _("CI/CD Settings")
|
||||
- page_title _("CI/CD")
|
||||
|
||||
- expanded = expanded_by_default?
|
||||
- general_expanded = @project.errors.empty? ? expanded : true
|
||||
|
|
|
@ -13,13 +13,6 @@
|
|||
.user-profile
|
||||
.cover-block.user-cover-block{ class: [('border-bottom' if profile_tabs.empty?)] }
|
||||
= render layout: 'users/cover_controls' do
|
||||
- if current_user && current_user.id != @user.id
|
||||
- if current_user.following?(@user)
|
||||
= link_to user_unfollow_path(@user, :json) , class: link_classes + 'btn gl-button btn-default', method: :post do
|
||||
= _('Unfollow')
|
||||
- else
|
||||
= link_to user_follow_path(@user, :json) , class: link_classes + 'btn gl-button btn-default', method: :post do
|
||||
= _('Follow')
|
||||
- if @user == current_user
|
||||
= link_to profile_path, class: link_classes + 'btn gl-button btn-default btn-icon has-tooltip',
|
||||
title: s_('UserProfile|Edit profile'), 'aria-label': 'Edit profile', data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
|
||||
|
@ -41,6 +34,13 @@
|
|||
= link_to [:admin, @user], class: link_classes + 'btn gl-button btn-default btn-icon', title: s_('UserProfile|View user in admin area'),
|
||||
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
|
||||
= sprite_icon('user')
|
||||
- if current_user && current_user.id != @user.id
|
||||
- if current_user.following?(@user)
|
||||
= link_to user_unfollow_path(@user, :json) , class: link_classes + 'btn gl-button btn-default', method: :post do
|
||||
= _('Unfollow')
|
||||
- else
|
||||
= link_to user_follow_path(@user, :json) , class: link_classes + 'btn gl-button btn-confirm', method: :post do
|
||||
= _('Follow')
|
||||
|
||||
.profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] }
|
||||
.avatar-holder
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Reorder user profile actions and use the confirm variant for the follow button
|
||||
merge_request: 55999
|
||||
author:
|
||||
type: other
|
5
changelogs/unreleased/322128-token-used-field.yml
Normal file
5
changelogs/unreleased/322128-token-used-field.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add last_used_at field to cluster agent token
|
||||
merge_request: 56023
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/chore-bump-swagger-ui-dist.yml
Normal file
5
changelogs/unreleased/chore-bump-swagger-ui-dist.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Bump swagger-ui-dist to 3.44.1
|
||||
merge_request: 55310
|
||||
author: Roger Meier
|
||||
type: changed
|
5
changelogs/unreleased/dictionary-md-generated-links.yml
Normal file
5
changelogs/unreleased/dictionary-md-generated-links.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fixed vestigial Anchor links in doc/development/usage_ping/dictionary.md
|
||||
merge_request: 55874
|
||||
author: Raimund Hook
|
||||
type: fixed
|
5
changelogs/unreleased/expand-stopped-env.yml
Normal file
5
changelogs/unreleased/expand-stopped-env.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Expand nested stopped environments
|
||||
merge_request: 55676
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Migrate group milestones when using Bulk Import
|
||||
merge_request: 55981
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
title: Change the default batch_class_name for batched_background_migrations to the
|
||||
unqualified class name
|
||||
merge_request: 56036
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/update-cicd-naming.yml
Normal file
5
changelogs/unreleased/update-cicd-naming.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Update UI text to CI/CD from CI / CD
|
||||
merge_request: 56070
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,10 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ChangeBatchedBackgroundMigrationsBatchClassNameDefault < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
change_column_default :batched_background_migrations, :batch_class_name,
|
||||
from: 'Gitlab::Database::BackgroundMigration::PrimaryKeyBatchingStrategy', to: 'PrimaryKeyBatchingStrategy'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddLastUsedAtToClusterAgentToken < ActiveRecord::Migration[6.0]
|
||||
DOWNTIME = false
|
||||
|
||||
def change
|
||||
add_column :cluster_agent_tokens, :last_used_at, :datetime_with_timezone
|
||||
end
|
||||
end
|
1
db/schema_migrations/20210308190413
Normal file
1
db/schema_migrations/20210308190413
Normal file
|
@ -0,0 +1 @@
|
|||
cc131cf37f2af8f0f58c7fa6e5055e88a3b2ed413862c155b0d18383aba06058
|
1
db/schema_migrations/20210309181019
Normal file
1
db/schema_migrations/20210309181019
Normal file
|
@ -0,0 +1 @@
|
|||
a31b85b8ab0db2ad4daa5f2c15eacae97432e75e0e0a28f10d81f6a5aa94c8e0
|
|
@ -9876,7 +9876,7 @@ CREATE TABLE batched_background_migrations (
|
|||
"interval" smallint NOT NULL,
|
||||
status smallint DEFAULT 0 NOT NULL,
|
||||
job_class_name text NOT NULL,
|
||||
batch_class_name text DEFAULT 'Gitlab::Database::BackgroundMigration::PrimaryKeyBatchingStrategy'::text NOT NULL,
|
||||
batch_class_name text DEFAULT 'PrimaryKeyBatchingStrategy'::text NOT NULL,
|
||||
table_name text NOT NULL,
|
||||
column_name text NOT NULL,
|
||||
job_arguments jsonb DEFAULT '"[]"'::jsonb NOT NULL,
|
||||
|
@ -11156,6 +11156,7 @@ CREATE TABLE cluster_agent_tokens (
|
|||
created_by_user_id bigint,
|
||||
description text,
|
||||
name text,
|
||||
last_used_at timestamp with time zone,
|
||||
CONSTRAINT check_2b79dbb315 CHECK ((char_length(name) <= 255)),
|
||||
CONSTRAINT check_4e4ec5070a CHECK ((char_length(description) <= 1024)),
|
||||
CONSTRAINT check_c60daed227 CHECK ((char_length(token_encrypted) <= 255))
|
||||
|
|
|
@ -1063,6 +1063,70 @@ encounter this error.
|
|||
Administrators can increase the token duration in **Admin area > Settings >
|
||||
CI/CD > Container Registry > Authorization token duration (minutes)**.
|
||||
|
||||
### Docker login attempt fails with: 'token signed by untrusted key'
|
||||
|
||||
[Registry relies on GitLab to validate credentials](https://docs.gitlab.com/omnibus/architecture/registry/).
|
||||
If the registry fails to authenticate valid login attempts, you get the following error message:
|
||||
|
||||
```shell
|
||||
# docker login gitlab.company.com:4567
|
||||
Username: user
|
||||
Password:
|
||||
Error response from daemon: login attempt to https://gitlab.company.com:4567/v2/ failed with status: 401 Unauthorized
|
||||
```
|
||||
|
||||
And more specifically, this appears in the `/var/log/gitlab/registry/current` log file:
|
||||
|
||||
```plaintext
|
||||
level=info msg="token signed by untrusted key with ID: "TOKE:NL6Q:7PW6:EXAM:PLET:OKEN:BG27:RCIB:D2S3:EXAM:PLET:OKEN""
|
||||
level=warning msg="error authorizing context: invalid token" go.version=go1.12.7 http.request.host="gitlab.company.com:4567" http.request.id=74613829-2655-4f96-8991-1c9fe33869b8 http.request.method=GET http.request.remoteaddr=10.72.11.20 http.request.uri="/v2/" http.request.useragent="docker/19.03.2 go/go1.12.8 git-commit/6a30dfc kernel/3.10.0-693.2.2.el7.x86_64 os/linux arch/amd64 UpstreamClient(Docker-Client/19.03.2 \(linux\))"
|
||||
```
|
||||
|
||||
GitLab uses the contents of the certificate key pair's two sides to encrypt the authentication token
|
||||
for the Registry. This message means that those contents do not align.
|
||||
|
||||
Check which files are in use:
|
||||
|
||||
- `grep -A6 'auth:' /var/opt/gitlab/registry/config.yml`
|
||||
|
||||
```yaml
|
||||
## Container Registry Certificate
|
||||
auth:
|
||||
token:
|
||||
realm: https://gitlab.my.net/jwt/auth
|
||||
service: container_registry
|
||||
issuer: omnibus-gitlab-issuer
|
||||
--> rootcertbundle: /var/opt/gitlab/registry/gitlab-registry.crt
|
||||
autoredirect: false
|
||||
```
|
||||
|
||||
- `grep -A9 'Container Registry' /var/opt/gitlab/gitlab-rails/etc/gitlab.yml`
|
||||
|
||||
```yaml
|
||||
## Container Registry Key
|
||||
registry:
|
||||
enabled: true
|
||||
host: gitlab.company.com
|
||||
port: 4567
|
||||
api_url: http://127.0.0.1:5000 # internal address to the registry, will be used by GitLab to directly communicate with API
|
||||
path: /var/opt/gitlab/gitlab-rails/shared/registry
|
||||
--> key: /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key
|
||||
issuer: omnibus-gitlab-issuer
|
||||
notification_secret:
|
||||
```
|
||||
|
||||
The output of these `openssl` commands should match, proving that the cert-key pair is a match:
|
||||
|
||||
```shell
|
||||
openssl x509 -noout -modulus -in /var/opt/gitlab/registry/gitlab-registry.crt | openssl sha256
|
||||
openssl rsa -noout -modulus -in /var/opt/gitlab/gitlab-rails/etc/gitlab-registry.key | openssl sha256
|
||||
```
|
||||
|
||||
If the two pieces of the certificate do not align, remove the files and run `gitlab-ctl reconfigure`
|
||||
to regenerate the pair. If you have overridden the automatically generated self-signed pair with
|
||||
your own certificates and have made sure that their contents align, you can delete the 'registry'
|
||||
section in your `/etc/gitlab/gitlab-secrets.json` and run `gitlab-ctl reconfigure`.
|
||||
|
||||
### AWS S3 with the GitLab registry error when pushing large images
|
||||
|
||||
When using AWS S3 with the GitLab registry, an error may occur when pushing
|
||||
|
|
|
@ -5386,8 +5386,8 @@ Type of file the position refers to.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `image` | |
|
||||
| `text` | |
|
||||
| `image` | An image |
|
||||
| `text` | A text file |
|
||||
|
||||
### `EntryType`
|
||||
|
||||
|
|
|
@ -45,8 +45,8 @@ GET /projects
|
|||
| `archived` | boolean | **{dotted-circle}** No | Limit by archived status. |
|
||||
| `id_after` | integer | **{dotted-circle}** No | Limit results to projects with IDs greater than the specified ID. |
|
||||
| `id_before` | integer | **{dotted-circle}** No | Limit results to projects with IDs less than the specified ID. |
|
||||
| `last_activity_after` | datetime | **{dotted-circle}** No | Limit results to projects with last_activity after specified time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
|
||||
| `last_activity_before` | datetime | **{dotted-circle}** No | Limit results to projects with last_activity before specified time. Format: ISO 8601 YYYY-MM-DDTHH:MM:SSZ |
|
||||
| `last_activity_after` | datetime | **{dotted-circle}** No | Limit results to projects with last_activity after specified time. Format: ISO 8601 `YYYY-MM-DDTHH:MM:SSZ` |
|
||||
| `last_activity_before` | datetime | **{dotted-circle}** No | Limit results to projects with last_activity before specified time. Format: ISO 8601 `YYYY-MM-DDTHH:MM:SSZ` |
|
||||
| `membership` | boolean | **{dotted-circle}** No | Limit by projects that the current user is a member of. |
|
||||
| `min_access_level` | integer | **{dotted-circle}** No | Limit by current user minimal [access level](members.md#valid-access-levels). |
|
||||
| `order_by` | string | **{dotted-circle}** No | Return projects ordered by `id`, `name`, `path`, `created_at`, `updated_at`, or `last_activity_at` fields. `repository_size`, `storage_size`, `packages_size` or `wiki_size` fields are only allowed for admins. Default is `created_at`. |
|
||||
|
@ -1005,10 +1005,13 @@ If the project is a fork, and you provide a valid token to authenticate, the
|
|||
}
|
||||
```
|
||||
|
||||
### Templates for issues and merge requests **(PREMIUM)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55718) in GitLab 13.10.
|
||||
|
||||
Users of [GitLab Premium or higher](https://about.gitlab.com/pricing/)
|
||||
can also see the `issues_template` and `merge_requests_template` parameters:
|
||||
[introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/55718)
|
||||
in GitLab 13.10.
|
||||
can also see the `issues_template` and `merge_requests_template` parameters for managing
|
||||
[issue and merge request description templates](../user/project/description_templates.md).
|
||||
|
||||
```json
|
||||
{
|
||||
|
@ -1110,7 +1113,7 @@ POST /projects
|
|||
| Attribute | Type | Required | Description |
|
||||
|-------------------------------------------------------------|---------|------------------------|-------------|
|
||||
| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
|
||||
| `analytics_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
|
||||
| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge requests by default. |
|
||||
| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This isn't a boolean, but enabled/disabled. |
|
||||
| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
|
||||
|
@ -1184,7 +1187,7 @@ POST /projects/user/:user_id
|
|||
| Attribute | Type | Required | Description |
|
||||
|-------------------------------------------------------------|---------|------------------------|-------------|
|
||||
| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
|
||||
| `analytics_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
|
||||
| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge requests by default. |
|
||||
| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This isn't a boolean, but enabled/disabled. |
|
||||
| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual` or `timed_incremental`). |
|
||||
|
@ -1257,7 +1260,7 @@ PUT /projects/:id
|
|||
| Attribute | Type | Required | Description |
|
||||
|-------------------------------------------------------------|----------------|------------------------|-------------|
|
||||
| `allow_merge_on_skipped_pipeline` | boolean | **{dotted-circle}** No | Set whether or not merge requests can be merged with skipped jobs. |
|
||||
| `analytics_access_level` | string | no | One of `disabled`, `private` or `enabled` |
|
||||
| `analytics_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private` or `enabled` |
|
||||
| `approvals_before_merge` **(PREMIUM)** | integer | **{dotted-circle}** No | How many approvers should approve merge request by default. |
|
||||
| `auto_cancel_pending_pipelines` | string | **{dotted-circle}** No | Auto-cancel pending pipelines. This isn't a boolean, but enabled/disabled. |
|
||||
| `auto_devops_deploy_strategy` | string | **{dotted-circle}** No | Auto Deploy strategy (`continuous`, `manual`, or `timed_incremental`). |
|
||||
|
@ -1317,8 +1320,8 @@ PUT /projects/:id
|
|||
| `visibility` | string | **{dotted-circle}** No | See [project visibility level](#project-visibility-level). |
|
||||
| `wiki_access_level` | string | **{dotted-circle}** No | One of `disabled`, `private`, or `enabled`. |
|
||||
| `wiki_enabled` | boolean | **{dotted-circle}** No | _(Deprecated)_ Enable wiki for this project. Use `wiki_access_level` instead. |
|
||||
| `issues_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. |
|
||||
| `merge_requests_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Merge Requests. Description is parsed with GitLab Flavored Markdown. |
|
||||
| `issues_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Issues. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
|
||||
| `merge_requests_template` **(PREMIUM)** | string | **{dotted-circle}** No | Default description for Merge Requests. Description is parsed with GitLab Flavored Markdown. See [Templates for issues and merge requests](#templates-for-issues-and-merge-requests). |
|
||||
|
||||
## Fork project
|
||||
|
||||
|
@ -2537,12 +2540,6 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitla
|
|||
|
||||
Read more in the [Project Badges](project_badges.md) documentation.
|
||||
|
||||
## Issue and merge request description templates
|
||||
|
||||
The non-default [issue and merge request description templates](../user/project/description_templates.md)
|
||||
are managed inside the project's repository. So you can manage them with the API
|
||||
through the [Repositories API](repositories.md) and the [Repository Files API](repository_files.md).
|
||||
|
||||
## Download snapshot of a Git repository
|
||||
|
||||
> Introduced in GitLab 10.7
|
||||
|
|
|
@ -347,13 +347,112 @@ example, you can find which tests take longest to run or which execute the most
|
|||
queries. This can be handy for optimizing our tests or identifying performance
|
||||
issues in our code.
|
||||
|
||||
## Memory profiling
|
||||
## Memory optimization
|
||||
|
||||
We can use two approaches, often in combination, to track down memory issues:
|
||||
We can use a set of different techniques, often in combination, to track down memory issues:
|
||||
|
||||
- Leaving the code intact and wrapping a profiler around it.
|
||||
- Use memory allocation counters for requests and services.
|
||||
- Monitor memory usage of the process while disabling/enabling different parts of the code we suspect could be problematic.
|
||||
|
||||
### Memory allocations
|
||||
|
||||
Ruby shipped with GitLab includes a special patch to allow [tracing memory allocations](https://gitlab.com/gitlab-org/gitlab/-/issues/296530).
|
||||
This patch is available by default for
|
||||
[Omnibus](https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/4948),
|
||||
[CNG](https://gitlab.com/gitlab-org/build/CNG/-/merge_requests/591),
|
||||
[GitLab CI](https://gitlab.com/gitlab-org/gitlab-build-images/-/merge_requests/355),
|
||||
[GCK](https://gitlab.com/gitlab-org/gitlab-compose-kit/-/merge_requests/149)
|
||||
and can additionally be enabled for [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/master/doc/advanced.md#apply-custom-patches-for-ruby).
|
||||
|
||||
This patch provides a set of 3 metrics that makes it easier to understand efficiency of memory usage for a given codepath:
|
||||
|
||||
- `mem_objects`: the number of objects allocated.
|
||||
- `mem_bytes`: the number of bytes allocated by malloc.
|
||||
- `mem_mallocs`: the number of malloc allocations.
|
||||
|
||||
The number of objects and bytes allocated impact how often GC cycles happen.
|
||||
Fewer objects allocations result in a significantly more responsive application.
|
||||
|
||||
It is advised that web server requests do not allocate more than `100k mem_objects`
|
||||
and `100M mem_bytes`. You can view the current usage on [GitLab.com](https://log.gprd.gitlab.net/goto/3a9678bb595e3f89a0c7b5c61bcc47b9).
|
||||
|
||||
#### Checking memory pressure of own code
|
||||
|
||||
There are two ways of measuring your own code:
|
||||
|
||||
1. Review `api_json.log`, `development_json.log`, `sidekiq.log` that includes memory allocation counters.
|
||||
1. Use `Gitlab::Memory::Instrumentation.with_memory_allocations` for a given codeblock and log it.
|
||||
1. Use [Measuring module](service_measurement.md)
|
||||
|
||||
```json
|
||||
{"time":"2021-02-15T11:20:40.821Z","severity":"INFO","duration_s":0.27412,"db_duration_s":0.05755,"view_duration_s":0.21657,"status":201,"method":"POST","path":"/api/v4/projects/user/1","mem_objects":86705,"mem_bytes":4277179,"mem_mallocs":22693,"correlation_id":"...}
|
||||
```
|
||||
|
||||
#### Different types of allocations
|
||||
|
||||
The `mem_*` values represent different aspects of how objects and memory are allocated in Ruby:
|
||||
|
||||
- The following example will create around of `1000` of `mem_objects` since strings
|
||||
can be frozen, and while the underlying string object remains the same, we still need to allocate 1000 references to this string:
|
||||
|
||||
```ruby
|
||||
Gitlab::Memory::Instrumentation.with_memory_allocations do
|
||||
1_000.times { '0123456789' }
|
||||
end
|
||||
|
||||
=> {:mem_objects=>1001, :mem_bytes=>0, :mem_mallocs=>0}
|
||||
```
|
||||
|
||||
- The following example will create around of `1000` of `mem_objects`, as strings are created dynamically.
|
||||
Each of them will not allocate additional memory, as they fit into Ruby slot of 40 bytes:
|
||||
|
||||
```ruby
|
||||
Gitlab::Memory::Instrumentation.with_memory_allocations do
|
||||
s = '0'
|
||||
1_000.times { s * 23 }
|
||||
end
|
||||
|
||||
=> {:mem_objects=>1002, :mem_bytes=>0, :mem_mallocs=>0}
|
||||
```
|
||||
|
||||
- The following example will create around of `1000` of `mem_objects`, as strings are created dynamically.
|
||||
Each of them will allocate additional memory as strings are larger than Ruby slot of 40 bytes:
|
||||
|
||||
```ruby
|
||||
Gitlab::Memory::Instrumentation.with_memory_allocations do
|
||||
s = '0'
|
||||
1_000.times { s * 24 }
|
||||
end
|
||||
|
||||
=> {:mem_objects=>1002, :mem_bytes=>32000, :mem_mallocs=>1000}
|
||||
```
|
||||
|
||||
- The following example will allocate over 40kB of data, and perform only a single memory allocation.
|
||||
The existing object will be reallocated/resized on subsequent iterations:
|
||||
|
||||
```ruby
|
||||
Gitlab::Memory::Instrumentation.with_memory_allocations do
|
||||
str = ''
|
||||
append = '0123456789012345678901234567890123456789' # 40 bytes
|
||||
1_000.times { str.concat(append) }
|
||||
end
|
||||
=> {:mem_objects=>3, :mem_bytes=>49152, :mem_mallocs=>1}
|
||||
```
|
||||
|
||||
- The following example will create over 1k of objects, perform over 1k of allocations, each time mutating the object.
|
||||
This does result in copying a lot of data and perform a lot of memory allocations
|
||||
(as represented by `mem_bytes` counter) indicating very inefficient method of appending string:
|
||||
|
||||
```ruby
|
||||
Gitlab::Memory::Instrumentation.with_memory_allocations do
|
||||
str = ''
|
||||
append = '0123456789012345678901234567890123456789' # 40 bytes
|
||||
1_000.times { str += append }
|
||||
end
|
||||
=> {:mem_objects=>1003, :mem_bytes=>21968752, :mem_mallocs=>1000}
|
||||
```
|
||||
|
||||
### Using Memory Profiler
|
||||
|
||||
We can use `memory_profiler` for profiling.
|
||||
|
|
|
@ -2818,7 +2818,7 @@ Tiers: `free`, `premium`, `ultimate`
|
|||
|
||||
### `counts.ldap_group_links`
|
||||
|
||||
Number of groups that are synced via LDAP group sync `https://docs.gitlab.com/ee/user/group/index.html#manage-group-memberships-via-ldap-starter-only`
|
||||
Number of groups that are synced via LDAP group sync `https://docs.gitlab.com/ee/user/group/index.html#manage-group-memberships-via-ldap`
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216174822_ldap_group_links.yml)
|
||||
|
||||
|
@ -2830,7 +2830,7 @@ Tiers: `premium`, `ultimate`
|
|||
|
||||
### `counts.ldap_keys`
|
||||
|
||||
Number of keys synced as part of LDAP `https://docs.gitlab.com/ee/administration/auth/ldap/#ldap-sync-configuration-settings-starter-only`
|
||||
Number of keys synced as part of LDAP `https://docs.gitlab.com/ee/administration/auth/ldap/#ldap-sync-configuration-settings`
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216174824_ldap_keys.yml)
|
||||
|
||||
|
@ -14158,7 +14158,7 @@ Tiers: `free`
|
|||
|
||||
### `usage_activity_by_stage.manage.ldap_admin_sync_enabled`
|
||||
|
||||
Has the instance configured LDAP Admin Sync `https://docs.gitlab.com/ee/administration/auth/ldap/#administrator-sync-starter-only`?
|
||||
Has the instance configured LDAP Admin Sync `https://docs.gitlab.com/ee/administration/auth/ldap/#administrator-sync`?
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/settings/20210216180811_ldap_admin_sync_enabled.yml)
|
||||
|
||||
|
@ -14170,7 +14170,7 @@ Tiers:
|
|||
|
||||
### `usage_activity_by_stage.manage.ldap_group_sync_enabled`
|
||||
|
||||
Has the instance configured LDAP Group Sync `https://docs.gitlab.com/ee/administration/auth/ldap/#group-sync-starter-only`?
|
||||
Has the instance configured LDAP Group Sync `https://docs.gitlab.com/ee/administration/auth/ldap/#group-sync`?
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/settings/20210216180809_ldap_group_sync_enabled.yml)
|
||||
|
||||
|
@ -14194,7 +14194,7 @@ Tiers: `free`
|
|||
|
||||
### `usage_activity_by_stage.manage.ldap_servers`
|
||||
|
||||
Number of LDAP servers configured for the instance `https://docs.gitlab.com/ee/administration/auth/ldap/#multiple-ldap-servers-starter-only`
|
||||
Number of LDAP servers configured for the instance `https://docs.gitlab.com/ee/administration/auth/ldap/#multiple-ldap-servers`
|
||||
|
||||
[YAML definition](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/config/metrics/counts_all/20210216180807_ldap_servers.yml)
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ A **project** in GitLab is what holds a repository, which holds your files.
|
|||
Often, the word "repository" is shortened to "repo".
|
||||
<!-- vale gitlab.Spelling = YES -->
|
||||
<!-- vale gitlab.SubstitutionWarning = YES -->
|
||||
|
||||
### Fork
|
||||
|
||||
When you want to copy someone else's repository, you [**fork**](../user/project/repository/forking_workflow.md#creating-a-fork)
|
||||
|
@ -175,7 +176,7 @@ To create a copy of a remote repository's files on your computer, you can either
|
|||
**download** or **clone**. If you download, you cannot sync it with the
|
||||
remote repository on GitLab.
|
||||
|
||||
Cloning a repository is the same as downloading, except it preserves the Git connection
|
||||
[Cloning](#clone-a-repository) a repository is the same as downloading, except it preserves the Git connection
|
||||
with the remote repository. This allows you to modify the files locally and
|
||||
upload the changes to the remote repository on GitLab.
|
||||
|
||||
|
@ -210,11 +211,13 @@ to GitLab, see how to [convert a local folder into a Git repository](#convert-a-
|
|||
### Clone a repository
|
||||
|
||||
To start working locally on an existing remote repository, clone it with the
|
||||
command `git clone <repository path>`. You can either clone it via [HTTPS](#clone-via-https) or [SSH](#clone-via-ssh), according to your preferred [authentication method](#git-authentication-methods).
|
||||
command `git clone <repository path>`. You can either clone it via [HTTPS](#clone-via-https)
|
||||
or [SSH](#clone-via-ssh), according to your preferred [authentication method](#git-authentication-methods).
|
||||
|
||||
You can find both paths (HTTPS and SSH) by navigating to your project's landing page
|
||||
and clicking **Clone**. GitLab prompts you with both paths, from which you can copy
|
||||
and paste in your command line.
|
||||
and paste in your command line. You can also
|
||||
[clone and open directly in Visual Studio Code](../user/project/repository/index.md#clone-and-open-in-apple-xcode).
|
||||
|
||||
For example, considering our [sample project](https://gitlab.com/gitlab-tests/sample-project/):
|
||||
|
||||
|
|
|
@ -49,6 +49,14 @@ The following resources are migrated to the target instance:
|
|||
- parent epic ([Introduced in 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/297459))
|
||||
- emoji award ([Introduced in 13.9](https://gitlab.com/gitlab-org/gitlab/-/issues/297466))
|
||||
- events ([Introduced in 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/297465))
|
||||
- Milestones ([Introduced in 13.10](https://gitlab.com/gitlab-org/gitlab/-/issues/292427))
|
||||
- title
|
||||
- description
|
||||
- state (active / closed)
|
||||
- start date
|
||||
- due date
|
||||
- created at
|
||||
- updated at
|
||||
|
||||
Any other items are **not** migrated.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ group: Package
|
|||
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
|
||||
---
|
||||
|
||||
# Package Registry
|
||||
# Package Registry **(FREE)**
|
||||
|
||||
> [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/221259) to GitLab Free in 13.3.
|
||||
|
||||
|
|
|
@ -146,6 +146,10 @@ After you add the description, hit **Save changes** for the settings to take
|
|||
effect. Now, every time a new merge request or issue is created, it is
|
||||
pre-filled with the text you entered in the template(s).
|
||||
|
||||
[GitLab versions 13.10 and later](https://gitlab.com/gitlab-org/gitlab/-/issues/885)
|
||||
provide `issues_template` and `merge_requests_template` attributes in the
|
||||
[Projects API](../../api/projects.md) to help you keep your templates up to date.
|
||||
|
||||
## Description template example
|
||||
|
||||
We make use of description templates for issues and merge requests in the GitLab project.
|
||||
|
|
|
@ -49,8 +49,9 @@ The steps you take depend on whether you are importing from GitHub.com or GitHub
|
|||
[GitHub Rake task](../../../administration/raketasks/github_import.md) to import
|
||||
projects without the constraints of a [Sidekiq](../../../development/sidekiq_style_guide.md) worker.
|
||||
- If you're importing from GitHub Enterprise to your self-managed GitLab instance, you must first enable
|
||||
[GitHub integration](../../../integration/github.md). However, you cannot import projects from GitHub Enterprise to GitLab.com.
|
||||
- If you're importing from GitHub.com to your self-managed GitLab instance, you do not need to set up GitHub integration.
|
||||
[GitHub integration](../../../integration/github.md).
|
||||
- To import projects from GitHub Enterprise to GitLab.com, use the [Import API](../../../api/import.md).
|
||||
- If you're importing from GitHub.com to your self-managed GitLab instance, you do not need to set up GitHub integration. You can use the [Import API](../../../api/import.md).
|
||||
|
||||
## How it works
|
||||
|
||||
|
|
|
@ -166,8 +166,8 @@ There are two main ways of how you can discover snippets in GitLab.
|
|||
|
||||
For exploring all snippets that are visible to you, you can go to the Snippets
|
||||
dashboard of your GitLab instance via the top navigation. For GitLab.com you can
|
||||
navigate to an [overview]((https://gitlab.com/dashboard/snippets)) that shows snippets
|
||||
you created and allows you to explore all snippets.
|
||||
visit [GitLab Snippets](http://snippets.gitlab.com/) or navigate to an [overview]((https://gitlab.com/dashboard/snippets)) that shows snippets
|
||||
you created and allows you to explore all snippets.
|
||||
|
||||
To discover snippets that belong to a specific project, navigate
|
||||
to the Snippets page via the left side navigation on the project page.
|
||||
|
|
54
lib/bulk_imports/groups/graphql/get_milestones_query.rb
Normal file
54
lib/bulk_imports/groups/graphql/get_milestones_query.rb
Normal file
|
@ -0,0 +1,54 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module BulkImports
|
||||
module Groups
|
||||
module Graphql
|
||||
module GetMilestonesQuery
|
||||
extend self
|
||||
|
||||
def to_s
|
||||
<<-'GRAPHQL'
|
||||
query ($full_path: ID!, $cursor: String) {
|
||||
group(fullPath: $full_path) {
|
||||
milestones(first: 100, after: $cursor, includeDescendants: false) {
|
||||
page_info: pageInfo {
|
||||
end_cursor: endCursor
|
||||
has_next_page: hasNextPage
|
||||
}
|
||||
nodes {
|
||||
title
|
||||
description
|
||||
state
|
||||
start_date: startDate
|
||||
due_date: dueDate
|
||||
created_at: createdAt
|
||||
updated_at: updatedAt
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
def variables(context)
|
||||
{
|
||||
full_path: context.entity.source_full_path,
|
||||
cursor: context.entity.next_page_for(:milestones)
|
||||
}
|
||||
end
|
||||
|
||||
def base_path
|
||||
%w[data group milestones]
|
||||
end
|
||||
|
||||
def data_path
|
||||
base_path << 'nodes'
|
||||
end
|
||||
|
||||
def page_info_path
|
||||
base_path << 'page_info'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
42
lib/bulk_imports/groups/pipelines/milestones_pipeline.rb
Normal file
42
lib/bulk_imports/groups/pipelines/milestones_pipeline.rb
Normal file
|
@ -0,0 +1,42 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module BulkImports
|
||||
module Groups
|
||||
module Pipelines
|
||||
class MilestonesPipeline
|
||||
include Pipeline
|
||||
|
||||
extractor BulkImports::Common::Extractors::GraphqlExtractor,
|
||||
query: BulkImports::Groups::Graphql::GetMilestonesQuery
|
||||
|
||||
transformer Common::Transformers::ProhibitedAttributesTransformer
|
||||
|
||||
def load(context, data)
|
||||
return unless data
|
||||
|
||||
raise ::BulkImports::Pipeline::NotAllowedError unless authorized?
|
||||
|
||||
context.group.milestones.create!(data)
|
||||
end
|
||||
|
||||
def after_run(extracted_data)
|
||||
context.entity.update_tracker_for(
|
||||
relation: :milestones,
|
||||
has_next_page: extracted_data.has_next_page?,
|
||||
next_page: extracted_data.next_page
|
||||
)
|
||||
|
||||
if extracted_data.has_next_page?
|
||||
run
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def authorized?
|
||||
context.current_user.can?(:admin_milestone, context.group)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -24,7 +24,8 @@ module BulkImports
|
|||
BulkImports::Groups::Pipelines::GroupPipeline,
|
||||
BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline,
|
||||
BulkImports::Groups::Pipelines::MembersPipeline,
|
||||
BulkImports::Groups::Pipelines::LabelsPipeline
|
||||
BulkImports::Groups::Pipelines::LabelsPipeline,
|
||||
BulkImports::Groups::Pipelines::MilestonesPipeline
|
||||
]
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,11 +1,22 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Database
|
||||
module BackgroundMigration
|
||||
module BackgroundMigration
|
||||
module BatchingStrategies
|
||||
# Generic batching class for use with a BatchedBackgroundMigration.
|
||||
# Batches over the given table and column combination, returning the MIN() and MAX()
|
||||
# values for the next batch as an array.
|
||||
#
|
||||
# If no more batches exist in the table, returns nil.
|
||||
class PrimaryKeyBatchingStrategy
|
||||
include Gitlab::Database::DynamicModelHelpers
|
||||
|
||||
# Finds and returns the next batch in the table.
|
||||
#
|
||||
# table_name - The table to batch over
|
||||
# column_name - The column to batch over
|
||||
# batch_min_value - The minimum value which the next batch will start at
|
||||
# batch_size - The size of the next batch
|
||||
def next_batch(table_name, column_name, batch_min_value:, batch_size:)
|
||||
model_class = define_batchable_model(table_name)
|
||||
|
|
@ -99,10 +99,18 @@ module Gitlab
|
|||
initial_config
|
||||
end
|
||||
|
||||
def find_sha(project)
|
||||
branches = project&.repository&.branches || []
|
||||
|
||||
unless branches.empty?
|
||||
project.repository.root_ref_sha
|
||||
end
|
||||
end
|
||||
|
||||
def build_context(project:, sha:, user:, parent_pipeline:)
|
||||
Config::External::Context.new(
|
||||
project: project,
|
||||
sha: sha || project&.repository&.root_ref_sha,
|
||||
sha: sha || find_sha(project),
|
||||
user: user,
|
||||
parent_pipeline: parent_pipeline,
|
||||
variables: project&.predefined_variables&.to_runner_variables)
|
||||
|
|
|
@ -21,7 +21,7 @@ module Gitlab
|
|||
def initialize(project:, current_user:, sha: nil)
|
||||
@project = project
|
||||
@current_user = current_user
|
||||
@sha = sha || project.repository.commit.sha
|
||||
@sha = sha || project.repository.commit&.sha
|
||||
end
|
||||
|
||||
def validate(content, dry_run: false)
|
||||
|
|
|
@ -4,6 +4,9 @@ module Gitlab
|
|||
module Database
|
||||
module BackgroundMigration
|
||||
class BatchedMigration < ActiveRecord::Base # rubocop:disable Rails/ApplicationRecord
|
||||
JOB_CLASS_MODULE = 'Gitlab::BackgroundMigration'
|
||||
BATCH_CLASS_MODULE = "#{JOB_CLASS_MODULE}::BatchingStrategies".freeze
|
||||
|
||||
self.table_name = :batched_background_migrations
|
||||
|
||||
has_many :batched_jobs, foreign_key: :batched_background_migration_id
|
||||
|
@ -20,10 +23,6 @@ module Gitlab
|
|||
finished: 3
|
||||
}
|
||||
|
||||
def self.remove_toplevel_prefix(name)
|
||||
name&.sub(/\A::/, '')
|
||||
end
|
||||
|
||||
def interval_elapsed?
|
||||
last_job.nil? || last_job.created_at <= Time.current - interval
|
||||
end
|
||||
|
@ -37,19 +36,19 @@ module Gitlab
|
|||
end
|
||||
|
||||
def job_class
|
||||
job_class_name.constantize
|
||||
"#{JOB_CLASS_MODULE}::#{job_class_name}".constantize
|
||||
end
|
||||
|
||||
def batch_class
|
||||
batch_class_name.constantize
|
||||
"#{BATCH_CLASS_MODULE}::#{batch_class_name}".constantize
|
||||
end
|
||||
|
||||
def job_class_name=(class_name)
|
||||
write_attribute(:job_class_name, self.class.remove_toplevel_prefix(class_name))
|
||||
write_attribute(:job_class_name, class_name.demodulize)
|
||||
end
|
||||
|
||||
def batch_class_name=(class_name)
|
||||
write_attribute(:batch_class_name, self.class.remove_toplevel_prefix(class_name))
|
||||
write_attribute(:batch_class_name, class_name.demodulize)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5207,15 +5207,6 @@ msgstr ""
|
|||
msgid "CHANGELOG"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI / CD"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI / CD Analytics"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI / CD Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI Lint"
|
||||
msgstr ""
|
||||
|
||||
|
@ -5234,6 +5225,12 @@ msgstr ""
|
|||
msgid "CI/CD"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI/CD Analytics"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI/CD Settings"
|
||||
msgstr ""
|
||||
|
||||
msgid "CI/CD configuration"
|
||||
msgstr ""
|
||||
|
||||
|
@ -6277,6 +6274,21 @@ msgstr ""
|
|||
msgid "Closes this %{quick_action_target}."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cloud License"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Activate"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Paste your activation code"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|Paste your activation code below"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloudLicense|This instance is currently using the Core plan."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cluster"
|
||||
msgstr ""
|
||||
|
||||
|
@ -22141,7 +22153,7 @@ msgstr ""
|
|||
msgid "PipelineCharts|An unknown error occurred while processing CI/CD analytics."
|
||||
msgstr ""
|
||||
|
||||
msgid "PipelineCharts|CI / CD Analytics"
|
||||
msgid "PipelineCharts|CI/CD Analytics"
|
||||
msgstr ""
|
||||
|
||||
msgid "PipelineCharts|Failed:"
|
||||
|
|
|
@ -141,7 +141,7 @@
|
|||
"sql.js": "^0.4.0",
|
||||
"string-hash": "1.1.3",
|
||||
"style-loader": "^1.3.0",
|
||||
"swagger-ui-dist": "^3.43.0",
|
||||
"swagger-ui-dist": "^3.44.1",
|
||||
"three": "^0.84.0",
|
||||
"three-orbit-controls": "^82.1.0",
|
||||
"three-stl-loader": "^1.0.4",
|
||||
|
|
|
@ -25,7 +25,7 @@ module QA
|
|||
def go_to_ci_cd_settings
|
||||
hover_settings do
|
||||
within_submenu do
|
||||
click_link('CI / CD')
|
||||
click_link('CI/CD')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,7 +6,7 @@ FactoryBot.define do
|
|||
batch_size { 5 }
|
||||
sub_batch_size { 1 }
|
||||
interval { 2.minutes }
|
||||
job_class_name { 'Gitlab::BackgroundMigration::CopyColumnUsingBackgroundMigrationJob' }
|
||||
job_class_name { 'CopyColumnUsingBackgroundMigrationJob' }
|
||||
table_name { :events }
|
||||
column_name { :id }
|
||||
end
|
||||
|
|
|
@ -132,13 +132,13 @@ RSpec.describe 'Project active tab' do
|
|||
it_behaves_like 'page has active sub tab', _('Value Stream')
|
||||
end
|
||||
|
||||
context 'on project Analytics/"CI / CD"' do
|
||||
context 'on project Analytics/"CI/CD"' do
|
||||
before do
|
||||
click_tab(_('CI / CD'))
|
||||
click_tab(_('CI/CD'))
|
||||
end
|
||||
|
||||
it_behaves_like 'page has active tab', _('Analytics')
|
||||
it_behaves_like 'page has active sub tab', _('CI / CD')
|
||||
it_behaves_like 'page has active sub tab', _('CI/CD')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -429,39 +429,69 @@ RSpec.describe 'Environments page', :js do
|
|||
end
|
||||
|
||||
describe 'environments folders' do
|
||||
before do
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-1',
|
||||
state: :available)
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-2',
|
||||
state: :available)
|
||||
end
|
||||
|
||||
it 'users unfurls an environment folder' do
|
||||
visit_environments(project)
|
||||
|
||||
expect(page).not_to have_content 'review-1'
|
||||
expect(page).not_to have_content 'review-2'
|
||||
expect(page).to have_content 'staging 2'
|
||||
|
||||
within('.folder-row') do
|
||||
find('.folder-name', text: 'staging').click
|
||||
describe 'available environments' do
|
||||
before do
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-1',
|
||||
state: :available)
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-2',
|
||||
state: :available)
|
||||
end
|
||||
|
||||
expect(page).to have_content 'review-1'
|
||||
expect(page).to have_content 'review-2'
|
||||
within('.ci-table') do
|
||||
within('[data-qa-selector="environment_item"]', text: 'review-1') do
|
||||
expect(find('.js-auto-stop').text).not_to be_empty
|
||||
it 'users unfurls an environment folder' do
|
||||
visit_environments(project)
|
||||
|
||||
expect(page).not_to have_content 'review-1'
|
||||
expect(page).not_to have_content 'review-2'
|
||||
expect(page).to have_content 'staging 2'
|
||||
|
||||
within('.folder-row') do
|
||||
find('.folder-name', text: 'staging').click
|
||||
end
|
||||
within('[data-qa-selector="environment_item"]', text: 'review-2') do
|
||||
expect(find('.js-auto-stop').text).not_to be_empty
|
||||
|
||||
expect(page).to have_content 'review-1'
|
||||
expect(page).to have_content 'review-2'
|
||||
within('.ci-table') do
|
||||
within('[data-qa-selector="environment_item"]', text: 'review-1') do
|
||||
expect(find('.js-auto-stop').text).not_to be_empty
|
||||
end
|
||||
within('[data-qa-selector="environment_item"]', text: 'review-2') do
|
||||
expect(find('.js-auto-stop').text).not_to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'stopped environments' do
|
||||
before do
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-1',
|
||||
state: :stopped)
|
||||
create(:environment, :will_auto_stop,
|
||||
project: project,
|
||||
name: 'staging/review-2',
|
||||
state: :stopped)
|
||||
end
|
||||
|
||||
it 'users unfurls an environment folder' do
|
||||
visit_environments(project, scope: 'stopped')
|
||||
|
||||
expect(page).not_to have_content 'review-1'
|
||||
expect(page).not_to have_content 'review-2'
|
||||
expect(page).to have_content 'staging 2'
|
||||
|
||||
within('.folder-row') do
|
||||
find('.folder-name', text: 'staging').click
|
||||
end
|
||||
|
||||
expect(page).to have_content 'review-1'
|
||||
expect(page).to have_content 'review-2'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'environments folders view' do
|
||||
|
|
|
@ -201,7 +201,7 @@ RSpec.describe 'Projects > User sees sidebar' do
|
|||
expect(page).to have_content 'Operations'
|
||||
|
||||
expect(page).not_to have_content 'Repository'
|
||||
expect(page).not_to have_content 'CI / CD'
|
||||
expect(page).not_to have_content 'CI/CD'
|
||||
expect(page).not_to have_content 'Merge Requests'
|
||||
end
|
||||
end
|
||||
|
@ -213,7 +213,7 @@ RSpec.describe 'Projects > User sees sidebar' do
|
|||
visit project_path(project)
|
||||
|
||||
within('.nav-sidebar') do
|
||||
expect(page).to have_content 'CI / CD'
|
||||
expect(page).to have_content 'CI/CD'
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -155,12 +155,12 @@ RSpec.describe 'User uses shortcuts', :js do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when navigating to the CI / CD pages' do
|
||||
context 'when navigating to the CI/CD pages' do
|
||||
it 'redirects to the Jobs page' do
|
||||
find('body').native.send_key('g')
|
||||
find('body').native.send_key('j')
|
||||
|
||||
expect(page).to have_active_navigation('CI / CD')
|
||||
expect(page).to have_active_navigation('CI/CD')
|
||||
expect(page).to have_active_sub_navigation('Jobs')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::Groups::Graphql::GetMilestonesQuery do
|
||||
it 'has a valid query' do
|
||||
entity = create(:bulk_import_entity)
|
||||
context = BulkImports::Pipeline::Context.new(entity)
|
||||
|
||||
query = GraphQL::Query.new(
|
||||
GitlabSchema,
|
||||
described_class.to_s,
|
||||
variables: described_class.variables(context)
|
||||
)
|
||||
result = GitlabSchema.static_validator.validate(query)
|
||||
|
||||
expect(result[:errors]).to be_empty
|
||||
end
|
||||
|
||||
describe '#data_path' do
|
||||
it 'returns data path' do
|
||||
expected = %w[data group milestones nodes]
|
||||
|
||||
expect(described_class.data_path).to eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#page_info_path' do
|
||||
it 'returns pagination information path' do
|
||||
expected = %w[data group milestones page_info]
|
||||
|
||||
expect(described_class.page_info_path).to eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,151 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe BulkImports::Groups::Pipelines::MilestonesPipeline do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:cursor) { 'cursor' }
|
||||
let_it_be(:timestamp) { Time.new(2020, 01, 01).utc }
|
||||
let_it_be(:bulk_import) { create(:bulk_import, user: user) }
|
||||
|
||||
let(:entity) do
|
||||
create(
|
||||
:bulk_import_entity,
|
||||
bulk_import: bulk_import,
|
||||
source_full_path: 'source/full/path',
|
||||
destination_name: 'My Destination Group',
|
||||
destination_namespace: group.full_path,
|
||||
group: group
|
||||
)
|
||||
end
|
||||
|
||||
let(:context) { BulkImports::Pipeline::Context.new(entity) }
|
||||
|
||||
subject { described_class.new(context) }
|
||||
|
||||
def milestone_data(title)
|
||||
{
|
||||
'title' => title,
|
||||
'description' => 'desc',
|
||||
'state' => 'closed',
|
||||
'start_date' => '2020-10-21',
|
||||
'due_date' => '2020-10-22',
|
||||
'created_at' => timestamp.to_s,
|
||||
'updated_at' => timestamp.to_s
|
||||
}
|
||||
end
|
||||
|
||||
def extracted_data(title:, has_next_page:, cursor: nil)
|
||||
page_info = {
|
||||
'end_cursor' => cursor,
|
||||
'has_next_page' => has_next_page
|
||||
}
|
||||
|
||||
BulkImports::Pipeline::ExtractedData.new(data: [milestone_data(title)], page_info: page_info)
|
||||
end
|
||||
|
||||
before do
|
||||
group.add_owner(user)
|
||||
end
|
||||
|
||||
describe '#run' do
|
||||
it 'imports group milestones' do
|
||||
first_page = extracted_data(title: 'milestone1', has_next_page: true, cursor: cursor)
|
||||
last_page = extracted_data(title: 'milestone2', has_next_page: false)
|
||||
|
||||
allow_next_instance_of(BulkImports::Common::Extractors::GraphqlExtractor) do |extractor|
|
||||
allow(extractor)
|
||||
.to receive(:extract)
|
||||
.and_return(first_page, last_page)
|
||||
end
|
||||
|
||||
expect { subject.run }.to change(Milestone, :count).by(2)
|
||||
|
||||
expect(group.milestones.pluck(:title)).to contain_exactly('milestone1', 'milestone2')
|
||||
|
||||
milestone = group.milestones.last
|
||||
|
||||
expect(milestone.description).to eq('desc')
|
||||
expect(milestone.state).to eq('closed')
|
||||
expect(milestone.start_date.to_s).to eq('2020-10-21')
|
||||
expect(milestone.due_date.to_s).to eq('2020-10-22')
|
||||
expect(milestone.created_at).to eq(timestamp)
|
||||
expect(milestone.updated_at).to eq(timestamp)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#after_run' do
|
||||
context 'when extracted data has next page' do
|
||||
it 'updates tracker information and runs pipeline again' do
|
||||
data = extracted_data(title: 'milestone', has_next_page: true, cursor: cursor)
|
||||
|
||||
expect(subject).to receive(:run)
|
||||
|
||||
subject.after_run(data)
|
||||
|
||||
tracker = entity.trackers.find_by(relation: :milestones)
|
||||
|
||||
expect(tracker.has_next_page).to eq(true)
|
||||
expect(tracker.next_page).to eq(cursor)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when extracted data has no next page' do
|
||||
it 'updates tracker information and does not run pipeline' do
|
||||
data = extracted_data(title: 'milestone', has_next_page: false)
|
||||
|
||||
expect(subject).not_to receive(:run)
|
||||
|
||||
subject.after_run(data)
|
||||
|
||||
tracker = entity.trackers.find_by(relation: :milestones)
|
||||
|
||||
expect(tracker.has_next_page).to eq(false)
|
||||
expect(tracker.next_page).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#load' do
|
||||
it 'creates the milestone' do
|
||||
data = milestone_data('milestone')
|
||||
|
||||
expect { subject.load(context, data) }.to change(Milestone, :count).by(1)
|
||||
end
|
||||
|
||||
context 'when user is not authorized to create the milestone' do
|
||||
before do
|
||||
allow(user).to receive(:can?).with(:admin_milestone, group).and_return(false)
|
||||
end
|
||||
|
||||
it 'raises NotAllowedError' do
|
||||
data = extracted_data(title: 'milestone', has_next_page: false)
|
||||
|
||||
expect { subject.load(context, data) }.to raise_error(::BulkImports::Pipeline::NotAllowedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'pipeline parts' do
|
||||
it { expect(described_class).to include_module(BulkImports::Pipeline) }
|
||||
it { expect(described_class).to include_module(BulkImports::Pipeline::Runner) }
|
||||
|
||||
it 'has extractors' do
|
||||
expect(described_class.get_extractor)
|
||||
.to eq(
|
||||
klass: BulkImports::Common::Extractors::GraphqlExtractor,
|
||||
options: {
|
||||
query: BulkImports::Groups::Graphql::GetMilestonesQuery
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
it 'has transformers' do
|
||||
expect(described_class.transformers)
|
||||
.to contain_exactly(
|
||||
{ klass: BulkImports::Common::Transformers::ProhibitedAttributesTransformer, options: nil }
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22,6 +22,7 @@ RSpec.describe BulkImports::Importers::GroupImporter do
|
|||
expect_to_run_pipeline BulkImports::Groups::Pipelines::SubgroupEntitiesPipeline, context: context
|
||||
expect_to_run_pipeline BulkImports::Groups::Pipelines::MembersPipeline, context: context
|
||||
expect_to_run_pipeline BulkImports::Groups::Pipelines::LabelsPipeline, context: context
|
||||
expect_to_run_pipeline BulkImports::Groups::Pipelines::MilestonesPipeline, context: context
|
||||
|
||||
if Gitlab.ee?
|
||||
expect_to_run_pipeline('EE::BulkImports::Groups::Pipelines::EpicsPipeline'.constantize, context: context)
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy, '#next_batch' do
|
||||
let(:batching_strategy) { described_class.new }
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
|
||||
let!(:namespace1) { namespaces.create!(name: 'batchtest1', path: 'batch-test1') }
|
||||
let!(:namespace2) { namespaces.create!(name: 'batchtest2', path: 'batch-test2') }
|
||||
let!(:namespace3) { namespaces.create!(name: 'batchtest3', path: 'batch-test3') }
|
||||
let!(:namespace4) { namespaces.create!(name: 'batchtest4', path: 'batch-test4') }
|
||||
|
||||
context 'when starting on the first batch' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace1.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([namespace1.id, namespace3.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when additional batches remain' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace2.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([namespace2.id, namespace4.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on the final batch' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([namespace4.id, namespace4.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no additional batches remain' do
|
||||
it 'returns nil' do
|
||||
batch_bounds = batching_strategy.next_batch(:namespaces, :id, batch_min_value: namespace4.id + 1, batch_size: 1)
|
||||
|
||||
expect(batch_bounds).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -122,7 +122,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
|
|||
end
|
||||
|
||||
describe '#batch_class' do
|
||||
let(:batch_class) { Gitlab::Database::BackgroundMigration::PrimaryKeyBatchingStrategy}
|
||||
let(:batch_class) { Gitlab::BackgroundMigration::BatchingStrategies::PrimaryKeyBatchingStrategy}
|
||||
let(:batched_migration) { build(:batched_background_migration) }
|
||||
|
||||
it 'returns the class of the batch strategy for the migration' do
|
||||
|
@ -130,31 +130,31 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples_for 'an attr_writer that normalizes assigned class names' do |attribute_name|
|
||||
shared_examples_for 'an attr_writer that demodulizes assigned class names' do |attribute_name|
|
||||
let(:batched_migration) { build(:batched_background_migration) }
|
||||
|
||||
context 'when the toplevel namespace prefix exists' do
|
||||
it 'removes the leading prefix' do
|
||||
context 'when a module name exists' do
|
||||
it 'removes the module name' do
|
||||
batched_migration.public_send(:"#{attribute_name}=", '::Foo::Bar')
|
||||
|
||||
expect(batched_migration[attribute_name]).to eq('Foo::Bar')
|
||||
expect(batched_migration[attribute_name]).to eq('Bar')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the toplevel namespace prefix does not exist' do
|
||||
context 'when a module name does not exist' do
|
||||
it 'does not change the given class name' do
|
||||
batched_migration.public_send(:"#{attribute_name}=", '::Foo::Bar')
|
||||
batched_migration.public_send(:"#{attribute_name}=", 'Bar')
|
||||
|
||||
expect(batched_migration[attribute_name]).to eq('Foo::Bar')
|
||||
expect(batched_migration[attribute_name]).to eq('Bar')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#job_class_name=' do
|
||||
it_behaves_like 'an attr_writer that normalizes assigned class names', :job_class_name
|
||||
it_behaves_like 'an attr_writer that demodulizes assigned class names', :job_class_name
|
||||
end
|
||||
|
||||
describe '#batch_class_name=' do
|
||||
it_behaves_like 'an attr_writer that normalizes assigned class names', :batch_class_name
|
||||
it_behaves_like 'an attr_writer that demodulizes assigned class names', :batch_class_name
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Database::BackgroundMigration::PrimaryKeyBatchingStrategy, '#next_batch' do
|
||||
let(:batching_strategy) { described_class.new }
|
||||
|
||||
let_it_be(:event1) { create(:event) }
|
||||
let_it_be(:event2) { create(:event) }
|
||||
let_it_be(:event3) { create(:event) }
|
||||
let_it_be(:event4) { create(:event) }
|
||||
|
||||
context 'when starting on the first batch' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:events, :id, batch_min_value: event1.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([event1.id, event3.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when additional batches remain' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:events, :id, batch_min_value: event2.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([event2.id, event4.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when on the final batch' do
|
||||
it 'returns the bounds of the next batch' do
|
||||
batch_bounds = batching_strategy.next_batch(:events, :id, batch_min_value: event4.id, batch_size: 3)
|
||||
|
||||
expect(batch_bounds).to eq([event4.id, event4.id])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when no additional batches remain' do
|
||||
it 'returns nil' do
|
||||
batch_bounds = batching_strategy.next_batch(:events, :id, batch_min_value: event4.id + 1, batch_size: 1)
|
||||
|
||||
expect(batch_bounds).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -406,6 +406,24 @@ RSpec.describe API::Lint do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with an empty repository' do
|
||||
let_it_be(:empty_project) { create(:project_empty_repo) }
|
||||
let_it_be(:yaml_content) do
|
||||
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci.yml'))
|
||||
end
|
||||
|
||||
before do
|
||||
empty_project.add_developer(api_user)
|
||||
end
|
||||
|
||||
it 'passes validation without errors' do
|
||||
post api("/projects/#{empty_project.id}/ci/lint", api_user), params: { content: yaml_content }
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['valid']).to eq(true)
|
||||
expect(json_response['errors']).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when unauthenticated' do
|
||||
let_it_be(:api_user) { nil }
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ RSpec.shared_context 'project navbar structure' do
|
|||
{
|
||||
nav_item: _('Analytics'),
|
||||
nav_sub_items: [
|
||||
_('CI / CD'),
|
||||
_('CI/CD'),
|
||||
(_('Code Review') if Gitlab.ee?),
|
||||
(_('Merge Request') if Gitlab.ee?),
|
||||
_('Repository'),
|
||||
|
@ -63,7 +63,7 @@ RSpec.shared_context 'project navbar structure' do
|
|||
nav_sub_items: []
|
||||
},
|
||||
{
|
||||
nav_item: _('CI / CD'),
|
||||
nav_item: _('CI/CD'),
|
||||
nav_sub_items: [
|
||||
_('Pipelines'),
|
||||
s_('Pipelines|Editor'),
|
||||
|
@ -111,7 +111,7 @@ RSpec.shared_context 'project navbar structure' do
|
|||
_('Webhooks'),
|
||||
_('Access Tokens'),
|
||||
_('Repository'),
|
||||
_('CI / CD'),
|
||||
_('CI/CD'),
|
||||
_('Operations')
|
||||
].compact
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ RSpec.shared_context 'group navbar structure' do
|
|||
_('Integrations'),
|
||||
_('Projects'),
|
||||
_('Repository'),
|
||||
_('CI / CD'),
|
||||
_('CI/CD'),
|
||||
_('Packages & Registries'),
|
||||
_('Webhooks')
|
||||
]
|
||||
|
|
|
@ -204,7 +204,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
|
|||
it 'does not show the ci/cd settings tab' do
|
||||
render
|
||||
|
||||
expect(rendered).not_to have_link('CI / CD', href: project_settings_ci_cd_path(project))
|
||||
expect(rendered).not_to have_link('CI/CD', href: project_settings_ci_cd_path(project))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -214,7 +214,7 @@ RSpec.describe 'layouts/nav/sidebar/_project' do
|
|||
it 'shows the ci/cd settings tab' do
|
||||
render
|
||||
|
||||
expect(rendered).to have_link('CI / CD', href: project_settings_ci_cd_path(project))
|
||||
expect(rendered).to have_link('CI/CD', href: project_settings_ci_cd_path(project))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11412,10 +11412,10 @@ svg-tags@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
|
||||
integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q=
|
||||
|
||||
swagger-ui-dist@^3.43.0:
|
||||
version "3.43.0"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.43.0.tgz#b064a2cec1d27776f9a124bc70423cfa0bbc0d3f"
|
||||
integrity sha512-PtE+g23bNbYv8qqAVoPBqNQth8hU5Sl5ZsQ7gHXlO5jlCt31dVTiKI9ArHIT1b23ZzUYTnKsFgPYYFoiWyNCAw==
|
||||
swagger-ui-dist@^3.44.1:
|
||||
version "3.44.1"
|
||||
resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.44.1.tgz#757385a79698b8ef7045287be585671db4e4a252"
|
||||
integrity sha512-N0u+aN55bp53RRwi/wFbEbkQxcHqZ445ShZR/Ct1Jg+XCMxYtocrsGavh7kdNKw5+6Rs4QDD6GzUMiT28Z1u3Q==
|
||||
|
||||
symbol-observable@^1.0.2:
|
||||
version "1.2.0"
|
||||
|
|
Loading…
Reference in a new issue