Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-10-07 09:10:18 +00:00
parent 8e656d0d45
commit 2a296e6d58
29 changed files with 419 additions and 289 deletions

View File

@ -574,3 +574,6 @@ gem 'error_tracking_open_api', path: 'vendor/gems/error_tracking_open_api'
# Vulnerability advisories
gem 'cvss-suite', '~> 3.0.1', require: 'cvss_suite'
# Work with RPM packages
gem 'arr-pm', '~> 0.0.12'

View File

@ -19,6 +19,7 @@
{"name":"akismet","version":"3.0.0","platform":"ruby","checksum":"74991b8e3d3257eeea996b47069abb8da2006c84a144255123e8dffd1c86b230"},
{"name":"android_key_attestation","version":"0.3.0","platform":"ruby","checksum":"467eb01a99d2bb48ef9cf24cc13712669d7056cba5a52d009554ff037560570b"},
{"name":"apollo_upload_server","version":"2.1.0","platform":"ruby","checksum":"e5f3c9dda0c2ca775d007072742b98d517dfd91a667111fedbcdc94dfabd904e"},
{"name":"arr-pm","version":"0.0.12","platform":"ruby","checksum":"fdff482f75239239201f4d667d93424412639aad0b3b0ad4d827e7c637e0ad39"},
{"name":"asana","version":"0.10.13","platform":"ruby","checksum":"36d0d37f8dd6118a54580f1b80224875d7b6a9027598938e1722a508bfc2d7ac"},
{"name":"asciidoctor","version":"2.0.17","platform":"ruby","checksum":"ed5b5e399e8d64994cc16f0983f993d6e33990909a8415b6fc8b786cdeb00f3d"},
{"name":"asciidoctor-include-ext","version":"0.4.0","platform":"ruby","checksum":"406adb9d2fbfc25536609ca13b787ed704dc06a4e49d6709b83f3bad578f7878"},

View File

@ -169,6 +169,7 @@ GEM
apollo_upload_server (2.1.0)
actionpack (>= 4.2)
graphql (>= 1.8)
arr-pm (0.0.12)
asana (0.10.13)
faraday (~> 1.0)
faraday_middleware (~> 1.0)
@ -1535,6 +1536,7 @@ DEPENDENCIES
addressable (~> 2.8)
akismet (~> 3.0)
apollo_upload_server (~> 2.1.0)
arr-pm (~> 0.0.12)
asana (~> 0.10.13)
asciidoctor (~> 2.0.17)
asciidoctor-include-ext (~> 0.4.0)

View File

@ -0,0 +1,84 @@
# frozen_string_literal: true
module Packages
module Rpm
class ParsePackageService
include ::Gitlab::Utils::StrongMemoize
BUILD_ATTRIBUTES_METHOD_NAMES = %i[changelogs requirements provides].freeze
STATIC_ATTRIBUTES = %i[name version release summary description arch
license sourcerpm group buildhost packager vendor].freeze
CHANGELOGS_RPM_KEYS = %i[changelogtext changelogtime].freeze
REQUIREMENTS_RPM_KEYS = %i[requirename requireversion requireflags].freeze
PROVIDES_RPM_KEYS = %i[providename provideflags provideversion].freeze
def initialize(package_file)
@rpm = RPM::File.new(package_file)
end
def execute
raise ArgumentError, 'Unable to parse package' unless valid_package?
{
files: rpm.files || [],
epoch: package_tags[:epoch] || '0',
changelogs: build_changelogs,
requirements: build_requirements,
provides: build_provides
}.merge(extract_static_attributes)
end
private
attr_reader :rpm
def valid_package?
rpm.files && package_tags && true
rescue RuntimeError
# if arr-pm throws an error due to an incorrect file format,
# we just want this validation to fail rather than throw an exception
false
end
def package_tags
strong_memoize(:package_tags) do
rpm.tags
end
end
def extract_static_attributes
STATIC_ATTRIBUTES.each_with_object({}) do |attribute, hash|
hash[attribute] = package_tags[attribute]
end
end
# Define methods for building RPM attribute data from parsed package
# Transform
# changelogtime: [123, 234],
# changelogname: ["First", "Second"]
# changelogtext: ["Work1", "Work2"]
# Into
# changelog: [
# {changelogname: "First", changelogtext: "Work1", changelogtime: 123},
# {changelogname: "Second", changelogtext: "Work2", changelogtime: 234}
# ]
BUILD_ATTRIBUTES_METHOD_NAMES.each do |resource|
define_method("build_#{resource}") do
resource_keys = self.class.const_get("#{resource.upcase}_RPM_KEYS", false).dup
return [] if resource_keys.any? { package_tags[_1].blank? }
first_attributes = package_tags[resource_keys.first]
zipped_data = first_attributes.zip(*resource_keys[1..].map { package_tags[_1] })
build_hashes(resource_keys, zipped_data)
end
end
def build_hashes(resource_keys, zipped_data)
zipped_data.map do |data|
resource_keys.zip(data).to_h
end
end
end
end
end

