Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2024-11-08 09:26:31 +00:00
parent d2c017750b
commit 58d64663d0
23 changed files with 255 additions and 237 deletions

View File

@ -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": {

View File

@ -1 +1 @@
eebf475a4a423f93d58ecb66152ca96261c2f8dc
e39eef132f47d2c679e0cc5d199406084135540b

View File

@ -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');
}

View File

@ -24,9 +24,6 @@ const tooltipsApp = () => {
name: 'TooltipsRoot',
render(h) {
return h(Tooltips, {
props: {
elements: this.elements,
},
ref: 'tooltips',
});
},

View File

@ -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;
}
}

View File

@ -1,3 +1,3 @@
@import './themes/dark';
@import './color_modes/dark';
@import 'application_utilities';

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -0,0 +1 @@
4bf6b5209258b7a630fdbf4d0ffe9801c5085ae2a7a7eb7e950d1c8cd18b065b

View File

@ -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 -->

View File

@ -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.

View File

@ -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.

View 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

View File

@ -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

View File

@ -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

View File

@ -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');
});

View File

@ -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

View File

@ -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

View File

@ -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