Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
0eea37aefa
commit
d0bb0e04f4
|
@ -44,7 +44,7 @@ docs-lint markdown:
|
||||||
- .default-retry
|
- .default-retry
|
||||||
- .docs:rules:docs-lint
|
- .docs:rules:docs-lint
|
||||||
# When updating the image version here, update it in /scripts/lint-doc.sh too.
|
# When updating the image version here, update it in /scripts/lint-doc.sh too.
|
||||||
image: registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.15-vale-2.15.5-markdownlint-0.31.1
|
image: registry.gitlab.com/gitlab-org/gitlab-docs/lint-markdown:alpine-3.15-vale-2.16.1-markdownlint-0.31.1
|
||||||
stage: lint
|
stage: lint
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
|
@ -53,7 +53,7 @@ docs-lint markdown:
|
||||||
docs-lint links:
|
docs-lint links:
|
||||||
extends:
|
extends:
|
||||||
- .docs:rules:docs-lint
|
- .docs:rules:docs-lint
|
||||||
image: registry.gitlab.com/gitlab-org/gitlab-docs/lint-html:alpine-3.15-ruby-2.7.5-cee62c13
|
image: registry.gitlab.com/gitlab-org/gitlab-docs/lint-html:alpine-3.15-ruby-2.7.5-e6a8a48a
|
||||||
stage: lint
|
stage: lint
|
||||||
needs: []
|
needs: []
|
||||||
script:
|
script:
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { DynamicScroller, DynamicScrollerItem } from 'vendor/vue-virtual-scrolle
|
||||||
import api from '~/api';
|
import api from '~/api';
|
||||||
import { sprintf, s__, __ } from '~/locale';
|
import { sprintf, s__, __ } from '~/locale';
|
||||||
import Poll from '~/lib/utils/poll';
|
import Poll from '~/lib/utils/poll';
|
||||||
|
import { normalizeHeaders } from '~/lib/utils/common_utils';
|
||||||
import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants';
|
import { EXTENSION_ICON_CLASS, EXTENSION_ICONS } from '../../constants';
|
||||||
import StatusIcon from './status_icon.vue';
|
import StatusIcon from './status_icon.vue';
|
||||||
import Actions from './actions.vue';
|
import Actions from './actions.vue';
|
||||||
|
@ -147,6 +148,35 @@ export default {
|
||||||
this.triggerRedisTracking();
|
this.triggerRedisTracking();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
initExtensionMultiPolling() {
|
||||||
|
const allData = [];
|
||||||
|
const requests = this.fetchMultiData();
|
||||||
|
|
||||||
|
requests.forEach((request) => {
|
||||||
|
const poll = new Poll({
|
||||||
|
resource: {
|
||||||
|
fetchData: () => request(this.$props),
|
||||||
|
},
|
||||||
|
method: 'fetchData',
|
||||||
|
successCallback: (response) => {
|
||||||
|
const headers = normalizeHeaders(response.headers);
|
||||||
|
|
||||||
|
if (!headers['POLL-INTERVAL']) {
|
||||||
|
allData.push(response.data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allData.length === requests.length) {
|
||||||
|
this.setCollapsedData(allData);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
errorCallback: (e) => {
|
||||||
|
this.setCollapsedError(e);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
poll.makeRequest();
|
||||||
|
});
|
||||||
|
},
|
||||||
initExtensionPolling() {
|
initExtensionPolling() {
|
||||||
const poll = new Poll({
|
const poll = new Poll({
|
||||||
resource: {
|
resource: {
|
||||||
|
@ -172,7 +202,11 @@ export default {
|
||||||
this.loadingState = LOADING_STATES.collapsedLoading;
|
this.loadingState = LOADING_STATES.collapsedLoading;
|
||||||
|
|
||||||
if (this.$options.enablePolling) {
|
if (this.$options.enablePolling) {
|
||||||
this.initExtensionPolling();
|
if (this.fetchMultiData) {
|
||||||
|
this.initExtensionMultiPolling();
|
||||||
|
} else {
|
||||||
|
this.initExtensionPolling();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.fetchCollapsedData(this.$props)
|
this.fetchCollapsedData(this.$props)
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
|
|
@ -98,13 +98,15 @@ export default {
|
||||||
<span v-else-if="isConfidential" ref="confidential">
|
<span v-else-if="isConfidential" ref="confidential">
|
||||||
{{ confidentialContextText }}
|
{{ confidentialContextText }}
|
||||||
{{ __('People without permission will never get a notification.') }}
|
{{ __('People without permission will never get a notification.') }}
|
||||||
<gl-link :href="confidentialNoteableDocsPath" target="_blank">{{ __('Learn more') }}</gl-link>
|
<gl-link :href="confidentialNoteableDocsPath" target="_blank">{{
|
||||||
|
__('Learn more.')
|
||||||
|
}}</gl-link>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span v-else-if="isLocked" ref="locked">
|
<span v-else-if="isLocked" ref="locked">
|
||||||
{{ lockedContextText }}
|
{{ lockedContextText }}
|
||||||
{{ __('Only project members can comment.') }}
|
{{ __('Only project members can comment.') }}
|
||||||
<gl-link :href="lockedNoteableDocsPath" target="_blank">{{ __('Learn more') }}</gl-link>
|
<gl-link :href="lockedNoteableDocsPath" target="_blank">{{ __('Learn more.') }}</gl-link>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -106,15 +106,15 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-blue {
|
@mixin btn-blue {
|
||||||
@include btn-color($blue-500, $blue-600, $blue-600, $blue-700, $blue-700, $blue-800, $white);
|
@include btn-color($blue-500, $blue-600, $blue-600, $blue-700, $blue-700, $blue-800, $white-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-orange {
|
@mixin btn-orange {
|
||||||
@include btn-color($orange-500, $orange-600, $orange-500, $orange-600, $orange-600, $orange-800, $white);
|
@include btn-color($orange-500, $orange-600, $orange-500, $orange-600, $orange-600, $orange-800, $white-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-red {
|
@mixin btn-red {
|
||||||
@include btn-color($red-500, $red-600, $red-600, $red-700, $red-700, $red-800, $white);
|
@include btn-color($red-500, $red-600, $red-600, $red-700, $red-700, $red-800, $white-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-white {
|
@mixin btn-white {
|
||||||
|
@ -122,7 +122,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-purple {
|
@mixin btn-purple {
|
||||||
@include btn-color($purple-700, $purple-800, $purple-800, $purple-900, $purple-900, $purple-950, $white);
|
@include btn-color($purple-700, $purple-800, $purple-800, $purple-900, $purple-900, $purple-950, $white-contrast);
|
||||||
}
|
}
|
||||||
|
|
||||||
@mixin btn-with-margin {
|
@mixin btn-with-margin {
|
||||||
|
@ -417,16 +417,6 @@ fieldset[disabled] .btn,
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This class helps convert `.gl-button` children so that they consistently
|
|
||||||
// match the style of `.btn` elements which might be around them. Ideally we
|
|
||||||
// wouldn't need this class.
|
|
||||||
//
|
|
||||||
// Remove by upgrading all buttons in a container to use the new `.gl-button` style.
|
|
||||||
.gl-button-deprecated-adapter .gl-button {
|
|
||||||
box-shadow: none;
|
|
||||||
border-width: 1px;
|
|
||||||
}
|
|
||||||
|
|
||||||
copy-code {
|
copy-code {
|
||||||
@include gl-absolute;
|
@include gl-absolute;
|
||||||
@include gl-transition-medium;
|
@include gl-transition-medium;
|
||||||
|
|
|
@ -78,12 +78,15 @@ module Boards
|
||||||
end
|
end
|
||||||
|
|
||||||
def list
|
def list
|
||||||
return unless params.key?(:id)
|
return unless params.key?(:id) || params.key?(:list)
|
||||||
|
|
||||||
strong_memoize(:list) do
|
strong_memoize(:list) do
|
||||||
id = params[:id]
|
id = params[:id]
|
||||||
|
list = params[:list]
|
||||||
|
|
||||||
if board.lists.loaded?
|
if list.present?
|
||||||
|
list
|
||||||
|
elsif board.lists.loaded?
|
||||||
board.lists.find { |l| l.id == id }
|
board.lists.find { |l| l.id == id }
|
||||||
else
|
else
|
||||||
board.lists.find(id)
|
board.lists.find(id)
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
stage: create
|
stage: create
|
||||||
reporter: phikai
|
reporter: phikai
|
||||||
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||||
issue_url: # (optional) This is a link to the deprecation issue in GitLab
|
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345451 # (optional) This is a link to the deprecation issue in GitLab
|
||||||
documentation_url: # (optional) This is a link to the current documentation page
|
documentation_url: https://docs.gitlab.com/ee/api/graphql/removed_items.html#graphql-types # (optional) This is a link to the current documentation page
|
||||||
image_url: # (optional) This is a link to a thumbnail image depicting the feature
|
image_url: # (optional) This is a link to a thumbnail image depicting the feature
|
||||||
video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
|
video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
- name: "`defaultMergeCommitMessageWithDescription` GraphQL API field"
|
||||||
|
announcement_milestone: "14.5" # The milestone when this feature was first announced as deprecated.
|
||||||
|
announcement_date: "2021-11-22" # The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
|
||||||
|
removal_milestone: "15.0" # The milestone when this feature is planned to be removed
|
||||||
|
removal_date: "2022-05-22" # the date of the milestone release when this feature is planned to be removed
|
||||||
|
breaking_change: true # (required) Change to true if this removal is a breaking change.
|
||||||
|
reporter: phikai # (required) GitLab username of the person reporting the removal
|
||||||
|
stage: create # (required) String value of the stage that the feature was created in. e.g., Growth
|
||||||
|
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/345451 # (required) Link to the deprecation issue in GitLab
|
||||||
|
body: | # (required) Do not modify this line, instead modify the lines below.
|
||||||
|
The GraphQL API field `defaultMergeCommitMessageWithDescription` has been removed in GitLab 15.0. For projects with a commit message template set, it will ignore the template.
|
||||||
|
# The following items are not published on the docs page, but may be used in the future.
|
||||||
|
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
|
||||||
|
documentation_url: https://docs.gitlab.com/ee/api/graphql/removed_items.html#graphql-types # (optional) This is a link to the current documentation page
|
||||||
|
image_url: # (optional) This is a link to a thumbnail image depicting the feature
|
||||||
|
video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg
|
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class SchedulePurgingStaleSecurityScans < Gitlab::Database::Migration[2.0]
|
||||||
|
MIGRATION = 'PurgeStaleSecurityScans'
|
||||||
|
BATCH_SIZE = 10_000
|
||||||
|
DELAY_INTERVAL = 2.minutes
|
||||||
|
|
||||||
|
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
return unless should_run?
|
||||||
|
|
||||||
|
queue_background_migration_jobs_by_range_at_intervals(
|
||||||
|
Gitlab::BackgroundMigration::PurgeStaleSecurityScans::SecurityScan.to_purge,
|
||||||
|
MIGRATION,
|
||||||
|
DELAY_INTERVAL,
|
||||||
|
batch_size: BATCH_SIZE,
|
||||||
|
track_jobs: true
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# no-op
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def should_run?
|
||||||
|
Gitlab.dev_or_test_env? || Gitlab.com?
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1 @@
|
||||||
|
dabbd8b95ec49b4267d53768013b4e62ae1219a4575dc8b0fccb0e117e725885
|
|
@ -3,52 +3,11 @@ stage: Manage
|
||||||
group: Optimize
|
group: Optimize
|
||||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||||
type: reference, api
|
type: reference, api
|
||||||
|
remove_date: '2022-05-18'
|
||||||
|
redirect_to: 'dora/metrics.md'
|
||||||
---
|
---
|
||||||
|
|
||||||
# DORA4 Analytics Project API **(ULTIMATE)**
|
# DORA4 Analytics Project API (removed) **(ULTIMATE)**
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/279039) in GitLab 13.7.
|
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
These endpoints have been removed in GitLab 14.0. Use the [DORA metrics API](dora/metrics.md) instead.
|
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/323713) in 13.11 and removed in GitLab 14.0. Use the [DORA metrics API](dora/metrics.md) instead.
|
||||||
|
|
||||||
All methods require reporter authorization.
|
|
||||||
|
|
||||||
## List project deployment frequencies
|
|
||||||
|
|
||||||
Get a list of all project deployment frequencies, sorted by date:
|
|
||||||
|
|
||||||
```plaintext
|
|
||||||
GET /projects/:id/analytics/deployment_frequency?environment=:environment&from=:from&to=:to&interval=:interval
|
|
||||||
```
|
|
||||||
|
|
||||||
| Attribute | Type | Required | Description |
|
|
||||||
|--------------|--------|----------|-----------------------|
|
|
||||||
| `id` | string | yes | The ID of the project |
|
|
||||||
| `environment`| string | yes | The name of the environment to filter by |
|
|
||||||
| `from` | string | yes | Datetime range to start from, inclusive, ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`) |
|
|
||||||
| `to` | string | no | Datetime range to end at, exclusive, ISO 8601 format (`YYYY-MM-DDTHH:MM:SSZ`) |
|
|
||||||
| `interval` | string | no | The bucketing interval (`all`, `monthly`, `daily`) |
|
|
||||||
|
|
||||||
Example request:
|
|
||||||
|
|
||||||
```shell
|
|
||||||
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/:id/analytics/deployment_frequency?environment=:environment&from=:from&to=:to&interval=:interval"
|
|
||||||
```
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
|
|
||||||
```json
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"from": "2017-01-01",
|
|
||||||
"to": "2017-01-02",
|
|
||||||
"value": 106
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"from": "2017-01-02",
|
|
||||||
"to": "2017-01-03",
|
|
||||||
"value": 55
|
|
||||||
}
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
|
@ -145,6 +145,17 @@ Returns [`String!`](#string).
|
||||||
| ---- | ---- | ----------- |
|
| ---- | ---- | ----------- |
|
||||||
| <a id="queryechotext"></a>`text` | [`String!`](#string) | Text to echo back. |
|
| <a id="queryechotext"></a>`text` | [`String!`](#string) | Text to echo back. |
|
||||||
|
|
||||||
|
### `Query.epicBoardList`
|
||||||
|
|
||||||
|
Returns [`EpicList`](#epiclist).
|
||||||
|
|
||||||
|
#### Arguments
|
||||||
|
|
||||||
|
| Name | Type | Description |
|
||||||
|
| ---- | ---- | ----------- |
|
||||||
|
| <a id="queryepicboardlistepicfilters"></a>`epicFilters` | [`EpicFilters`](#epicfilters) | Filters applied when getting epic metadata in the epic board list. |
|
||||||
|
| <a id="queryepicboardlistid"></a>`id` | [`BoardsEpicListID!`](#boardsepiclistid) | Global ID of the list. |
|
||||||
|
|
||||||
### `Query.geoNode`
|
### `Query.geoNode`
|
||||||
|
|
||||||
Find a Geo node.
|
Find a Geo node.
|
||||||
|
|
|
@ -422,6 +422,15 @@ Response:
|
||||||
|
|
||||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22988) in GitLab 11.6.
|
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/22988) in GitLab 11.6.
|
||||||
|
|
||||||
|
Deleting a pipeline expires all pipeline caches, and deletes all immediately
|
||||||
|
related objects, such as builds, logs, artifacts, and triggers.
|
||||||
|
**This action cannot be undone.**
|
||||||
|
|
||||||
|
Deleting a pipeline does not automatically delete its
|
||||||
|
[child pipelines](../ci/pipelines/parent_child_pipelines.md).
|
||||||
|
See the [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/39503)
|
||||||
|
for details.
|
||||||
|
|
||||||
```plaintext
|
```plaintext
|
||||||
DELETE /projects/:id/pipelines/:pipeline_id
|
DELETE /projects/:id/pipelines/:pipeline_id
|
||||||
```
|
```
|
||||||
|
|
|
@ -50,10 +50,10 @@ Example response:
|
||||||
|
|
||||||
## Export Service Ping SQL queries
|
## Export Service Ping SQL queries
|
||||||
|
|
||||||
This action is available only for the GitLab instance [Administrator](../user/permissions.md) users.
|
This action is behind the `usage_data_queries_api` feature flag and is available only for the GitLab instance [Administrator](../user/permissions.md) users.
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57016) in GitLab 13.11.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57016) in GitLab 13.11.
|
||||||
> - [Deployed behind a feature flag](../user/feature_flags.md), disabled by default.
|
> - [Deployed behind a feature flag](../user/feature_flags.md) named `usage_data_queries_api`, disabled by default.
|
||||||
|
|
||||||
Return all of the raw SQL queries used to compute Service Ping.
|
Return all of the raw SQL queries used to compute Service Ping.
|
||||||
|
|
||||||
|
@ -113,8 +113,10 @@ Example response:
|
||||||
|
|
||||||
## UsageDataNonSqlMetrics API
|
## UsageDataNonSqlMetrics API
|
||||||
|
|
||||||
|
This action is behind the `usage_data_non_sql_metrics` feature flag and is available only for the GitLab instance [Administrator](../user/permissions.md) users.
|
||||||
|
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57050) in GitLab 13.11.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57050) in GitLab 13.11.
|
||||||
> - [Deployed behind a feature flag](../user/feature_flags.md), disabled by default.
|
> - [Deployed behind a feature flag](../user/feature_flags.md), named `usage_data_non_sql_metrics`, disabled by default.
|
||||||
|
|
||||||
Return all non-SQL metrics data used in the Service ping.
|
Return all non-SQL metrics data used in the Service ping.
|
||||||
|
|
||||||
|
|
|
@ -287,9 +287,15 @@ page, then selecting **Delete**.
|
||||||
|
|
||||||
![Pipeline Delete](img/pipeline-delete.png)
|
![Pipeline Delete](img/pipeline-delete.png)
|
||||||
|
|
||||||
|
Deleting a pipeline does not automatically delete its
|
||||||
|
[child pipelines](parent_child_pipelines.md).
|
||||||
|
See the [related issue](https://gitlab.com/gitlab-org/gitlab/-/issues/39503)
|
||||||
|
for details.
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
Deleting a pipeline expires all pipeline caches, and deletes all related objects,
|
Deleting a pipeline expires all pipeline caches, and deletes all immediately
|
||||||
such as builds, logs, artifacts, and triggers. **This action cannot be undone.**
|
related objects, such as builds, logs, artifacts, and triggers.
|
||||||
|
**This action cannot be undone.**
|
||||||
|
|
||||||
### Pipeline security on protected branches
|
### Pipeline security on protected branches
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
fetchCollapsedData(props) {}, // Required: Fetches data required for collapsed state
|
fetchCollapsedData(props) {}, // Required: Fetches data required for collapsed state
|
||||||
fetchFullData(props) {}, // Required: Fetches data for the full expanded content
|
fetchFullData(props) {}, // Required: Fetches data for the full expanded content
|
||||||
|
fetchMultiData() {}, // Optional: Works in conjunction with `enablePolling` and allows polling multiple endpoints
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
@ -232,6 +233,30 @@ export default {
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
If the extension needs to poll multiple endpoints at the same time, then `fetchMultiData`
|
||||||
|
can be used to return an array of functions. A new `poll` object will be created for each
|
||||||
|
endpoint and they will be polled separately. Once all endpoints are resolved, polling will
|
||||||
|
be stopped and `setCollapsedData` will be called with an array of `response.data`.
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
export default {
|
||||||
|
//...
|
||||||
|
enablePolling: true
|
||||||
|
methods: {
|
||||||
|
fetchMultiData() {
|
||||||
|
return [
|
||||||
|
() => axios.get(this.reportPath1),
|
||||||
|
() => axios.get(this.reportPath2),
|
||||||
|
() => axios.get(this.reportPath3)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**Important** The function needs to return a `Promise` that resolves the `response` object.
|
||||||
|
The implementation relies on the `POLL-INTERVAL` header to keep polling, therefore it is
|
||||||
|
important not to alter the status code and headers.
|
||||||
|
|
||||||
### Errors
|
### Errors
|
||||||
|
|
||||||
If `fetchCollapsedData()` or `fetchFullData()` methods throw an error:
|
If `fetchCollapsedData()` or `fetchFullData()` methods throw an error:
|
||||||
|
|
|
@ -118,12 +118,16 @@ NOTE:
|
||||||
There is a [video showing how to see the slow log](https://youtu.be/BBI68QuYRH8) (GitLab internal)
|
There is a [video showing how to see the slow log](https://youtu.be/BBI68QuYRH8) (GitLab internal)
|
||||||
on GitLab.com
|
on GitLab.com
|
||||||
|
|
||||||
|
<!-- vale gitlab.Substitutions = NO -->
|
||||||
|
|
||||||
On GitLab.com, entries from the [Redis
|
On GitLab.com, entries from the [Redis
|
||||||
slow log](https://redis.io/commands/slowlog) are available in the
|
slow log](https://redis.io/commands/slowlog) are available in the
|
||||||
`pubsub-redis-inf-gprd*` index with the [`redis.slowlog` tag](https://log.gprd.gitlab.net/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&_a=(columns:!(json.type,json.command,json.exec_time_s),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:AWSQX_Vf93rHTYrsexmk,key:json.tag,negate:!f,params:(query:redis.slowlog),type:phrase),query:(match:(json.tag:(query:redis.slowlog,type:phrase))))),index:AWSQX_Vf93rHTYrsexmk)).
|
`pubsub-redis-inf-gprd*` index with the [`redis.slowlog` tag](https://log.gprd.gitlab.net/app/kibana#/discover?_g=(filters:!(),refreshInterval:(pause:!t,value:0),time:(from:now-1d,to:now))&_a=(columns:!(json.type,json.command,json.exec_time_s),filters:!(('$state':(store:appState),meta:(alias:!n,disabled:!f,index:AWSQX_Vf93rHTYrsexmk,key:json.tag,negate:!f,params:(query:redis.slowlog),type:phrase),query:(match:(json.tag:(query:redis.slowlog,type:phrase))))),index:AWSQX_Vf93rHTYrsexmk)).
|
||||||
This shows commands that have taken a long time and may be a performance
|
This shows commands that have taken a long time and may be a performance
|
||||||
concern.
|
concern.
|
||||||
|
|
||||||
|
<!-- vale gitlab.Substitutions = YES -->
|
||||||
|
|
||||||
The
|
The
|
||||||
[`fluent-plugin-redis-slowlog`](https://gitlab.com/gitlab-org/fluent-plugin-redis-slowlog)
|
[`fluent-plugin-redis-slowlog`](https://gitlab.com/gitlab-org/fluent-plugin-redis-slowlog)
|
||||||
project is responsible for taking the `slowlog` entries from Redis and
|
project is responsible for taking the `slowlog` entries from Redis and
|
||||||
|
|
|
@ -11,7 +11,7 @@ This operation should be very uncommon. We do not recommend it for the vast majo
|
||||||
|
|
||||||
Sidekiq routing rules allow administrators to re-route certain background jobs from their regular queue to an alternative queue. By default, GitLab uses one queue per background job type. GitLab has over 400 background job types, and so correspondingly it has over 400 queues.
|
Sidekiq routing rules allow administrators to re-route certain background jobs from their regular queue to an alternative queue. By default, GitLab uses one queue per background job type. GitLab has over 400 background job types, and so correspondingly it has over 400 queues.
|
||||||
|
|
||||||
Most administrators will not need to change this setting. In some cases with particularly large background job processing workloads, Redis performance may suffer due to the number of queues that GitLab listens to.
|
Most administrators do not need to change this setting. In some cases with particularly large background job processing workloads, Redis performance may suffer due to the number of queues that GitLab listens to.
|
||||||
|
|
||||||
If the Sidekiq routing rules are changed, administrators need to take care with the migration to avoid losing jobs entirely. The basic migration steps are:
|
If the Sidekiq routing rules are changed, administrators need to take care with the migration to avoid losing jobs entirely. The basic migration steps are:
|
||||||
|
|
||||||
|
|
|
@ -517,6 +517,8 @@ that may remain stuck permanently in a **pending** state.
|
||||||
sudo printf "x /tmp/gitaly-%s-*\n" hooks git-exec-path >/etc/tmpfiles.d/gitaly-workaround.conf
|
sudo printf "x /tmp/gitaly-%s-*\n" hooks git-exec-path >/etc/tmpfiles.d/gitaly-workaround.conf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
This issue is fixed in GitLab 14.10 and later.
|
||||||
|
|
||||||
### 14.6.0
|
### 14.6.0
|
||||||
|
|
||||||
- See [LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2](#lfs-objects-import-and-mirror-issue-in-gitlab-1460-to-1472).
|
- See [LFS objects import and mirror issue in GitLab 14.6.0 to 14.7.2](#lfs-objects-import-and-mirror-issue-in-gitlab-1460-to-1472).
|
||||||
|
|
|
@ -675,6 +675,16 @@ keyword has been [replaced](https://gitlab.com/gitlab-org/gitlab/-/issues/344533
|
||||||
[`artifacts:reports:coverage_report`](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report).
|
[`artifacts:reports:coverage_report`](https://docs.gitlab.com/ee/ci/yaml/artifacts_reports.html#artifactsreportscoverage_report).
|
||||||
Cobertura is the only supported report file, but this is the first step towards GitLab supporting other report types.
|
Cobertura is the only supported report file, but this is the first step towards GitLab supporting other report types.
|
||||||
|
|
||||||
|
### `defaultMergeCommitMessageWithDescription` GraphQL API field
|
||||||
|
|
||||||
|
WARNING:
|
||||||
|
This feature was changed or removed in 15.0
|
||||||
|
as a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
|
||||||
|
Before updating GitLab, review the details carefully to determine if you need to make any
|
||||||
|
changes to your code, settings, or workflow.
|
||||||
|
|
||||||
|
The GraphQL API field `defaultMergeCommitMessageWithDescription` has been removed in GitLab 15.0. For projects with a commit message template set, it will ignore the template.
|
||||||
|
|
||||||
### `omniauth-kerberos` gem
|
### `omniauth-kerberos` gem
|
||||||
|
|
||||||
WARNING:
|
WARNING:
|
||||||
|
|
|
@ -47,7 +47,8 @@ The policy editor currently only supports the YAML mode. The Rule mode is tracke
|
||||||
|
|
||||||
The YAML file with scan execution policies consists of an array of objects matching scan execution
|
The YAML file with scan execution policies consists of an array of objects matching scan execution
|
||||||
policy schema nested under the `scan_execution_policy` key. You can configure a maximum of 5
|
policy schema nested under the `scan_execution_policy` key. You can configure a maximum of 5
|
||||||
policies under the `scan_execution_policy` key.
|
policies under the `scan_execution_policy` key. Any other policies configured after
|
||||||
|
the first 5 are not applied.
|
||||||
|
|
||||||
When you save a new policy, GitLab validates its contents against [this JSON schema](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/security_orchestration_policy.json).
|
When you save a new policy, GitLab validates its contents against [this JSON schema](https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/app/validators/json_schemas/security_orchestration_policy.json).
|
||||||
If you're not familiar with how to read [JSON schemas](https://json-schema.org/),
|
If you're not familiar with how to read [JSON schemas](https://json-schema.org/),
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Gitlab
|
||||||
|
module BackgroundMigration
|
||||||
|
# rubocop:disable Style/Documentation
|
||||||
|
class PurgeStaleSecurityScans # rubocop:disable Migration/BackgroundMigrationBaseClass
|
||||||
|
class SecurityScan < ::ApplicationRecord
|
||||||
|
include EachBatch
|
||||||
|
|
||||||
|
STALE_AFTER = 90.days
|
||||||
|
|
||||||
|
self.table_name = 'security_scans'
|
||||||
|
|
||||||
|
# Otherwise the schema_spec fails
|
||||||
|
validates :info, json_schema: { filename: 'security_scan_info', draft: 7 }
|
||||||
|
|
||||||
|
enum status: { succeeded: 1, purged: 6 }
|
||||||
|
|
||||||
|
scope :to_purge, -> { where('id <= ?', last_stale_record_id) }
|
||||||
|
scope :by_range, -> (range) { where(id: range) }
|
||||||
|
|
||||||
|
def self.last_stale_record_id
|
||||||
|
where('created_at < ?', STALE_AFTER.ago).order(created_at: :desc).first
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform(_start_id, _end_id); end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Gitlab::BackgroundMigration::PurgeStaleSecurityScans.prepend_mod
|
|
@ -33677,6 +33677,9 @@ msgstr ""
|
||||||
msgid "SecurityOrchestration|After dismissing the alert, the information will never be shown again."
|
msgid "SecurityOrchestration|After dismissing the alert, the information will never be shown again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SecurityOrchestration|After enabling a group-level policy, this policy automatically applies to all projects in this group."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SecurityOrchestration|All policies"
|
msgid "SecurityOrchestration|All policies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -33743,6 +33746,9 @@ msgstr ""
|
||||||
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
|
msgid "SecurityOrchestration|Enforce security for this project. %{linkStart}More information.%{linkEnd}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "SecurityOrchestration|Group level policy"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
|
msgid "SecurityOrchestration|If any scanner finds a newly detected critical vulnerability in an open merge request targeting the master branch, then require two approvals from any member of App security."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@
|
||||||
"@gitlab/at.js": "1.5.7",
|
"@gitlab/at.js": "1.5.7",
|
||||||
"@gitlab/favicon-overlay": "2.0.0",
|
"@gitlab/favicon-overlay": "2.0.0",
|
||||||
"@gitlab/svgs": "2.14.0",
|
"@gitlab/svgs": "2.14.0",
|
||||||
"@gitlab/ui": "40.2.1",
|
"@gitlab/ui": "40.6.0",
|
||||||
"@gitlab/visual-review-tools": "1.7.3",
|
"@gitlab/visual-review-tools": "1.7.3",
|
||||||
"@rails/actioncable": "6.1.4-7",
|
"@rails/actioncable": "6.1.4-7",
|
||||||
"@rails/ujs": "6.1.4-7",
|
"@rails/ujs": "6.1.4-7",
|
||||||
|
|
|
@ -31,6 +31,7 @@ import {
|
||||||
fullDataErrorExtension,
|
fullDataErrorExtension,
|
||||||
pollingExtension,
|
pollingExtension,
|
||||||
pollingErrorExtension,
|
pollingErrorExtension,
|
||||||
|
multiPollingExtension,
|
||||||
} from './test_extensions';
|
} from './test_extensions';
|
||||||
|
|
||||||
jest.mock('~/api.js');
|
jest.mock('~/api.js');
|
||||||
|
@ -987,6 +988,8 @@ describe('MrWidgetOptions', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
|
pollRequest = jest.spyOn(Poll.prototype, 'makeRequest');
|
||||||
pollStop = jest.spyOn(Poll.prototype, 'stop');
|
pollStop = jest.spyOn(Poll.prototype, 'stop');
|
||||||
|
|
||||||
|
registeredExtensions.extensions = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
@ -996,6 +999,63 @@ describe('MrWidgetOptions', () => {
|
||||||
registeredExtensions.extensions = [];
|
registeredExtensions.extensions = [];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('success - multi polling', () => {
|
||||||
|
const findWidgetTestExtension = () => wrapper.find('[data-testid="widget-extension"]');
|
||||||
|
|
||||||
|
// Clear all left-over timeouts that may be registered in the poll class
|
||||||
|
afterEach(() => {
|
||||||
|
let id = window.setTimeout(() => {}, 0);
|
||||||
|
|
||||||
|
while (id > 0) {
|
||||||
|
window.clearTimeout(id);
|
||||||
|
id -= 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sets data when polling is complete', async () => {
|
||||||
|
registerExtension(
|
||||||
|
multiPollingExtension([
|
||||||
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
headers: { 'poll-interval': 0 },
|
||||||
|
status: 200,
|
||||||
|
data: { reports: 'parsed' },
|
||||||
|
}),
|
||||||
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
status: 200,
|
||||||
|
data: { reports: 'parsed' },
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
await createComponent();
|
||||||
|
expect(findWidgetTestExtension().html()).toContain(
|
||||||
|
'Multi polling test extension reports: parsed, count: 2',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('shows loading state until polling is complete', async () => {
|
||||||
|
registerExtension(
|
||||||
|
multiPollingExtension([
|
||||||
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
headers: { 'poll-interval': 1 },
|
||||||
|
status: 204,
|
||||||
|
}),
|
||||||
|
() =>
|
||||||
|
Promise.resolve({
|
||||||
|
status: 200,
|
||||||
|
data: { reports: 'parsed' },
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
|
await createComponent();
|
||||||
|
expect(findWidgetTestExtension().html()).toContain('Loading...');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('success', () => {
|
describe('success', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
registerExtension(pollingExtension);
|
registerExtension(pollingExtension);
|
||||||
|
|
|
@ -106,6 +106,25 @@ export const pollingExtension = {
|
||||||
enablePolling: true,
|
enablePolling: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const multiPollingExtension = (endpointsToBePolled) => ({
|
||||||
|
name: 'WidgetTestMultiPollingExtension',
|
||||||
|
props: ['targetProjectFullPath'],
|
||||||
|
computed: {
|
||||||
|
summary(data) {
|
||||||
|
return `Multi polling test extension reports: ${data?.[0]?.reports}, count: ${data.length}`;
|
||||||
|
},
|
||||||
|
statusIcon(data) {
|
||||||
|
return data?.[0]?.reports === 'parsed' ? EXTENSION_ICONS.success : EXTENSION_ICONS.warning;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
enablePolling: true,
|
||||||
|
methods: {
|
||||||
|
fetchMultiData() {
|
||||||
|
return endpointsToBePolled;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
export const pollingErrorExtension = {
|
export const pollingErrorExtension = {
|
||||||
...collapsedDataErrorExtension,
|
...collapsedDataErrorExtension,
|
||||||
enablePolling: true,
|
enablePolling: true,
|
||||||
|
|
|
@ -10,7 +10,7 @@ exports[`Issue Warning Component when issue is locked but not confidential rende
|
||||||
href="locked-path"
|
href="locked-path"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more.
|
||||||
</gl-link-stub>
|
</gl-link-stub>
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
|
@ -25,7 +25,7 @@ exports[`Issue Warning Component when noteable is confidential but not locked re
|
||||||
href="confidential-path"
|
href="confidential-path"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
>
|
>
|
||||||
Learn more
|
Learn more.
|
||||||
</gl-link-stub>
|
</gl-link-stub>
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
require_migration!
|
||||||
|
|
||||||
|
RSpec.describe SchedulePurgingStaleSecurityScans do
|
||||||
|
let_it_be(:namespaces) { table(:namespaces) }
|
||||||
|
let_it_be(:projects) { table(:projects) }
|
||||||
|
let_it_be(:pipelines) { table(:ci_pipelines) }
|
||||||
|
let_it_be(:builds) { table(:ci_builds) }
|
||||||
|
let_it_be(:security_scans) { table(:security_scans) }
|
||||||
|
|
||||||
|
let_it_be(:namespace) { namespaces.create!(name: "foo", path: "bar") }
|
||||||
|
let_it_be(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
|
||||||
|
let_it_be(:pipeline) { pipelines.create!(project_id: project.id, ref: 'master', sha: 'adf43c3a', status: 'success') }
|
||||||
|
let_it_be(:ci_build) { builds.create!(commit_id: pipeline.id, retried: false, type: 'Ci::Build') }
|
||||||
|
|
||||||
|
let!(:security_scan_1) { security_scans.create!(build_id: ci_build.id, scan_type: 1, created_at: 91.days.ago) }
|
||||||
|
let!(:security_scan_2) { security_scans.create!(build_id: ci_build.id, scan_type: 2, created_at: 91.days.ago) }
|
||||||
|
|
||||||
|
let(:com?) { false }
|
||||||
|
let(:dev_or_test_env?) { false }
|
||||||
|
|
||||||
|
before do
|
||||||
|
allow(::Gitlab).to receive(:com?).and_return(com?)
|
||||||
|
allow(::Gitlab).to receive(:dev_or_test_env?).and_return(dev_or_test_env?)
|
||||||
|
|
||||||
|
stub_const("#{described_class.name}::BATCH_SIZE", 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
shared_examples_for 'schedules the background jobs' do
|
||||||
|
before do
|
||||||
|
# This will not be scheduled as it's not stale
|
||||||
|
security_scans.create!(build_id: ci_build.id, scan_type: 3)
|
||||||
|
end
|
||||||
|
|
||||||
|
around do |example|
|
||||||
|
freeze_time { Sidekiq::Testing.fake! { example.run } }
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'creates 2 jobs', :aggregate_failures do
|
||||||
|
migrate!
|
||||||
|
|
||||||
|
expect(BackgroundMigrationWorker.jobs.size).to be(2)
|
||||||
|
expect(described_class::MIGRATION)
|
||||||
|
.to be_scheduled_delayed_migration(2.minutes, security_scan_1.id, security_scan_1.id)
|
||||||
|
expect(described_class::MIGRATION)
|
||||||
|
.to be_scheduled_delayed_migration(4.minutes, security_scan_2.id, security_scan_2.id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the migration does not run on GitLab.com or `dev_or_test_env`' do
|
||||||
|
it 'does not run the migration' do
|
||||||
|
expect { migrate! }.not_to change { BackgroundMigrationWorker.jobs.size }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the migration runs on GitLab.com' do
|
||||||
|
let(:com?) { true }
|
||||||
|
|
||||||
|
it_behaves_like 'schedules the background jobs'
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the migration runs on dev or test env' do
|
||||||
|
let(:dev_or_test_env?) { true }
|
||||||
|
|
||||||
|
it_behaves_like 'schedules the background jobs'
|
||||||
|
end
|
||||||
|
end
|
|
@ -3,17 +3,17 @@
|
||||||
RSpec.shared_examples 'items list service' do
|
RSpec.shared_examples 'items list service' do
|
||||||
it 'avoids N+1' do
|
it 'avoids N+1' do
|
||||||
params = { board_id: board.id }
|
params = { board_id: board.id }
|
||||||
control = ActiveRecord::QueryRecorder.new { described_class.new(parent, user, params).execute }
|
control = ActiveRecord::QueryRecorder.new { list_service(params).execute }
|
||||||
|
|
||||||
new_list
|
new_list
|
||||||
|
|
||||||
expect { described_class.new(parent, user, params).execute }.not_to exceed_query_limit(control)
|
expect { list_service(params).execute }.not_to exceed_query_limit(control)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns opened items when list_id is missing' do
|
it 'returns opened items when list_id and list are missing' do
|
||||||
params = { board_id: board.id }
|
params = { board_id: board.id }
|
||||||
|
|
||||||
items = described_class.new(parent, user, params).execute
|
items = list_service(params).execute
|
||||||
|
|
||||||
expect(items).to match_array(backlog_items)
|
expect(items).to match_array(backlog_items)
|
||||||
end
|
end
|
||||||
|
@ -21,7 +21,7 @@ RSpec.shared_examples 'items list service' do
|
||||||
it 'returns opened items when listing items from Backlog' do
|
it 'returns opened items when listing items from Backlog' do
|
||||||
params = { board_id: board.id, id: backlog.id }
|
params = { board_id: board.id, id: backlog.id }
|
||||||
|
|
||||||
items = described_class.new(parent, user, params).execute
|
items = list_service(params).execute
|
||||||
|
|
||||||
expect(items).to match_array(backlog_items)
|
expect(items).to match_array(backlog_items)
|
||||||
end
|
end
|
||||||
|
@ -29,7 +29,7 @@ RSpec.shared_examples 'items list service' do
|
||||||
it 'returns opened items that have label list applied when listing items from a label list' do
|
it 'returns opened items that have label list applied when listing items from a label list' do
|
||||||
params = { board_id: board.id, id: list1.id }
|
params = { board_id: board.id, id: list1.id }
|
||||||
|
|
||||||
items = described_class.new(parent, user, params).execute
|
items = list_service(params).execute
|
||||||
|
|
||||||
expect(items).to match_array(list1_items)
|
expect(items).to match_array(list1_items)
|
||||||
end
|
end
|
||||||
|
@ -37,20 +37,24 @@ RSpec.shared_examples 'items list service' do
|
||||||
it 'returns closed items when listing items from Closed sorted by closed_at in descending order' do
|
it 'returns closed items when listing items from Closed sorted by closed_at in descending order' do
|
||||||
params = { board_id: board.id, id: closed.id }
|
params = { board_id: board.id, id: closed.id }
|
||||||
|
|
||||||
items = described_class.new(parent, user, params).execute
|
items = list_service(params).execute
|
||||||
|
|
||||||
expect(items).to eq(closed_items)
|
expect(items).to eq(closed_items)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error if the list does not belong to the board' do
|
it 'raises an error if the list does not belong to the board' do
|
||||||
list = create(list_factory) # rubocop:disable Rails/SaveBang
|
list = create(list_factory) # rubocop:disable Rails/SaveBang
|
||||||
service = described_class.new(parent, user, board_id: board.id, id: list.id)
|
params = { board_id: board.id, id: list.id }
|
||||||
|
|
||||||
|
service = list_service(params)
|
||||||
|
|
||||||
expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'raises an error if list id is invalid' do
|
it 'raises an error if list and list id are invalid or missing' do
|
||||||
service = described_class.new(parent, user, board_id: board.id, id: nil)
|
params = { board_id: board.id, id: nil, list: nil }
|
||||||
|
|
||||||
|
service = list_service(params)
|
||||||
|
|
||||||
expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
|
expect { service.execute }.to raise_error(ActiveRecord::RecordNotFound)
|
||||||
end
|
end
|
||||||
|
@ -58,8 +62,22 @@ RSpec.shared_examples 'items list service' do
|
||||||
it 'returns items from all lists if :all_list is used' do
|
it 'returns items from all lists if :all_list is used' do
|
||||||
params = { board_id: board.id, all_lists: true }
|
params = { board_id: board.id, all_lists: true }
|
||||||
|
|
||||||
items = described_class.new(parent, user, params).execute
|
items = list_service(params).execute
|
||||||
|
|
||||||
expect(items).to match_array(all_items)
|
expect(items).to match_array(all_items)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'returns opened items that have label list applied when using list param' do
|
||||||
|
params = { board_id: board.id, list: list1 }
|
||||||
|
|
||||||
|
items = list_service(params).execute
|
||||||
|
|
||||||
|
expect(items).to match_array(list1_items)
|
||||||
|
end
|
||||||
|
|
||||||
|
def list_service(params)
|
||||||
|
args = [parent, user].push(params)
|
||||||
|
|
||||||
|
described_class.new(*args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -968,10 +968,10 @@
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.14.0.tgz#92b36bc98ccbed49a4dbca310862146275091cb2"
|
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-2.14.0.tgz#92b36bc98ccbed49a4dbca310862146275091cb2"
|
||||||
integrity sha512-U9EYmEIiTMl7R3X5DmCrw6fz7gz8c1kjvQtaF6HfJ15xDtR7trRAyCNbn3z7YGk1QJ8Cv/Ifw2/T5SxXwYd7dw==
|
integrity sha512-U9EYmEIiTMl7R3X5DmCrw6fz7gz8c1kjvQtaF6HfJ15xDtR7trRAyCNbn3z7YGk1QJ8Cv/Ifw2/T5SxXwYd7dw==
|
||||||
|
|
||||||
"@gitlab/ui@40.2.1":
|
"@gitlab/ui@40.6.0":
|
||||||
version "40.2.1"
|
version "40.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-40.2.1.tgz#510ea1cda0a62afbfb0bc6a74b56e1128ddef428"
|
resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-40.6.0.tgz#67ee263d2ce88cb9ef27235e19b2a0844a321c29"
|
||||||
integrity sha512-dDsyu8Zuf5MYZwx6A6m2TeIPJL+ytTP7J0x0M8649MOqJJB2/3pq8IfcowWSQAvpO57w5N+G/QlotNypZ3e31w==
|
integrity sha512-aib9szbLX/UlejMp1ZG3dzZSLmDwK1V6fKxS5bueaaeHRNKPkQ7sFcyIZNG8sF3sHKUxDwA/OEfciIsRW6xzCQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@popperjs/core" "^2.11.2"
|
"@popperjs/core" "^2.11.2"
|
||||||
bootstrap-vue "2.20.1"
|
bootstrap-vue "2.20.1"
|
||||||
|
|
Loading…
Reference in New Issue