Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d49d44c810
commit
6fa3630aad
39 changed files with 471 additions and 89 deletions
|
@ -15,9 +15,6 @@ tasks:
|
|||
cd /workspace/gitlab-development-kit
|
||||
[[ ! -L /workspace/gitlab-development-kit/gitlab ]] && ln -fs /workspace/gitlab /workspace/gitlab-development-kit/gitlab
|
||||
mv /workspace/gitlab-development-kit/secrets.yml /workspace/gitlab-development-kit/gitlab/config
|
||||
# make webpack static, prevents that GitLab tries to connect to localhost webpack from browser outside the workspace
|
||||
echo "webpack:" >> gdk.yml
|
||||
echo " static: true" >> gdk.yml
|
||||
# reconfigure GDK
|
||||
echo "$(date) – Reconfiguring GDK" | tee -a /workspace/startup.log
|
||||
gdk reconfigure
|
||||
|
@ -43,6 +40,7 @@ tasks:
|
|||
fi
|
||||
# start GDK
|
||||
echo "$(date) – Starting GDK" | tee -a /workspace/startup.log
|
||||
export DEV_SERVER_PUBLIC_ADDR=$(gp url 3808)
|
||||
export RAILS_HOSTS=$(gp url 3000 | sed -e 's+^http[s]*://++')
|
||||
gdk start
|
||||
# Run DB migrations
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
<script>
|
||||
import { GlButton, GlDropdown, GlDropdownItem, GlIcon, GlLink, GlModal } from '@gitlab/ui';
|
||||
import { mapGetters } from 'vuex';
|
||||
import createFlash from '~/flash';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
import { IssuableType } from '~/issuable_show/constants';
|
||||
import { IssuableStatus, IssueStateEvent } from '~/issue_show/constants';
|
||||
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { __, sprintf } from '~/locale';
|
||||
import promoteToEpicMutation from '../queries/promote_to_epic.mutation.graphql';
|
||||
import updateIssueMutation from '../queries/update_issue.mutation.graphql';
|
||||
|
||||
export default {
|
||||
|
@ -24,10 +26,21 @@ export default {
|
|||
text: __('Yes, close issue'),
|
||||
attributes: [{ variant: 'warning' }],
|
||||
},
|
||||
i18n: {
|
||||
promoteErrorMessage: __(
|
||||
'Something went wrong while promoting the issue to an epic. Please try again.',
|
||||
),
|
||||
promoteSuccessMessage: __(
|
||||
'The issue was successfully promoted to an epic. Redirecting to epic...',
|
||||
),
|
||||
},
|
||||
inject: {
|
||||
canCreateIssue: {
|
||||
default: false,
|
||||
},
|
||||
canPromoteToEpic: {
|
||||
default: false,
|
||||
},
|
||||
canReopenIssue: {
|
||||
default: false,
|
||||
},
|
||||
|
@ -135,6 +148,37 @@ export default {
|
|||
this.isUpdatingState = false;
|
||||
});
|
||||
},
|
||||
promoteToEpic() {
|
||||
this.isUpdatingState = true;
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: promoteToEpicMutation,
|
||||
variables: {
|
||||
input: {
|
||||
iid: this.iid,
|
||||
projectPath: this.projectPath,
|
||||
},
|
||||
},
|
||||
})
|
||||
.then(({ data }) => {
|
||||
if (data.promoteToEpic.errors.length) {
|
||||
createFlash({ message: data.promoteToEpic.errors.join('; ') });
|
||||
return;
|
||||
}
|
||||
|
||||
createFlash({
|
||||
message: this.$options.i18n.promoteSuccessMessage,
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
});
|
||||
|
||||
visitUrl(data.promoteToEpic.epic.webPath);
|
||||
})
|
||||
.catch(() => createFlash({ message: this.$options.i18n.promoteErrorMessage }))
|
||||
.finally(() => {
|
||||
this.isUpdatingState = false;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -152,6 +196,9 @@ export default {
|
|||
<gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath">
|
||||
{{ newIssueTypeText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="canPromoteToEpic" :disabled="isUpdatingState" @click="promoteToEpic">
|
||||
{{ __('Promote to epic') }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="!isIssueAuthor" :href="reportAbusePath">
|
||||
{{ __('Report abuse') }}
|
||||
</gl-dropdown-item>
|
||||
|
@ -190,6 +237,14 @@ export default {
|
|||
<gl-dropdown-item v-if="canCreateIssue" :href="newIssuePath">
|
||||
{{ newIssueTypeText }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item
|
||||
v-if="canPromoteToEpic"
|
||||
:disabled="isUpdatingState"
|
||||
data-testid="promote-button"
|
||||
@click="promoteToEpic"
|
||||
>
|
||||
{{ __('Promote to epic') }}
|
||||
</gl-dropdown-item>
|
||||
<gl-dropdown-item v-if="!isIssueAuthor" :href="reportAbusePath">
|
||||
{{ __('Report abuse') }}
|
||||
</gl-dropdown-item>
|
||||
|
|
|
@ -45,6 +45,7 @@ export function initIssueHeaderActions(store) {
|
|||
store,
|
||||
provide: {
|
||||
canCreateIssue: parseBoolean(el.dataset.canCreateIssue),
|
||||
canPromoteToEpic: parseBoolean(el.dataset.canPromoteToEpic),
|
||||
canReopenIssue: parseBoolean(el.dataset.canReopenIssue),
|
||||
canReportSpam: parseBoolean(el.dataset.canReportSpam),
|
||||
canUpdateIssue: parseBoolean(el.dataset.canUpdateIssue),
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
mutation promoteToEpic($input: PromoteToEpicInput!) {
|
||||
promoteToEpic(input: $input) {
|
||||
epic {
|
||||
webPath
|
||||
}
|
||||
errors
|
||||
}
|
||||
}
|
|
@ -2,8 +2,6 @@ import UsersSelect from '~/users_select';
|
|||
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
|
||||
import initBoards from '~/boards';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new UsersSelect(); // eslint-disable-line no-new
|
||||
new ShortcutsNavigation(); // eslint-disable-line no-new
|
||||
initBoards();
|
||||
});
|
||||
new UsersSelect(); // eslint-disable-line no-new
|
||||
new ShortcutsNavigation(); // eslint-disable-line no-new
|
||||
initBoards();
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import initForm from '../../../../shared/milestones/form';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => initForm(false));
|
||||
initForm(false);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
import initForm from '../../../../shared/milestones/form';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => initForm(false));
|
||||
initForm(false);
|
||||
|
|
|
@ -4,13 +4,11 @@ import Group from '~/group';
|
|||
import GroupPathValidator from './group_path_validator';
|
||||
import initFilePickers from '~/file_pickers';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const parentId = $('#group_parent_id');
|
||||
if (!parentId.val()) {
|
||||
new GroupPathValidator(); // eslint-disable-line no-new
|
||||
}
|
||||
BindInOut.initAll();
|
||||
initFilePickers();
|
||||
const parentId = $('#group_parent_id');
|
||||
if (!parentId.val()) {
|
||||
new GroupPathValidator(); // eslint-disable-line no-new
|
||||
}
|
||||
BindInOut.initAll();
|
||||
initFilePickers();
|
||||
|
||||
return new Group();
|
||||
});
|
||||
new Group(); // eslint-disable-line no-new
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
import initPackageList from '~/packages/list/packages_list_app_bundle';
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
if (document.getElementById('js-vue-packages-list')) {
|
||||
initPackageList();
|
||||
}
|
||||
});
|
||||
if (document.getElementById('js-vue-packages-list')) {
|
||||
initPackageList();
|
||||
}
|
||||
|
|
|
@ -141,10 +141,9 @@ export default {
|
|||
addMultipleToDiscussionWarning() {
|
||||
return sprintf(
|
||||
__(
|
||||
'%{icon}You are about to add %{usersTag} people to the discussion. They will all receive a notification.',
|
||||
'You are about to add %{usersTag} people to the discussion. They will all receive a notification.',
|
||||
),
|
||||
{
|
||||
icon: '<i class="fa fa-exclamation-triangle" aria-hidden="true"></i>',
|
||||
usersTag: `<strong><span class="js-referenced-users-count">${this.referencedUsers.length}</span></strong>`,
|
||||
},
|
||||
false,
|
||||
|
@ -293,6 +292,7 @@ export default {
|
|||
<template v-if="previewMarkdown && !markdownPreviewLoading">
|
||||
<div v-if="referencedCommands" class="referenced-commands" v-html="referencedCommands"></div>
|
||||
<div v-if="shouldShowReferencedUsers" class="referenced-users">
|
||||
<gl-icon name="warning-solid" />
|
||||
<span v-html="addMultipleToDiscussionWarning"></span>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -201,6 +201,15 @@ $line-removed-dark: $red-200;
|
|||
// Misc component overrides that should live elsewhere
|
||||
.gl-label {
|
||||
filter: brightness(0.9) contrast(1.1);
|
||||
|
||||
// This applies to the gl-label markups
|
||||
// rendered and cached in the backend (labels_helper.rb)
|
||||
&.gl-label-scoped {
|
||||
.gl-label-text-scoped,
|
||||
.gl-label-close {
|
||||
color: $gray-900;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// white-ish text for light labels
|
||||
|
@ -210,6 +219,15 @@ $line-removed-dark: $red-200;
|
|||
color: $gray-900;
|
||||
}
|
||||
|
||||
// This applies to "gl-labels" from "gitlab-ui"
|
||||
.gl-label.gl-label-scoped.gl-label-text-dark,
|
||||
.gl-label.gl-label-scoped.gl-label-text-light {
|
||||
.gl-label-text-scoped,
|
||||
.gl-label-close {
|
||||
color: $gray-900;
|
||||
}
|
||||
}
|
||||
|
||||
// duplicated class as the original .atwho-view style is added later
|
||||
.atwho-view.atwho-view {
|
||||
background-color: $white;
|
||||
|
|
|
@ -14,7 +14,7 @@ class Projects::PipelinesController < Projects::ApplicationController
|
|||
before_action do
|
||||
push_frontend_feature_flag(:dag_pipeline_tab, project, default_enabled: true)
|
||||
push_frontend_feature_flag(:pipelines_security_report_summary, project)
|
||||
push_frontend_feature_flag(:new_pipeline_form, project)
|
||||
push_frontend_feature_flag(:new_pipeline_form, project, default_enabled: true)
|
||||
push_frontend_feature_flag(:graphql_pipeline_header, project, type: :development, default_enabled: false)
|
||||
push_frontend_feature_flag(:graphql_pipeline_details, project, type: :development, default_enabled: false)
|
||||
push_frontend_feature_flag(:new_pipeline_form_prefilled_vars, project, type: :development)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
class ContainerRepositoryCleanupStatusEnum < BaseEnum
|
||||
graphql_name 'ContainerRepositoryCleanupStatus'
|
||||
description 'Status of the tags cleanup of a container repository'
|
||||
|
||||
value 'UNSCHEDULED', value: 'cleanup_unscheduled', description: 'The tags cleanup is not scheduled. This is the default state.'
|
||||
value 'SCHEDULED', value: 'cleanup_scheduled', description: 'The tags cleanup is scheduled and is going to be executed shortly.'
|
||||
value 'UNFINISHED', value: 'cleanup_unfinished', description: 'The tags cleanup has been partially executed. There are still remaining tags to delete.'
|
||||
value 'ONGOING', value: 'cleanup_ongoing', description: 'The tags cleanup is ongoing.'
|
||||
end
|
||||
end
|
|
@ -15,6 +15,7 @@ module Types
|
|||
field :created_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was created.'
|
||||
field :updated_at, Types::TimeType, null: false, description: 'Timestamp when the container repository was updated.'
|
||||
field :expiration_policy_started_at, Types::TimeType, null: true, description: 'Timestamp when the cleanup done by the expiration policy was started on the container repository.'
|
||||
field :expiration_policy_cleanup_status, Types::ContainerRepositoryCleanupStatusEnum, null: true, description: 'The tags cleanup status for the container repository.'
|
||||
field :status, Types::ContainerRepositoryStatusEnum, null: true, description: 'Status of the container repository.'
|
||||
field :tags_count, GraphQL::INT_TYPE, null: false, description: 'Number of tags associated with this image.'
|
||||
field :can_delete, GraphQL::BOOLEAN_TYPE, null: false, description: 'Can the current user delete the container repository.'
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
.dropdown.inline.js-ca-dropdown
|
||||
%button.dropdown-menu-toggle{ "data-toggle" => "dropdown", :type => "button" }
|
||||
%span.dropdown-label {{ n__('Last %d day', 'Last %d days', 30) }}
|
||||
%i.fa.fa-chevron-down
|
||||
= sprite_icon("chevron-down", css_class: "dropdown-menu-toggle-icon gl-top-3")
|
||||
%ul.dropdown-menu.dropdown-menu-right
|
||||
%li
|
||||
%a{ "href" => "#", "data-value" => "7" }
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
= s_('Pipeline|Run Pipeline')
|
||||
%hr
|
||||
|
||||
- if Feature.enabled?(:new_pipeline_form, @project)
|
||||
- if Feature.enabled?(:new_pipeline_form, @project, default_enabled: true)
|
||||
#js-new-pipeline{ data: { project_id: @project.id,
|
||||
pipelines_path: project_pipelines_path(@project),
|
||||
config_variables_path: config_variables_namespace_project_pipelines_path(@project.namespace, @project),
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add cleanup status field to graphQL ContainerRepositoryType
|
||||
merge_request: 47544
|
||||
author:
|
||||
type: added
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace fa-chevron-down in project level VSA
|
||||
merge_request: 47885
|
||||
author:
|
||||
type: changed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Replace fa-exclamation-triangle in markdown field MERGE_REQUEST_ID
|
||||
merge_request: 47786
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/new-pipeline-form-default-true.yml
Normal file
5
changelogs/unreleased/new-pipeline-form-default-true.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Default enable new_pipeline_form
|
||||
merge_request: 46915
|
||||
author:
|
||||
type: added
|
|
@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/229632
|
|||
milestone: '13.2'
|
||||
type: development
|
||||
group: group::continuous integration
|
||||
default_enabled: false
|
||||
default_enabled: true
|
||||
|
|
|
@ -18,6 +18,7 @@ const IS_DEV_SERVER = process.env.WEBPACK_DEV_SERVER === 'true';
|
|||
const IS_EE = require('./helpers/is_ee_env');
|
||||
const DEV_SERVER_HOST = process.env.DEV_SERVER_HOST || 'localhost';
|
||||
const DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808;
|
||||
const DEV_SERVER_PUBLIC_ADDR = process.env.DEV_SERVER_PUBLIC_ADDR;
|
||||
const DEV_SERVER_HTTPS = process.env.DEV_SERVER_HTTPS && process.env.DEV_SERVER_HTTPS !== 'false';
|
||||
const DEV_SERVER_LIVERELOAD = IS_DEV_SERVER && process.env.DEV_SERVER_LIVERELOAD !== 'false';
|
||||
const WEBPACK_REPORT = process.env.WEBPACK_REPORT && process.env.WEBPACK_REPORT !== 'false';
|
||||
|
@ -554,6 +555,7 @@ module.exports = {
|
|||
devServer: {
|
||||
host: DEV_SERVER_HOST,
|
||||
port: DEV_SERVER_PORT,
|
||||
public: DEV_SERVER_PUBLIC_ADDR,
|
||||
https: DEV_SERVER_HTTPS,
|
||||
headers: {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
|
|
|
@ -3313,6 +3313,11 @@ type ContainerRepository {
|
|||
"""
|
||||
createdAt: Time!
|
||||
|
||||
"""
|
||||
The tags cleanup status for the container repository.
|
||||
"""
|
||||
expirationPolicyCleanupStatus: ContainerRepositoryCleanupStatus
|
||||
|
||||
"""
|
||||
Timestamp when the cleanup done by the expiration policy was started on the container repository.
|
||||
"""
|
||||
|
@ -3354,6 +3359,31 @@ type ContainerRepository {
|
|||
updatedAt: Time!
|
||||
}
|
||||
|
||||
"""
|
||||
Status of the tags cleanup of a container repository
|
||||
"""
|
||||
enum ContainerRepositoryCleanupStatus {
|
||||
"""
|
||||
The tags cleanup is ongoing.
|
||||
"""
|
||||
ONGOING
|
||||
|
||||
"""
|
||||
The tags cleanup is scheduled and is going to be executed shortly.
|
||||
"""
|
||||
SCHEDULED
|
||||
|
||||
"""
|
||||
The tags cleanup has been partially executed. There are still remaining tags to delete.
|
||||
"""
|
||||
UNFINISHED
|
||||
|
||||
"""
|
||||
The tags cleanup is not scheduled. This is the default state.
|
||||
"""
|
||||
UNSCHEDULED
|
||||
}
|
||||
|
||||
"""
|
||||
The connection type for ContainerRepository.
|
||||
"""
|
||||
|
@ -3388,6 +3418,11 @@ type ContainerRepositoryDetails {
|
|||
"""
|
||||
createdAt: Time!
|
||||
|
||||
"""
|
||||
The tags cleanup status for the container repository.
|
||||
"""
|
||||
expirationPolicyCleanupStatus: ContainerRepositoryCleanupStatus
|
||||
|
||||
"""
|
||||
Timestamp when the cleanup done by the expiration policy was started on the container repository.
|
||||
"""
|
||||
|
|
|
@ -8947,6 +8947,20 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "expirationPolicyCleanupStatus",
|
||||
"description": "The tags cleanup status for the container repository.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "ENUM",
|
||||
"name": "ContainerRepositoryCleanupStatus",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "expirationPolicyStartedAt",
|
||||
"description": "Timestamp when the cleanup done by the expiration policy was started on the container repository.",
|
||||
|
@ -9091,6 +9105,41 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "ENUM",
|
||||
"name": "ContainerRepositoryCleanupStatus",
|
||||
"description": "Status of the tags cleanup of a container repository",
|
||||
"fields": null,
|
||||
"inputFields": null,
|
||||
"interfaces": null,
|
||||
"enumValues": [
|
||||
{
|
||||
"name": "UNSCHEDULED",
|
||||
"description": "The tags cleanup is not scheduled. This is the default state.",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "SCHEDULED",
|
||||
"description": "The tags cleanup is scheduled and is going to be executed shortly.",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "UNFINISHED",
|
||||
"description": "The tags cleanup has been partially executed. There are still remaining tags to delete.",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "ONGOING",
|
||||
"description": "The tags cleanup is ongoing.",
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "ContainerRepositoryConnection",
|
||||
|
@ -9199,6 +9248,20 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "expirationPolicyCleanupStatus",
|
||||
"description": "The tags cleanup status for the container repository.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "ENUM",
|
||||
"name": "ContainerRepositoryCleanupStatus",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "expirationPolicyStartedAt",
|
||||
"description": "Timestamp when the cleanup done by the expiration policy was started on the container repository.",
|
||||
|
|
|
@ -535,6 +535,7 @@ A container repository.
|
|||
| ----- | ---- | ----------- |
|
||||
| `canDelete` | Boolean! | Can the current user delete the container repository. |
|
||||
| `createdAt` | Time! | Timestamp when the container repository was created. |
|
||||
| `expirationPolicyCleanupStatus` | ContainerRepositoryCleanupStatus | The tags cleanup status for the container repository. |
|
||||
| `expirationPolicyStartedAt` | Time | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
||||
| `id` | ID! | ID of the container repository. |
|
||||
| `location` | String! | URL of the container repository. |
|
||||
|
@ -552,6 +553,7 @@ Details of a container repository.
|
|||
| ----- | ---- | ----------- |
|
||||
| `canDelete` | Boolean! | Can the current user delete the container repository. |
|
||||
| `createdAt` | Time! | Timestamp when the container repository was created. |
|
||||
| `expirationPolicyCleanupStatus` | ContainerRepositoryCleanupStatus | The tags cleanup status for the container repository. |
|
||||
| `expirationPolicyStartedAt` | Time | Timestamp when the cleanup done by the expiration policy was started on the container repository. |
|
||||
| `id` | ID! | ID of the container repository. |
|
||||
| `location` | String! | URL of the container repository. |
|
||||
|
@ -3812,6 +3814,17 @@ Mode of a commit action.
|
|||
| `SEVEN_DAYS` | 7 days until tags are automatically removed |
|
||||
| `THIRTY_DAYS` | 30 days until tags are automatically removed |
|
||||
|
||||
### ContainerRepositoryCleanupStatus
|
||||
|
||||
Status of the tags cleanup of a container repository.
|
||||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| `ONGOING` | The tags cleanup is ongoing. |
|
||||
| `SCHEDULED` | The tags cleanup is scheduled and is going to be executed shortly. |
|
||||
| `UNFINISHED` | The tags cleanup has been partially executed. There are still remaining tags to delete. |
|
||||
| `UNSCHEDULED` | The tags cleanup is not scheduled. This is the default state. |
|
||||
|
||||
### ContainerRepositoryStatus
|
||||
|
||||
Status of a container repository.
|
||||
|
|
|
@ -397,7 +397,7 @@ field :foo, GraphQL::STRING_TYPE,
|
|||
'if `my_feature_flag` feature flag is disabled'
|
||||
|
||||
def foo
|
||||
object.foo unless Feature.enabled?(:my_feature_flag, object)
|
||||
object.foo if Feature.enabled?(:my_feature_flag, object)
|
||||
end
|
||||
```
|
||||
|
||||
|
|
|
@ -63,6 +63,8 @@ job finishes but the DAST job fails, the security dashboard doesn't show SAST re
|
|||
the analyzer outputs an
|
||||
[exit code](../../../development/integrations/secure.md#exit-code).
|
||||
|
||||
You can filter the vulnerabilities list by selecting from the **Severity** and **Scanner** dropdowns.
|
||||
|
||||
## Project Security Dashboard
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/235558) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 13.6.
|
||||
|
@ -105,6 +107,11 @@ You can filter the vulnerabilities by one or more of the following:
|
|||
| Severity | Critical, High, Medium, Low, Info, Unknown |
|
||||
| Scanner | [Available Scanners](../index.md#security-scanning-tools) |
|
||||
|
||||
You can filter the vulnerabilities list by selecting from the **Status**, **Severity**, and
|
||||
**Scanner** dropdowns. In the **Scanner** dropdown, select individual scanners or scanner groups to
|
||||
toggle those scanners. The **Scanner** dropdown includes both GitLab scanners, and in GitLab 13.6
|
||||
and later, custom scanners.
|
||||
|
||||
You can also dismiss vulnerabilities in the table:
|
||||
|
||||
1. Select the checkbox for each vulnerability you want to dismiss.
|
||||
|
@ -260,6 +267,11 @@ You can filter which vulnerabilities the vulnerability report displays by:
|
|||
| Scanner | [Available Scanners](../index.md#security-scanning-tools) |
|
||||
| Project | Projects configured in the Security Center settings |
|
||||
|
||||
You can filter the vulnerabilities list by selecting from the **Status**, **Severity**, and
|
||||
**Scanner**, and **Project** dropdowns. In the **Scanner** dropdown, select individual scanners or
|
||||
scanner groups to toggle those scanners. The **Scanner** dropdown includes both GitLab scanners, and
|
||||
in GitLab 13.6 and later, custom scanners.
|
||||
|
||||
Clicking any vulnerability in the table takes you to its
|
||||
[Vulnerability Details](../vulnerabilities) page to see more information on that vulnerability.
|
||||
To create an issue associated with the vulnerability, click the **Create Issue** button.
|
||||
|
|
|
@ -95,12 +95,13 @@ While you can view and manage the full details of an issue on the [issue page](#
|
|||
you can also work with multiple issues at a time using the [Issues List](#issues-list),
|
||||
[Issue Boards](#issue-boards), Issue references, and [Epics](#epics)**(PREMIUM)**.
|
||||
|
||||
Key actions for Issues include:
|
||||
Key actions for issues include:
|
||||
|
||||
- [Creating issues](managing_issues.md#create-a-new-issue)
|
||||
- [Moving issues](managing_issues.md#moving-issues)
|
||||
- [Closing issues](managing_issues.md#closing-issues)
|
||||
- [Deleting issues](managing_issues.md#deleting-issues)
|
||||
- [Promoting issues](managing_issues.md#promote-an-issue-to-an-epic) **(PREMIUM)**
|
||||
|
||||
### Issue page
|
||||
|
||||
|
|
|
@ -7,9 +7,15 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
|||
# Managing issues
|
||||
|
||||
[GitLab Issues](index.md) are the fundamental medium for collaborating on ideas and
|
||||
planning work in GitLab. [Creating](#create-a-new-issue), [moving](#moving-issues),
|
||||
[closing](#closing-issues), and [deleting](#deleting-issues) are key actions that
|
||||
you can do with issues.
|
||||
planning work in GitLab.
|
||||
|
||||
Key actions for issues include:
|
||||
|
||||
- [Creating issues](#create-a-new-issue)
|
||||
- [Moving issues](#moving-issues)
|
||||
- [Closing issues](#closing-issues)
|
||||
- [Deleting issues](#deleting-issues)
|
||||
- [Promoting issues](#promote-an-issue-to-an-epic) **(PREMIUM)**
|
||||
|
||||
## Create a new issue
|
||||
|
||||
|
@ -280,6 +286,23 @@ editing it and clicking on the delete button.
|
|||
|
||||
![delete issue - button](img/delete_issue.png)
|
||||
|
||||
## Promote an issue to an epic **(PREMIUM)**
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3777) in [GitLab Ultimate](https://about.gitlab.com/pricing/) 11.6.
|
||||
> - [Moved](https://gitlab.com/gitlab-org/gitlab/-/issues/37081) to [GitLab Premium](https://about.gitlab.com/pricing/) in 12.8.
|
||||
> - Promoting issues to epics via the UI [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/233974) in [GitLab Premium](https://about.gitlab.com/pricing/) 13.6.
|
||||
|
||||
You can promote an issue to an epic in the immediate parent group.
|
||||
|
||||
To promote an issue to an epic:
|
||||
|
||||
1. In an issue, select the vertical ellipsis (**{ellipsis_v}**) button.
|
||||
1. Select **Promote to epic**.
|
||||
|
||||
Alternatively, you can use the `/promote` [quick action](../quick_actions.md#quick-actions-for-issues-merge-requests-and-epics).
|
||||
|
||||
Read more about promoting an issue to an epic on the [Manage epics page](../../group/epics/manage_epics.md#promote-an-issue-to-an-epic).
|
||||
|
||||
## Add an issue to an iteration **(STARTER)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216158) in [GitLab Starter](https://about.gitlab.com/pricing/) 13.2.
|
||||
|
|
|
@ -528,9 +528,6 @@ msgstr ""
|
|||
msgid "%{host} sign-in from new location"
|
||||
msgstr ""
|
||||
|
||||
msgid "%{icon}You are about to add %{usersTag} people to the discussion. They will all receive a notification."
|
||||
msgstr ""
|
||||
|
||||
msgid "%{integrations_link_start}Integrations%{link_end} enable you to make third-party applications part of your GitLab workflow. If the available integrations don't meet your needs, consider using a %{webhooks_link_start}webhook%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -7707,6 +7704,9 @@ msgstr ""
|
|||
msgid "Could not restore the group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Could not retrieve custom scanners for scanner filter. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
msgid "Could not revoke impersonation token %{token_name}."
|
||||
msgstr ""
|
||||
|
||||
|
@ -21810,6 +21810,9 @@ msgstr ""
|
|||
msgid "Promote issue to an epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promote to epic"
|
||||
msgstr ""
|
||||
|
||||
msgid "Promote to group label"
|
||||
msgstr ""
|
||||
|
||||
|
@ -25341,6 +25344,9 @@ msgstr ""
|
|||
msgid "Something went wrong while performing the action."
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while promoting the issue to an epic. Please try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Something went wrong while reopening a requirement."
|
||||
msgstr ""
|
||||
|
||||
|
@ -26956,6 +26962,9 @@ msgstr ""
|
|||
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
|
||||
msgstr ""
|
||||
|
||||
msgid "The issue was successfully promoted to an epic. Redirecting to epic..."
|
||||
msgstr ""
|
||||
|
||||
msgid "The license for Deploy Board is required to use this feature."
|
||||
msgstr ""
|
||||
|
||||
|
@ -30764,6 +30773,9 @@ msgstr ""
|
|||
msgid "You already have pending todo for this alert"
|
||||
msgstr ""
|
||||
|
||||
msgid "You are about to add %{usersTag} people to the discussion. They will all receive a notification."
|
||||
msgstr ""
|
||||
|
||||
msgid "You are about to delete %{domain} from your instance. This domain will no longer be available to any Knative application."
|
||||
msgstr ""
|
||||
|
||||
|
|
12
spec/fixtures/api/schemas/graphql/container_repositories.json
vendored
Normal file
12
spec/fixtures/api/schemas/graphql/container_repositories.json
vendored
Normal file
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["node"],
|
||||
"properties": {
|
||||
"node": {
|
||||
"$ref": "./container_repository.json"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "path", "location", "createdAt", "updatedAt", "tagsCount", "canDelete"],
|
||||
"required": ["id", "name", "path", "location", "createdAt", "updatedAt", "tagsCount", "canDelete", "expirationPolicyCleanupStatus"],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
|
@ -31,6 +31,10 @@
|
|||
},
|
||||
"canDelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"expirationPolicyCleanupStatus": {
|
||||
"type": "string",
|
||||
"enum": ["UNSCHEDULED", "SCHEDULED", "UNFINISHED", "ONGOING"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,37 +1,8 @@
|
|||
{
|
||||
"type": "object",
|
||||
"required": ["id", "name", "path", "location", "createdAt", "updatedAt", "tagsCount", "canDelete", "tags"],
|
||||
"required": ["tags"],
|
||||
"allOf": [{ "$ref": "./container_repository.json" }],
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
},
|
||||
"location": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"updatedAt": {
|
||||
"type": "string"
|
||||
},
|
||||
"expirationPolicyStartedAt": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"status": {
|
||||
"type": ["string", "null"]
|
||||
},
|
||||
"tagsCount": {
|
||||
"type": "integer"
|
||||
},
|
||||
"canDelete": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"tags": {
|
||||
"type": "object",
|
||||
"required": ["nodes"],
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import { GlButton, GlDropdown, GlDropdownItem, GlLink, GlModal } from '@gitlab/ui';
|
||||
import { createLocalVue, shallowMount } from '@vue/test-utils';
|
||||
import Vuex from 'vuex';
|
||||
import createFlash, { FLASH_TYPES } from '~/flash';
|
||||
import { IssuableType } from '~/issuable_show/constants';
|
||||
import HeaderActions from '~/issue_show/components/header_actions.vue';
|
||||
import { IssuableStatus, IssueStateEvent } from '~/issue_show/constants';
|
||||
import promoteToEpicMutation from '~/issue_show/queries/promote_to_epic.mutation.graphql';
|
||||
import * as urlUtility from '~/lib/utils/url_utility';
|
||||
import createStore from '~/notes/stores';
|
||||
|
||||
jest.mock('~/flash');
|
||||
|
||||
describe('HeaderActions component', () => {
|
||||
let dispatchEventSpy;
|
||||
let mutateMock;
|
||||
let wrapper;
|
||||
let visitUrlSpy;
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(Vuex);
|
||||
|
@ -16,6 +23,7 @@ describe('HeaderActions component', () => {
|
|||
|
||||
const defaultProps = {
|
||||
canCreateIssue: true,
|
||||
canPromoteToEpic: true,
|
||||
canReopenIssue: true,
|
||||
canReportSpam: true,
|
||||
canUpdateIssue: true,
|
||||
|
@ -29,7 +37,27 @@ describe('HeaderActions component', () => {
|
|||
submitAsSpamPath: 'gitlab-org/gitlab-test/-/issues/32/submit_as_spam',
|
||||
};
|
||||
|
||||
const mutate = jest.fn().mockResolvedValue({ data: { updateIssue: { errors: [] } } });
|
||||
const updateIssueMutationResponse = { data: { updateIssue: { errors: [] } } };
|
||||
|
||||
const promoteToEpicMutationResponse = {
|
||||
data: {
|
||||
promoteToEpic: {
|
||||
errors: [],
|
||||
epic: {
|
||||
webPath: '/groups/gitlab-org/-/epics/1',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const promoteToEpicMutationErrorResponse = {
|
||||
data: {
|
||||
promoteToEpic: {
|
||||
errors: ['The issue has already been promoted to an epic.'],
|
||||
epic: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const findToggleIssueStateButton = () => wrapper.find(GlButton);
|
||||
|
||||
|
@ -50,7 +78,10 @@ describe('HeaderActions component', () => {
|
|||
props = {},
|
||||
issueState = IssuableStatus.Open,
|
||||
blockedByIssues = [],
|
||||
mutateResponse = {},
|
||||
} = {}) => {
|
||||
mutateMock = jest.fn().mockResolvedValue(mutateResponse);
|
||||
|
||||
store.getters.getNoteableData.state = issueState;
|
||||
store.getters.getNoteableData.blocked_by_issues = blockedByIssues;
|
||||
|
||||
|
@ -63,7 +94,7 @@ describe('HeaderActions component', () => {
|
|||
},
|
||||
mocks: {
|
||||
$apollo: {
|
||||
mutate,
|
||||
mutate: mutateMock,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
@ -73,6 +104,9 @@ describe('HeaderActions component', () => {
|
|||
if (dispatchEventSpy) {
|
||||
dispatchEventSpy.mockRestore();
|
||||
}
|
||||
if (visitUrlSpy) {
|
||||
visitUrlSpy.mockRestore();
|
||||
}
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
|
@ -90,7 +124,11 @@ describe('HeaderActions component', () => {
|
|||
beforeEach(() => {
|
||||
dispatchEventSpy = jest.spyOn(document, 'dispatchEvent');
|
||||
|
||||
wrapper = mountComponent({ props: { issueType }, issueState });
|
||||
wrapper = mountComponent({
|
||||
props: { issueType },
|
||||
issueState,
|
||||
mutateResponse: updateIssueMutationResponse,
|
||||
});
|
||||
});
|
||||
|
||||
it(`has text "${buttonText}"`, () => {
|
||||
|
@ -100,11 +138,11 @@ describe('HeaderActions component', () => {
|
|||
it('calls apollo mutation', () => {
|
||||
findToggleIssueStateButton().vm.$emit('click');
|
||||
|
||||
expect(mutate).toHaveBeenCalledWith(
|
||||
expect(mutateMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
input: {
|
||||
iid: defaultProps.iid.toString(),
|
||||
iid: defaultProps.iid,
|
||||
projectPath: defaultProps.projectPath,
|
||||
stateEvent: newIssueState,
|
||||
},
|
||||
|
@ -129,15 +167,17 @@ describe('HeaderActions component', () => {
|
|||
${'desktop dropdown'} | ${false} | ${findDesktopDropdownItems}
|
||||
`('$description', ({ isCloseIssueItemVisible, findDropdownItems }) => {
|
||||
describe.each`
|
||||
description | itemText | isItemVisible | canUpdateIssue | canCreateIssue | isIssueAuthor | canReportSpam
|
||||
${`when user can update ${issueType}`} | ${`Close ${issueType}`} | ${isCloseIssueItemVisible} | ${true} | ${true} | ${true} | ${true}
|
||||
${`when user cannot update ${issueType}`} | ${`Close ${issueType}`} | ${false} | ${false} | ${true} | ${true} | ${true}
|
||||
${`when user can create ${issueType}`} | ${`New ${issueType}`} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${`when user cannot create ${issueType}`} | ${`New ${issueType}`} | ${false} | ${true} | ${false} | ${true} | ${true}
|
||||
${'when user can report abuse'} | ${'Report abuse'} | ${true} | ${true} | ${true} | ${false} | ${true}
|
||||
${'when user cannot report abuse'} | ${'Report abuse'} | ${false} | ${true} | ${true} | ${true} | ${true}
|
||||
${'when user can submit as spam'} | ${'Submit as spam'} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${'when user cannot submit as spam'} | ${'Submit as spam'} | ${false} | ${true} | ${true} | ${true} | ${false}
|
||||
description | itemText | isItemVisible | canUpdateIssue | canCreateIssue | isIssueAuthor | canReportSpam | canPromoteToEpic
|
||||
${`when user can update ${issueType}`} | ${`Close ${issueType}`} | ${isCloseIssueItemVisible} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${`when user cannot update ${issueType}`} | ${`Close ${issueType}`} | ${false} | ${false} | ${true} | ${true} | ${true} | ${true}
|
||||
${`when user can create ${issueType}`} | ${`New ${issueType}`} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${`when user cannot create ${issueType}`} | ${`New ${issueType}`} | ${false} | ${true} | ${false} | ${true} | ${true} | ${true}
|
||||
${'when user can promote to epic'} | ${'Promote to epic'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${'when user cannot promote to epic'} | ${'Promote to epic'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${false}
|
||||
${'when user can report abuse'} | ${'Report abuse'} | ${true} | ${true} | ${true} | ${false} | ${true} | ${true}
|
||||
${'when user cannot report abuse'} | ${'Report abuse'} | ${false} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${'when user can submit as spam'} | ${'Submit as spam'} | ${true} | ${true} | ${true} | ${true} | ${true} | ${true}
|
||||
${'when user cannot submit as spam'} | ${'Submit as spam'} | ${false} | ${true} | ${true} | ${true} | ${false} | ${true}
|
||||
`(
|
||||
'$description',
|
||||
({
|
||||
|
@ -147,6 +187,7 @@ describe('HeaderActions component', () => {
|
|||
canCreateIssue,
|
||||
isIssueAuthor,
|
||||
canReportSpam,
|
||||
canPromoteToEpic,
|
||||
}) => {
|
||||
beforeEach(() => {
|
||||
wrapper = mountComponent({
|
||||
|
@ -156,6 +197,7 @@ describe('HeaderActions component', () => {
|
|||
isIssueAuthor,
|
||||
issueType,
|
||||
canReportSpam,
|
||||
canPromoteToEpic,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
@ -172,6 +214,65 @@ describe('HeaderActions component', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('when "Promote to epic" button is clicked', () => {
|
||||
describe('when response is successful', () => {
|
||||
beforeEach(() => {
|
||||
visitUrlSpy = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
|
||||
|
||||
wrapper = mountComponent({
|
||||
mutateResponse: promoteToEpicMutationResponse,
|
||||
});
|
||||
|
||||
wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
|
||||
});
|
||||
|
||||
it('invokes GraphQL mutation when clicked', () => {
|
||||
expect(mutateMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
mutation: promoteToEpicMutation,
|
||||
variables: {
|
||||
input: {
|
||||
iid: defaultProps.iid,
|
||||
projectPath: defaultProps.projectPath,
|
||||
},
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('shows a success message and tells the user they are being redirected', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
message: 'The issue was successfully promoted to an epic. Redirecting to epic...',
|
||||
type: FLASH_TYPES.SUCCESS,
|
||||
});
|
||||
});
|
||||
|
||||
it('redirects to newly created epic path', () => {
|
||||
expect(visitUrlSpy).toHaveBeenCalledWith(
|
||||
promoteToEpicMutationResponse.data.promoteToEpic.epic.webPath,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when response contains errors', () => {
|
||||
beforeEach(() => {
|
||||
visitUrlSpy = jest.spyOn(urlUtility, 'visitUrl').mockReturnValue({});
|
||||
|
||||
wrapper = mountComponent({
|
||||
mutateResponse: promoteToEpicMutationErrorResponse,
|
||||
});
|
||||
|
||||
wrapper.find('[data-testid="promote-button"]').vm.$emit('click');
|
||||
});
|
||||
|
||||
it('shows an error message', () => {
|
||||
expect(createFlash).toHaveBeenCalledWith({
|
||||
message: promoteToEpicMutationErrorResponse.data.promoteToEpic.errors.join('; '),
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('modal', () => {
|
||||
const blockedByIssues = [
|
||||
{ iid: 13, web_url: 'gitlab-org/gitlab-test/-/issues/13' },
|
||||
|
@ -197,7 +298,7 @@ describe('HeaderActions component', () => {
|
|||
it('calls apollo mutation when primary button is clicked', () => {
|
||||
findModal().vm.$emit('primary');
|
||||
|
||||
expect(mutate).toHaveBeenCalledWith(
|
||||
expect(mutateMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
variables: {
|
||||
input: {
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe GitlabSchema.types['ContainerRepositoryCleanupStatus'] do
|
||||
it 'exposes all statuses' do
|
||||
expected_keys = ContainerRepository.expiration_policy_cleanup_statuses
|
||||
.keys
|
||||
.map { |k| k.gsub('cleanup_', '') }
|
||||
.map(&:upcase)
|
||||
expect(described_class.values.keys).to contain_exactly(*expected_keys)
|
||||
end
|
||||
end
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe GitlabSchema.types['ContainerRepositoryDetails'] do
|
||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete tags]
|
||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status tags]
|
||||
|
||||
it { expect(described_class.graphql_name).to eq('ContainerRepositoryDetails') }
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe GitlabSchema.types['ContainerRepository'] do
|
||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete]
|
||||
fields = %i[id name path location created_at updated_at expiration_policy_started_at status tags_count can_delete expiration_policy_cleanup_status]
|
||||
|
||||
it { expect(described_class.graphql_name).to eq('ContainerRepository') }
|
||||
|
||||
|
@ -20,4 +20,12 @@ RSpec.describe GitlabSchema.types['ContainerRepository'] do
|
|||
is_expected.to have_graphql_type(Types::ContainerRepositoryStatusEnum)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'expiration_policy_cleanup_status field' do
|
||||
subject { described_class.fields['expirationPolicyCleanupStatus'] }
|
||||
|
||||
it 'returns cleanup status enum' do
|
||||
is_expected.to have_graphql_type(Types::ContainerRepositoryCleanupStatusEnum)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -34,7 +34,7 @@ RSpec.describe 'container repository details' do
|
|||
subject
|
||||
end
|
||||
|
||||
it 'matches the expected schema' do
|
||||
it 'matches the JSON schema' do
|
||||
expect(container_repository_details_response).to match_schema('graphql/container_repository_details')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,6 +47,10 @@ RSpec.describe 'getting container repositories in a project' do
|
|||
before do
|
||||
subject
|
||||
end
|
||||
|
||||
it 'matches the JSON schema' do
|
||||
expect(container_repositories_response).to match_schema('graphql/container_repositories')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with different permissions' do
|
||||
|
|
Loading…
Reference in a new issue