View File

@ -0,0 +1,8 @@
---
name: child_epics_from_different_hierarchies
introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/99147"
rollout_issue_url: "https://gitlab.com/gitlab-org/gitlab/-/issues/375622"
milestone: '15.5'
type: development
group: group::product planning
default_enabled: false

View File

@ -41034,6 +41034,27 @@ msgstr ""
msgid "This epic already has the maximum number of child epics."
msgstr ""
msgid "This epic cannot be added. An epic cannot be added to itself."
msgstr ""
msgid "This epic cannot be added. An epic cannot belong to an ancestor group of its parent epic."
msgstr ""
msgid "This epic cannot be added. An epic must belong to the same group or subgroup as its parent epic."
msgstr ""
msgid "This epic cannot be added. It is already an ancestor of the parent epic."
msgstr ""
msgid "This epic cannot be added. It is already assigned to the parent epic."
msgstr ""
msgid "This epic cannot be added. One or more epics would exceed the maximum depth (%{max_depth}) from its most distant ancestor."
msgstr ""
msgid "This epic cannot be added. You don't have access to perform this action."
msgstr ""
msgid "This epic does not exist or you don't have sufficient permission."
msgstr ""

View File

@ -202,7 +202,7 @@
"yaml": "^2.0.0-10"
},
"devDependencies": {
"@gitlab/eslint-plugin": "17.0.0",
"@gitlab/eslint-plugin": "18.1.0",
"@gitlab/stylelint-config": "4.1.0",
"@graphql-eslint/eslint-plugin": "3.11.2",
"@testing-library/dom": "^7.16.2",

Binary file not shown.

View File

@ -1,10 +0,0 @@
// eslint-disable-next-line jest/no-export
export default class ClassSpecHelper {
static itShouldBeAStaticMethod(base, method) {
return it('should be a static method', () => {
expect(Object.prototype.hasOwnProperty.call(base, method)).toBeTruthy();
});
}
}
window.ClassSpecHelper = ClassSpecHelper;

View File

@ -1,26 +0,0 @@
/* global ClassSpecHelper */
import './class_spec_helper';
describe('ClassSpecHelper', () => {
let testContext;
beforeEach(() => {
testContext = {};
});
describe('itShouldBeAStaticMethod', () => {
beforeEach(() => {
class TestClass {
instanceMethod() {
this.prop = 'val';
}
static staticMethod() {}
}
testContext.TestClass = TestClass;
});
ClassSpecHelper.itShouldBeAStaticMethod(ClassSpecHelper, 'itShouldBeAStaticMethod');
});
});

View File

@ -61,6 +61,7 @@ Object.assign(global, {
beforeEach(() => {
// make sure that each test actually tests something
// see https://jestjs.io/docs/en/expect#expecthasassertions
// eslint-disable-next-line jest/no-standalone-expect
expect.hasAssertions();
// Reset the mocked window.location. This ensures tests don't interfere with

View File

@ -304,12 +304,12 @@ describe('AlertsSettingsForm', () => {
});
describe.each`
payload | resetPayloadAndMappingConfirmed | disabled
${validSamplePayload} | ${true} | ${undefined}
${emptySamplePayload} | ${true} | ${undefined}
${validSamplePayload} | ${false} | ${'disabled'}
${emptySamplePayload} | ${false} | ${undefined}
`('', ({ payload, resetPayloadAndMappingConfirmed, disabled }) => {
context | payload | resetPayloadAndMappingConfirmed | disabled
${'valid payload, confirmed and enabled'} | ${validSamplePayload} | ${true} | ${undefined}
${'empty payload, confirmed and enabled'} | ${emptySamplePayload} | ${true} | ${undefined}
${'valid payload, unconfirmed and disabled'} | ${validSamplePayload} | ${false} | ${'disabled'}
${'empty payload, unconfirmed and enabled'} | ${emptySamplePayload} | ${false} | ${undefined}
`('given $context', ({ payload, resetPayloadAndMappingConfirmed, disabled }) => {
const payloadResetMsg = resetPayloadAndMappingConfirmed
? 'was confirmed'
: 'was not confirmed';
@ -333,12 +333,12 @@ describe('AlertsSettingsForm', () => {
describe('action buttons for sample payload', () => {
describe.each`
resetPayloadAndMappingConfirmed | payloadExample | caption
${false} | ${validSamplePayload} | ${'Edit payload'}
${true} | ${emptySamplePayload} | ${'Parse payload fields'}
${true} | ${validSamplePayload} | ${'Parse payload fields'}
${false} | ${emptySamplePayload} | ${'Parse payload fields'}
`('', ({ resetPayloadAndMappingConfirmed, payloadExample, caption }) => {
context | resetPayloadAndMappingConfirmed | payloadExample | caption
${'valid payload, unconfirmed'} | ${false} | ${validSamplePayload} | ${'Edit payload'}
${'empty payload, confirmed'} | ${true} | ${emptySamplePayload} | ${'Parse payload fields'}
${'valid payload, confirmed'} | ${true} | ${validSamplePayload} | ${'Parse payload fields'}
${'empty payload, unconfirmed'} | ${false} | ${emptySamplePayload} | ${'Parse payload fields'}
`('given $context', ({ resetPayloadAndMappingConfirmed, payloadExample, caption }) => {
const samplePayloadMsg = payloadExample ? 'was provided' : 'was not provided';
const payloadResetMsg = resetPayloadAndMappingConfirmed
? 'was confirmed'
@ -402,24 +402,27 @@ describe('AlertsSettingsForm', () => {
${true} | ${true} | ${2} | ${false}
${true} | ${false} | ${1} | ${false}
${false} | ${true} | ${1} | ${false}
`('', ({ alertFieldsProvided, multiIntegrations, integrationOption, visible }) => {
const visibleMsg = visible ? 'rendered' : 'not rendered';
const alertFieldsMsg = alertFieldsProvided ? 'provided' : 'not provided';
const integrationType = integrationOption === 1 ? typeSet.http : typeSet.prometheus;
const multiIntegrationsEnabled = multiIntegrations ? 'enabled' : 'not enabled';
`(
'given alertFieldsProvided: $alertFieldsProvided, multiIntegrations: $multiIntegrations, integrationOption: $integrationOption, visible: $visible',
({ alertFieldsProvided, multiIntegrations, integrationOption, visible }) => {
const visibleMsg = visible ? 'rendered' : 'not rendered';
const alertFieldsMsg = alertFieldsProvided ? 'provided' : 'not provided';
const integrationType = integrationOption === 1 ? typeSet.http : typeSet.prometheus;
const multiIntegrationsEnabled = multiIntegrations ? 'enabled' : 'not enabled';
it(`is ${visibleMsg} when multiIntegrations are ${multiIntegrationsEnabled}, integration type is ${integrationType} and alert fields are ${alertFieldsMsg}`, async () => {
createComponent({
multiIntegrations,
props: {
alertFields: alertFieldsProvided ? alertFields : [],
},
it(`is ${visibleMsg} when multiIntegrations are ${multiIntegrationsEnabled}, integration type is ${integrationType} and alert fields are ${alertFieldsMsg}`, async () => {
createComponent({
multiIntegrations,
props: {
alertFields: alertFieldsProvided ? alertFields : [],
},
});
await selectOptionAtIndex(integrationOption);
expect(findMappingBuilder().exists()).toBe(visible);
});
await selectOptionAtIndex(integrationOption);
expect(findMappingBuilder().exists()).toBe(visible);
});
});
},
);
});
describe('Form validation', () => {

View File

@ -1,4 +1,3 @@
import ClassSpecHelper from 'helpers/class_spec_helper';
import BindInOut from '~/behaviors/bind_in_out';
describe('BindInOut', () => {
@ -142,7 +141,9 @@ describe('BindInOut', () => {
testContext.initAll = BindInOut.initAll();
});
ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'initAll');
it('should be a static method', () => {
expect(BindInOut.initAll).toEqual(expect.any(Function));
});
it('should call .querySelectorAll', () => {
expect(document.querySelectorAll).toHaveBeenCalledWith('*[data-bind-in]');
@ -169,7 +170,9 @@ describe('BindInOut', () => {
testContext.init = BindInOut.init({}, {});
});
ClassSpecHelper.itShouldBeAStaticMethod(BindInOut, 'init');
it('should be a static method', () => {
expect(BindInOut.init).toEqual(expect.any(Function));
});
it('should call .addEvents', () => {
expect(BindInOut.prototype.addEvents).toHaveBeenCalled();

View File

@ -1047,60 +1047,58 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
let undoMutations;
describe('when re-ordering card', () => {
beforeEach(
({
itemId = 123,
fromListId = 'gid://gitlab/List/1',
toListId = 'gid://gitlab/List/1',
originalIssue = { foo: 'bar' },
originalIndex = 0,
moveBeforeId = undefined,
moveAfterId = undefined,
allItemsLoadedInList = true,
listPosition = undefined,
} = {}) => {
state = {
boardLists: {
[toListId]: { listType: ListType.backlog },
[fromListId]: { listType: ListType.backlog },
beforeEach(() => {
const itemId = 123;
const fromListId = 'gid://gitlab/List/1';
const toListId = 'gid://gitlab/List/1';
const originalIssue = { foo: 'bar' };
const originalIndex = 0;
const moveBeforeId = undefined;
const moveAfterId = undefined;
const allItemsLoadedInList = true;
const listPosition = undefined;
state = {
boardLists: {
[toListId]: { listType: ListType.backlog },
[fromListId]: { listType: ListType.backlog },
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123] },
};
params = {
itemId,
fromListId,
toListId,
moveBeforeId,
moveAfterId,
listPosition,
allItemsLoadedInList,
};
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: {
itemId,
listId: toListId,
moveBeforeId,
moveAfterId,
listPosition,
allItemsLoadedInList,
atIndex: originalIndex,
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123] },
};
params = {
itemId,
fromListId,
toListId,
moveBeforeId,
moveAfterId,
listPosition,
allItemsLoadedInList,
};
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: {
itemId,
listId: toListId,
moveBeforeId,
moveAfterId,
listPosition,
allItemsLoadedInList,
atIndex: originalIndex,
},
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
},
);
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
});
it('moveIssueCard commits a correct set of actions', () => {
testAction({
@ -1144,42 +1142,40 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
},
],
])('when %s', (_, { toListType, fromListType }) => {
beforeEach(
({
itemId = 123,
fromListId = 'gid://gitlab/List/1',
toListId = 'gid://gitlab/List/2',
originalIssue = { foo: 'bar' },
originalIndex = 0,
moveBeforeId = undefined,
moveAfterId = undefined,
} = {}) => {
state = {
boardLists: {
[fromListId]: { listType: fromListType },
[toListId]: { listType: toListType },
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123], [toListId]: [] },
};
params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: toListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
},
);
beforeEach(() => {
const itemId = 123;
const fromListId = 'gid://gitlab/List/1';
const toListId = 'gid://gitlab/List/2';
const originalIssue = { foo: 'bar' };
const originalIndex = 0;
const moveBeforeId = undefined;
const moveAfterId = undefined;
state = {
boardLists: {
[fromListId]: { listType: fromListType },
[toListId]: { listType: toListType },
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123], [toListId]: [] },
};
params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: toListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
});
it('moveIssueCard commits a correct set of actions', () => {
testAction({
@ -1216,47 +1212,45 @@ describe('moveIssueCard and undoMoveIssueCard', () => {
},
],
])('when %s', (_, { toListType, fromListType }) => {
beforeEach(
({
itemId = 123,
fromListId = 'gid://gitlab/List/1',
toListId = 'gid://gitlab/List/2',
originalIssue = { foo: 'bar' },
originalIndex = 0,
moveBeforeId = undefined,
moveAfterId = undefined,
} = {}) => {
state = {
boardLists: {
[fromListId]: { listType: fromListType },
[toListId]: { listType: toListType },
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123], [toListId]: [] },
};
params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
},
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: toListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
},
);
beforeEach(() => {
const itemId = 123;
const fromListId = 'gid://gitlab/List/1';
const toListId = 'gid://gitlab/List/2';
const originalIssue = { foo: 'bar' };
const originalIndex = 0;
const moveBeforeId = undefined;
const moveAfterId = undefined;
state = {
boardLists: {
[fromListId]: { listType: fromListType },
[toListId]: { listType: toListType },
},
boardItems: { [itemId]: originalIssue },
boardItemsByListId: { [fromListId]: [123], [toListId]: [] },
};
params = { itemId, fromListId, toListId, moveBeforeId, moveAfterId };
moveMutations = [
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: toListId, moveBeforeId, moveAfterId },
},
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
undoMutations = [
{ type: types.UPDATE_BOARD_ITEM, payload: originalIssue },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: fromListId } },
{ type: types.REMOVE_BOARD_ITEM_FROM_LIST, payload: { itemId, listId: toListId } },
{
type: types.ADD_BOARD_ITEM_TO_LIST,
payload: { itemId, listId: fromListId, atIndex: originalIndex },
},
];
});
it('moveIssueCard commits a correct set of actions', () => {
testAction({

View File

@ -1,5 +1,4 @@
import {
RECAPTCHA_API_URL_PREFIX,
RECAPTCHA_ONLOAD_CALLBACK_NAME,
clearMemoizeCache,
initRecaptchaScript,
@ -26,7 +25,7 @@ describe('initRecaptchaScript', () => {
<head>
<script
class="js-recaptcha-script"
src="${RECAPTCHA_API_URL_PREFIX}?onload=${RECAPTCHA_ONLOAD_CALLBACK_NAME}&render=explicit"
src="undefined?onload=recaptchaOnloadCallback&render=explicit"
/>
</head>
`);

View File

@ -84,7 +84,7 @@ export const describeMarkdownProcessing = (description, markdownYamlPath) => {
return;
}
it(exampleName, async () => {
it(`${exampleName}`, async () => {
await testSerializesHtmlToMarkdownForElement(example);
});
});

View File

@ -175,31 +175,6 @@ describe('DiffsStoreActions', () => {
[{ type: 'startRenderDiffsQueue' }, { type: 'startRenderDiffsQueue' }],
);
});
it.each`
viewStyle | otherView
${'inline'} | ${'parallel'}
${'parallel'} | ${'inline'}
`(
'should make a request with the view parameter "$viewStyle" when the batchEndpoint already contains "$otherView"',
({ viewStyle, otherView }) => {
const endpointBatch = '/fetch/diffs_batch';
diffActions
.fetchDiffFilesBatch({
commit: () => {},
state: {
endpointBatch: `${endpointBatch}?view=${otherView}`,
diffViewType: viewStyle,
},
})
.then(() => {
expect(mock.history.get[0].url).toContain(`view=${viewStyle}`);
expect(mock.history.get[0].url).not.toContain(`view=${otherView}`);
})
.catch(() => {});
},
);
});
describe('fetchDiffFilesMeta', () => {

View File

@ -396,7 +396,7 @@ describe('AppComponent', () => {
`(
'when `action` is $action, `groups` is $groups, `fromSearch` is $fromSearch, and `renderEmptyState` is $renderEmptyState',
({ action, groups, fromSearch, renderEmptyState, expected }) => {
it(expected ? 'renders empty state' : 'does not render empty state', async () => {
it(`${expected ? 'renders' : 'does not render'} empty state`, async () => {
createShallowComponent({
propsData: { action, renderEmptyState },
});

View File

@ -238,7 +238,7 @@ describe('NewBranchForm', () => {
scenario | mutation | alertTitle | alertText
${'with errors-as-data'} | ${mockCreateBranchMutationWithErrors} | ${CREATE_BRANCH_ERROR_WITH_CONTEXT} | ${mockCreateBranchMutationResponseWithErrors.data.createBranch.errors[0]}
${'top-level error'} | ${mockCreateBranchMutationFailed} | ${''} | ${CREATE_BRANCH_ERROR_GENERIC}
`('', ({ mutation, alertTitle, alertText }) => {
`('given $scenario', ({ mutation, alertTitle, alertText }) => {
beforeEach(async () => {
createComponent({
mockApollo: createMockApolloProvider({

View File

@ -81,7 +81,7 @@ describe('DiscussionActions', () => {
});
});
it(shouldRender ? 'renders resolve buttons' : 'does not render resolve buttons', () => {
it(`${shouldRender ? 'renders' : 'does not render'} resolve buttons`, () => {
expect(wrapper.findComponent(ResolveDiscussionButton).exists()).toBe(shouldRender);
expect(wrapper.findComponent(ResolveWithIssueButton).exists()).toBe(shouldRender);
});

View File

@ -58,7 +58,7 @@ describe('Harbor tag list row', () => {
expect(findByTestId('name').text()).toBe(harborTagsList[0].name);
});
describe(' clipboard button', () => {
describe('clipboard button', () => {
it('exists', () => {
expect(findClipboardButton().exists()).toBe(true);
});

View File

@ -74,7 +74,7 @@ describe('Infrastructure Title', () => {
mountComponent({ ...exampleProps, count });
});
it(exist ? 'exists' : 'does not exist', () => {
it(`${exist ? 'exists' : 'does not exist'}`, () => {
expect(findMetadataItem().exists()).toBe(exist);
});

View File

@ -317,7 +317,7 @@ describe('Release edit/new getters', () => {
{ milestones: ['release.milestone[0].title'] },
],
])('releaseUpdateMutatationVariables', (description, state, expectedVariables) => {
it(description, () => {
it(`${description}`, () => {
const expectedVariablesObject = { input: expect.objectContaining(expectedVariables) };
const actualVariables = getters.releaseUpdateMutatationVariables(state, {

View File

@ -281,7 +281,7 @@ describe('App component', () => {
});
});
it(shouldRender ? 'renders' : 'does not render', () => {
it(`${shouldRender ? 'renders' : 'does not render'}`, () => {
expect(findAutoDevopsEnabledAlert().exists()).toBe(shouldRender);
});
});

View File

@ -9,7 +9,7 @@ describe('~/snippet/collapsible_input', () => {
beforeEach(() => {
setHTMLFixture(`
<form>
<form>
<div class="js-collapsible-input js-title">
<div class="js-collapsed d-none">
<input type="text" />
@ -72,7 +72,7 @@ describe('~/snippet/collapsible_input', () => {
${'is collapsed'} | ${''} | ${true}
${'stays open if given value'} | ${'Hello world!'} | ${false}
`('when loses focus', ({ desc, value, isCollapsed }) => {
it(desc, () => {
it(`${desc}`, () => {
findExpandedInput(descriptionEl).value = value;
focusIn(fooEl);

View File

@ -62,7 +62,7 @@ describe('WorkItemDueDate component', () => {
createComponent({ canUpdate: true, startDate });
});
it(exists ? 'renders' : 'does not render', () => {
it(`${exists ? 'renders' : 'does not render'}`, () => {
expect(findStartDateButton().exists()).toBe(exists);
});
});
@ -172,7 +172,7 @@ describe('WorkItemDueDate component', () => {
createComponent({ canUpdate: true, dueDate });
});
it(exists ? 'renders' : 'does not render', () => {
it(`${exists ? 'renders' : 'does not render'}`, () => {
expect(findDueDateButton().exists()).toBe(exists);
});
});

View File

@ -121,6 +121,7 @@ describe('diffs third party interoperability', () => {
vm = startDiffsApp();
// eslint-disable-next-line jest/no-standalone-expect
await waitFor(() => expect(hasLines(rowSelector)).toBe(true));
});

View File

@ -0,0 +1,60 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::ParsePackageService do
let(:package_file) { File.open('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }
describe 'dynamic private methods' do
described_class::BUILD_ATTRIBUTES_METHOD_NAMES.each do |attribute|
it 'define dynamic build attribute method' do
expect(described_class).to be_private_method_defined("build_#{attribute}")
end
end
end
describe '#execute' do
subject { described_class.new(package_file).execute }
shared_examples 'valid package parsing' do
it 'return hash' do
expect(subject).to be_a(Hash)
end
it 'has all static attribute keys' do
expect(subject.keys).to include(*described_class::STATIC_ATTRIBUTES)
end
it 'includes epoch attribute' do
expect(subject[:epoch]).not_to be_blank
end
it 'has all built attributes with array values' do
result = subject
described_class::BUILD_ATTRIBUTES_METHOD_NAMES.each do |attribute|
expect(result).to have_key(attribute)
expect(result[attribute]).to be_a(Array)
end
end
end
context 'when wrong format file received' do
let(:package_file) { File.open('spec/fixtures/rails_sample.jpg') }
it 'raise error' do
expect { subject }.to raise_error(ArgumentError)
end
end
context 'when valid file uploaded' do
context 'when .rpm file uploaded' do
it_behaves_like 'valid package parsing'
end
context 'when .src.rpm file uploaded' do
let(:package_file) { File.open('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.src.rpm') }
it_behaves_like 'valid package parsing'
end
end
end
end

115
yarn.lock
View File

@ -1037,10 +1037,10 @@
resolved "https://registry.yarnpkg.com/@gitlab/at.js/-/at.js-1.5.7.tgz#1ee6f838cc4410a1d797770934df91d90df8179e"
integrity sha512-c6ySRK/Ma7lxwpIVbSAF3P+xiTLrNTGTLRx4/pHK111AdFxwgUwrYF6aVZFXvmG65jHOJHoa0eQQ21RW6rm0Rg==
"@gitlab/eslint-plugin@17.0.0":
version "17.0.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-17.0.0.tgz#5451fbbad96b09d812af2afb247f6602fe0be6c6"
integrity sha512-c+sJtjzYl+KGPtZScU8Mji9seJw7dSEn31APyYEYTyWp72yMsFvXmg46txT2QCz+ueZlqk0/C2IQmgfe6fLcBw==
"@gitlab/eslint-plugin@18.1.0":
version "18.1.0"
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-18.1.0.tgz#8300cc938f50114b3e74d97660721486c13caea5"
integrity sha512-O803ResZfPpbSk8USzYwT79OXKSyuR4z4qbjOae/NIhzobxrlEHm4LbauVuaFpHurF5gYceNtHltczwK8e+mOg==
dependencies:
"@babel/core" "^7.17.0"
"@babel/eslint-parser" "^7.17.0"
@ -1049,8 +1049,8 @@
eslint-config-prettier "^6.10.0"
eslint-plugin-babel "^5.3.0"
eslint-plugin-import "^2.26.0"
eslint-plugin-jest "^23.8.2"
eslint-plugin-promise "^4.2.1"
eslint-plugin-jest "^27.0.4"
eslint-plugin-promise "^6.0.1"
eslint-plugin-unicorn "^40.1.0"
eslint-plugin-vue "^9.3.0"
lodash "^4.17.21"
@ -2066,7 +2066,7 @@
jest-matcher-utils "^27.0.0"
pretty-format "^27.0.0"
"@types/json-schema@^7.0.0", "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
"@types/json-schema@^7.0.0", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
version "7.0.11"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3"
integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==
@ -2223,28 +2223,51 @@
dependencies:
"@types/yargs-parser" "*"
"@typescript-eslint/experimental-utils@^2.5.0":
version "2.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.30.0.tgz#9845e868c01f3aed66472c561d4b6bac44809dd0"
integrity sha512-L3/tS9t+hAHksy8xuorhOzhdefN0ERPDWmR9CclsIGOUqGKy6tqc/P+SoXeJRye5gazkuPO0cK9MQRnolykzkA==
"@typescript-eslint/scope-manager@5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.38.0.tgz#8f0927024b6b24e28671352c93b393a810ab4553"
integrity sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==
dependencies:
"@types/json-schema" "^7.0.3"
"@typescript-eslint/typescript-estree" "2.30.0"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
"@typescript-eslint/types" "5.38.0"
"@typescript-eslint/visitor-keys" "5.38.0"
"@typescript-eslint/typescript-estree@2.30.0":
version "2.30.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.30.0.tgz#1b8e848b55144270255ffbfe4c63291f8f766615"
integrity sha512-nI5WOechrA0qAhnr+DzqwmqHsx7Ulr/+0H7bWCcClDhhWkSyZR5BmTvnBEyONwJCTWHfc5PAQExX24VD26IAVw==
"@typescript-eslint/types@5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.38.0.tgz#8cd15825e4874354e31800dcac321d07548b8a5f"
integrity sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==
"@typescript-eslint/typescript-estree@5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.38.0.tgz#89f86b2279815c6fb7f57d68cf9b813f0dc25d98"
integrity sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==
dependencies:
debug "^4.1.1"
eslint-visitor-keys "^1.1.0"
glob "^7.1.6"
is-glob "^4.0.1"
lodash "^4.17.15"
semver "^6.3.0"
tsutils "^3.17.1"
"@typescript-eslint/types" "5.38.0"
"@typescript-eslint/visitor-keys" "5.38.0"
debug "^4.3.4"
globby "^11.1.0"
is-glob "^4.0.3"
semver "^7.3.7"
tsutils "^3.21.0"
"@typescript-eslint/utils@^5.10.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.38.0.tgz#5b31f4896471818153790700eb02ac869a1543f4"
integrity sha512-6sdeYaBgk9Fh7N2unEXGz+D+som2QCQGPAf1SxrkEr+Z32gMreQ0rparXTNGRRfYUWk/JzbGdcM8NSSd6oqnTA==
dependencies:
"@types/json-schema" "^7.0.9"
"@typescript-eslint/scope-manager" "5.38.0"
"@typescript-eslint/types" "5.38.0"
"@typescript-eslint/typescript-estree" "5.38.0"
eslint-scope "^5.1.1"
eslint-utils "^3.0.0"
"@typescript-eslint/visitor-keys@5.38.0":
version "5.38.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.38.0.tgz#60591ca3bf78aa12b25002c0993d067c00887e34"
integrity sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==
dependencies:
"@typescript-eslint/types" "5.38.0"
eslint-visitor-keys "^3.3.0"
"@vue/component-compiler-utils@^3.1.0":
version "3.3.0"
@ -5358,12 +5381,12 @@ eslint-plugin-import@^2.26.0:
resolve "^1.22.0"
tsconfig-paths "^3.14.1"
eslint-plugin-jest@^23.8.2:
version "23.8.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-23.8.2.tgz#6f28b41c67ef635f803ebd9e168f6b73858eb8d4"
integrity sha512-xwbnvOsotSV27MtAe7s8uGWOori0nUsrXh2f1EnpmXua8sDfY6VZhHAhHg2sqK7HBNycRQExF074XSZ7DvfoFg==
eslint-plugin-jest@^27.0.4:
version "27.0.4"
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.0.4.tgz#ab9c7b3f48bfade4762c24c415a5d9bbc0174a61"
integrity sha512-BuvY78pHMpMJ6Cio7sKg6jrqEcnRYPUc4Nlihku4vKx3FjlmMINSX4vcYokZIe+8TKcyr1aI5Kq7vYwgJNdQSA==
dependencies:
"@typescript-eslint/experimental-utils" "^2.5.0"
"@typescript-eslint/utils" "^5.10.0"
eslint-plugin-no-jquery@2.7.0:
version "2.7.0"
@ -5375,10 +5398,10 @@ eslint-plugin-no-unsanitized@^4.0.1:
resolved "https://registry.yarnpkg.com/eslint-plugin-no-unsanitized/-/eslint-plugin-no-unsanitized-4.0.1.tgz#e2343265467ba2270ade478cbe07bbafeaea412d"
integrity sha512-y/lAMWnPPC7RYuUdxlEL/XiCL8FehN9h9s3Kjqbp/Kv0i9NZs+IXSC2kS546Fa4Bumwy31HlVS/OdWX0Kxb5Xg==
eslint-plugin-promise@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
eslint-plugin-promise@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz#a8cddf96a67c4059bdabf4d724a29572188ae423"
integrity sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==
eslint-plugin-unicorn@^40.1.0:
version "40.1.0"
@ -5426,7 +5449,7 @@ eslint-scope@^4.0.3:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
eslint-scope@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
@ -5442,13 +5465,6 @@ eslint-scope@^7.1.1:
esrecurse "^4.3.0"
estraverse "^5.2.0"
eslint-utils@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
dependencies:
eslint-visitor-keys "^1.1.0"
eslint-utils@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
@ -5456,11 +5472,6 @@ eslint-utils@^3.0.0:
dependencies:
eslint-visitor-keys "^2.0.0"
eslint-visitor-keys@^1.1.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==
eslint-visitor-keys@^2.0.0, eslint-visitor-keys@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303"
@ -11704,10 +11715,10 @@ tslib@^2, tslib@^2.1.0, tslib@^2.2.0, tslib@^2.3.0, tslib@^2.4.0, tslib@~2.4.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
tsutils@^3.17.1:
version "3.17.1"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759"
integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g==
tsutils@^3.21.0:
version "3.21.0"
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
dependencies:
tslib "^1.8.1"