Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
d2c017750b
commit
58d64663d0
|
|
@ -20,8 +20,8 @@
|
|||
},
|
||||
{
|
||||
"files": [
|
||||
"app/assets/stylesheets/application_dark.scss",
|
||||
"app/assets/stylesheets/framework/**/*.scss",
|
||||
"app/assets/stylesheets/themes/dark_mode_overrides.scss",
|
||||
"app/assets/stylesheets/page_bundles/_ide_theme_overrides.scss"
|
||||
],
|
||||
"rules": {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
eebf475a4a423f93d58ecb66152ca96261c2f8dc
|
||||
e39eef132f47d2c679e0cc5d199406084135540b
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ export class AwardsHandler {
|
|||
}
|
||||
|
||||
// eslint-disable-next-line max-params
|
||||
addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) {
|
||||
addAward(votesBlock, awardUrl, emoji, callback) {
|
||||
const isMainAwardsBlock = votesBlock.closest('.js-noteable-awards').length;
|
||||
|
||||
if (isInVueNoteablePage() && !isMainAwardsBlock) {
|
||||
|
|
@ -303,7 +303,7 @@ export class AwardsHandler {
|
|||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).closest('button');
|
||||
|
||||
this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => {
|
||||
this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality);
|
||||
this.addAwardToEmojiBar(votesBlock, normalizedEmoji);
|
||||
return typeof callback === 'function' ? callback() : undefined;
|
||||
});
|
||||
|
||||
|
|
@ -312,10 +312,7 @@ export class AwardsHandler {
|
|||
return $(`${this.toggleButtonSelector}.is-active`).removeClass('is-active');
|
||||
}
|
||||
|
||||
addAwardToEmojiBar(votesBlock, emoji, checkForMutuality) {
|
||||
if (checkForMutuality || checkForMutuality === null) {
|
||||
this.checkMutuality(votesBlock, emoji);
|
||||
}
|
||||
addAwardToEmojiBar(votesBlock, emoji) {
|
||||
this.addEmojiToFrequentlyUsedList(emoji);
|
||||
const normalizedEmoji = this.emoji.normalizeEmojiName(emoji);
|
||||
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).closest('button');
|
||||
|
|
@ -357,18 +354,6 @@ export class AwardsHandler {
|
|||
return this.getVotesBlock().data('awardUrl');
|
||||
}
|
||||
|
||||
checkMutuality(votesBlock, emoji) {
|
||||
const awardUrl = this.getAwardUrl();
|
||||
if (emoji === EMOJI_THUMBS_UP || emoji === EMOJI_THUMBS_DOWN) {
|
||||
const mutualVote = emoji === EMOJI_THUMBS_UP ? EMOJI_THUMBS_DOWN : EMOJI_THUMBS_UP;
|
||||
const $emojiButton = votesBlock.find(`[data-name="${mutualVote}"]`).closest('button');
|
||||
const isAlreadyVoted = $emojiButton.hasClass('active');
|
||||
if (isAlreadyVoted) {
|
||||
this.addAward(votesBlock, awardUrl, mutualVote, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isActive($emojiButton) {
|
||||
return $emojiButton.hasClass('active');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ const tooltipsApp = () => {
|
|||
name: 'TooltipsRoot',
|
||||
render(h) {
|
||||
return h(Tooltips, {
|
||||
props: {
|
||||
elements: this.elements,
|
||||
},
|
||||
ref: 'tooltips',
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,5 +1,44 @@
|
|||
@import './themes/dark';
|
||||
|
||||
@import './color_modes/dark';
|
||||
@import './application_base';
|
||||
|
||||
@import './themes/dark_mode_overrides';
|
||||
:root.gl-dark {
|
||||
color-scheme: dark;
|
||||
|
||||
/**
|
||||
* Sets fill color for status SVGs in gitlab-svgs
|
||||
*/
|
||||
--svg-status-bg: #{$white};
|
||||
|
||||
/**
|
||||
* Redefine some colors and values to prevent sourcegraph conflicts
|
||||
*/
|
||||
--gray-10: #{$gray-10};
|
||||
--white: #{$white};
|
||||
--black: #{$black};
|
||||
|
||||
/**
|
||||
* Invert image assets in dark mode with same hue
|
||||
*/
|
||||
.gl-dark-invert-keep-hue {
|
||||
filter: invert(0.8) hue-rotate(180deg);
|
||||
}
|
||||
|
||||
.gl-dark-invert-keep-hue\! {
|
||||
filter: invert(0.8) hue-rotate(180deg) !important;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrease brightness and increase contrast for GlLabel in dark mode
|
||||
*/
|
||||
.gl-label {
|
||||
filter: brightness(0.9) contrast(1.1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override <code> background-color in dark mode to provide higher
|
||||
* contrast on background.color.strong surface
|
||||
*/
|
||||
.md :not(pre.code) > code {
|
||||
background-color: $gray-200;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
@import './themes/dark';
|
||||
@import './color_modes/dark';
|
||||
|
||||
@import 'application_utilities';
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
@import './themes/dark';
|
||||
@import 'page_bundles/mixins_and_variables_and_functions';
|
||||
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
|
||||
--dark-icon-color-purple-1: #524a68;
|
||||
--dark-icon-color-purple-2: #715bae;
|
||||
--dark-icon-color-purple-3: #9a79f7;
|
||||
--dark-icon-color-orange-1: #665349;
|
||||
--dark-icon-color-orange-2: #b37a5d;
|
||||
|
||||
--svg-status-bg: #{$white};
|
||||
}
|
||||
|
||||
:root.gl-dark {
|
||||
// redefine some colors and values to prevent sourcegraph conflicts
|
||||
color-scheme: dark;
|
||||
--gray-10: #{$gray-10};
|
||||
--white: #{$white};
|
||||
--black: #{$black};
|
||||
}
|
||||
|
||||
.gl-dark {
|
||||
.gl-dark-invert-keep-hue {
|
||||
filter: invert(0.8) hue-rotate(180deg);
|
||||
}
|
||||
|
||||
.gl-dark-invert-keep-hue\! {
|
||||
filter: invert(0.8) hue-rotate(180deg) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Decrease brightness and increase contrast for GlLabel in dark mode
|
||||
.gl-label {
|
||||
filter: brightness(0.9) contrast(1.1);
|
||||
}
|
||||
|
||||
:root.gl-dark {
|
||||
.md :not(pre.code) > code {
|
||||
background-color: $gray-200;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Search
|
||||
class Cache
|
||||
DEFAULT_EXPIRES_IN = 1.minute
|
||||
|
||||
def self.lookup(...)
|
||||
new(...).lookup { yield }
|
||||
end
|
||||
|
||||
attr_reader :cache_key, :expires_in, :enabled
|
||||
|
||||
def initialize(resource:, action:, expires_in: DEFAULT_EXPIRES_IN, cache_key: nil, enabled: true)
|
||||
@cache_key = cache_key || generate_cache_key(resource, action)
|
||||
@expires_in = expires_in
|
||||
@enabled = enabled
|
||||
end
|
||||
|
||||
def lookup
|
||||
return yield unless enabled
|
||||
|
||||
Rails.cache.fetch(cache_key, expires_in: expires_in) { yield }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_cache_key(resource, action)
|
||||
"search_#{resource.class.name.downcase}_#{resource.id}_#{action}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -34,7 +34,7 @@ class JsonSchemaValidator < ActiveModel::EachValidator
|
|||
record.errors.add(attribute, message)
|
||||
end
|
||||
else
|
||||
record.errors.add(attribute, _("must be a valid json schema")) unless valid_schema?(value)
|
||||
record.errors.add(attribute, error_message) unless valid_schema?(value)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -87,6 +87,10 @@ class JsonSchemaValidator < ActiveModel::EachValidator
|
|||
def draft_version
|
||||
options[:draft] || JSON_VALIDATOR_MAX_DRAFT_VERSION
|
||||
end
|
||||
|
||||
def error_message
|
||||
options[:message] || _('must be a valid json schema')
|
||||
end
|
||||
end
|
||||
|
||||
JsonSchemaValidator.prepend_mod
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: search_cache_authorizations
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/472011
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/169630
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/499721
|
||||
milestone: '17.6'
|
||||
group: group::global search
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateSoftwareLicenseWithoutSpdxIdentifierToCustomLicensesTable < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.6'
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
disable_ddl_transaction!
|
||||
|
||||
BATCH_SIZE = 100
|
||||
|
||||
def up
|
||||
each_batch_range('software_license_policies', of: BATCH_SIZE) do |min, max|
|
||||
execute <<~SQL
|
||||
INSERT INTO custom_software_licenses (name, project_id)
|
||||
SELECT
|
||||
name,
|
||||
project_id
|
||||
FROM
|
||||
software_license_policies
|
||||
INNER JOIN software_licenses ON (software_licenses.id = software_license_policies.software_license_id)
|
||||
WHERE
|
||||
software_licenses.spdx_identifier IS NULL
|
||||
AND software_license_policies.id BETWEEN #{min} AND #{max}
|
||||
ON CONFLICT DO NOTHING
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
4bf6b5209258b7a630fdbf4d0ffe9801c5085ae2a7a7eb7e950d1c8cd18b065b
|
||||
|
|
@ -262,12 +262,18 @@ runners do not use regular runners, they must be [tagged](../yaml/index.md#tags)
|
|||
Review the [deployment safety](../environments/deployment_safety.md)
|
||||
page for additional security recommendations for securing your pipelines.
|
||||
|
||||
## Trigger a pipeline when an upstream project is rebuilt
|
||||
<!--- start_remove The following content will be removed on remove_date: '2025-08-15' -->
|
||||
|
||||
## Trigger a pipeline when an upstream project is rebuilt (deprecated)
|
||||
|
||||
DETAILS:
|
||||
**Tier:** Premium, Ultimate
|
||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
||||
|
||||
WARNING:
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitlab/-/issues/501460) in GitLab 17.6
|
||||
and is planned for removal in 18.0. Use [CI/CD jobs with pipeline trigger tokens](../../ci/triggers/index.md#use-a-cicd-job) instead. This is a breaking change.
|
||||
|
||||
You can set up your project to automatically trigger a pipeline based on tags in a different project.
|
||||
When a new tag pipeline in the subscribed project finishes, it triggers a pipeline on your project's default branch,
|
||||
regardless of the tag pipeline's success, failure, or cancellation.
|
||||
|
|
@ -292,6 +298,8 @@ The maximum number of upstream pipeline subscriptions is 2 by default, for both
|
|||
downstream projects. On self-managed instances, an administrator can change this
|
||||
[limit](../../administration/instance_limits.md#number-of-cicd-subscriptions-to-a-project).
|
||||
|
||||
<!--- end_remove -->
|
||||
|
||||
## How pipeline duration is calculated
|
||||
|
||||
The total running time for a given pipeline excludes:
|
||||
|
|
@ -479,11 +487,15 @@ running pipeline job. This ref can be created even after the associated branch o
|
|||
deleted. It's therefore useful in some features such as [automatically stopping an environment](../environments/index.md#stopping-an-environment),
|
||||
and [merge trains](../pipelines/merge_trains.md) that might run pipelines after branch deletion.
|
||||
|
||||
<!--- start_remove The following content will be removed on remove_date: '2025-08-15' -->
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Pipeline subscriptions continue after user deletion
|
||||
|
||||
When a user [deletes their GitLab.com account](../../user/profile/account/delete_account.md#delete-your-own-account),
|
||||
the deletion does not occur for seven days. During this period, any [pipeline subscriptions created by that user](#trigger-a-pipeline-when-an-upstream-project-is-rebuilt)
|
||||
the deletion does not occur for seven days. During this period, any [pipeline subscriptions created by that user](#trigger-a-pipeline-when-an-upstream-project-is-rebuilt-deprecated)
|
||||
continue to run with the user's original permissions. To prevent unauthorized pipeline executions,
|
||||
immediately update pipeline subscription settings for the deleted user.
|
||||
|
||||
<!--- end_remove -->
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ On the left side we have the events that can trigger a pipeline based on various
|
|||
- When a [merge request is created or updated](../../ci/pipelines/merge_request_pipelines.md).
|
||||
- When an MR is added to a [Merge Train](../../ci/pipelines/merge_trains.md#merge-trains).
|
||||
- A [scheduled pipeline](../../ci/pipelines/schedules.md).
|
||||
- When project is [subscribed to an upstream project](../../ci/pipelines/index.md#trigger-a-pipeline-when-an-upstream-project-is-rebuilt).
|
||||
- When project is [subscribed to an upstream project](../../ci/pipelines/index.md#trigger-a-pipeline-when-an-upstream-project-is-rebuilt-deprecated).
|
||||
- When [Auto DevOps](../../topics/autodevops/index.md) is enabled.
|
||||
- When GitHub integration is used with [external pull requests](../../ci/ci_cd_for_external_repos/index.md#pipelines-for-external-pull-requests).
|
||||
- When an upstream pipeline contains a [bridge job](../../ci/yaml/index.md#trigger) which triggers a downstream pipeline.
|
||||
|
|
|
|||
|
|
@ -10,58 +10,30 @@ This page is about developing dark mode for GitLab. For more information on how
|
|||
|
||||
## How dark mode works
|
||||
|
||||
1. The [color palette](https://design.gitlab.com/product-foundations/color) values are reversed using [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) to provide darker colors for smaller scales.
|
||||
1. `app/assets/stylesheets/themes/_dark.scss` imports dark mode [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) SCSS variables for colors.
|
||||
1. `app/assets/stylesheets/themes/dark_mode_overrides.scss` imports dark mode [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) CSS custom properties for colors.
|
||||
### Current approach
|
||||
|
||||
1. GitLab UI includes light and dark mode [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) CSS custom properties for colors and components.
|
||||
1. [Semantic design tokens](https://design.gitlab.com/product-foundations/design-tokens#semantic-design-tokens) provide values for light and dark mode in general usage, for example: background, text, and border colors.
|
||||
|
||||
### Legacy approach
|
||||
|
||||
1. SCSS variables for the [color palette](https://design.gitlab.com/product-foundations/color) are reversed using [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) to provide darker colors for smaller scales.
|
||||
1. `app/assets/stylesheets/color_modes/_dark.scss` imports dark mode [design tokens](https://gitlab.com/gitlab-org/gitlab-ui/-/blob/main/doc/contributing/design_tokens.md) SCSS variables for colors.
|
||||
1. Bootstrap variables overridden in `app/assets/stylesheets/framework/variables_overrides.scss` are given dark mode values in `_dark.scss`.
|
||||
1. `_dark.scss` is loaded _before_ `application.scss` to generate separate `application_dark.css` stylesheet for dark mode users only.
|
||||
|
||||
## SCSS variables vs CSS custom properties
|
||||
|
||||
Design tokens generate both SCSS variables and CSS custom properties which are imported into the dark mode stylesheet.
|
||||
|
||||
- **SCSS variables:** are used in framework, components, and utility classes and override existing color usage for dark mode.
|
||||
- **CSS custom properties:** are used for any colors within the `app/assets/stylesheets/page_bundles` directory.
|
||||
|
||||
As we do not want to generate separate `*_dark.css` variants of every `page_bundle` file,
|
||||
we use CSS custom properties with SCSS variables as fallbacks. This is because when we generate the `page_bundles`
|
||||
CSS, we get the variable values from `_variables.scss`, so any SCSS variables have light mode values.
|
||||
|
||||
As the CSS custom properties defined in `_dark.scss` are available in the browser, they have the correct colors for dark mode.
|
||||
|
||||
```scss
|
||||
color: var(--gray-500, $gray-500);
|
||||
```
|
||||
|
||||
## Utility classes
|
||||
|
||||
We generate a separate `utilities_dark.css` file for utility classes containing the inverted values. So a class
|
||||
such as `gl-text-white` specifies a text color of `#333` in dark mode. This means you do not have to
|
||||
add multiple classes every time you want to add a color.
|
||||
Design tokens for dark mode can be applied with Tailwind classes (`gl-text-subtle`) or with `@apply` rule (`@apply gl-text-subtle`).
|
||||
|
||||
Currently, we cannot set up a utility class only in dark mode. We hope to address that
|
||||
[issue](https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1141) soon.
|
||||
## CSS custom properties vs SCSS variables
|
||||
|
||||
## Using different values between light and dark mode
|
||||
Design tokens generate both CSS custom properties and SCSS variables which are imported into the dark mode stylesheet.
|
||||
|
||||
In most cases, we can use the same values for light and dark mode. If that is not possible, you
|
||||
can add an override using the `.gl-dark` class that dark mode adds to `body`:
|
||||
- **CSS custom properties:** are preferred to update color modes without loading a color mode specific stylesheet, and are required for any colors within the `app/assets/stylesheets/page_bundles` directory.
|
||||
- **SCSS variables:** override existing color usage for dark mode and are compiled into a color mode specific stylesheet.
|
||||
|
||||
```scss
|
||||
color: $gray-700;
|
||||
.gl-dark & {
|
||||
color: var(--gray-500);
|
||||
}
|
||||
```
|
||||
### Page bundles
|
||||
|
||||
NOTE:
|
||||
Avoid using a different value for the SCSS fallback
|
||||
|
||||
```scss
|
||||
// avoid where possible
|
||||
// --gray-500 (#999) in dark mode
|
||||
// $gray-700 (#525252) in light mode
|
||||
color: var(--gray-500, $gray-700);
|
||||
```
|
||||
|
||||
We [plan to add](https://gitlab.com/groups/gitlab-org/-/epics/7400) the CSS variables to light mode. When that happens, different values for the SCSS fallback will no longer work.
|
||||
To support dark mode CSS custom properties should be used in `page_bundle` styles as we do not generate separate
|
||||
`*_dark.css` variants of each `page_bundle` file.
|
||||
|
|
|
|||
|
|
@ -267,9 +267,9 @@ A finding's primary identifier is a value that is unique to each finding. The ex
|
|||
of the finding's [first identifier](https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/v2.4.0-rc1/dist/sast-report-format.json#L228)
|
||||
combine to create the value.
|
||||
|
||||
Examples of primary identifiers include `PluginID` for Zed Attack Proxy (ZAP), or `CVE` for
|
||||
Trivy. The identifier must be stable. Subsequent scans must return the same value for the
|
||||
same finding, even if the location has slightly changed.
|
||||
An example primary identifier is `CVE`, which is used for Trivy. The identifier must be stable.
|
||||
Subsequent scans must return the same value for the same finding, even if the location has slightly
|
||||
changed.
|
||||
|
||||
## Report finding
|
||||
|
||||
|
|
@ -293,8 +293,8 @@ This list is subject to change as scanners are added.
|
|||
|
||||
## Scanner
|
||||
|
||||
Software that can scan for vulnerabilities. The resulting scan report is typically not in the
|
||||
[Secure report format](#secure-report-format). Examples include ESLint, Trivy, and ZAP.
|
||||
Software that can scan for vulnerabilities (for example, Trivy). The resulting scan report is
|
||||
typically not in the [Secure report format](#secure-report-format).
|
||||
|
||||
## Secure product
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ to move any project to any namespace.
|
|||
When you transfer a project from a namespace licensed for GitLab.com Premium or Ultimate to GitLab Free:
|
||||
|
||||
- [Project access tokens](../../../user/project/settings/project_access_tokens.md) are revoked.
|
||||
- [Pipeline subscriptions](../../../ci/pipelines/index.md#trigger-a-pipeline-when-an-upstream-project-is-rebuilt)
|
||||
- [Pipeline subscriptions](../../../ci/pipelines/index.md#trigger-a-pipeline-when-an-upstream-project-is-rebuilt-deprecated)
|
||||
and [test cases](../../../ci/test_cases/index.md) are deleted.
|
||||
|
||||
## Troubleshooting
|
||||
|
|
|
|||
|
|
@ -113,7 +113,6 @@ ee/spec/frontend/requirements/components/requirements_root_spec.js
|
|||
ee/spec/frontend/roadmap/components/roadmap_shell_spec.js
|
||||
ee/spec/frontend/roles_and_permissions/components/create_member_role_spec.js
|
||||
ee/spec/frontend/roles_and_permissions/components/role_selector_spec.js
|
||||
ee/spec/frontend/saml_providers/saml_settings_form_spec.js
|
||||
ee/spec/frontend/security_configuration/components/app_spec.js
|
||||
ee/spec/frontend/security_configuration/components/dynamic_fields_spec.js
|
||||
ee/spec/frontend/security_configuration/components/expandable_section_spec.js
|
||||
|
|
@ -157,7 +156,6 @@ ee/spec/frontend/users/identity_verification/components/credit_card_verification
|
|||
ee/spec/frontend/users/identity_verification/components/international_phone_input_spec.js
|
||||
ee/spec/frontend/users/identity_verification/components/phone_verification_spec.js
|
||||
ee/spec/frontend/users/identity_verification/components/verify_phone_verification_code_spec.js
|
||||
ee/spec/frontend/users_select/index_spec.js
|
||||
ee/spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_container_spec.js
|
||||
ee/spec/frontend/vue_merge_request_widget/components/states/mr_widget_ready_to_merge_spec.js
|
||||
ee/spec/frontend/vue_shared/components/groups_list/groups_list_item_spec.js
|
||||
|
|
@ -180,7 +178,6 @@ spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
|
|||
spec/frontend/analytics/shared/components/date_ranges_dropdown_spec.js
|
||||
spec/frontend/authentication/two_factor_auth/components/recovery_codes_spec.js
|
||||
spec/frontend/authentication/two_factor_auth/index_spec.js
|
||||
spec/frontend/awards_handler_spec.js
|
||||
spec/frontend/boards/board_list_spec.js
|
||||
spec/frontend/boards/components/board_content_sidebar_spec.js
|
||||
spec/frontend/boards/components/board_content_spec.js
|
||||
|
|
@ -376,7 +373,6 @@ spec/frontend/repository/components/header_area/breadcrumbs_spec.js
|
|||
spec/frontend/repository/components/table/index_spec.js
|
||||
spec/frontend/repository/components/table/row_spec.js
|
||||
spec/frontend/repository/router_spec.js
|
||||
spec/frontend/right_sidebar_spec.js
|
||||
spec/frontend/search/results/components/status_bar_spec.js
|
||||
spec/frontend/search/sidebar/components/branch_dropdown_spec.js
|
||||
spec/frontend/search/sidebar/components/checkbox_filter_spec.js
|
||||
|
|
@ -413,7 +409,6 @@ spec/frontend/tooltips/components/tooltips_spec.js
|
|||
spec/frontend/tooltips/index_spec.js
|
||||
spec/frontend/usage_quotas/storage/components/container_registry_usage_spec.js
|
||||
spec/frontend/usage_quotas/storage/components/namespace_storage_app_spec.js
|
||||
spec/frontend/users_select/index_spec.js
|
||||
spec/frontend/vue_alerts_spec.js
|
||||
spec/frontend/vue_merge_request_widget/components/mr_widget_pipeline_spec.js
|
||||
spec/frontend/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog_spec.js
|
||||
|
|
|
|||
|
|
@ -160,7 +160,7 @@ describe('AwardsHandler', () => {
|
|||
describe('::addAwardToEmojiBar', () => {
|
||||
it('should add emoji to votes block', () => {
|
||||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
const $emojiButton = $votesBlock.find('[data-name=heart]');
|
||||
|
||||
expect($emojiButton.length).toBe(1);
|
||||
|
|
@ -170,8 +170,8 @@ describe('AwardsHandler', () => {
|
|||
|
||||
it('should remove the emoji when we click again', () => {
|
||||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
const $emojiButton = $votesBlock.find('[data-name=heart]');
|
||||
|
||||
expect($emojiButton.length).toBe(0);
|
||||
|
|
@ -179,10 +179,10 @@ describe('AwardsHandler', () => {
|
|||
|
||||
it('should decrement the emoji counter', () => {
|
||||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
const $emojiButton = $votesBlock.find('[data-name=heart]');
|
||||
$emojiButton.next('.js-counter').text(5);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart', false);
|
||||
awardsHandler.addAwardToEmojiBar($votesBlock, 'heart');
|
||||
|
||||
expect($emojiButton.length).toBe(1);
|
||||
expect($emojiButton.next('.js-counter').text()).toBe('4');
|
||||
|
|
@ -205,13 +205,13 @@ describe('AwardsHandler', () => {
|
|||
const $thumbsDownEmoji = $votesBlock
|
||||
.find(`[data-name=${EMOJI_THUMBS_DOWN}]`)
|
||||
.closest('button');
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP, false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP);
|
||||
|
||||
expect($thumbsUpEmoji.hasClass('active')).toBe(true);
|
||||
expect($thumbsDownEmoji.hasClass('active')).toBe(false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_DOWN, true);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_DOWN);
|
||||
|
||||
expect($thumbsUpEmoji.hasClass('active')).toBe(false);
|
||||
expect($thumbsUpEmoji.hasClass('active')).toBe(true);
|
||||
expect($thumbsDownEmoji.hasClass('active')).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
@ -220,7 +220,7 @@ describe('AwardsHandler', () => {
|
|||
it('should remove emoji', () => {
|
||||
const awardUrl = awardsHandler.getAwardUrl();
|
||||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, 'fire', false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, 'fire');
|
||||
|
||||
expect($votesBlock.find('[data-name=fire]').length).toBe(1);
|
||||
awardsHandler.removeEmoji($votesBlock.find('[data-name=fire]').closest('button'));
|
||||
|
|
@ -235,7 +235,7 @@ describe('AwardsHandler', () => {
|
|||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
const $thumbsUpEmoji = $votesBlock.find(`[data-name=${EMOJI_THUMBS_UP}]`).closest('button');
|
||||
$thumbsUpEmoji.attr('data-title', 'sam, jerry, max, and andy');
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP, false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP);
|
||||
|
||||
expect($thumbsUpEmoji.attr('title')).toBe('You, sam, jerry, max, and andy');
|
||||
});
|
||||
|
|
@ -245,7 +245,7 @@ describe('AwardsHandler', () => {
|
|||
const $votesBlock = $('.js-awards-block').eq(0);
|
||||
const $thumbsUpEmoji = $votesBlock.find(`[data-name=${EMOJI_THUMBS_UP}]`).closest('button');
|
||||
$thumbsUpEmoji.attr('data-title', 'sam');
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP, false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP);
|
||||
|
||||
expect($thumbsUpEmoji.attr('title')).toBe('You and sam');
|
||||
});
|
||||
|
|
@ -258,7 +258,7 @@ describe('AwardsHandler', () => {
|
|||
const $thumbsUpEmoji = $votesBlock.find(`[data-name=${EMOJI_THUMBS_UP}]`).closest('button');
|
||||
$thumbsUpEmoji.attr('data-title', 'You, sam, jerry, max, and andy');
|
||||
$thumbsUpEmoji.addClass('active');
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP, false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP);
|
||||
|
||||
expect($thumbsUpEmoji.attr('title')).toBe('sam, jerry, max, and andy');
|
||||
});
|
||||
|
|
@ -269,7 +269,7 @@ describe('AwardsHandler', () => {
|
|||
const $thumbsUpEmoji = $votesBlock.find(`[data-name=${EMOJI_THUMBS_UP}]`).closest('button');
|
||||
$thumbsUpEmoji.attr('data-title', 'You and sam');
|
||||
$thumbsUpEmoji.addClass('active');
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP, false);
|
||||
awardsHandler.addAward($votesBlock, awardUrl, EMOJI_THUMBS_UP);
|
||||
|
||||
expect($thumbsUpEmoji.attr('title')).toBe('sam');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,103 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe MigrateSoftwareLicenseWithoutSpdxIdentifierToCustomLicensesTable, migration: :gitlab_main, feature_category: :security_policy_management do
|
||||
let(:software_licenses_table) { table(:software_licenses) }
|
||||
let(:custom_software_licenses_table) { table(:custom_software_licenses) }
|
||||
let(:software_license_policies_table) { table(:software_license_policies) }
|
||||
let(:projects_table) { table(:projects) }
|
||||
let(:namespace_table) { table(:namespaces) }
|
||||
|
||||
describe '#up' do
|
||||
shared_examples 'does not create custom software licenses records' do
|
||||
it 'does not creates custom software licenses records' do
|
||||
expect { migrate! }.not_to change { custom_software_licenses_table.count }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'creates new software licenses records' do |number_of_new_records:|
|
||||
it 'creates new custom software licenses records' do
|
||||
expect { migrate! }.to change { custom_software_licenses_table.count }.by(number_of_new_records)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are software licenses without spdx_identifier' do
|
||||
let!(:software_licenses_without_spdx) { software_licenses_table.create!(name: 'Custom License') }
|
||||
|
||||
context 'when the software licenses is linked to a software license policy' do
|
||||
let!(:namespace) { namespace_table.create!(name: 'namespace', path: 'namespace') }
|
||||
let!(:project) { projects_table.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
|
||||
let!(:software_license_policy) do
|
||||
software_license_policies_table.create!(project_id: project.id,
|
||||
software_license_id: software_licenses_without_spdx.id)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates new software licenses records', number_of_new_records: 1
|
||||
|
||||
it 'creates a new custom software license record with the correct attributes' do
|
||||
migrate!
|
||||
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name,
|
||||
project_id: project.id).count).to eq(1)
|
||||
end
|
||||
|
||||
context 'when the same software license is linked to software license policies from different projects' do
|
||||
let!(:namespace_2) { namespace_table.create!(name: 'namespace 2', path: 'namespace 2') }
|
||||
let!(:project_2) do
|
||||
projects_table.create!(namespace_id: namespace_2.id, project_namespace_id: namespace_2.id)
|
||||
end
|
||||
|
||||
let!(:software_license_policy_2) do
|
||||
software_license_policies_table.create!(project_id: project_2.id,
|
||||
software_license_id: software_licenses_without_spdx.id)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates new software licenses records', number_of_new_records: 2
|
||||
|
||||
it 'creates new custom software license records with the correct attributes' do
|
||||
migrate!
|
||||
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name).count).to eq(2)
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name,
|
||||
project_id: project.id).count).to eq(1)
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name,
|
||||
project_id: project_2.id).count).to eq(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when a project contains multiple software licenses' do
|
||||
let!(:other_software_licenses_without_spdx) { software_licenses_table.create!(name: 'Other Custom License') }
|
||||
|
||||
let!(:other_software_license_policy) do
|
||||
software_license_policies_table.create!(project_id: project.id,
|
||||
software_license_id: other_software_licenses_without_spdx.id)
|
||||
end
|
||||
|
||||
it_behaves_like 'creates new software licenses records', number_of_new_records: 2
|
||||
|
||||
it 'creates the new custom software license records with the correct attributes' do
|
||||
migrate!
|
||||
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name).count).to eq(1)
|
||||
expect(custom_software_licenses_table.where(name: other_software_licenses_without_spdx.name).count).to eq(1)
|
||||
|
||||
expect(custom_software_licenses_table.where(name: software_licenses_without_spdx.name,
|
||||
project_id: project.id).count).to eq(1)
|
||||
expect(custom_software_licenses_table.where(name: other_software_licenses_without_spdx.name,
|
||||
project_id: project.id).count).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the software licenses are not linked to a software license policy' do
|
||||
it_behaves_like 'does not create custom software licenses records'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are no software licenses without spdx_identifier' do
|
||||
it_behaves_like 'does not create custom software licenses records'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Search::Cache, feature_category: :global_search do
|
||||
let_it_be(:resource) { create(:user) }
|
||||
let(:action) { 'test' }
|
||||
let(:cache_key) { "search_user_#{resource.id}_#{action}" }
|
||||
|
||||
describe '.lookup' do
|
||||
it 'uses Rails.cache to fetch the value' do
|
||||
expect(Rails.cache).to receive(:fetch)
|
||||
.with(cache_key, expires_in: described_class::DEFAULT_EXPIRES_IN)
|
||||
.and_call_original
|
||||
|
||||
described_class.lookup(resource: resource, action: action) { 'cached_value' }
|
||||
end
|
||||
|
||||
context 'when caching is disabled' do
|
||||
it 'does not use the cache' do
|
||||
expect(Rails.cache).not_to receive(:fetch)
|
||||
result = described_class.lookup(resource: resource, action: action, enabled: false) { 'uncached_value' }
|
||||
expect(result).to eq('uncached_value')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a custom cache key' do
|
||||
let(:custom_cache_key) { 'my_cache_key' }
|
||||
|
||||
it 'uses the cache key' do
|
||||
expect(Rails.cache).to receive(:fetch)
|
||||
.with(custom_cache_key, expires_in: described_class::DEFAULT_EXPIRES_IN)
|
||||
.and_call_original
|
||||
|
||||
described_class.lookup(resource: resource, action: action, cache_key: custom_cache_key) { 'cached_value' }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a custom expiration' do
|
||||
let(:custom_expiration) { 5.minutes }
|
||||
|
||||
it 'uses the expiration' do
|
||||
expect(Rails.cache).to receive(:fetch)
|
||||
.with(cache_key, expires_in: custom_expiration)
|
||||
.and_call_original
|
||||
|
||||
described_class.lookup(resource: resource, action: action, expires_in: custom_expiration) { 'cached_value' }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -20,13 +20,26 @@ RSpec.describe JsonSchemaValidator, feature_category: :shared do
|
|||
end
|
||||
|
||||
context 'when data is invalid' do
|
||||
it 'returns json schema is invalid' do
|
||||
build_report_result.data = { invalid: 'data' }
|
||||
context 'when error message is not provided' do
|
||||
it 'returns default set error message i.e `must be a valid json schema`' do
|
||||
build_report_result.data = { invalid: 'data' }
|
||||
validator.validate(build_report_result)
|
||||
|
||||
expect(build_report_result.errors.size).to eq(1)
|
||||
expect(build_report_result.errors.full_messages).to eq(["Data must be a valid json schema"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when error message is provided' do
|
||||
let(:validator) { described_class.new(attributes: [:data], filename: "build_report_result_data", message: "error in build-report-json") }
|
||||
|
||||
it 'returns the provided error message' do
|
||||
build_report_result.data = { invalid: 'data' }
|
||||
validator.validate(build_report_result)
|
||||
|
||||
expect(build_report_result.errors.size).to eq(1)
|
||||
expect(build_report_result.errors.full_messages).to eq(["Data must be a valid json schema"])
|
||||
expect(build_report_result.errors.full_messages).to eq(["Data error in build-report-json"])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue