Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
44c74f7b06
commit
bc9a474793
31 changed files with 651 additions and 89 deletions
|
@ -0,0 +1,57 @@
|
|||
<script>
|
||||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VersionRow,
|
||||
GlKeysetPagination,
|
||||
PackagesListLoader,
|
||||
},
|
||||
props: {
|
||||
versions: {
|
||||
type: Array,
|
||||
required: true,
|
||||
default: () => [],
|
||||
},
|
||||
pageInfo: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
isLoading: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showPagination() {
|
||||
return this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage;
|
||||
},
|
||||
isListEmpty() {
|
||||
return this.versions.length === 0;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div>
|
||||
<div v-if="isLoading">
|
||||
<packages-list-loader />
|
||||
</div>
|
||||
<slot v-else-if="isListEmpty" name="empty-state"></slot>
|
||||
<div v-else>
|
||||
<version-row v-for="version in versions" :key="version.id" :package-entity="version" />
|
||||
<div class="gl-display-flex gl-justify-content-center">
|
||||
<gl-keyset-pagination
|
||||
v-if="showPagination"
|
||||
v-bind="pageInfo"
|
||||
class="gl-mt-3"
|
||||
@prev="$emit('prev-page')"
|
||||
@next="$emit('next-page')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -1,4 +1,10 @@
|
|||
query getPackageDetails($id: PackagesPackageID!) {
|
||||
query getPackageDetails(
|
||||
$id: PackagesPackageID!
|
||||
$first: Int
|
||||
$last: Int
|
||||
$after: String
|
||||
$before: String
|
||||
) {
|
||||
package(id: $id) {
|
||||
id
|
||||
name
|
||||
|
@ -55,7 +61,7 @@ query getPackageDetails($id: PackagesPackageID!) {
|
|||
downloadPath
|
||||
}
|
||||
}
|
||||
versions(first: 100) {
|
||||
versions(after: $after, before: $before, first: $first, last: $last) {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
|
@ -69,6 +75,12 @@ query getPackageDetails($id: PackagesPackageID!) {
|
|||
}
|
||||
}
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
endCursor
|
||||
startCursor
|
||||
}
|
||||
}
|
||||
dependencyLinks {
|
||||
nodes {
|
||||
|
|
|
@ -22,7 +22,7 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
|
|||
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
||||
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
||||
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
||||
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||
import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
|
||||
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
|
||||
import {
|
||||
PACKAGE_TYPE_NUGET,
|
||||
|
@ -48,6 +48,7 @@ import {
|
|||
DELETE_MODAL_CONTENT,
|
||||
DELETE_ALL_PACKAGE_FILES_MODAL_CONTENT,
|
||||
DELETE_LAST_PACKAGE_FILE_MODAL_CONTENT,
|
||||
GRAPHQL_PAGE_SIZE,
|
||||
} from '~/packages_and_registries/package_registry/constants';
|
||||
|
||||
import destroyPackageFilesMutation from '~/packages_and_registries/package_registry/graphql/mutations/destroy_package_files.mutation.graphql';
|
||||
|
@ -65,13 +66,13 @@ export default {
|
|||
GlTabs,
|
||||
GlSprintf,
|
||||
PackageTitle,
|
||||
VersionRow,
|
||||
DependencyRow,
|
||||
PackageHistory,
|
||||
AdditionalMetadata,
|
||||
InstallationCommands,
|
||||
PackageFiles,
|
||||
DeletePackage,
|
||||
PackageVersionsList,
|
||||
},
|
||||
directives: {
|
||||
GlTooltip: GlTooltipDirective,
|
||||
|
@ -132,6 +133,7 @@ export default {
|
|||
queryVariables() {
|
||||
return {
|
||||
id: convertToGraphQLId('Packages::Package', this.packageId),
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
};
|
||||
},
|
||||
packageFiles() {
|
||||
|
@ -157,6 +159,9 @@ export default {
|
|||
hasVersions() {
|
||||
return this.packageEntity.versions?.nodes?.length > 0;
|
||||
},
|
||||
versionPageInfo() {
|
||||
return this.packageEntity?.versions?.pageInfo ?? {};
|
||||
},
|
||||
packageDependencies() {
|
||||
return this.packageEntity.dependencyLinks?.nodes || [];
|
||||
},
|
||||
|
@ -264,6 +269,34 @@ export default {
|
|||
resetDeleteModalContent() {
|
||||
this.deletePackageModalContent = DELETE_MODAL_CONTENT;
|
||||
},
|
||||
updateQuery(_, { fetchMoreResult }) {
|
||||
return fetchMoreResult;
|
||||
},
|
||||
fetchPreviousVersionsPage() {
|
||||
const variables = {
|
||||
...this.queryVariables,
|
||||
first: null,
|
||||
last: GRAPHQL_PAGE_SIZE,
|
||||
before: this.versionPageInfo?.startCursor,
|
||||
};
|
||||
this.$apollo.queries.packageEntity.fetchMore({
|
||||
variables,
|
||||
updateQuery: this.updateQuery,
|
||||
});
|
||||
},
|
||||
fetchNextVersionsPage() {
|
||||
const variables = {
|
||||
...this.queryVariables,
|
||||
first: GRAPHQL_PAGE_SIZE,
|
||||
last: null,
|
||||
after: this.versionPageInfo?.endCursor,
|
||||
};
|
||||
|
||||
this.$apollo.queries.packageEntity.fetchMore({
|
||||
variables,
|
||||
updateQuery: this.updateQuery,
|
||||
});
|
||||
},
|
||||
},
|
||||
i18n: {
|
||||
DELETE_MODAL_TITLE,
|
||||
|
@ -271,6 +304,7 @@ export default {
|
|||
deleteFileModalContent: s__(
|
||||
`PackageRegistry|You are about to delete %{filename}. This is a destructive action that may render your package unusable. Are you sure?`,
|
||||
),
|
||||
otherVersionsTabTitle: __('Other versions'),
|
||||
},
|
||||
modal: {
|
||||
packageDeletePrimaryAction: {
|
||||
|
@ -303,7 +337,7 @@ export default {
|
|||
:description="s__('PackageRegistry|There was a problem fetching the details for this package.')"
|
||||
:svg-path="emptyListIllustration"
|
||||
/>
|
||||
<div v-else-if="!isLoading" class="packages-app">
|
||||
<div v-else-if="projectName" class="packages-app">
|
||||
<package-title :package-entity="packageEntity">
|
||||
<template #delete-button>
|
||||
<gl-button
|
||||
|
@ -358,14 +392,20 @@ export default {
|
|||
</p>
|
||||
</gl-tab>
|
||||
|
||||
<gl-tab :title="__('Other versions')" title-item-class="js-versions-tab">
|
||||
<template v-if="hasVersions">
|
||||
<version-row v-for="v in packageEntity.versions.nodes" :key="v.id" :package-entity="v" />
|
||||
</template>
|
||||
|
||||
<p v-else class="gl-mt-3" data-testid="no-versions-message">
|
||||
{{ s__('PackageRegistry|There are no other versions of this package.') }}
|
||||
</p>
|
||||
<gl-tab :title="$options.i18n.otherVersionsTabTitle" title-item-class="js-versions-tab" lazy>
|
||||
<package-versions-list
|
||||
:is-loading="isLoading"
|
||||
:page-info="versionPageInfo"
|
||||
:versions="packageEntity.versions.nodes"
|
||||
@prev-page="fetchPreviousVersionsPage"
|
||||
@next-page="fetchNextVersionsPage"
|
||||
>
|
||||
<template #empty-state>
|
||||
<p class="gl-mt-3" data-testid="no-versions-message">
|
||||
{{ s__('PackageRegistry|There are no other versions of this package.') }}
|
||||
</p>
|
||||
</template>
|
||||
</package-versions-list>
|
||||
</gl-tab>
|
||||
</gl-tabs>
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ module DiffHelper
|
|||
end
|
||||
|
||||
def show_only_context_commits?
|
||||
!!params[:only_context_commits] || @merge_request&.commits&.empty?
|
||||
!!params[:only_context_commits] || @merge_request.has_no_commits?
|
||||
end
|
||||
|
||||
def diff_options
|
||||
|
|
|
@ -43,6 +43,8 @@ metadata:
|
|||
description: Operations related to merge requests
|
||||
- name: metadata
|
||||
description: Operations related to metadata of the GitLab instance
|
||||
- name: project_export
|
||||
description: Operations related to export projects
|
||||
- name: project_hooks
|
||||
description: Operations related to project hooks
|
||||
- name: project_import_bitbucket
|
||||
|
@ -55,5 +57,7 @@ metadata:
|
|||
description: Operations related to releases
|
||||
- name: suggestions
|
||||
description: Operations related to suggestions
|
||||
- name: system_hooks
|
||||
description: Operations related to system hooks
|
||||
- name: unleash_api
|
||||
description: Operations related to Unleash API
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddTempIndexForProjectStatisticsUploadSizeMigration < Gitlab::Database::Migration[2.0]
|
||||
INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE = 'tmp_index_project_statistics_uploads_size'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
def up
|
||||
# Temporary index is to be used to trigger refresh for all project_statistics with
|
||||
# upload_size <> 0
|
||||
add_concurrent_index :project_statistics, [:project_id],
|
||||
name: INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE,
|
||||
where: "uploads_size <> 0"
|
||||
end
|
||||
|
||||
def down
|
||||
remove_concurrent_index_by_name :project_statistics, INDEX_PROJECT_STATSISTICS_UPLOADS_SIZE
|
||||
end
|
||||
end
|
1
db/schema_migrations/20221104074652
Normal file
1
db/schema_migrations/20221104074652
Normal file
|
@ -0,0 +1 @@
|
|||
167032d562467c3d6be9e6c6c8c072f117e23798db35301f95386130ae115a00
|
|
@ -31217,6 +31217,8 @@ CREATE INDEX tmp_index_on_vulnerabilities_non_dismissed ON vulnerabilities USING
|
|||
|
||||
CREATE INDEX tmp_index_project_statistics_cont_registry_size ON project_statistics USING btree (project_id) WHERE (container_registry_size = 0);
|
||||
|
||||
CREATE INDEX tmp_index_project_statistics_uploads_size ON project_statistics USING btree (project_id) WHERE (uploads_size <> 0);
|
||||
|
||||
CREATE INDEX tmp_index_vulnerability_occurrences_on_id_and_scanner_id ON vulnerability_occurrences USING btree (id, scanner_id) WHERE (report_type = ANY (ARRAY[7, 99]));
|
||||
|
||||
CREATE UNIQUE INDEX uniq_pkgs_deb_grp_architectures_on_distribution_id_and_name ON packages_debian_group_architectures USING btree (distribution_id, name);
|
||||
|
|
|
@ -6980,6 +6980,29 @@ The edge type for [`ContainerRepositoryTag`](#containerrepositorytag).
|
|||
| <a id="containerrepositorytagedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="containerrepositorytagedgenode"></a>`node` | [`ContainerRepositoryTag`](#containerrepositorytag) | The item at the end of the edge. |
|
||||
|
||||
#### `ContributionAnalyticsContributionConnection`
|
||||
|
||||
The connection type for [`ContributionAnalyticsContribution`](#contributionanalyticscontribution).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="contributionanalyticscontributionconnectionedges"></a>`edges` | [`[ContributionAnalyticsContributionEdge]`](#contributionanalyticscontributionedge) | A list of edges. |
|
||||
| <a id="contributionanalyticscontributionconnectionnodes"></a>`nodes` | [`[ContributionAnalyticsContribution]`](#contributionanalyticscontribution) | A list of nodes. |
|
||||
| <a id="contributionanalyticscontributionconnectionpageinfo"></a>`pageInfo` | [`PageInfo!`](#pageinfo) | Information to aid in pagination. |
|
||||
|
||||
#### `ContributionAnalyticsContributionEdge`
|
||||
|
||||
The edge type for [`ContributionAnalyticsContribution`](#contributionanalyticscontribution).
|
||||
|
||||
##### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="contributionanalyticscontributionedgecursor"></a>`cursor` | [`String!`](#string) | A cursor for use in pagination. |
|
||||
| <a id="contributionanalyticscontributionedgenode"></a>`node` | [`ContributionAnalyticsContribution`](#contributionanalyticscontribution) | The item at the end of the edge. |
|
||||
|
||||
#### `CoverageFuzzingCorpusConnection`
|
||||
|
||||
The connection type for [`CoverageFuzzingCorpus`](#coveragefuzzingcorpus).
|
||||
|
@ -11236,6 +11259,24 @@ A tag from a container repository.
|
|||
| <a id="containerrepositorytagshortrevision"></a>`shortRevision` | [`String`](#string) | Short revision of the tag. |
|
||||
| <a id="containerrepositorytagtotalsize"></a>`totalSize` | [`BigInt`](#bigint) | Size of the tag. |
|
||||
|
||||
### `ContributionAnalyticsContribution`
|
||||
|
||||
Represents the contributions of a user.
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="contributionanalyticscontributionissuesclosed"></a>`issuesClosed` | [`Int`](#int) | Number of issues closed by the user. |
|
||||
| <a id="contributionanalyticscontributionissuescreated"></a>`issuesCreated` | [`Int`](#int) | Number of issues created by the user. |
|
||||
| <a id="contributionanalyticscontributionmergerequestsapproved"></a>`mergeRequestsApproved` | [`Int`](#int) | Number of merge requests approved by the user. |
|
||||
| <a id="contributionanalyticscontributionmergerequestsclosed"></a>`mergeRequestsClosed` | [`Int`](#int) | Number of merge requests closed by the user. |
|
||||
| <a id="contributionanalyticscontributionmergerequestscreated"></a>`mergeRequestsCreated` | [`Int`](#int) | Number of merge requests created by the user. |
|
||||
| <a id="contributionanalyticscontributionmergerequestsmerged"></a>`mergeRequestsMerged` | [`Int`](#int) | Number of merge requests merged by the user. |
|
||||
| <a id="contributionanalyticscontributionrepopushed"></a>`repoPushed` | [`Int`](#int) | Number of repository pushes the user made. |
|
||||
| <a id="contributionanalyticscontributiontotalevents"></a>`totalEvents` | [`Int`](#int) | Total number of events contributed by the user. |
|
||||
| <a id="contributionanalyticscontributionuser"></a>`user` | [`UserCore`](#usercore) | Contributor User object. |
|
||||
|
||||
### `CoverageFuzzingCorpus`
|
||||
|
||||
Corpus for a coverage fuzzing job.
|
||||
|
@ -13079,6 +13120,23 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| <a id="groupcontainerrepositoriesname"></a>`name` | [`String`](#string) | Filter the container repositories by their name. |
|
||||
| <a id="groupcontainerrepositoriessort"></a>`sort` | [`ContainerRepositorySort`](#containerrepositorysort) | Sort container repositories by this criteria. |
|
||||
|
||||
##### `Group.contributions`
|
||||
|
||||
Provides the aggregated contributions by users within the group and its subgroups.
|
||||
|
||||
Returns [`ContributionAnalyticsContributionConnection`](#contributionanalyticscontributionconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
###### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="groupcontributionsfrom"></a>`from` | [`ISO8601Date!`](#iso8601date) | Start date of the reporting time range. |
|
||||
| <a id="groupcontributionsto"></a>`to` | [`ISO8601Date!`](#iso8601date) | End date of the reporting time range. The end date must be within 31 days after the start date. |
|
||||
|
||||
##### `Group.descendantGroups`
|
||||
|
||||
List of descendant groups of this group.
|
||||
|
|
|
@ -58,14 +58,19 @@ All Work Item types share the same pool of predefined widgets and are customized
|
|||
|
||||
### Work Item widget types (updating)
|
||||
|
||||
- assignees
|
||||
- description
|
||||
- hierarchy
|
||||
- iteration
|
||||
- labels
|
||||
- start and due date
|
||||
- verification status
|
||||
- weight
|
||||
| widget type | feature flag |
|
||||
|---|---|---|
|
||||
| assignees | |
|
||||
| description | |
|
||||
| hierarchy | |
|
||||
| [iteration](https://gitlab.com/gitlab-org/gitlab/-/issues/367456) | work_items_mvc_2 |
|
||||
| [milestone](https://gitlab.com/gitlab-org/gitlab/-/issues/367463) | work_items_mvc_2 |
|
||||
| labels | |
|
||||
| start and due date | |
|
||||
| status\* | |
|
||||
| weight | |
|
||||
|
||||
\* status is not currently a widget, but a part of the root work item, similar to title
|
||||
|
||||
### Work Item view
|
||||
|
||||
|
@ -75,6 +80,16 @@ The new frontend view that renders Work Items of any type using global Work Item
|
|||
|
||||
Task is a special Work Item type. Tasks can be added to issues as child items and can be displayed in the modal on the issue view.
|
||||
|
||||
### Feature flags
|
||||
|
||||
Since this is a large project with numerous moving parts, feature flags are being used to track promotions of available widgets. The table below shows the different feature flags that are being used, and the audience that they are available to.
|
||||
|
||||
| feature flag name | audience |
|
||||
|---|---|
|
||||
| `work_items` | defaulted to on |
|
||||
| `work_items_mvc` | `gitlab-org`, `gitlab-com` |
|
||||
| `work_items_mvc_2` | `gitlab-org/plan-stage` |
|
||||
|
||||
## Motivation
|
||||
|
||||
Work Items main goal is to enhance the planning toolset to become the most popular collaboration tool for knowledge workers in any industry.
|
||||
|
|
|
@ -122,7 +122,7 @@ the value of the [`$CI_PIPELINE_SOURCE` predefined variable](../variables/predef
|
|||
for all jobs is:
|
||||
|
||||
- `pipeline` for multi-project pipelines.
|
||||
- `parent` for parent-child pipelines.
|
||||
- `parent_pipeline` for parent-child pipelines.
|
||||
|
||||
For example, to control jobs in multi-project pipelines in a project that also runs
|
||||
merge request pipelines:
|
||||
|
|
|
@ -392,6 +392,46 @@ time.
|
|||
1. Check the exit status of build script.
|
||||
1. Remove the build container and all created service containers.
|
||||
|
||||
## Capturing service container logs
|
||||
|
||||
Logs generated by applications running in service containers can be captured for subsequent examination and debugging.
|
||||
You might want to look at service container's logs when the service container has started successfully, but is not
|
||||
behaving es expected, leading to job failures. The logs can indicate missing or incorrect configuration of the service
|
||||
within the container.
|
||||
|
||||
`CI_DEBUG_SERVICES` should only by enabled when service containers are being actively debugged as there are both storage
|
||||
and performance consequences to capturing service container logs.
|
||||
|
||||
To enable service logging, add the `CI_DEBUG_SERVICES` variable to the project's
|
||||
`.gitlab-ci.yml` file:
|
||||
|
||||
```yaml
|
||||
variables:
|
||||
CI_DEBUG_SERVICES: "true"
|
||||
```
|
||||
|
||||
Accepted values are:
|
||||
|
||||
- Enabled: `TRUE`, `true`, `True`
|
||||
- Disabled: `FALSE`, `false`, `False`
|
||||
|
||||
Any other values will result in an error message and effectively disable the feature.
|
||||
|
||||
When enabled, logs for _all_ service containers will be captured and streamed into the jobs trace log concurrently with
|
||||
other logs. Logs from each container will be prefixed with the container's aliases, and displayed in a different color.
|
||||
|
||||
NOTE:
|
||||
You may want to adjust the logging level in the service container for which you want to capture logs since the default
|
||||
logging level may not provide sufficient details to diagnose job failures.
|
||||
|
||||
WARNING:
|
||||
Enabling `CI_DEBUG_SERVICES` _may_ result in masked variables being revealed. When `CI_DEBUG_SERVICES` is enabled,
|
||||
service container logs and the CI job's logs are streamed to the job's trace log _concurrently_, which makes it possible
|
||||
for a service container log to be inserted _inside_ a job's masked log. This would thwart the variable masking mechanism
|
||||
and result in the masked variable being revealed.
|
||||
|
||||
See [Mask a CI/CD Variable](../variables/index.md#mask-a-cicd-variable)
|
||||
|
||||
## Debug a job locally
|
||||
|
||||
The following commands are run without root privileges. You should be
|
||||
|
|
|
@ -357,15 +357,22 @@ The value of the variable must:
|
|||
- The `~` character (In [GitLab 13.12 and later](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61517)).
|
||||
- Not match the name of an existing predefined or custom CI/CD variable.
|
||||
|
||||
NOTE:
|
||||
Masking a CI/CD variable is not a guaranteed way to prevent malicious users from accessing
|
||||
variable values. To make variables more secure, you can [use external secrets](../secrets/index.md).
|
||||
|
||||
WARNING:
|
||||
Due to a technical limitation, masked variables that are more than 4 KiB in length are not recommended. Printing such
|
||||
a large value to the trace log has the potential to be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128).
|
||||
When using GitLab Runner 14.2, only the tail of the variable, characters beyond 4KiB in length, have the potential to
|
||||
be revealed.
|
||||
Masking a CI/CD variable is not a guaranteed way to prevent malicious users from
|
||||
accessing variable values. The masking feature is "best-effort" and there to
|
||||
help when a variable is accidentally revealed. To make variables more secure,
|
||||
consider using [external secrets](../secrets/index.md) and [file type variables](#cicd-variable-types)
|
||||
to prevent commands such as `env`/`printenv` from printing secret variables.
|
||||
|
||||
Runner versions implement masking in different ways, some with technical
|
||||
limitations. Below is a table of such limitations.
|
||||
|
||||
| Version from | Version to | Limitations |
|
||||
| ------------ | ---------- | ------ |
|
||||
| v0.1.0 | v11.8.0 | No masking functionality supported. |
|
||||
| v11.9.0 | v14.1.0 | Masking of large (> 4KiB) secrets could potentially be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128). No sensitive URL parameter masking. |
|
||||
| v14.2.0 | v15.3.0 | The tail of a large (> 4KiB) secret could potentially be [revealed](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/28128). No sensitive URL parameter masking. |
|
||||
| v15.7.0 | | Potential for secrets to be revealed when `CI_DEBUG_SERVICES` is enabled. For details, read about [service container logging](../services/index.md#capturing-service-container-logs). |
|
||||
|
||||
### Protected CI/CD variables
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ as it can cause the pipeline to behave unexpectedly.
|
|||
| `CI_CONCURRENT_PROJECT_ID` | all | 11.10 | The unique ID of build execution in a single executor and project. |
|
||||
| `CI_CONFIG_PATH` | 9.4 | 0.5 | The path to the CI/CD configuration file. Defaults to `.gitlab-ci.yml`. Read-only inside a running pipeline. |
|
||||
| `CI_DEBUG_TRACE` | all | 1.7 | `true` if [debug logging (tracing)](index.md#debug-logging) is enabled. |
|
||||
| `CI_DEBUG_SERVICES` | 15.7 | 15.7 | `true` if [service container logging](../services/index.md#capturing-service-container-logs) is enabled. |
|
||||
| `CI_DEFAULT_BRANCH` | 12.4 | all | The name of the project's default branch. |
|
||||
| `CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX` | 13.7 | all | The top-level group image prefix for pulling images through the Dependency Proxy. |
|
||||
| `CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX` | 14.3 | all | The direct group image prefix for pulling images through the Dependency Proxy. |
|
||||
|
|
|
@ -357,13 +357,13 @@ a merge request or an issue.
|
|||
The following table lists all GitLab-specific email headers:
|
||||
|
||||
| Header | Description |
|
||||
|---------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| ------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `List-Id` | The path of the project in an RFC 2919 mailing list identifier. You can use it for email organization with filters. |
|
||||
| `X-GitLab-(Resource)-ID` | The ID of the resource the notification is for. The resource, for example, can be `Issue`, `MergeRequest`, `Commit`, or another such resource. |
|
||||
| `X-GitLab-Discussion-ID` | The ID of the thread the comment belongs to, in notification emails for comments. |
|
||||
| `X-GitLab-Group-Id` | The group's ID. Only present on notification emails for [epics](../group/epics/index.md). |
|
||||
| `X-GitLab-Group-Path` | The group's path. Only present on notification emails for [epics](../group/epics/index.md) |
|
||||
| [`X-GitLab-NotificationReason`](#x-gitlab-notificationreason) | The reason for the notification. This can be `mentioned`, `assigned`, or `own_activity`. |
|
||||
| `X-GitLab-NotificationReason` | The reason for the notification. [See possible values.](#x-gitlab-notificationreason). |
|
||||
| `X-GitLab-Pipeline-Id` | The ID of the pipeline the notification is for, in notification emails for pipelines. |
|
||||
| `X-GitLab-Project-Id` | The project's ID. |
|
||||
| `X-GitLab-Project-Path` | The project's path. |
|
||||
|
@ -377,21 +377,35 @@ The value is one of the following, in order of priority:
|
|||
|
||||
- `own_activity`
|
||||
- `assigned`
|
||||
- `review_requested`
|
||||
- `mentioned`
|
||||
- `subscribed`
|
||||
|
||||
The reason for the notification is also included in the footer of the notification email.
|
||||
For example, an email with the reason `assigned` has this sentence in the footer:
|
||||
|
||||
> You are receiving this email because you have been assigned an item on \<configured GitLab hostname>.
|
||||
|
||||
For example, an alert notification email can have one of
|
||||
[the alert's](../../operations/incident_management/alerts.md) statuses:
|
||||
#### On-call alerts notifications **(PREMIUM)**
|
||||
|
||||
An [on-call alert](../../operations/incident_management/oncall_schedules.md)
|
||||
notification email can have one of [the alert's](../../operations/incident_management/alerts.md) statuses:
|
||||
|
||||
- `alert_triggered`
|
||||
- `alert_acknowledged`
|
||||
- `alert_resolved`
|
||||
- `alert_ignored`
|
||||
|
||||
#### Incident escalation notifications **(PREMIUM)**
|
||||
|
||||
An [incident escalation](../../operations/incident_management/escalation_policies.md)
|
||||
notification email can have one of [the incident's](../../operations/incident_management/incidents.md) status:
|
||||
|
||||
- `incident_triggered`
|
||||
- `incident_acknowledged`
|
||||
- `incident_resolved`
|
||||
- `incident_ignored`
|
||||
|
||||
Expanding the list of events included in the `X-GitLab-NotificationReason` header is tracked in
|
||||
[issue 20689](https://gitlab.com/gitlab-org/gitlab/-/issues/20689).
|
||||
|
||||
|
|
|
@ -193,6 +193,7 @@ module API
|
|||
mount ::API::Metadata
|
||||
mount ::API::MergeRequestDiffs
|
||||
mount ::API::PersonalAccessTokens::SelfInformation
|
||||
mount ::API::ProjectExport
|
||||
mount ::API::ProjectHooks
|
||||
mount ::API::ProjectRepositoryStorageMoves
|
||||
mount ::API::Releases
|
||||
|
@ -205,6 +206,7 @@ module API
|
|||
mount ::API::Statistics
|
||||
mount ::API::Submodules
|
||||
mount ::API::Suggestions
|
||||
mount ::API::SystemHooks
|
||||
mount ::API::Tags
|
||||
mount ::API::Unleash
|
||||
mount ::API::UserCounts
|
||||
|
@ -293,7 +295,6 @@ module API
|
|||
mount ::API::ProjectContainerRepositories
|
||||
mount ::API::ProjectDebianDistributions
|
||||
mount ::API::ProjectEvents
|
||||
mount ::API::ProjectExport
|
||||
mount ::API::ProjectImport
|
||||
mount ::API::ProjectMilestones
|
||||
mount ::API::ProjectPackages
|
||||
|
@ -315,7 +316,6 @@ module API
|
|||
mount ::API::SidekiqMetrics
|
||||
mount ::API::Snippets
|
||||
mount ::API::Subscriptions
|
||||
mount ::API::SystemHooks
|
||||
mount ::API::Tags
|
||||
mount ::API::Templates
|
||||
mount ::API::Terraform::Modules::V1::Packages
|
||||
|
|
|
@ -244,6 +244,8 @@ module API
|
|||
# current_authenticated_job will be nil if user is using
|
||||
# a valid authentication (like PRIVATE-TOKEN) that is not CI_JOB_TOKEN
|
||||
not_found!('Job') unless current_authenticated_job
|
||||
|
||||
::Gitlab::ApplicationContext.push(job: current_authenticated_job)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,10 +4,10 @@ module API
|
|||
module Entities
|
||||
module BulkImports
|
||||
class ExportStatus < Grape::Entity
|
||||
expose :relation
|
||||
expose :status
|
||||
expose :error
|
||||
expose :updated_at
|
||||
expose :relation, documentation: { type: 'string', example: 'issues' }
|
||||
expose :status, documentation: { type: 'string', example: 'started', values: %w[started finished failed] }
|
||||
expose :error, documentation: { type: 'string', example: 'Error message' }
|
||||
expose :updated_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,12 +3,18 @@
|
|||
module API
|
||||
module Entities
|
||||
class Hook < Grape::Entity
|
||||
expose :id, :url, :created_at, :push_events, :tag_push_events, :merge_requests_events, :repository_update_events
|
||||
expose :enable_ssl_verification
|
||||
expose :id, documentation: { type: 'string', example: 1 }
|
||||
expose :url, documentation: { type: 'string', example: 'https://webhook.site' }
|
||||
expose :created_at, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
|
||||
expose :push_events, documentation: { type: 'boolean' }
|
||||
expose :tag_push_events, documentation: { type: 'boolean' }
|
||||
expose :merge_requests_events, documentation: { type: 'boolean' }
|
||||
expose :repository_update_events, documentation: { type: 'boolean' }
|
||||
expose :enable_ssl_verification, documentation: { type: 'boolean' }
|
||||
|
||||
expose :alert_status
|
||||
expose :disabled_until
|
||||
expose :url_variables
|
||||
expose :alert_status, documentation: { type: 'symbol', example: :executable }
|
||||
expose :disabled_until, documentation: { type: 'dateTime', example: '2012-05-28T04:42:42-07:00' }
|
||||
expose :url_variables, documentation: { type: 'Hash', example: { "token" => "secr3t" }, is_array: true }
|
||||
|
||||
def url_variables
|
||||
object.url_variables.keys.map { { key: _1 } }
|
||||
|
|
|
@ -5,13 +5,21 @@ module API
|
|||
class ProjectExportStatus < ProjectIdentity
|
||||
include ::API::Helpers::RelatedResourcesHelpers
|
||||
|
||||
expose :export_status
|
||||
expose :export_status, documentation: {
|
||||
type: 'string', example: 'finished', values: %w[queued started finished failed]
|
||||
}
|
||||
expose :_links, if: lambda { |project, _options| project.export_status == :finished } do
|
||||
expose :api_url do |project|
|
||||
expose :api_url, documentation: {
|
||||
type: 'string',
|
||||
example: 'https://gitlab.example.com/api/v4/projects/1/export/download'
|
||||
} do |project|
|
||||
expose_url(api_v4_projects_export_download_path(id: project.id))
|
||||
end
|
||||
|
||||
expose :web_url do |project|
|
||||
expose :web_url, documentation: {
|
||||
type: 'string',
|
||||
example: 'https://gitlab.example.com/gitlab-org/gitlab-test/download_export'
|
||||
} do |project|
|
||||
Gitlab::Routing.url_helpers.download_export_project_url(project)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,7 +16,14 @@ module API
|
|||
resource :projects, requirements: { id: %r{[^/]+} } do
|
||||
desc 'Get export status' do
|
||||
detail 'This feature was introduced in GitLab 10.6.'
|
||||
success Entities::ProjectExportStatus
|
||||
success code: 200, model: Entities::ProjectExportStatus
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
end
|
||||
get ':id/export' do
|
||||
present user_project, with: Entities::ProjectExportStatus
|
||||
|
@ -24,6 +31,15 @@ module API
|
|||
|
||||
desc 'Download export' do
|
||||
detail 'This feature was introduced in GitLab 10.6.'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
produces %w[application/octet-stream application/json]
|
||||
end
|
||||
get ':id/export/download' do
|
||||
check_rate_limit! :project_download_export, scope: [current_user, user_project.namespace]
|
||||
|
@ -41,6 +57,16 @@ module API
|
|||
|
||||
desc 'Start export' do
|
||||
detail 'This feature was introduced in GitLab 10.6.'
|
||||
success code: 202
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 429, message: 'Too many requests' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
end
|
||||
params do
|
||||
optional :description, type: String, desc: 'Override the project description'
|
||||
|
@ -86,6 +112,15 @@ module API
|
|||
|
||||
desc 'Start relations export' do
|
||||
detail 'This feature was introduced in GitLab 14.4'
|
||||
success code: 202
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
end
|
||||
post ':id/export_relations' do
|
||||
response = ::BulkImports::ExportService.new(portable: user_project, user: current_user).execute
|
||||
|
@ -93,12 +128,23 @@ module API
|
|||
if response.success?
|
||||
accepted!
|
||||
else
|
||||
render_api_error!(message: 'Project relations export could not be started.')
|
||||
render_api_error!('Project relations export could not be started.', 500)
|
||||
end
|
||||
end
|
||||
|
||||
desc 'Download relations export' do
|
||||
detail 'This feature was introduced in GitLab 14.4'
|
||||
success code: 200
|
||||
failure [
|
||||
{ code: 400, message: 'Bad request' },
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 500, message: 'Internal Server Error' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
produces %w[application/octet-stream application/json]
|
||||
end
|
||||
params do
|
||||
requires :relation,
|
||||
|
@ -119,6 +165,15 @@ module API
|
|||
|
||||
desc 'Relations export status' do
|
||||
detail 'This feature was introduced in GitLab 14.4'
|
||||
is_array true
|
||||
success code: 200, model: Entities::BulkImports::ExportStatus
|
||||
failure [
|
||||
{ code: 401, message: 'Unauthorized' },
|
||||
{ code: 403, message: 'Forbidden' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 503, message: 'Service unavailable' }
|
||||
]
|
||||
tags ['project_export']
|
||||
end
|
||||
get ':id/export_relations/status' do
|
||||
present user_project.bulk_import_exports, with: Entities::BulkImports::ExportStatus
|
||||
|
|
|
@ -4,6 +4,8 @@ module API
|
|||
class SystemHooks < ::API::Base
|
||||
include PaginationParams
|
||||
|
||||
system_hooks_tags = %w[system_hooks]
|
||||
|
||||
feature_category :integrations
|
||||
|
||||
before do
|
||||
|
@ -19,12 +21,13 @@ module API
|
|||
end
|
||||
|
||||
params :hook_parameters do
|
||||
optional :token, type: String, desc: 'The token used to validate payloads'
|
||||
optional :push_events, type: Boolean, desc: "Trigger hook on push events"
|
||||
optional :tag_push_events, type: Boolean, desc: "Trigger hook on tag push events"
|
||||
optional :merge_requests_events, type: Boolean, desc: "Trigger hook on tag push events"
|
||||
optional :repository_update_events, type: Boolean, desc: "Trigger hook on repository update events"
|
||||
optional :enable_ssl_verification, type: Boolean, desc: "Do SSL verification when triggering the hook"
|
||||
optional :token, type: String,
|
||||
desc: "Secret token to validate received payloads; this isn't returned in the response"
|
||||
optional :push_events, type: Boolean, desc: 'When true, the hook fires on push events'
|
||||
optional :tag_push_events, type: Boolean, desc: 'When true, the hook fires on new tags being pushed'
|
||||
optional :merge_requests_events, type: Boolean, desc: 'Trigger hook on merge requests events'
|
||||
optional :repository_update_events, type: Boolean, desc: 'Trigger hook on repository update events'
|
||||
optional :enable_ssl_verification, type: Boolean, desc: 'Do SSL verification when triggering the hook'
|
||||
use :url_variables
|
||||
end
|
||||
end
|
||||
|
@ -32,8 +35,11 @@ module API
|
|||
resource :hooks do
|
||||
mount ::API::Hooks::UrlVariables
|
||||
|
||||
desc 'Get the list of system hooks' do
|
||||
desc 'List system hooks' do
|
||||
detail 'Get a list of all system hooks'
|
||||
success Entities::Hook
|
||||
is_array true
|
||||
tags system_hooks_tags
|
||||
end
|
||||
params do
|
||||
use :pagination
|
||||
|
@ -42,8 +48,13 @@ module API
|
|||
present paginate(SystemHook.all), with: Entities::Hook
|
||||
end
|
||||
|
||||
desc 'Get a hook' do
|
||||
desc 'Get system hook' do
|
||||
detail 'Get a system hook by its ID. Introduced in GitLab 14.9.'
|
||||
success Entities::Hook
|
||||
failure [
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags system_hooks_tags
|
||||
end
|
||||
params do
|
||||
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
|
||||
|
@ -52,8 +63,15 @@ module API
|
|||
present find_hook, with: Entities::Hook
|
||||
end
|
||||
|
||||
desc 'Create a new system hook' do
|
||||
desc 'Add new system hook' do
|
||||
detail 'Add a new system hook'
|
||||
success Entities::Hook
|
||||
failure [
|
||||
{ code: 400, message: 'Validation error' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 422, message: 'Unprocessable entity' }
|
||||
]
|
||||
tags system_hooks_tags
|
||||
end
|
||||
params do
|
||||
use :requires_url
|
||||
|
@ -66,11 +84,18 @@ module API
|
|||
save_hook(hook, Entities::Hook)
|
||||
end
|
||||
|
||||
desc 'Update an existing system hook' do
|
||||
desc 'Edit system hook' do
|
||||
detail 'Edits a system hook'
|
||||
success Entities::Hook
|
||||
failure [
|
||||
{ code: 400, message: 'Validation error' },
|
||||
{ code: 404, message: 'Not found' },
|
||||
{ code: 422, message: 'Unprocessable entity' }
|
||||
]
|
||||
tags system_hooks_tags
|
||||
end
|
||||
params do
|
||||
requires :hook_id, type: Integer, desc: "The ID of the hook to update"
|
||||
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
|
||||
use :optional_url
|
||||
use :hook_parameters
|
||||
end
|
||||
|
@ -90,8 +115,13 @@ module API
|
|||
kind: 'system_hooks'
|
||||
}
|
||||
|
||||
desc 'Delete a hook' do
|
||||
desc 'Delete system hook' do
|
||||
detail 'Deletes a system hook'
|
||||
success Entities::Hook
|
||||
failure [
|
||||
{ code: 404, message: 'Not found' }
|
||||
]
|
||||
tags system_hooks_tags
|
||||
end
|
||||
params do
|
||||
requires :hook_id, type: Integer, desc: 'The ID of the system hook'
|
||||
|
|
|
@ -12,6 +12,7 @@ stages:
|
|||
- test
|
||||
- build
|
||||
- deploy
|
||||
- cleanup
|
||||
|
||||
fmt:
|
||||
extends: .terraform:fmt
|
||||
|
|
|
@ -12,6 +12,7 @@ stages:
|
|||
- test
|
||||
- build
|
||||
- deploy
|
||||
- cleanup
|
||||
|
||||
fmt:
|
||||
extends: .terraform:fmt
|
||||
|
|
|
@ -10782,6 +10782,12 @@ msgstr ""
|
|||
msgid "ContributionAnalytics|No pushes for the selected time period."
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|The given date range is larger than 31 days"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|The to date is earlier than the given from date"
|
||||
msgstr ""
|
||||
|
||||
msgid "ContributionAnalytics|There is too much data to calculate. Try lowering the period_limit setting in the insights configuration file."
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
import { GlKeysetPagination } from '@gitlab/ui';
|
||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||
import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
|
||||
import PackagesListLoader from '~/packages_and_registries/shared/components/packages_list_loader.vue';
|
||||
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||
import { packageData } from '../../mock_data';
|
||||
|
||||
describe('PackageVersionsList', () => {
|
||||
let wrapper;
|
||||
|
||||
const EmptySlotStub = { name: 'empty-slot-stub', template: '<div>empty message</div>' };
|
||||
const packageList = [
|
||||
packageData({
|
||||
name: 'version 1',
|
||||
}),
|
||||
packageData({
|
||||
id: `gid://gitlab/Packages::Package/112`,
|
||||
name: 'version 2',
|
||||
}),
|
||||
];
|
||||
|
||||
const uiElements = {
|
||||
findLoader: () => wrapper.findComponent(PackagesListLoader),
|
||||
findListPagination: () => wrapper.findComponent(GlKeysetPagination),
|
||||
findEmptySlot: () => wrapper.findComponent(EmptySlotStub),
|
||||
findListRow: () => wrapper.findAllComponents(VersionRow),
|
||||
};
|
||||
const mountComponent = (props) => {
|
||||
wrapper = shallowMountExtended(PackageVersionsList, {
|
||||
propsData: {
|
||||
versions: packageList,
|
||||
pageInfo: {},
|
||||
isLoading: false,
|
||||
...props,
|
||||
},
|
||||
slots: {
|
||||
'empty-state': EmptySlotStub,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
describe('when list is loading', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ isLoading: true, versions: [] });
|
||||
});
|
||||
it('displays loader', () => {
|
||||
expect(uiElements.findLoader().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not display rows', () => {
|
||||
expect(uiElements.findListRow().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display empty slot message', () => {
|
||||
expect(uiElements.findEmptySlot().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display pagination', () => {
|
||||
expect(uiElements.findListPagination().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when list is loaded and has no data', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ isLoading: false, versions: [] });
|
||||
});
|
||||
|
||||
it('displays empty slot message', () => {
|
||||
expect(uiElements.findEmptySlot().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('does not display loader', () => {
|
||||
expect(uiElements.findLoader().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display rows', () => {
|
||||
expect(uiElements.findListRow().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display pagination', () => {
|
||||
expect(uiElements.findListPagination().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when list is loaded with data', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent();
|
||||
});
|
||||
|
||||
it('displays package version rows', () => {
|
||||
expect(uiElements.findListRow().exists()).toEqual(true);
|
||||
expect(uiElements.findListRow()).toHaveLength(packageList.length);
|
||||
});
|
||||
|
||||
it('binds the correct props', () => {
|
||||
expect(uiElements.findListRow().at(0).props()).toMatchObject({
|
||||
packageEntity: expect.objectContaining(packageList[0]),
|
||||
});
|
||||
|
||||
expect(uiElements.findListRow().at(1).props()).toMatchObject({
|
||||
packageEntity: expect.objectContaining(packageList[1]),
|
||||
});
|
||||
});
|
||||
|
||||
describe('pagination display', () => {
|
||||
it('does not display pagination if there is no previous or next page', () => {
|
||||
expect(uiElements.findListPagination().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('displays pagination if pageInfo.hasNextPage is true', async () => {
|
||||
await wrapper.setProps({ pageInfo: { hasNextPage: true } });
|
||||
expect(uiElements.findListPagination().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays pagination if pageInfo.hasPreviousPage is true', async () => {
|
||||
await wrapper.setProps({ pageInfo: { hasPreviousPage: true } });
|
||||
expect(uiElements.findListPagination().exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('displays pagination if both pageInfo.hasNextPage and pageInfo.hasPreviousPage are true', async () => {
|
||||
await wrapper.setProps({ pageInfo: { hasNextPage: true, hasPreviousPage: true } });
|
||||
expect(uiElements.findListPagination().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('does not display loader', () => {
|
||||
expect(uiElements.findLoader().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('does not display empty slot message', () => {
|
||||
expect(uiElements.findEmptySlot().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('when user interacts with pagination', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({ pageInfo: { hasNextPage: true } });
|
||||
});
|
||||
|
||||
it('emits prev-page event when paginator emits prev event', () => {
|
||||
uiElements.findListPagination().vm.$emit('prev');
|
||||
|
||||
expect(wrapper.emitted('prev-page')).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('emits next-page when paginator emits next event', () => {
|
||||
uiElements.findListPagination().vm.$emit('next');
|
||||
|
||||
expect(wrapper.emitted('next-page')).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -233,6 +233,12 @@ export const packageDetailsQuery = (extendPackage) => ({
|
|||
},
|
||||
versions: {
|
||||
nodes: packageVersions(),
|
||||
pageInfo: {
|
||||
hasNextPage: true,
|
||||
hasPreviousPage: false,
|
||||
endCursor: 'endCursor',
|
||||
startCursor: 'startCursor',
|
||||
},
|
||||
__typename: 'PackageConnection',
|
||||
},
|
||||
dependencyLinks: {
|
||||
|
|
|
@ -15,8 +15,8 @@ import InstallationCommands from '~/packages_and_registries/package_registry/com
|
|||
import PackageFiles from '~/packages_and_registries/package_registry/components/details/package_files.vue';
|
||||
import PackageHistory from '~/packages_and_registries/package_registry/components/details/package_history.vue';
|
||||
import PackageTitle from '~/packages_and_registries/package_registry/components/details/package_title.vue';
|
||||
import VersionRow from '~/packages_and_registries/package_registry/components/details/version_row.vue';
|
||||
import DeletePackage from '~/packages_and_registries/package_registry/components/functional/delete_package.vue';
|
||||
import PackageVersionsList from '~/packages_and_registries/package_registry/components/details/package_versions_list.vue';
|
||||
import {
|
||||
FETCH_PACKAGE_DETAILS_ERROR_MESSAGE,
|
||||
PACKAGE_TYPE_COMPOSER,
|
||||
|
@ -99,6 +99,7 @@ describe('PackagesApp', () => {
|
|||
GlSprintf,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
PackageVersionsList,
|
||||
},
|
||||
mocks: {
|
||||
$route: {
|
||||
|
@ -120,8 +121,7 @@ describe('PackagesApp', () => {
|
|||
const findPackageFiles = () => wrapper.findComponent(PackageFiles);
|
||||
const findDeleteFileModal = () => wrapper.findByTestId('delete-file-modal');
|
||||
const findDeleteFilesModal = () => wrapper.findByTestId('delete-files-modal');
|
||||
const findVersionRows = () => wrapper.findAllComponents(VersionRow);
|
||||
const noVersionsMessage = () => wrapper.findByTestId('no-versions-message');
|
||||
const findVersionsList = () => wrapper.findComponent(PackageVersionsList);
|
||||
const findDependenciesCountBadge = () => wrapper.findComponent(GlBadge);
|
||||
const findNoDependenciesMessage = () => wrapper.findByTestId('no-dependencies-message');
|
||||
const findDependencyRows = () => wrapper.findAllComponents(DependencyRow);
|
||||
|
@ -558,38 +558,23 @@ describe('PackagesApp', () => {
|
|||
});
|
||||
|
||||
describe('versions', () => {
|
||||
it('displays the correct version count when the package has versions', async () => {
|
||||
it('displays versions list when the package has versions', async () => {
|
||||
createComponent();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(findVersionRows()).toHaveLength(packageVersions().length);
|
||||
expect(findVersionsList()).toBeDefined();
|
||||
});
|
||||
|
||||
it('binds the correct props', async () => {
|
||||
const [versionPackage] = packageVersions();
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
delete versionPackage.__typename;
|
||||
delete versionPackage.tags;
|
||||
|
||||
createComponent();
|
||||
|
||||
const versionNodes = packageVersions();
|
||||
createComponent({ packageEntity: { versions: { nodes: versionNodes } } });
|
||||
await waitForPromises();
|
||||
|
||||
expect(findVersionRows().at(0).props()).toMatchObject({
|
||||
packageEntity: expect.objectContaining(versionPackage),
|
||||
expect(findVersionsList().props()).toMatchObject({
|
||||
versions: expect.arrayContaining(versionNodes),
|
||||
});
|
||||
});
|
||||
|
||||
it('displays the no versions message when there are none', async () => {
|
||||
createComponent({
|
||||
resolver: jest.fn().mockResolvedValue(packageDetailsQuery({ versions: { nodes: [] } })),
|
||||
});
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(noVersionsMessage().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
describe('dependency links', () => {
|
||||
it('does not show the dependency links for a non nuget package', async () => {
|
||||
|
|
|
@ -539,4 +539,42 @@ RSpec.describe DiffHelper do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#show_only_context_commits?' do
|
||||
let(:params) { {} }
|
||||
let(:merge_request) { build_stubbed(:merge_request) }
|
||||
let(:has_no_commits) { true }
|
||||
|
||||
subject(:result) { helper.show_only_context_commits? }
|
||||
|
||||
before do
|
||||
assign(:merge_request, merge_request)
|
||||
allow(helper).to receive(:params).and_return(params)
|
||||
allow(merge_request).to receive(:has_no_commits?).and_return(has_no_commits)
|
||||
end
|
||||
|
||||
context 'when only_context_commits param is set to true' do
|
||||
let(:params) { { only_context_commits: true } }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
|
||||
context 'when merge request has commits' do
|
||||
let(:has_no_commits) { false }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when only_context_commits param is set to false' do
|
||||
let(:params) { { only_context_commits: false } }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
|
||||
context 'when merge request has commits' do
|
||||
let(:has_no_commits) { false }
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -78,7 +78,6 @@ require_relative '../tooling/quality/test_level'
|
|||
quality_level = Quality::TestLevel.new
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.threadsafe = false
|
||||
config.use_transactional_fixtures = true
|
||||
config.use_instantiated_fixtures = false
|
||||
config.fixture_path = Rails.root
|
||||
|
|
|
@ -11,6 +11,9 @@ require_relative "helpers/fast_rails_root"
|
|||
RSpec::Expectations.configuration.on_potential_false_positives = :raise
|
||||
|
||||
RSpec.configure do |config|
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/379686
|
||||
config.threadsafe = false
|
||||
|
||||
# Re-run failures locally with `--only-failures`
|
||||
config.example_status_persistence_file_path = ENV.fetch('RSPEC_LAST_RUN_RESULTS_FILE', './spec/examples.txt')
|
||||
|
||||
|
|
Loading…
Reference in a new issue