Commit 0011883a authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents aa621050 411b8819
......@@ -24,7 +24,6 @@
/doc/administration/troubleshooting @axil @marcia @mjang1
/doc/ci/ @marcel.amirault @sselhorn
/doc/ci/environments/ @axil
/doc/ci/release/ @axil
/doc/ci/services/ @sselhorn
/doc/ci/test_cases/ @msedlakjakubowski
/doc/development/ @marcia @mjang1
......@@ -205,15 +204,16 @@ Dangerfile @gl-quality/eng-prod
# Secure & Threat Management ownership delineation
# https://about.gitlab.com/handbook/engineering/development/threat-management/delineate-secure-threat-management.html#technical-boundaries
[Threat Insights]
/app/models/vulnerability.rb @gitlab-org/secure/threat-insights-backend-team
/ee/app/finders/security/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/security/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/models/vulnerability.rb @gitlab-org/secure/threat-insights-backend-team
/ee/app/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/app/policies/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team
/ee/lib/api/vulnerabilit*.rb @gitlab-org/secure/threat-insights-backend-team
/ee/spec/policies/vulnerabilities/ @gitlab-org/secure/threat-insights-backend-team
/ee/spec/policies/vulnerabilities/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team
/ee/spec/policies/vulnerability*.rb @gitlab-org/secure/threat-insights-backend-team
[Secure]
/ee/lib/gitlab/ci/parsers/license_compliance/ @gitlab-org/secure/composition-analysis-be
/ee/lib/gitlab/ci/parsers/security/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/dynamic-analysis-be @gitlab-org/secure/static-analysis-be @gitlab-org/secure/fuzzing-be
......@@ -260,9 +260,7 @@ Dangerfile @gl-quality/eng-prod
[Product Intelligence]
/ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
/ee/lib/ee/gitlab/usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/grafana_embed_usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/usage_data.rb @gitlab-org/growth/product_intelligence/engineers
/lib/gitlab/cycle_analytics/usage_data.rb @gitlab-org/growth/product-intelligence/engineers
/lib/gitlab/usage_data_counters/ @gitlab-org/growth/product-intelligence/engineers
[Growth Experiments]
......
......@@ -162,6 +162,7 @@ setup-test-env:
- tmp/tests/gitaly/gitaly-lfs-smudge
- tmp/tests/gitaly/gitaly-ssh
- tmp/tests/gitaly/internal/
- tmp/tests/gitaly/internal_gitaly2/
- tmp/tests/gitaly/internal_sockets/
- tmp/tests/gitaly/Makefile
- tmp/tests/gitaly/praefect
......
......@@ -73,21 +73,19 @@ export default {
</script>
<template>
<div class="gl-display-flex gl-align-items-center gl-h-full">
<div>
<gl-modal
:modal-id="modalId"
:title="$options.modal.title"
:action-primary="$options.modal.actionPrimary"
:action-cancel="$options.modal.actionCancel"
@ok="$emit('deleteSelectedDesigns')"
@ok="$emit('delete-selected-designs')"
>
<p>
{{
s__(
'DesignManagement|Archived designs will still be available in previous versions of the design collection.',
)
}}
</p>
{{
s__(
'DesignManagement|Archived designs will still be available in previous versions of the design collection.',
)
}}
</gl-modal>
<gl-button
v-gl-modal-directive="modalId"
......
......@@ -55,6 +55,7 @@ export default {
iid,
}"
:update="updateStoreAfterDelete"
:tag="null"
v-on="$listeners"
>
<slot v-bind="{ mutate, loading, error }"></slot>
......
......@@ -130,7 +130,7 @@ export default {
button-icon="archive"
button-category="secondary"
:title="s__('DesignManagement|Archive design')"
@deleteSelectedDesigns="$emit('delete')"
@delete-selected-designs="$emit('delete')"
/>
</header>
</template>
......@@ -50,7 +50,7 @@ export default {
type="file"
name="design_file"
:accept="$options.VALID_DESIGN_FILE_MIMETYPE.mimetype"
class="hide"
class="gl-display-none"
multiple
@change="onFileUploadChange"
/>
......
......@@ -365,7 +365,8 @@ export default {
v-if="isLatestVersion"
variant="link"
size="small"
class="gl-mr-4 js-select-all"
class="gl-mr-3"
data-testid="select-all-designs-button"
@click="toggleDesignsSelection"
>{{ selectAllButtonText }}
</gl-button>
......@@ -385,7 +386,7 @@ export default {
data-qa-selector="archive_button"
:loading="loading"
:has-selected-designs="hasSelectedDesigns"
@deleteSelectedDesigns="mutate()"
@delete-selected-designs="mutate()"
>
{{ s__('DesignManagement|Archive selected') }}
</delete-button>
......
......@@ -7,6 +7,7 @@ import PipelineGraph from './graph_component.vue';
import {
getQueryHeaders,
reportToSentry,
serializeGqlErr,
toggleQueryPollingByVisibility,
unwrapPipelineData,
} from './utils';
......@@ -60,8 +61,8 @@ export default {
update(data) {
return unwrapPipelineData(this.pipelineProjectPath, data);
},
error() {
this.reportFailure(LOAD_FAILURE);
error({ gqlError }) {
this.reportFailure(LOAD_FAILURE, serializeGqlErr(gqlError));
},
},
},
......@@ -112,10 +113,10 @@ export default {
refreshPipelineGraph() {
this.$apollo.queries.pipeline.refetch();
},
reportFailure(type) {
reportFailure(type, err = '') {
this.showAlert = true;
this.alertType = type;
reportToSentry(this.$options.name, this.alertType);
reportToSentry(this.$options.name, `type: ${this.alertType}, info: ${err}`);
},
},
};
......
......@@ -6,6 +6,7 @@ import LinkedPipeline from './linked_pipeline.vue';
import {
getQueryHeaders,
reportToSentry,
serializeGqlErr,
toggleQueryPollingByVisibility,
unwrapPipelineData,
validateConfigPaths,
......@@ -99,12 +100,14 @@ export default {
this.loadingPipelineId = null;
this.$emit('scrollContainer');
},
error(err, _vm, _key, type) {
error({ gqlError }, _vm, _key, type) {
this.$emit('error', LOAD_FAILURE);
reportToSentry(
'linked_pipelines_column',
`error type: ${LOAD_FAILURE}, error: ${err}, apollo error type: ${type}`,
`error type: ${LOAD_FAILURE}, error: ${serializeGqlErr(
gqlError,
)}, apollo error type: ${type}`,
);
},
});
......
......@@ -23,7 +23,6 @@ const getQueryHeaders = (etagResource) => {
},
};
};
/* eslint-enable @gitlab/require-i18n-strings */
const reportToSentry = (component, failureType) => {
Sentry.withScope((scope) => {
......@@ -32,6 +31,25 @@ const reportToSentry = (component, failureType) => {
});
};
const serializeGqlErr = (gqlError) => {
if (!gqlError) {
return 'gqlError data not available.';
}
const { locations, message, path } = gqlError;
return `
${message}.
Locations: ${locations
.flatMap((loc) => Object.entries(loc))
.flat(2)
.join(' ')}.
Path: ${path.join(', ')}.
`;
};
/* eslint-enable @gitlab/require-i18n-strings */
const toggleQueryPollingByVisibility = (queryRef, interval = 10000) => {
const stopStartQuery = (query) => {
if (!Visibility.hidden()) {
......@@ -82,6 +100,7 @@ const validateConfigPaths = (value) => value.graphqlResourceEtag?.length > 0;
export {
getQueryHeaders,
reportToSentry,
serializeGqlErr,
toggleQueryPollingByVisibility,
unwrapPipelineData,
validateConfigPaths,
......
<script>
import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
import { __ } from '~/locale';
import eventHub from '../../event_hub';
import PipelinesArtifactsComponent from './pipelines_artifacts.vue';
import PipelinesManualActions from './pipelines_manual_actions.vue';
export default {
i18n: {
cancelTitle: __('Cancel'),
redeployTitle: __('Retry'),
},
directives: {
GlTooltip: GlTooltipDirective,
GlModalDirective,
},
components: {
GlButton,
PipelinesManualActions,
PipelinesArtifactsComponent,
},
props: {
pipeline: {
type: Object,
required: true,
},
cancelingPipeline: {
type: Number,
required: false,
default: null,
},
},
data() {
return {
isRetrying: false,
};
},
computed: {
displayPipelineActions() {
return (
this.pipeline.flags.retryable ||
this.pipeline.flags.cancelable ||
this.pipeline.details.manual_actions.length ||
this.pipeline.details.artifacts.length
);
},
actions() {
if (!this.pipeline || !this.pipeline.details) {
return [];
}
const { details } = this.pipeline;
return [...(details.manual_actions || []), ...(details.scheduled_actions || [])];
},
isCancelling() {
return this.cancelingPipeline === this.pipeline.id;
},
},
watch: {
pipeline() {
this.isRetrying = false;
},
},
methods: {
handleCancelClick() {
eventHub.$emit('openConfirmationModal', {
pipeline: this.pipeline,
endpoint: this.pipeline.cancel_path,
});
},
handleRetryClick() {
this.isRetrying = true;
eventHub.$emit('retryPipeline', this.pipeline.retry_path);
},
},
};
</script>
<template>
<div v-if="displayPipelineActions" class="gl-text-right">
<div class="btn-group">
<pipelines-manual-actions v-if="actions.length > 0" :actions="actions" />
<pipelines-artifacts-component
v-if="pipeline.details.artifacts.length"
:artifacts="pipeline.details.artifacts"
/>
<gl-button
v-if="pipeline.flags.retryable"
v-gl-tooltip.hover
:aria-label="$options.i18n.redeployTitle"
:title="$options.i18n.redeployTitle"
:disabled="isRetrying"
:loading="isRetrying"
class="js-pipelines-retry-button"
data-qa-selector="pipeline_retry_button"
icon="repeat"
variant="default"
category="secondary"
@click="handleRetryClick"
/>
<gl-button
v-if="pipeline.flags.cancelable"
v-gl-tooltip.hover
v-gl-modal-directive="'confirmation-modal'"
:aria-label="$options.i18n.cancelTitle"
:title="$options.i18n.cancelTitle"
:loading="isCancelling"
:disabled="isCancelling"
icon="close"
variant="danger"
category="primary"
class="js-pipelines-cancel-button"
@click="handleCancelClick"
/>
</div>
</div>
</template>
......@@ -29,7 +29,7 @@ export default {
};
</script>
<template>
<div :class="classes">
<div :class="classes" data-testid="pipeline-triggerer">
<user-avatar-link
v-if="user"
:link-href="user.path"
......
......@@ -61,7 +61,7 @@ export default {
};
</script>
<template>
<div :class="classes">
<div :class="classes" data-testid="pipeline-url-table-cell">
<gl-link
:href="pipeline.path"
data-testid="pipeline-url-link"
......
<script>
import { CHILD_VIEW } from '~/pipelines/constants';
import CommitComponent from '~/vue_shared/components/commit.vue';
export default {
components: {
CommitComponent,
},
props: {
pipeline: {
type: Object,
required: true,
},
viewType: {
type: String,
required: true,
},
},
computed: {
commitAuthor() {
let commitAuthorInformation;
if (!this.pipeline || !this.pipeline.commit) {
return null;
}
// 1. person who is an author of a commit might be a GitLab user
if (this.pipeline.commit.author) {
// 2. if person who is an author of a commit is a GitLab user
// they can have a GitLab avatar
if (this.pipeline.commit.author.avatar_url) {
commitAuthorInformation = this.pipeline.commit.author;
// 3. If GitLab user does not have avatar, they might have a Gravatar
} else if (this.pipeline.commit.author_gravatar_url) {
commitAuthorInformation = {
...this.pipeline.commit.author,
avatar_url: this.pipeline.commit.author_gravatar_url,
};
}
// 4. If committer is not a GitLab User, they can have a Gravatar
} else {
commitAuthorInformation = {
avatar_url: this.pipeline.commit.author_gravatar_url,
path: `mailto:${this.pipeline.commit.author_email}`,
username: this.pipeline.commit.author_name,
};
}
return commitAuthorInformation;
},
commitTag() {
return this.pipeline?.ref?.tag;
},
commitRef() {
return this.pipeline?.ref;
},
commitUrl() {
return this.pipeline?.commit?.commit_path;
},
commitShortSha() {
return this.pipeline?.commit?.short_id;
},
commitTitle() {
return this.pipeline?.commit?.title;
},
isChildView() {
return this.viewType === CHILD_VIEW;
},
},
};
</script>
<template>
<commit-component
:tag="commitTag"
:commit-ref="commitRef"
:commit-url="commitUrl"
:merge-request-ref="pipeline.merge_request"
:short-sha="commitShortSha"
:title="commitTitle"
:author="commitAuthor"
:show-ref-info="!isChildView"
/>
</template>
<script>
import { CHILD_VIEW } from '~/pipelines/constants';
import CiBadge from '~/vue_shared/components/ci_badge_link.vue';
export default {
components: {
CiBadge,
},
props: {
pipeline: {
type: Object,
required: true,
},
viewType: {
type: String,
required: true,
},
},
computed: {
pipelineStatus() {
return this.pipeline?.details?.status ?? {};
},
isChildView() {
return this.viewType === CHILD_VIEW;
},
},
};
</script>
<template>
<ci-badge
:status="pipelineStatus"
:show-text="!isChildView"
:icon-classes="'gl-vertical-align-middle!'"
data-qa-selector="pipeline_commit_status"
/>
</template>
<script>
import { GlTable, GlTooltipDirective } from '@gitlab/ui';
import { s__ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../../event_hub';
import PipelineOperations from './pipeline_operations.vue';
import PipelineStopModal from './pipeline_stop_modal.vue';
import PipelineTriggerer from './pipeline_triggerer.vue';
import PipelineUrl from './pipeline_url.vue';
import PipelinesCommit from './pipelines_commit.vue';
import PipelinesStatusBadge from './pipelines_status_badge.vue';
import PipelinesTableRowComponent from './pipelines_table_row.vue';
import PipelineStage from './stage.vue';
import PipelinesTimeago from './time_ago.vue';
const DEFAULT_TD_CLASS = 'gl-p-5!';
const HIDE_TD_ON_MOBILE = 'gl-display-none! gl-lg-display-table-cell!';
const DEFAULT_TH_CLASSES =
'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1! gl-font-sm!';
export default {
fields: [
{
key: 'status',
label: s__('Pipeline|Status'),
thClass: DEFAULT_TH_CLASSES,
columnClass: 'gl-w-10p',
tdClass: DEFAULT_TD_CLASS,
thAttr: { 'data-testid': 'status-th' },
},
{
key: 'pipeline',
label: s__('Pipeline|Pipeline'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`,
columnClass: 'gl-w-10p',
thAttr: { 'data-testid': 'pipeline-th' },
},
{
key: 'triggerer',
label: s__('Pipeline|Triggerer'),
thClass: DEFAULT_TH_CLASSES,
tdClass: `${DEFAULT_TD_CLASS} ${HIDE_TD_ON_MOBILE}`,
columnClass: 'gl-w-10p',
thAttr: { 'data-testid': 'triggerer-th' },
},
{
key: 'commit',
label: s__('Pipeline|Commit'),
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-20p',
thAttr: { 'data-testid': 'commit-th' },
},
{
key: 'stages',
label: s__('Pipeline|Stages'),
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-15p',
thAttr: { 'data-testid': 'stages-th' },
},
{
key: 'timeago',
label: s__('Pipeline|Duration'),
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-15p',
thAttr: { 'data-testid': 'timeago-th' },
},
{
key: 'actions',
label: '',
thClass: DEFAULT_TH_CLASSES,
tdClass: DEFAULT_TD_CLASS,
columnClass: 'gl-w-20p',
thAttr: { 'data-testid': 'actions-th' },
},
],
components: {
GlTable,
PipelinesTableRowComponent,
PipelinesCommit,
PipelineOperations,
PipelineStage,
PipelinesStatusBadge,
PipelineStopModal,
PipelinesTableRowComponent,
PipelinesTimeago,
PipelineTriggerer,
PipelineUrl,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -43,11 +121,6 @@ export default {
cancelingPipeline: null,
};
},
computed: {
legacyTableClass() {
return !this.glFeatures.newPipelinesTable ? 'ci-table' : '';
},
},
watch: {
pipelines() {
this.cancelingPipeline = null;
......@@ -73,8 +146,8 @@ export default {
};
</script>
<template>
<div :class="legacyTableClass">
<div v-if="!glFeatures.newPipelinesTable" data-testid="ci-table">
<div class="ci-table">
<div v-if="!glFeatures.newPipelinesTable" data-testid="legacy-ci-table">
<div class="gl-responsive-table-row table-row-header" role="row">
<div class="table-section section-10 js-pipeline-status" role="rowheader">
{{ s__('Pipeline|Status') }}
......@@ -107,7 +180,71 @@ export default {
/>
</div>
<gl-table v-else />
<gl-table
v-else
:fields="$options.fields"
:items="pipelines"
tbody-tr-class="commit"
:tbody-tr-attr="{ 'data-testid': 'pipeline-table-row' }"
stacked="lg"
fixed
>
<template #head(actions)>
<slot name="table-header-actions"></slot>
</template>
<template #table-colgroup="{ fields }">
<col v-for="field in fields" :key="field.key" :class="field.columnClass" />
</template>
<template #cell(status)="{ item }">
<pipelines-status-badge :pipeline="item" :view-type="viewType" />
</template>
<template #cell(pipeline)="{ item }">
<pipeline-url
class="gl-text-truncate"
:pipeline="item"
:pipeline-schedule-url="pipelineScheduleUrl"
/>
</template>
<template #cell(triggerer)="{ item }">
<pipeline-triggerer :pipeline="item" />
</template>
<template #cell(commit)="{ item }">
<pipelines-commit :pipeline="item" :view-type="viewType" />
</template>
<template #cell(stages)="{ item }">
<div class="stage-cell">
<div></div>
<template v-if="item.details.stages.length > 0">
<div
v-for="(stage, index) in item.details.stages"
:key="index"
class="stage-container dropdown"
data-testid="widget-mini-pipeline-graph"
>
<pipeline-stage
:type="$options.pipelinesTable"
:stage="stage"
:update-dropdown="updateGraphDropdown"
/>
</div>
</template>
</div>
</template>
<template #cell(timeago)="{ item }">
<pipelines-timeago :pipeline="item" />
</template>
<template #cell(actions)="{ item }">
<pipeline-operations :pipeline="item" :canceling-pipeline="cancelingPipeline" />
</template>
</gl-table>
<pipeline-stop-modal :pipeline="pipeline" @submit="onSubmit" />
</div>
......
......@@ -33,3 +33,5 @@ export const LOAD_FAILURE = 'load_failure';
export const PARSE_FAILURE = 'parse_failure';
export const POST_FAILURE = 'post_failure';
export const UNSUPPORTED_DATA = 'unsupported_data';
export const CHILD_VIEW = 'child';
......@@ -42,6 +42,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:codequality_backend_comparison, @project, default_enabled: :yaml)
push_frontend_feature_flag(:local_file_reviews, default_enabled: :yaml)
push_frontend_feature_flag(:paginated_notes, @project, default_enabled: :yaml)
push_frontend_feature_flag(:new_pipelines_table, @project, default_enabled: :yaml)
record_experiment_user(:invite_members_version_a)
record_experiment_user(:invite_members_version_b)
......
---
title: Fix button alignment in design management header
merge_request: 48003
author:
type: fixed
......@@ -135,12 +135,12 @@ These variables are available when:
| `CI_MERGE_REQUEST_PROJECT_URL` | 11.6 | all | The URL of the project of the merge request. For example, `http://192.168.10.15:3000/namespace/awesome-project`. |
| `CI_MERGE_REQUEST_REF_PATH` | 11.6 | all | The ref path of the merge request. For example, `refs/merge-requests/1/head`. |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_NAME` | 11.6 | all | The source branch name of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request. Only available in [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
| `CI_MERGE_REQUEST_SOURCE_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the source branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_ID` | 11.6 | all | The ID of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_PATH` | 11.6 | all | The path of the source project of the merge request. |
| `CI_MERGE_REQUEST_SOURCE_PROJECT_URL` | 11.6 | all | The URL of the source project of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_NAME` | 11.6 | all | The target branch name of the merge request. |
| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request. Only available in [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
| `CI_MERGE_REQUEST_TARGET_BRANCH_SHA` | 11.9 | all | The HEAD SHA of the target branch of the merge request. The variable is empty in merge request pipelines. The SHA is present only in [merged results pipelines](../merge_request_pipelines/pipelines_for_merged_results/index.md). **(PREMIUM)** |
| `CI_MERGE_REQUEST_TITLE` | 11.9 | all | The title of the merge request. |
| `CI_MERGE_REQUEST_EVENT_TYPE` | 12.3 | all | The event type of the merge request. Can be `detached`, `merged_result` or `merge_train`. |
| `CI_MERGE_REQUEST_DIFF_ID` | 13.7 | all | The version of the merge request diff. |
......
---
stage: none
group: unassigned
stage: Manage
group: Access
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
type: reference, howto, concepts
---
......
......@@ -40,7 +40,7 @@ Prerequisites:
- You need to [authenticate with the API](../../../api/README.md#authentication). If authenticating with a deploy token, it must be configured with the `write_package_registry` scope.
```plaintext
PUT /projects/:id/packages/generic/:package_name/:package_version/:file_name
PUT /projects/:id/packages/generic/:package_name/:package_version/:file_name?status=:status
```
| Attribute | Type | Required | Description |
......@@ -58,7 +58,7 @@ Example request:
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" \
--upload-file path/to/file.txt \
"https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt"
"https://gitlab.example.com/api/v4/projects/24/packages/generic/my_package/0.0.1/file.txt?status=hidden"
```
Example response:
......
......@@ -115,7 +115,7 @@ module Gitlab
config[:storage] = storages
internal_socket_dir = File.join(gitaly_dir, 'internal_sockets')
internal_socket_dir = options[:internal_socket_dir] || File.join(gitaly_dir, 'internal_sockets')
FileUtils.mkdir(internal_socket_dir) unless File.exist?(internal_socket_dir)
config[:internal_socket_dir] = internal_socket_dir
......
......@@ -36,7 +36,7 @@ describe('Batch delete button component', () => {
expect(findButton().attributes('disabled')).toBeTruthy();
});
it('emits `deleteSelectedDesigns` event on modal ok click', () => {
it('emits `delete-selected-designs` event on modal ok click', () => {
createComponent();
findButton().vm.$emit('click');
return wrapper.vm
......@@ -46,7 +46,7 @@ describe('Batch delete button component', () => {
return wrapper.vm.$nextTick();
})
.then(() => {
expect(wrapper.emitted().deleteSelectedDesigns).toBeTruthy();
expect(wrapper.emitted('delete-selected-designs')).toBeTruthy();
});
});
......
......@@ -106,11 +106,11 @@ describe('Design management toolbar component', () => {
});
});
it('emits `delete` event on deleteButton `deleteSelectedDesigns` event', () => {
it('emits `delete` event on deleteButton `delete-selected-designs` event', () => {
createComponent();
return wrapper.vm.$nextTick().then(() => {
wrapper.find(DeleteButton).vm.$emit('deleteSelectedDesigns');
wrapper.find(DeleteButton).vm.$emit('delete-selected-designs');
expect(wrapper.emitted().delete).toBeTruthy();
});
});
......
......@@ -19,7 +19,7 @@ exports[`Design management upload button component renders inverted upload desig
<input
accept="image/*"
class="hide"
class="gl-display-none"
multiple="multiple"
name="design_file"
type="file"
......@@ -44,7 +44,7 @@ exports[`Design management upload button component renders upload design button
<input
accept="image/*"
class="hide"
class="gl-display-none"
multiple="multiple"
name="design_file"
type="file"
......
......@@ -97,7 +97,7 @@ describe('Design management index page', () => {
let moveDesignHandler;
const findDesignCheckboxes = () => wrapper.findAll('.design-checkbox');
const findSelectAllButton = () => wrapper.find('.js-select-all');
const findSelectAllButton = () => wrapper.find('[data-testid="select-all-designs-button"');
const findToolbar = () => wrapper.find('.qa-selector-toolbar');
const findDesignCollectionIsCopying = () =>
wrapper.find('[data-testid="design-collection-is-copying"');
......@@ -542,7 +542,9 @@ describe('Design management index page', () => {
await nextTick();
expect(findDeleteButton().exists()).toBe(true);
expect(findSelectAllButton().text()).toBe('Deselect all');
findDeleteButton().vm.$emit('deleteSelectedDesigns');
findDeleteButton().vm.$emit('delete-selected-designs');
const [{ variables }] = mutate.mock.calls[0];
expect(variables.filenames).toStrictEqual([mockDesigns[0].filename, mockDesigns[1].filename]);
});
......
......@@ -35,8 +35,8 @@ describe('Pipelines Triggerer', () => {
wrapper.destroy();
});
it('should render a table cell', () => {
expect(wrapper.find('.table-section').exists()).toBe(true);
it('should render pipeline triggerer table cell', () => {
expect(wrapper.find('[data-testid="pipeline-triggerer"]').exists()).toBe(true);
});
it('should pass triggerer information when triggerer is provided', () => {
......
......@@ -7,6 +7,7 @@ const projectPath = 'test/test';
describe('Pipeline Url Component', () => {
let wrapper;
const findTableCell = () => wrapper.find('[data-testid="pipeline-url-table-cell"]');
const findPipelineUrlLink = () => wrapper.find('[data-testid="pipeline-url-link"]');
const findScheduledTag = () => wrapper.find('[data-testid="pipeline-url-scheduled"]');
const findLatestTag = () => wrapper.find('[data-testid="pipeline-url-latest"]');
......@@ -43,10 +44,10 @@ describe('Pipeline Url Component', () => {
wrapper = null;
});
it('should render a table cell', () => {
it('should render pipeline url table cell', () => {
createComponent();
expect(wrapper.attributes('class')).toContain('table-section');
expect(findTableCell().exists()).toBe(true);
});
it('should render a link the provided path and id', () => {
......
import { GlFilteredSearch, GlButton, GlLoadingIcon, GlPagination } from '@gitlab/ui';
import { GlButton, GlFilteredSearch, GlLoadingIcon, GlPagination } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { chunk } from 'lodash';
......
import { GlTable } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import PipelineOperations from '~/pipelines/components/pipelines_list/pipeline_operations.vue';
import PipelineTriggerer from '~/pipelines/components/pipelines_list/pipeline_triggerer.vue';
import PipelineUrl from '~/pipelines/components/pipelines_list/pipeline_url.vue';
import PipelinesStatusBadge from '~/pipelines/components/pipelines_list/pipelines_status_badge.vue';
import PipelinesTable from '~/pipelines/components/pipelines_list/pipelines_table.vue';
import PipelinesTimeago from '~/pipelines/components/pipelines_list/time_ago.vue';
import CommitComponent from '~/vue_shared/components/commit.vue';
describe('Pipelines Table', () => {
let pipeline;
......@@ -29,7 +35,22 @@ describe('Pipelines Table', () => {
const findRows = () => wrapper.findAll('.commit.gl-responsive-table-row');
const findGlTable = () => wrapper.findComponent(GlTable);
const findLegacyTable = () => wrapper.findByTestId('ci-table');
const findStatusBadge = () => wrapper.findComponent(PipelinesStatusBadge);
const findPipelineInfo = () => wrapper.findComponent(PipelineUrl);
const findTriggerer = () => wrapper.findComponent(PipelineTriggerer);
const findCommit = () => wrapper.findComponent(CommitComponent);
const findTimeAgo = () => wrapper.findComponent(PipelinesTimeago);
const findActions = () => wrapper.findComponent(PipelineOperations);
const findLegacyTable = () => wrapper.findByTestId('legacy-ci-table');
const findTableRows = () => wrapper.findAll('[data-testid="pipeline-table-row"]');
const findStatusTh = () => wrapper.findByTestId('status-th');
const findPipelineTh = () => wrapper.findByTestId('pipeline-th');
const findTriggererTh = () => wrapper.findByTestId('triggerer-th');
const findCommitTh = () => wrapper.findByTestId('commit-th');
const findStagesTh = () => wrapper.findByTestId('stages-th');
const findTimeAgoTh = () => wrapper.findByTestId('timeago-th');
const findActionsTh = () => wrapper.findByTestId('actions-th');
preloadFixtures(jsonFixtureName);
......@@ -82,11 +103,82 @@ describe('Pipelines Table', () => {
});
describe('table with feature flag on', () => {
it('displays new table', () => {
createComponent(defaultProps, true);
beforeEach(() => {
createComponent({ pipelines: [pipeline], viewType: 'root' }, true);
});
it('displays new table', () => {
expect(findGlTable().exists()).toBe(true);
expect(findLegacyTable().exists()).toBe(false);
});
it('should render table head with correct columns', () => {
expect(findStatusTh().text()).toBe('Status');
expect(findPipelineTh().text()).toBe('Pipeline');
expect(findTriggererTh().text()).toBe('Triggerer');
expect(findCommitTh().text()).toBe('Commit');
expect(findStagesTh().text()).toBe('Stages');
expect(findTimeAgoTh().text()).toBe('Duration');
// last column should have no text in th
expect(findActionsTh().text()).toBe('');
});
it('should display a table row', () => {
expect(findTableRows()).toHaveLength(1);
});
describe('status cell', () => {
it('should render a status badge', () => {
expect(findStatusBadge().exists()).toBe(true);
});
it('should render status badge with correct path', () => {
expect(findStatusBadge().attributes('href')).toBe(pipeline.path);
});
});
describe('pipeline cell', () => {
it('should render pipeline information', () => {
expect(findPipelineInfo().exists()).toBe(true);
});
it('should display the pipeline id', () => {
expect(findPipelineInfo().text()).toContain(`#${pipeline.id}`);
});
});
describe('triggerer cell', () => {
it('should render the pipeline triggerer', () => {
expect(findTriggerer().exists()).toBe(true);
});
});
describe('commit cell', () => {
it('should render commit information', () => {
expect(findCommit().exists()).toBe(true);
});
it('should display and link to commit', () => {
expect(findCommit().text()).toContain(pipeline.commit.short_id);
expect(findCommit().props('commitUrl')).toBe(pipeline.commit.commit_path);
});
it('should display the commit author', () => {
expect(findCommit().props('author')).toEqual(pipeline.commit.author);
});
});
describe('duration cell', () => {
it('should render duration information', () => {
expect(findTimeAgo().exists()).toBe(true);
});
});
describe('operations cell', () => {
it('should render pipeline operations', () => {
expect(findActions().exists()).toBe(true);
});
});
});
});
......@@ -172,8 +172,13 @@ module TestEnv
Gitlab::SetupHelper::Gitaly.create_configuration(gitaly_dir, { 'default' => repos_path }, force: true)
Gitlab::SetupHelper::Gitaly.create_configuration(
gitaly_dir,
{ 'default' => repos_path }, force: true,
options: { gitaly_socket: "gitaly2.socket", config_filename: "gitaly2.config.toml" }
{ 'default' => repos_path },
force: true,
options: {
internal_socket_dir: File.join(gitaly_dir, "internal_gitaly2"),
gitaly_socket: "gitaly2.socket",
config_filename: "gitaly2.config.toml"
}
)
Gitlab::SetupHelper::Praefect.create_configuration(gitaly_dir, { 'praefect' => repos_path }, force: true)
end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment