Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-04-12 12:08:50 +00:00
parent 2e3f13a01a
commit 47bb4281f0
37 changed files with 342 additions and 178 deletions

View File

@ -1291,7 +1291,7 @@
},
"pipeline_variables": {
"type": "boolean",
"description": "Variables added for manual pipeline runs are passed to downstream pipelines.",
"description": "Variables added for manual pipeline runs and scheduled pipelines are passed to downstream pipelines.",
"default": false
}
}
@ -1407,7 +1407,7 @@
},
"pipeline_variables": {
"type": "boolean",
"description": "Variables added for manual pipeline runs are passed to downstream pipelines.",
"description": "Variables added for manual pipeline runs and scheduled pipelines are passed to downstream pipelines.",
"default": false
}
}

View File

@ -72,11 +72,15 @@ MergeRequest.prototype.initMRBtnListeners = function () {
const wipEvent = getParameterValues('merge_request[wip_event]', url)[0];
const mobileDropdown = draftToggle.closest('.dropdown.show');
const loader = document.createElement('span');
loader.classList.add('gl-spinner', 'gl-mr-3');
if (mobileDropdown) {
$(mobileDropdown.firstElementChild).dropdown('toggle');
}
draftToggle.setAttribute('disabled', 'disabled');
draftToggle.prepend(loader);
axios
.put(draftToggle.href, null, { params: { format: 'json' } })

View File

@ -10,23 +10,14 @@ export function setEndpoints({ commit }, endpoints) {
commit(types.SET_ENDPOINTS, endpoints);
}
export function setMrMetadata({ commit }, metadata) {
commit(types.SET_MR_METADATA, metadata);
}
export function fetchMrMetadata({ dispatch, state }) {
export async function fetchMrMetadata({ state, commit }) {
if (state.endpoints?.metadata) {
axios
.get(state.endpoints.metadata)
.then((response) => {
dispatch('setMrMetadata', response.data);
})
.catch(() => {
// https://gitlab.com/gitlab-org/gitlab/-/issues/324740
// We can't even do a simple console warning here because
// the pipeline will fail. However, the issue above will
// eventually handle errors appropriately.
// console.warn('Failed to load MR Metadata for the Overview tab.');
});
commit(types.SET_FAILED_TO_LOAD_METADATA, false);
try {
const { data } = await axios.get(state.endpoints.metadata);
commit(types.SET_MR_METADATA, data);
} catch (error) {
commit(types.SET_FAILED_TO_LOAD_METADATA, true);
}
}
}

View File

@ -7,6 +7,7 @@ export default () => ({
endpoints: {},
activeTab: null,
mrMetadata: {},
failedToLoadMetadata: false,
},
actions,
getters,

View File

@ -2,4 +2,5 @@ export default {
SET_ACTIVE_TAB: 'SET_ACTIVE_TAB',
SET_ENDPOINTS: 'SET_ENDPOINTS',
SET_MR_METADATA: 'SET_MR_METADATA',
SET_FAILED_TO_LOAD_METADATA: 'SET_FAILED_TO_LOAD_METADATA',
};

View File

@ -10,4 +10,7 @@ export default {
[types.SET_MR_METADATA](state, metadata) {
Object.assign(state, { mrMetadata: metadata });
},
[types.SET_FAILED_TO_LOAD_METADATA](state, value) {
Object.assign(state, { failedToLoadMetadata: value });
},
};

View File

@ -57,14 +57,15 @@ export default {
computed: {
...mapGetters(['getDiscussion', 'suggestionsCount', 'getSuggestionsFilePaths']),
...mapGetters('diffs', ['suggestionCommitMessage']),
...mapState({
batchSuggestionsInfo: (state) => state.notes.batchSuggestionsInfo,
failedToLoadMetadata: (state) => state.page.failedToLoadMetadata,
}),
discussion() {
if (!this.note.isDraft) return {};
return this.getDiscussion(this.note.discussion_id);
},
...mapState({
batchSuggestionsInfo: (state) => state.notes.batchSuggestionsInfo,
}),
noteBody() {
return this.note.note;
},
@ -165,6 +166,7 @@ export default {
:line-type="lineType"
:help-page-path="helpPagePath"
:default-commit-message="commitMessage"
:failed-to-load-metadata="failedToLoadMetadata"
@apply="applySuggestion"
@applyBatch="applySuggestionBatch"
@addToBatch="addSuggestionToBatch"

View File

@ -1,9 +1,9 @@
<script>
import { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton } from '@gitlab/ui';
import { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
import { __, n__ } from '~/locale';
export default {
components: { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton },
components: { GlDropdown, GlDropdownForm, GlFormTextarea, GlButton, GlAlert },
props: {
disabled: {
type: Boolean,
@ -19,6 +19,11 @@ export default {
required: false,
default: 0,
},
errorMessage: {
type: String,
required: false,
default: null,
},
},
data() {
return {
@ -55,6 +60,9 @@ export default {
>
<gl-dropdown-form class="gl-px-4! gl-m-0!">
<label for="commit-message">{{ __('Commit message') }}</label>
<gl-alert v-if="errorMessage" variant="danger" :dismissible="false" class="gl-mb-4">
{{ errorMessage }}
</gl-alert>
<gl-form-textarea
id="commit-message"
ref="commitMessage"

View File

@ -36,6 +36,11 @@ export default {
required: false,
default: 0,
},
failedToLoadMetadata: {
type: Boolean,
required: false,
default: false,
},
},
computed: {
batchSuggestionsCount() {
@ -80,6 +85,7 @@ export default {
:help-page-path="helpPagePath"
:default-commit-message="defaultCommitMessage"
:inapplicable-reason="suggestion.inapplicable_reason"
:failed-to-load-metadata="failedToLoadMetadata"
@apply="applySuggestion"
@applyBatch="applySuggestionBatch"
@addToBatch="addSuggestionToBatch"

View File

@ -4,6 +4,10 @@ import { isLoggedIn } from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import ApplySuggestion from './apply_suggestion.vue';
const APPLY_SUGGESTION_ERROR_MESSAGE = __(
'Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct.',
);
export default {
components: { GlBadge, GlIcon, GlButton, GlLoadingIcon, ApplySuggestion },
directives: { 'gl-tooltip': GlTooltipDirective },
@ -52,6 +56,11 @@ export default {
required: false,
default: 0,
},
failedToLoadMetadata: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -94,6 +103,9 @@ export default {
return true;
},
applySuggestionErrorMessage() {
return this.failedToLoadMetadata ? APPLY_SUGGESTION_ERROR_MESSAGE : null;
},
},
methods: {
apply(message) {
@ -171,6 +183,7 @@ export default {
:disabled="isDisableButton"
:default-commit-message="defaultCommitMessage"
:batch-suggestions-count="batchSuggestionsCount"
:error-message="applySuggestionErrorMessage"
class="gl-ml-3"
@apply="apply"
/>

View File

@ -47,6 +47,11 @@ export default {
required: false,
default: 0,
},
failedToLoadMetadata: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -60,6 +65,9 @@ export default {
noteHtml() {
this.reset();
},
failedToLoadMetadata() {
this.reset();
},
},
mounted() {
this.renderSuggestions();
@ -105,6 +113,7 @@ export default {
helpPagePath,
defaultCommitMessage,
suggestionsCount,
failedToLoadMetadata,
} = this;
const suggestion =
suggestions && suggestions[suggestionIndex] ? suggestions[suggestionIndex] : {};
@ -117,6 +126,7 @@ export default {
helpPagePath,
defaultCommitMessage,
suggestionsCount,
failedToLoadMetadata,
},
});

View File

@ -81,11 +81,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
path = Gitlab::Ci::Build::Artifacts::Path.new(params[:path])
if ::Feature.enabled?(:ci_safe_artifact_content_type, project, default_enabled: :yaml)
send_artifacts_entry(artifacts_file, path)
else
legacy_send_artifacts_entry(artifacts_file, path)
end
send_artifacts_entry(artifacts_file, path)
end
def keep

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Types
module Ci
class RunnerUpgradeStatusTypeEnum < BaseEnum
graphql_name 'CiRunnerUpgradeStatusType'
value 'NOT_AVAILABLE',
description: "An update is not available for the runner.",
value: :not_available
value 'AVAILABLE',
description: "An update is available for the runner.",
value: :available
value 'RECOMMENDED',
description: "An update is available and recommended for the runner.",
value: :recommended
end
end
end

View File

@ -35,12 +35,6 @@ module WorkhorseHelper
head :ok
end
# Send an entry from artifacts through Workhorse
def legacy_send_artifacts_entry(file, entry)
headers.store(*Gitlab::Workhorse.send_artifacts_entry(file, entry))
head :ok
end
# Send an entry from artifacts through Workhorse and set safe content type
def send_artifacts_entry(file, entry)
headers.store(*Gitlab::Workhorse.send_artifacts_entry(file, entry))

View File

@ -274,7 +274,8 @@ module Ci
# The order of this list refers to the priority of the variables
downstream_yaml_variables(expand_variables) +
downstream_pipeline_variables(expand_variables)
downstream_pipeline_variables(expand_variables) +
downstream_pipeline_schedule_variables(expand_variables)
end
def downstream_yaml_variables(expand_variables)
@ -293,6 +294,15 @@ module Ci
end
end
def downstream_pipeline_schedule_variables(expand_variables)
return [] unless forward_pipeline_variables?
return [] unless pipeline.pipeline_schedule
pipeline.pipeline_schedule.variables.to_a.map do |variable|
{ key: variable.key, value: ::ExpandVariables.expand(variable.value, expand_variables) }
end
end
def forward_yaml_variables?
strong_memoize(:forward_yaml_variables) do
result = options&.dig(:trigger, :forward, :yaml_variables)

View File

@ -509,7 +509,15 @@ class Note < ApplicationRecord
# Instead of calling touch which is throttled via ThrottledTouch concern,
# we bump the updated_at column directly. This also prevents executing
# after_commit callbacks that we don't need.
update_column(:updated_at, Time.current)
attributes_to_update = { updated_at: Time.current }
# Notes that were edited before the `last_edited_at` column was added, fall back to `updated_at` for the edit time.
# We copy this over to the correct column so we don't erroneously change the edit timestamp.
if updated_by_id.present? && read_attribute(:last_edited_at).blank?
attributes_to_update[:last_edited_at] = updated_at
end
update_columns(attributes_to_update)
end
def expire_etag_cache

View File

@ -1,6 +1,6 @@
- return unless Gitlab::Tracking.enabled?
- namespace = @group || @project&.namespace
- namespace = @group || @project&.namespace || @namespace
= javascript_tag do
:plain

View File

@ -1,8 +0,0 @@
---
name: ci_safe_artifact_content_type
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83826
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/357664
milestone: '14.10'
type: development
group: group::pipeline insights
default_enabled: false

View File

@ -23,11 +23,11 @@ GitLab can stream a single event more than once to the same destination. Use the
## Add a new event streaming destination
WARNING:
Event streaming destinations will receive **all** audit event data, which could include sensitive information. Make sure you trust the destination endpoint.
Event streaming destinations receive **all** audit event data, which could include sensitive information. Make sure you trust the destination endpoint.
### Add event streaming destination using GitLab UI
### Use the GitLab UI
Users with at least the Owner role of a group can add event streaming destinations for it:
Users with at least the Owner role for a group can add event streaming destinations for it:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Security & Compliance > Audit events**
@ -41,10 +41,10 @@ Event streaming is enabled if:
- No warning is shown.
- The added endpoint is displayed in the UI.
### Add event streaming destination using the API
### Use the API
To enable event streaming, a group owner must add a new event streaming destination using the `externalAuditEventDestinationCreate` mutation
in the GraphQL API.
To enable event streaming and add a destination, users with at least the Owner role for a group must use the
`externalAuditEventDestinationCreate` mutation in the GraphQL API.
```graphql
mutation {
@ -66,19 +66,24 @@ Event streaming is enabled if:
- The returned `errors` object is empty.
- The API responds with `200 OK`.
## List currently enabled streaming destinations
## List streaming destinations
### List currently enabled streaming destination using GitLab UI
Users with at least the Owner role for a group can list event streaming destinations.
Users with at least the Owner role of a group can list event streaming destinations:
### Use the GitLab UI
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336411) in GitLab 14.9.
Users with at least the Owner role for a group can list event streaming destinations:
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Security & Compliance > Audit events**
1. On the main area, select **Streams** tab.
### List currently enabled streaming destinations using the API
### Use the API
Group owners can view a list of event streaming destinations at any time using the `externalAuditEventDestinations` query type.
Users with at least the Owner role for a group can view a list of event streaming destinations at any time using the
`externalAuditEventDestinations` query type.
```graphql
query {
@ -97,27 +102,34 @@ query {
If the resulting list is empty, then audit event streaming is not enabled for that group.
## Delete currently enabled streaming destination
## Delete streaming destinations
Group Owners can delete event streaming destinations at any time using the `deleteAuditEventDestinations` mutation type.
Users with at least the Owner role for a group can delete event streaming destinations using the
`deleteAuditEventDestinations` mutation type.
### Delete currently enabled streaming using GitLab UI
When the last destination is successfully deleted, event streaming is disabled for the group.
Uses with at least the Owner role of a group can delete event streaming destination.
### Use the GitLab UI
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/336411) in GitLab 14.9.
Users with at least the Owner role for a group can delete event streaming destinations.
1. On the top bar, select **Menu > Groups** and find your group.
1. On the left sidebar, select **Security & Compliance > Audit events**
1. On the main area, select **Streams** tab.
1. Select **{remove}** at the right side of each item.
The external streaming destination is delete when:
The external streaming destination is deleted when:
- No warning is shown.
- The deleted endpoint is not displayed in the UI.
### Delete currently enabled streaming using the API
### Use the API
You can delete an event streaming destination by specifying an ID. Get the required ID by [listing the details](audit_event_streaming.md#list-currently-enabled-streaming-destinations-using-the-api) of event streaming destinations.
Delete an event streaming destination by specifying an ID. Get the required ID by
[listing the details](audit_event_streaming.md#use-the-api-1) of event
streaming destinations.
```graphql
@ -134,8 +146,6 @@ Destination is deleted if:
- The returned `errors` object is empty.
- The API responds with `200 OK`.
When the last destination is successfully deleted, event streaming is disabled for the group.
## Verify event authenticity
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345424) in GitLab 14.8.
@ -144,7 +154,7 @@ Each streaming destination has a unique verification token (`verificationToken`)
token is generated when the event destination is created and cannot be changed.
Each streamed event contains a random alphanumeric identifier for the `X-Gitlab-Event-Streaming-Token` HTTP header that can be verified against
the destination's value when [listing streaming destinations](#list-currently-enabled-streaming-destinations).
the destination's value when [listing streaming destinations](#list-streaming-destinations).
## Audit event streaming on Git operations
@ -163,9 +173,9 @@ Audit events are not captured for users that are not signed in. For example, whe
To configure streaming audit events for Git operations, see [Add a new event streaming destination](#add-a-new-event-streaming-destination).
### Request headers
### Headers
Request headers are formatted as follows:
Headers are formatted as follows:
```plaintext
POST /logs HTTP/1.1
@ -174,7 +184,7 @@ Content-Type: application/x-www-form-urlencoded
X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
```
### Example responses for SSH events
### Example payloads for SSH events
Fetch:
@ -236,7 +246,7 @@ Push:
}
```
### Example responses for HTTP and HTTPS events
### Example payloads for HTTP and HTTPS events
Fetch:
@ -298,7 +308,7 @@ Push:
}
```
### Example responses for events from GitLab UI download button
### Example payloads for events from GitLab UI download button
Fetch:
@ -333,9 +343,9 @@ Fetch:
Stream audit events that relate to merge approval actions performed within a project.
### Request headers
### Headers
Request headers are formatted as follows:
Headers are formatted as follows:
```plaintext
POST /logs HTTP/1.1
@ -344,7 +354,7 @@ Content-Type: application/x-www-form-urlencoded
X-Gitlab-Event-Streaming-Token: <DESTINATION_TOKEN>
```
### Example request body
### Example payload
```json
{

View File

@ -9450,6 +9450,7 @@ Represents the total number of issues and their weights for a particular day.
| <a id="cirunnershortsha"></a>`shortSha` | [`String`](#string) | First eight characters of the runner's token used to authenticate new job requests. Used as the runner's unique ID. |
| <a id="cirunnertaglist"></a>`tagList` | [`[String!]`](#string) | Tags associated with the runner. |
| <a id="cirunnertokenexpiresat"></a>`tokenExpiresAt` | [`Time`](#time) | Runner token expiration time. |
| <a id="cirunnerupgradestatus"></a>`upgradeStatus` **{warning-solid}** | [`CiRunnerUpgradeStatusType`](#cirunnerupgradestatustype) | **Deprecated** in 14.10. This feature is in Alpha, and can be removed or changed at any point. |
| <a id="cirunneruserpermissions"></a>`userPermissions` | [`RunnerPermissions!`](#runnerpermissions) | Permissions for the current user on the resource. |
| <a id="cirunnerversion"></a>`version` | [`String`](#string) | Version of the runner. |
@ -17841,6 +17842,14 @@ Values for sorting runners.
| <a id="cirunnertypeinstance_type"></a>`INSTANCE_TYPE` | A runner that is instance type. |
| <a id="cirunnertypeproject_type"></a>`PROJECT_TYPE` | A runner that is project type. |
### `CiRunnerUpgradeStatusType`
| Value | Description |
| ----- | ----------- |
| <a id="cirunnerupgradestatustypeavailable"></a>`AVAILABLE` | An update is available for the runner. |
| <a id="cirunnerupgradestatustypenot_available"></a>`NOT_AVAILABLE` | An update is not available for the runner. |
| <a id="cirunnerupgradestatustyperecommended"></a>`RECOMMENDED` | An update is available and recommended for the runner. |
### `CodeQualityDegradationSeverity`
| Value | Description |

View File

@ -18,10 +18,9 @@ The access levels are defined in the `Gitlab::Access` module. Currently, these l
- Maintainer (`40`)
- Owner (`50`) - Only valid to set for groups
WARNING:
Due to [an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/219299),
projects in personal namespaces don't show owner (`50`) permission
for owner.
NOTE:
In [GitLab 14.9](https://gitlab.com/gitlab-org/gitlab/-/issues/351211) and later, projects in personal namespaces have an `access_level` of `50`(Owner).
In GitLab 14.8 and earlier, projects in personal namespaces have an `access_level` of `40` (Maintainer) due to [an issue](https://gitlab.com/gitlab-org/gitlab/-/issues/219299)
## Limitations

View File

@ -3714,7 +3714,7 @@ and [multi-project pipelines](../pipelines/multi_project_pipelines.md).
- `yaml_variables`: `true` (default), or `false`. When `true`, variables defined
in the trigger job are passed to downstream pipelines.
- `pipeline_variables`: `true` or `false` (default). When `true`, [manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable)
- `pipeline_variables`: `true` or `false` (default). When `true`, [manual pipeline variables](../variables/index.md#override-a-defined-cicd-variable) and [scheduled pipeline variables](../pipelines/schedules.md#add-a-pipeline-schedule)
are passed to downstream pipelines.
**Example of `trigger:forward`**:

View File

@ -148,6 +148,9 @@ This sync job runs daily around 3AM UTC. If the job fails, it is retried up to 1
The daily job provides **only** the following information to the Customers Portal:
- Company name
- Licensee name
- Licensee email
- Date
- Timestamp
- License key

View File

@ -222,6 +222,7 @@ You can [configure](#customizing-the-container-scanning-settings) analyzers by u
| `CS_DISABLE_DEPENDENCY_LIST` | `"false"` | Disable Dependency Scanning for packages installed in the scanned image. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345434) in GitLab 14.6. | All |
| `CS_DISABLE_LANGUAGE_VULNERABILITY_SCAN` | `"true"` | Disable scanning for language-specific packages installed in the scanned image. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/345434) in GitLab 14.6. | All |
| `CS_DOCKER_INSECURE` | `"false"` | Allow access to secure Docker registries using HTTPS without validating the certificates. | All |
| `CS_IMAGE_SUFFIX` | `""` | Suffix added to `CS_ANALYZER_IMAGE`. If set to `-fips`, `FIPS-enabled` image is used for scan. See [FIPS-enabled images](#fips-enabled-images) for more details. [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/7630) in GitLab 14.10. | All |
| `CS_IGNORE_UNFIXED` | `"false"` | Ignore vulnerabilities that are not fixed. | All |
| `CS_REGISTRY_INSECURE` | `"false"` | Allow access to insecure registries (HTTP only). Should only be set to `true` when testing the image locally. Works with all scanners, but the registry must listen on port `80/tcp` for Trivy to work. | All |
| `CS_SEVERITY_THRESHOLD` | `UNKNOWN` | Severity level threshold. The scanner outputs vulnerabilities with severity level higher than or equal to this threshold. Supported levels are Unknown, Low, Medium, High, and Critical. | Trivy |
@ -238,20 +239,27 @@ Support depends on the scanner:
- [Grype](https://github.com/anchore/grype#grype)
- [Trivy](https://aquasecurity.github.io/trivy/latest/vulnerability/detection/os/) (Default).
#### UBI-based images
#### FIPS-enabled images
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/5775) in GitLab 14.1.
GitLab also offers [Red Hat UBI](https://www.redhat.com/en/blog/introducing-red-hat-universal-base-image)
versions of the container-scanning images. You can therefore replace standard images with UBI-based
images. To configure the images, set the `CS_ANALYZER_IMAGE` variable to the standard tag plus the
`-ubi` extension.
GitLab also offers [FIPS-enabled Red Hat UBI](https://www.redhat.com/en/blog/introducing-red-hat-universal-base-image)
versions of the container-scanning images. You can therefore replace standard images with FIPS-enabled
images. To configure the images, set the `CS_IMAGE_SUFFIX` to `-fips` or modify the `CS_ANALYZER_IMAGE` variable to the
standard tag plus the `-fips` extension.
| Scanner name | `CS_ANALYZER_IMAGE` |
| --------------- | ------------------- |
| Default (Trivy) | `registry.gitlab.com/security-products/container-scanning:4-ubi` |
| Grype | `registry.gitlab.com/security-products/container-scanning/grype:4-ubi` |
| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:4-ubi` |
| Default (Trivy) | `registry.gitlab.com/security-products/container-scanning:4-fips` |
| Grype | `registry.gitlab.com/security-products/container-scanning/grype:4-fips` |
| Trivy | `registry.gitlab.com/security-products/container-scanning/trivy:4-fips` |
NOTE:
Prior to GitLab 15.0, the `-ubi` image extension is also available. GitLab 15.0 and later only
support `-fips`.
Starting with GitLab 14.10, `-fips` is automatically added to `CS_ANALYZER_IMAGE` when FIPS mode is
enabled in the GitLab instance.
### Enable Container Scanning through an automatic merge request

View File

@ -449,6 +449,22 @@ The labels higher in the list get higher priority.
To learn what happens when you sort by priority or label priority, see
[Sorting and ordering issue lists](issues/sorting_issue_lists.md).
## Real-time changes to labels
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/241538) in GitLab 14.10 with a [feature flag](../../administration/feature_flags.md) named `realtime_labels`, disabled by default.
FLAG:
On self-managed GitLab, by default this feature is not available. To make it available, ask an
administrator to [enable the feature flag](../../administration/feature_flags.md) named `realtime_labels`.
On GitLab.com, this feature is unavailable.
Changed labels are immediately visible to other users, without refreshing the page, on the following:
- Epics
- Incidents
- Issues
- Merge requests
## Troubleshooting
### Some label titles end with `_duplicate<number>`

View File

@ -60,11 +60,7 @@ module API
bad_request! unless path.valid?
if ::Feature.enabled?(:ci_safe_artifact_content_type, build&.project, default_enabled: :yaml)
send_artifacts_entry(build.artifacts_file, path)
else
legacy_send_artifacts_entry(build.artifacts_file, path)
end
send_artifacts_entry(build.artifacts_file, path)
end
desc 'Download the artifacts archive from a job' do

View File

@ -25,7 +25,7 @@ variables:
CS_ANALYZER_IMAGE: registry.gitlab.com/security-products/container-scanning:4
container_scanning:
image: "$CS_ANALYZER_IMAGE"
image: "$CS_ANALYZER_IMAGE$CS_IMAGE_SUFFIX"
stage: test
variables:
# To provide a `vulnerability-allowlist.yml` file, override the GIT_STRATEGY variable in your
@ -46,5 +46,11 @@ container_scanning:
rules:
- if: $CONTAINER_SCANNING_DISABLED
when: never
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bcontainer_scanning\b/ &&
$CI_GITLAB_FIPS_MODE == "true" &&
$CS_ANALYZER_IMAGE !~ /-(fips|ubi)\z/
variables:
CS_IMAGE_SUFFIX: -fips
- if: $CI_COMMIT_BRANCH &&
$GITLAB_FEATURES =~ /\bcontainer_scanning\b/

View File

@ -7348,6 +7348,9 @@ msgstr ""
msgid "Checkout|Subtotal"
msgstr ""
msgid "Checkout|Success: subscription"
msgstr ""
msgid "Checkout|Tax"
msgstr ""
@ -40102,6 +40105,9 @@ msgstr ""
msgid "Unable to find Jira project to import data from."
msgstr ""
msgid "Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct."
msgstr ""
msgid "Unable to generate new instance ID"
msgstr ""

View File

@ -381,18 +381,6 @@ RSpec.describe Projects::ArtifactsController do
let(:store) { ObjectStorage::Store::LOCAL }
let(:archive_path) { JobArtifactUploader.root }
end
context 'when ci_safe_artifact_content_type is disabled' do
before do
stub_feature_flags(ci_safe_artifact_content_type: false)
end
it 'does not let workhorse set content type' do
subject
expect(response.headers).not_to include('Gitlab-Workhorse-Detect-Content-Type')
end
end
end
context 'when the artifact is not zip' do

View File

@ -379,4 +379,41 @@ RSpec.describe 'User comments on a diff', :js do
end
end
end
context 'failed to load metadata' do
let(:dummy_controller) do
Class.new(Projects::MergeRequests::DiffsController) do
def diffs_metadata
render json: '', status: :internal_server_error
end
end
end
before do
stub_const('Projects::MergeRequests::DiffsController', dummy_controller)
click_diff_line(find_by_scrolling("[id='#{sample_compare.changes[1][:line_code]}']"))
page.within('.js-discussion-note-form') do
fill_in('note_note', with: "```suggestion\n# change to a comment\n```")
click_button('Add comment now')
end
wait_for_requests
visit(project_merge_request_path(project, merge_request))
wait_for_requests
end
it 'displays an error' do
page.within('.discussion-notes') do
click_button('Apply suggestion')
wait_for_requests
expect(page).to have_content('Unable to fully load the default commit message. You can still apply this suggestion and the commit message will be correct.')
end
end
end
end

View File

@ -1,64 +1,37 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import axios from '~/lib/utils/axios_utils';
import { setEndpoints, setMrMetadata, fetchMrMetadata } from '~/mr_notes/stores/actions';
import mutationTypes from '~/mr_notes/stores/mutation_types';
import { createStore } from '~/mr_notes/stores';
describe('MR Notes Mutator Actions', () => {
describe('setEndpoints', () => {
it('should trigger the SET_ENDPOINTS state mutation', (done) => {
const endpoints = { endpointA: 'a' };
let store;
testAction(
setEndpoints,
endpoints,
{},
[
{
type: mutationTypes.SET_ENDPOINTS,
payload: endpoints,
},
],
[],
done,
);
});
beforeEach(() => {
store = createStore();
});
describe('setMrMetadata', () => {
it('should trigger the SET_MR_METADATA state mutation', async () => {
const mrMetadata = { propA: 'a', propB: 'b' };
describe('setEndpoints', () => {
it('sets endpoints', async () => {
const endpoints = { endpointA: 'a' };
await testAction(
setMrMetadata,
mrMetadata,
{},
[
{
type: mutationTypes.SET_MR_METADATA,
payload: mrMetadata,
},
],
[],
);
await store.dispatch('setEndpoints', endpoints);
expect(store.state.page.endpoints).toEqual(endpoints);
});
});
describe('fetchMrMetadata', () => {
const mrMetadata = { meta: true, data: 'foo' };
const state = {
endpoints: {
metadata: 'metadata',
},
};
const metadata = 'metadata';
const endpoints = { metadata };
let mock;
beforeEach(() => {
beforeEach(async () => {
await store.dispatch('setEndpoints', endpoints);
mock = new MockAdapter(axios);
mock.onGet(state.endpoints.metadata).reply(200, mrMetadata);
mock.onGet(metadata).reply(200, mrMetadata);
});
afterEach(() => {
@ -66,27 +39,26 @@ describe('MR Notes Mutator Actions', () => {
});
it('should fetch the data from the API', async () => {
await fetchMrMetadata({ state, dispatch: () => {} });
await store.dispatch('fetchMrMetadata');
await axios.waitForAll();
expect(mock.history.get).toHaveLength(1);
expect(mock.history.get[0].url).toBe(state.endpoints.metadata);
expect(mock.history.get[0].url).toBe(metadata);
});
it('should set the fetched data into state', () => {
return testAction(
fetchMrMetadata,
{},
state,
[],
[
{
type: 'setMrMetadata',
payload: mrMetadata,
},
],
);
it('should set the fetched data into state', async () => {
await store.dispatch('fetchMrMetadata');
expect(store.state.page.mrMetadata).toEqual(mrMetadata);
});
it('should set failedToLoadMetadata flag when request fails', async () => {
mock.onGet(metadata).reply(500);
await store.dispatch('fetchMrMetadata');
expect(store.state.page.failedToLoadMetadata).toBe(true);
});
});
});

View File

@ -1,4 +1,4 @@
import { GlDropdown, GlFormTextarea, GlButton } from '@gitlab/ui';
import { GlDropdown, GlFormTextarea, GlButton, GlAlert } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import ApplySuggestionComponent from '~/vue_shared/components/markdown/apply_suggestion.vue';
@ -10,9 +10,10 @@ describe('Apply Suggestion component', () => {
wrapper = shallowMount(ApplySuggestionComponent, { propsData: { ...propsData, ...props } });
};
const findDropdown = () => wrapper.find(GlDropdown);
const findTextArea = () => wrapper.find(GlFormTextarea);
const findApplyButton = () => wrapper.find(GlButton);
const findDropdown = () => wrapper.findComponent(GlDropdown);
const findTextArea = () => wrapper.findComponent(GlFormTextarea);
const findApplyButton = () => wrapper.findComponent(GlButton);
const findAlert = () => wrapper.findComponent(GlAlert);
beforeEach(() => createWrapper());
@ -53,6 +54,20 @@ describe('Apply Suggestion component', () => {
});
});
describe('error', () => {
it('displays an error message', () => {
const errorMessage = 'Error message';
createWrapper({ errorMessage });
const alert = findAlert();
expect(alert.exists()).toBe(true);
expect(alert.props('variant')).toBe('danger');
expect(alert.props('dismissible')).toBe(false);
expect(alert.text()).toBe(errorMessage);
});
});
describe('apply suggestion', () => {
it('emits an apply event with no message if no message was added', () => {
findTextArea().vm.$emit('input', null);

View File

@ -288,6 +288,26 @@ RSpec.describe Ci::Bridge do
)
end
end
context 'when the pipeline runs from a pipeline schedule' do
let(:pipeline_schedule) { create(:ci_pipeline_schedule, :nightly, project: project ) }
let(:pipeline) { create(:ci_pipeline, pipeline_schedule: pipeline_schedule) }
let(:options) do
{ trigger: { project: 'my/project', forward: { pipeline_variables: true } } }
end
before do
pipeline_schedule.variables.create!(key: 'schedule_var_key', value: 'schedule var value')
end
it 'adds the schedule variable' do
expect(bridge.downstream_variables).to contain_exactly(
{ key: 'BRIDGE', value: 'cross' },
{ key: 'schedule_var_key', value: 'schedule var value' }
)
end
end
end
end

View File

@ -1753,4 +1753,27 @@ RSpec.describe Note do
expect(note.commands_changes.keys).to contain_exactly(:emoji_award, :time_estimate, :spend_time)
end
end
describe '#bump_updated_at', :freeze_time do
it 'sets updated_at to the current timestamp' do
note = create(:note, updated_at: 1.day.ago)
note.bump_updated_at
note.reload
expect(note.updated_at).to be_like_time(Time.current)
end
context 'with legacy edited note' do
it 'copies updated_at to last_edited_at before bumping the timestamp' do
note = create(:note, updated_at: 1.day.ago, updated_by: create(:user), last_edited_at: nil)
note.bump_updated_at
note.reload
expect(note.last_edited_at).to be_like_time(1.day.ago)
expect(note.updated_at).to be_like_time(Time.current)
end
end
end
end

View File

@ -561,16 +561,6 @@ RSpec.describe API::Ci::JobArtifacts do
'Gitlab-Workhorse-Send-Data' => /artifacts-entry/,
'Gitlab-Workhorse-Detect-Content-Type' => 'true')
end
context 'when ci_safe_artifact_content_type is disabled' do
before do
stub_feature_flags(ci_safe_artifact_content_type: false)
end
it 'does not let workhorse set content type' do
expect(response.headers).not_to include('Gitlab-Workhorse-Detect-Content-Type')
end
end
end
context 'when project is public with builds access disabled' do

View File

@ -27,6 +27,10 @@ RSpec.describe 'Query.runner(id)' do
let_it_be(:active_project_runner) { create(:ci_runner, :project) }
before do
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_status)
end
shared_examples 'runner details fetch' do
let(:query) do
wrap_fields(query_graphql_path(query_path, all_graphql_fields_for('CiRunner')))

View File

@ -34,6 +34,8 @@ RSpec.describe 'Query.runners' do
end
before do
allow(Gitlab::Ci::RunnerUpgradeCheck.instance).to receive(:check_runner_upgrade_status)
post_graphql(query, current_user: current_user)
end