Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-01-11 03:07:33 +00:00
parent feb7a8f326
commit e2c044cf3f
85 changed files with 4213 additions and 481 deletions

View File

@ -603,7 +603,7 @@ ee:importers:
extends: .qa
variables:
QA_SCENARIO: Test::Integration::Import
QA_MOCK_GITHUB: "false"
QA_MOCK_GITHUB: "true"
GITLAB_QA_OPTS: --set-feature-flags bulk_import_projects=enabled
rules:
- !reference [.rules:test:qa, rules]

View File

@ -4,4 +4,3 @@ Database/MultipleDatabases:
- 'db/post_migrate/20210317104032_set_iteration_cadence_automatic_to_false.rb'
- 'db/post_migrate/20210811122206_update_external_project_bots.rb'
- 'db/post_migrate/20210812013042_remove_duplicate_project_authorizations.rb'
- 'ee/spec/services/ee/merge_requests/update_service_spec.rb'

View File

@ -8,7 +8,7 @@ import {
GlSprintf,
} from '@gitlab/ui';
import { sortBy } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
import { mapActions, mapState } from 'vuex';
import boardCardInner from 'ee_else_ce/boards/mixins/board_card_inner';
import { isScopedLabel } from '~/lib/utils/common_utils';
import { updateHistory } from '~/lib/utils/url_utility';
@ -43,7 +43,7 @@ export default {
GlTooltip: GlTooltipDirective,
},
mixins: [boardCardInner],
inject: ['rootPath', 'scopedLabelsAvailable', 'isEpicBoard', 'issuableType'],
inject: ['rootPath', 'scopedLabelsAvailable', 'isEpicBoard', 'issuableType', 'isGroupBoard'],
props: {
item: {
type: Object,
@ -78,7 +78,6 @@ export default {
},
computed: {
...mapState(['isShowingLabels', 'allowSubEpics']),
...mapGetters(['isProjectBoard']),
cappedAssignees() {
// e.g. maxRender is 4,
// Render up to all 4 assignees if there are only 4 assigness
@ -158,7 +157,7 @@ export default {
return Math.round((this.item.descendantWeightSum.closedIssues / this.totalWeight) * 100);
},
showReferencePath() {
return !this.isProjectBoard && this.itemReferencePath;
return this.isGroupBoard && this.itemReferencePath;
},
avatarSize() {
return { default: 16, lg: 24 };

View File

@ -9,7 +9,7 @@ import { s__ } from '~/locale';
import { formatBoardLists } from 'ee_else_ce/boards/boards_util';
import BoardAddNewColumn from 'ee_else_ce/boards/components/board_add_new_column.vue';
import { defaultSortableOptions } from '~/sortable/constants';
import { DraggableItemTypes, BoardType, listsQuery } from 'ee_else_ce/boards/constants';
import { DraggableItemTypes, listsQuery } from 'ee_else_ce/boards/constants';
import BoardColumn from './board_column.vue';
export default {
@ -35,6 +35,7 @@ export default {
'issuableType',
'isIssueBoard',
'isEpicBoard',
'isGroupBoard',
'isApolloBoard',
],
props: {
@ -89,8 +90,8 @@ export default {
queryVariables() {
return {
...(this.isIssueBoard && {
isGroup: this.boardType === BoardType.group,
isProject: this.boardType === BoardType.project,
isGroup: this.isGroupBoard,
isProject: !this.isGroupBoard,
}),
fullPath: this.fullPath,
boardId: this.boardId,

View File

@ -6,7 +6,7 @@ import SidebarDropdownWidget from 'ee_else_ce/sidebar/components/sidebar_dropdow
import { __, sprintf } from '~/locale';
import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { ISSUABLE, INCIDENT, issuableTypes } from '~/boards/constants';
import { BoardType, ISSUABLE, INCIDENT, issuableTypes } from '~/boards/constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
@ -68,11 +68,13 @@ export default {
issuableType: {
default: issuableTypes.issue,
},
isGroupBoard: {
default: false,
},
},
inheritAttrs: false,
computed: {
...mapGetters([
'isGroupBoard',
'isSidebarOpen',
'activeBoardItem',
'groupPathForActiveIssue',
@ -94,14 +96,17 @@ export default {
fullPath() {
return this.activeBoardItem?.referencePath?.split('#')[0] || '';
},
parentType() {
return this.isGroupBoard ? BoardType.group : BoardType.project;
},
createLabelTitle() {
return sprintf(__('Create %{workspace} label'), {
workspace: this.isGroupBoard ? 'group' : 'project',
workspace: this.parentType,
});
},
manageLabelTitle() {
return sprintf(__('Manage %{workspace} labels'), {
workspace: this.isGroupBoard ? 'group' : 'project',
workspace: this.parentType,
});
},
attrWorkspacePath() {

View File

@ -1,6 +1,6 @@
<script>
import { GlModal, GlAlert } from '@gitlab/ui';
import { mapGetters, mapActions, mapState } from 'vuex';
import { mapActions, mapState } from 'vuex';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { visitUrl, updateHistory, getParameterByName } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale';
@ -51,6 +51,12 @@ export default {
boardBaseUrl: {
default: '',
},
isGroupBoard: {
default: false,
},
isProjectBoard: {
default: false,
},
},
props: {
canAdminBoard: {
@ -84,7 +90,6 @@ export default {
},
computed: {
...mapState(['error']),
...mapGetters(['isGroupBoard', 'isProjectBoard']),
isNewForm() {
return this.currentPage === formType.new;
},

View File

@ -16,7 +16,7 @@ export default {
ProjectSelect,
},
mixins: [BoardNewIssueMixin],
inject: ['groupId', 'fullPath'],
inject: ['groupId', 'fullPath', 'isGroupBoard'],
props: {
list: {
type: Object,
@ -25,7 +25,7 @@ export default {
},
computed: {
...mapState(['selectedProject']),
...mapGetters(['isGroupBoard', 'getBoardItemsByList']),
...mapGetters(['getBoardItemsByList']),
formEventPrefix() {
return toggleFormEventPrefix.issue;
},

View File

@ -9,7 +9,7 @@ import {
GlModalDirective,
} from '@gitlab/ui';
import { throttle } from 'lodash';
import { mapActions, mapGetters, mapState } from 'vuex';
import { mapActions, mapState } from 'vuex';
import BoardForm from 'ee_else_ce/boards/components/board_form.vue';
@ -50,6 +50,7 @@ export default {
'scopedIssueBoardFeatureEnabled',
'weights',
'boardType',
'isGroupBoard',
],
props: {
throttleDuration: {
@ -76,7 +77,6 @@ export default {
computed: {
...mapState(['board', 'isBoardLoading']),
...mapGetters(['isGroupBoard', 'isProjectBoard']),
parentType() {
return this.boardType;
},

View File

@ -4,7 +4,6 @@ import fuzzaldrinPlus from 'fuzzaldrin-plus';
import { mapActions } from 'vuex';
import { orderBy } from 'lodash';
import BoardFilteredSearch from 'ee_else_ce/boards/components/board_filtered_search.vue';
import { BoardType } from '~/boards/constants';
import axios from '~/lib/utils/axios_utils';
import { joinPaths } from '~/lib/utils/url_utility';
import issueBoardFilters from '~/boards/issue_board_filters';
@ -47,23 +46,15 @@ export default {
issue: __('Issue'),
},
components: { BoardFilteredSearch },
inject: ['isSignedIn', 'releasesFetchPath', 'fullPath', 'boardType'],
inject: ['isSignedIn', 'releasesFetchPath', 'fullPath', 'isGroupBoard'],
computed: {
isGroupBoard() {
return this.boardType === BoardType.group;
},
epicsGroupPath() {
return this.isGroupBoard
? this.fullPath
: this.fullPath.slice(0, this.fullPath.lastIndexOf('/'));
},
tokensCE() {
const { issue, incident } = this.$options.i18n;
const { types } = this.$options;
const { fetchUsers, fetchLabels } = issueBoardFilters(
this.$apollo,
this.fullPath,
this.boardType,
this.isGroupBoard,
);
const tokens = [

View File

@ -3,7 +3,7 @@ import Vue from 'vue';
import VueApollo from 'vue-apollo';
import BoardApp from '~/boards/components/board_app.vue';
import '~/boards/filters/due_date_filters';
import { issuableTypes } from '~/boards/constants';
import { BoardType, issuableTypes } from '~/boards/constants';
import store from '~/boards/stores';
import {
NavigationType,
@ -31,17 +31,19 @@ function mountBoardApp(el) {
...convertObjectPropsToCamelCase(rawFilterParams),
};
const boardType = el.dataset.parent;
store.dispatch('fetchBoard', {
fullPath,
fullBoardId: fullBoardId(boardId),
boardType: el.dataset.parent,
boardType,
});
store.dispatch('setInitialBoardData', {
boardId,
fullBoardId: fullBoardId(boardId),
fullPath,
boardType: el.dataset.parent,
boardType,
disabled: parseBoolean(el.dataset.disabled) || true,
issuableType: issuableTypes.issue,
});
@ -61,7 +63,9 @@ function mountBoardApp(el) {
fullPath,
initialFilterParams,
boardBaseUrl: el.dataset.boardBaseUrl,
boardType: el.dataset.parent,
boardType,
isGroupBoard: boardType === BoardType.group,
isProjectBoard: boardType === BoardType.project,
currentUserId: gon.current_user_id || null,
boardWeight: el.dataset.boardWeight ? parseInt(el.dataset.boardWeight, 10) : null,
labelsManagePath: el.dataset.labelsManagePath,

View File

@ -1,11 +1,8 @@
import groupBoardMembers from '~/boards/graphql/group_board_members.query.graphql';
import projectBoardMembers from '~/boards/graphql/project_board_members.query.graphql';
import { BoardType } from './constants';
import boardLabels from './graphql/board_labels.query.graphql';
export default function issueBoardFilters(apollo, fullPath, boardType) {
const isGroupBoard = boardType === BoardType.group;
const isProjectBoard = boardType === BoardType.project;
export default function issueBoardFilters(apollo, fullPath, isGroupBoard) {
const transformLabels = ({ data }) => {
return isGroupBoard ? data.group?.labels.nodes || [] : data.project?.labels.nodes || [];
};
@ -34,7 +31,7 @@ export default function issueBoardFilters(apollo, fullPath, boardType) {
fullPath,
searchTerm: labelSearchTerm,
isGroup: isGroupBoard,
isProject: isProjectBoard,
isProject: !isGroupBoard,
},
})
.then(transformLabels);

View File

@ -1,9 +1,7 @@
import { find } from 'lodash';
import { BoardType, inactiveId, issuableTypes } from '../constants';
import { inactiveId, issuableTypes } from '../constants';
export default {
isGroupBoard: (state) => state.boardType === BoardType.group,
isProjectBoard: (state) => state.boardType === BoardType.project,
isSidebarOpen: (state) => state.activeId !== inactiveId,
isSwimlanesOn: () => false,
getBoardItemById: (state) => (id) => {

View File

@ -161,7 +161,7 @@ export default {
:work-item-parent-id="issueGid"
:work-item-id="displayedWorkItemId"
:work-item-iid="workItemIid"
class="gl-p-5 gl-mt-n3"
class="gl-p-5 gl-mt-n3 gl-reset-bg gl-isolate"
@close="hide"
@deleteWorkItem="deleteWorkItem"
@update-modal="updateModal"

View File

@ -294,3 +294,7 @@ to @gitlab/ui by https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1709
.gl-max-w-0 {
max-width: 0;
}
.gl-isolate {
isolation: isolate;
}

View File

@ -75,6 +75,13 @@ The `deploy-to-cloud-run` job:
* `GCP_PROJECT_ID`
* `GCP_SERVICE_ACCOUNT_KEY`
* Job definition can be found at: https://gitlab.com/gitlab-org/incubation-engineering/five-minute-production/library
* Uses CI/CD variables to configure the deployment. You can override the default values by adding these variables:
* `GCP_CLOUD_RUN_MAX_INSTANCES`
* `GCP_CLOUD_RUN_MIN_INSTANCES`
* `GCP_CLOUD_RUN_CONCURRENCY`
* `GCP_CLOUD_RUN_CPU`
* `GCP_CLOUD_RUN_MEMORY`
* `GCP_CLOUD_RUN_TIMEOUT`
This pipeline definition has been committed to the branch `#{branch_name}`.
You may modify the pipeline definition further or accept the changes as-is if suitable.

File diff suppressed because it is too large Load Diff

View File

@ -5727,11 +5727,12 @@ Input type: `UpdateRequirementInput`
| ---- | ---- | ----------- |
| <a id="mutationupdaterequirementclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationupdaterequirementdescription"></a>`description` | [`String`](#string) | Description of the requirement. |
| <a id="mutationupdaterequirementiid"></a>`iid` | [`String!`](#string) | IID of the requirement to update. |
| <a id="mutationupdaterequirementiid"></a>`iid` | [`String`](#string) | IID of the requirement to update. |
| <a id="mutationupdaterequirementlasttestreportstate"></a>`lastTestReportState` | [`TestReportState`](#testreportstate) | Creates a test report for the requirement with the given state. |
| <a id="mutationupdaterequirementprojectpath"></a>`projectPath` | [`ID!`](#id) | Full project path the requirement is associated with. |
| <a id="mutationupdaterequirementstate"></a>`state` | [`RequirementState`](#requirementstate) | State of the requirement. |
| <a id="mutationupdaterequirementtitle"></a>`title` | [`String`](#string) | Title of the requirement. |
| <a id="mutationupdaterequirementworkitemiid"></a>`workItemIid` | [`String`](#string) | IID of the requirement work item to update. |
#### Fields

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module QA
module Resource
class GroupRunner < RunnerBase
attribute :group do
Resource::Group.fabricate_via_api! do |resource|
resource.name = "group-with-ci-cd-#{SecureRandom.hex(8)}"
resource.description = 'Group with CI/CD Pipelines'
end
end
attribute :token do
group.runners_token
rescue NoValueError
group.reload!.runners_token
end
private
def runner(**kwargs)
fail_msg = "Wait for runner '#{name}' to register in group '#{group.name}'"
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: fail_msg) do
auto_paginated_response(request_url("/runners", **kwargs)).find { |runner| runner[:description] == name }
end
end
end
end
end

View File

@ -10,25 +10,25 @@ module QA
include ApprovalConfiguration
attr_accessor :initialize_with_readme,
:auto_devops_enabled,
:github_personal_access_token,
:github_repository_path,
:gitlab_repository_path,
:personal_namespace
:auto_devops_enabled,
:github_personal_access_token,
:github_repository_path,
:gitlab_repository_path,
:personal_namespace
attr_reader :repository_storage
attributes :id,
:name,
:path,
:add_name_uuid,
:runners_token,
:visibility,
:template_name,
:import,
:import_status,
:import_error,
:description
:name,
:path,
:add_name_uuid,
:runners_token,
:visibility,
:template_name,
:import,
:import_status,
:import_error,
:description
attribute :group do
Group.fabricate! do |group|
@ -43,7 +43,7 @@ module QA
alias_method :full_path, :path_with_namespace
def sandbox_path
return '' if personal_namespace || !group.respond_to?('sandbox')
return '' if personal_namespace || !group.respond_to?(:sandbox)
"#{group.sandbox.path}/"
end
@ -450,6 +450,14 @@ module QA
parse_body(response)
end
# Fetch project specific runners
#
# @param [Hash] **kwargs optional query arguments, see: https://docs.gitlab.com/ee/api/runners.html#list-projects-runners
# @return [Array]
def runners(**kwargs)
auto_paginated_response(request_url(api_runners_path, **kwargs))
end
# Uses the API to wait until a pull mirroring update is successful (pull mirroring is treated as an import)
def wait_for_pull_mirroring
mirror_succeeded = Support::Retrier.retry_until(

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
module QA
module Resource
class ProjectRunner < RunnerBase
attribute :project do
Project.fabricate_via_api! do |resource|
resource.name = 'project-with-ci-cd'
resource.description = 'Project with CI/CD Pipelines'
end
end
attribute :token do
project.runners_token
rescue NoValueError
project.reload!.runners_token
end
private
def runner(**kwargs)
fail_msg = "Wait for runner '#{name}' to register in project '#{project.name}'"
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1, message: fail_msg) do
project.runners(**kwargs).find { |runner| runner[:description] == name }
end
end
end
end
end

View File

@ -1,148 +0,0 @@
# frozen_string_literal: true
module QA
module Resource
class Runner < Base
attributes :id,
:active,
:paused,
:runner_type,
:online,
:status,
:ip_address,
:token,
:tags,
:config,
:run_untagged,
:name, # This attribute == runner[:description]
:image,
:executor,
:executor_image
attribute :project do
Project.fabricate_via_api! do |resource|
resource.name = 'project-with-ci-cd'
resource.description = 'Project with CI/CD Pipelines'
end
end
def initialize
@tags = nil
@config = nil
@run_untagged = nil
@name = "qa-runner-#{SecureRandom.hex(4)}"
@image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine'
@executor = :shell
@executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7'
end
# Initially we only support fabricate
# via API
def fabricate!
fabricate_via_api!
end
# Start container and register runner
# Fetch via API and populate attributes
#
def fabricate_via_api!
start_container_and_register
populate_runner_attributes
end
def remove_via_api!
super
ensure
@docker_container.remove!
end
def reload!
populate_runner_attributes
end
def api_delete_path
"/runners/#{id}"
end
def api_get_path
"/runners"
end
def api_post_path
"/runners"
end
def api_post_body; end
def not_found_by_tags?
url = "#{api_get_path}?tag_list=#{tags.compact.join(',')}"
auto_paginated_response(request_url(url)).empty?
end
def runners_list
runners_list = nil
url = tags ? "#{api_get_path}?tag_list=#{tags.compact.join(',')}" : api_get_path
Runtime::Logger.info('Looking for list of runners via API...')
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do
runners_list = auto_paginated_response(request_url(url))
runners_list.present?
end
runners_list
end
def wait_until_online
Runtime::Logger.info('Waiting for runner to come online...')
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do
this_runner[:status] == 'online'
end
end
def restart
Runtime::Logger.info("Restarting runner container #{name}...")
@docker_container.restart
wait_until_online
end
private
def start_container_and_register
@docker_container = Service::DockerRun::GitlabRunner.new(name).tap do |runner|
Support::Retrier.retry_on_exception(sleep_interval: 5) do
runner.pull
end
runner.token = @token ||= project.runners_token
runner.address = Runtime::Scenario.gitlab_address
runner.tags = tags if tags
runner.image = image
runner.config = config if config
runner.executor = executor
runner.executor_image = executor_image if executor == :docker
runner.run_untagged = run_untagged if run_untagged
runner.register!
end
end
def this_runner
runner = nil
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do
runner = runners_list.find { |runner| runner[:description] == name }
!runner.nil?
end
runner
end
def populate_runner_attributes
runner = this_runner
@id = runner[:id]
@active = runner[:active]
@paused = runner[:paused]
@runner_type = runner[:typed]
@online = runner[:online]
@status = runner[:status]
@ip_address = runner[:ip_address]
end
end
end
end

View File

@ -0,0 +1,129 @@
# frozen_string_literal: true
module QA
module Resource
class RunnerBase < Base
attr_accessor :run_untagged,
:image,
:executor,
:executor_image,
:tags,
:config
attributes :id,
:active,
:paused,
:runner_type,
:online,
:status,
:ip_address,
:description,
:name,
:is_shared,
:contacted_at,
:platform,
:architecture,
:projects,
:revision,
:tag_list,
:version,
:access_level,
:maximum_timeout
def initialize
@tags = nil
@config = nil
@run_untagged = nil
@name = "qa-runner-#{SecureRandom.hex(4)}"
@image = 'registry.gitlab.com/gitlab-org/gitlab-runner:alpine'
@executor = :shell
@executor_image = 'registry.gitlab.com/gitlab-org/gitlab-build-images:gitlab-qa-alpine-ruby-2.7'
end
# Initially we only support fabricate via API
def fabricate!
fabricate_via_api!
end
# Start container and register runner
# Fetch via API and populate attributes
#
def fabricate_via_api!
api_get
rescue NoValueError
# Start container on initial fabrication and populate all attributes once id is known
# see: https://docs.gitlab.com/ee/api/runners.html#get-runners-details
start_container_and_register
api_get
end
def remove_via_api!
super
ensure
@docker_container.remove!
@docker_container = nil
end
def api_get_path
"/runners/#{id}"
end
def api_post_path
"/runners"
end
def api_delete_path
api_get_path
end
def api_post_body; end
def wait_until_online
Runtime::Logger.info('Waiting for runner to come online...')
Support::Retrier.retry_until(max_duration: 60, sleep_interval: 1) do
reload! && status == 'online'
end
end
def restart
Runtime::Logger.info("Restarting runner container #{name}...")
@docker_container.restart
wait_until_online
end
private
def start_container_and_register
@docker_container ||= Service::DockerRun::GitlabRunner.new(name).tap do |runner|
Support::Retrier.retry_on_exception(sleep_interval: 5) do
runner.pull
end
runner.token = token
runner.address = Runtime::Scenario.gitlab_address
runner.tags = tags if tags
runner.image = image
runner.config = config if config
runner.executor = executor
runner.executor_image = executor_image if executor == :docker
runner.run_untagged = run_untagged if run_untagged
runner.register!
end
populate_initial_id
rescue StandardError => e
@docker_container&.remove!
raise(e)
end
def populate_initial_id
tag_list = tags ? { tag_list: tags.compact.join(',') } : {}
runner = runner(**tag_list)
@id = runner[:id]
end
def runner(**kwargs)
raise("Not implemented!")
end
end
end
end

View File

@ -8,6 +8,10 @@ module QA
def qa_root
::File.expand_path('../../', __dir__)
end
def fixtures_path
::File.expand_path('../fixtures', __dir__)
end
end
end
end

View File

@ -36,6 +36,8 @@ module QA
end
def register!
raise("Missing runner token value!") unless token
cmd = <<~CMD.tr("\n", ' ')
docker run -d --rm --network #{runner_network} --name #{@name}
#{'-v /var/run/docker.sock:/var/run/docker.sock' if @executor == :docker}

View File

@ -7,26 +7,45 @@ module QA
def initialize
@image = 'thiht/smocker:0.17.1'
@name = 'smocker-server'
@public_port = '8080'
@admin_port = '8081'
@public_port = 8080
@admin_port = 8081
super
@network_cache = network
end
# @param wait [Integer] seconds to wait for server
# @yieldparam [SmockerApi] the api object ready for interaction
def self.init(wait: 10)
if @container.nil?
@container = new
@container.register!
@container.wait_for_running
@api = Vendor::Smocker::SmockerApi.new(
host: @container.host_name,
public_port: @container.public_port,
admin_port: @container.admin_port
)
@api.wait_for_ready(wait: wait)
end
yield @api
end
def self.teardown!
@container&.remove!
@container = nil
@api = nil
end
attr_reader :public_port, :admin_port
def host_name
return '127.0.0.1' unless QA::Runtime::Env.running_in_ci? || QA::Runtime::Env.qa_hostname
"#{@name}.#{@network_cache}"
end
def base_url
"http://#{host_name}:#{@public_port}"
end
def admin_url
"http://#{host_name}:#{@admin_port}"
end
def wait_for_running
Support::Waiter.wait_until(raise_on_failure: false, reload_page: false) do
running?

View File

@ -9,10 +9,7 @@ module QA
context 'when imported via api' do
it 'imports project', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/347670' do
imported_project.reload! # import the project
expect { imported_project.project_import_status[:import_status] }.to eventually_eq('finished')
.within(max_duration: 240, sleep_interval: 1)
expect_project_import_finished_successfully
aggregate_failures do
verify_status_data

View File

@ -8,7 +8,7 @@ module QA
end
after(:context) do
Vendor::Smocker::SmockerApi.teardown!
Service::DockerRun::Smocker.teardown!
end
let(:session) { SecureRandom.hex(5) }
@ -72,7 +72,7 @@ module QA
end
it 'sends an issues and note event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/349723' do
setup_webhook(issues: true, note: true) do |webhook, smocker|
issue = Resource::Issue.fabricate_via_api! do |issue_init|
issue_init.project = webhook.project
@ -100,7 +100,7 @@ module QA
end
it 'sends a tag event',
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383577' do
testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/383577' do
setup_webhook(tag_push: true) do |webhook, smocker|
project_push = Resource::Repository::ProjectPush.fabricate! do |project_push|
project_push.project = webhook.project
@ -128,7 +128,7 @@ module QA
private
def setup_webhook(**event_args)
Vendor::Smocker::SmockerApi.init(wait: 10) do |smocker|
Service::DockerRun::Smocker.init(wait: 10) do |smocker|
smocker.register(session: session)
webhook = Resource::ProjectWebHook.fabricate_via_api! do |hook|

View File

@ -18,7 +18,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = "runner-for-#{project.name}"
runner.tags = ["runner-for-#{project.name}"]

View File

@ -12,7 +12,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -1,33 +0,0 @@
# frozen_string_literal: true
module QA
RSpec.describe 'Verify', :runner, product_group: :runner do
describe 'Runner removal' do
include Support::API
let(:api_client) { Runtime::API::Client.new(:gitlab) }
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:runner_tags) { ["runner-registration-e2e-test-#{Faker::Alphanumeric.alphanumeric(number: 8)}"] }
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.name = executor
runner.tags = runner_tags
end
end
# Removing a runner via the UI is covered by `spec/features/runners_spec.rb``
it 'removes the runner', testcase: 'https://gitlab.com/gitlab-org/gitlab/-/quality/test_cases/354828' do
runners_list = runner.runners_list
expect(runners_list.size).to eq(1)
expect(runners_list.first[:description]).to eq(executor)
request = Runtime::API::Request.new(api_client, "runners/#{runner.id}")
response = delete(request.url)
expect(response.code).to eq(Support::API::HTTP_STATUS_NO_CONTENT)
expect(response.body).to be_empty
expect(runner).to be_not_found_by_tags
end
end
end
end

View File

@ -36,7 +36,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -14,7 +14,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = runner_name
runner.tags = [runner_name]

View File

@ -34,7 +34,7 @@ module QA
# Update spec along with Feature Flag Removal.
Runtime::Feature.disable(:show_pages_in_deployments_menu)
Flow::Login.sign_in
Resource::Runner.fabricate_via_api! do |runner|
Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.project = project
runner.executor = :docker
end

View File

@ -37,7 +37,7 @@ module QA
)
end
@runner = Resource::Runner.fabricate_via_api! do |runner|
@runner = Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.project = project
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = %w[web-ide]

View File

@ -14,7 +14,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -14,7 +14,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -13,7 +13,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -15,7 +15,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -20,7 +20,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -15,7 +15,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -12,7 +12,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -14,7 +14,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -10,7 +10,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.project = project
runner.name = project.name
runner.tags = [project.name]

View File

@ -22,10 +22,10 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::GroupRunner.fabricate! do |runner|
runner.name = executor
runner.tags = [executor]
runner.token = group.reload!.runners_token
runner.group = group
end
end

View File

@ -13,7 +13,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = runner_name
runner.tags = [runner_name]

View File

@ -13,7 +13,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -12,7 +12,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -12,7 +12,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -12,7 +12,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.project = project
runner.name = random_test_string
runner.tags = [random_test_string]

View File

@ -5,7 +5,7 @@ module QA
describe 'Runner registration' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = executor
runner.tags = ['e2e-test']
end

View File

@ -18,7 +18,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.project = project
runner.name = project.name
runner.tags = [project.name]

View File

@ -5,7 +5,7 @@ module QA
describe 'Code coverage statistics' do
let(:executor) { "qa-runner-#{Time.now.to_i}" }
let(:runner) do
Resource::Runner.fabricate_via_api! do |runner|
Resource::ProjectRunner.fabricate_via_api! do |runner|
runner.name = executor
runner.tags = ['e2e-test']
end

View File

@ -28,7 +28,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -14,7 +14,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -16,12 +16,11 @@ module QA
end
let(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{imported_project.name}"]
runner.executor = :docker
runner.project = imported_project
runner.token = group.reload!.runners_token
end
end

View File

@ -20,7 +20,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -24,7 +24,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -20,7 +20,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -33,7 +33,7 @@ module QA
end
let(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{package_project.name}"]
runner.executor = :docker
@ -173,11 +173,11 @@ module QA
end
let(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{imported_project.name}"]
runner.executor = :docker
runner.token = group.reload!.runners_token
runner.group = group
end
end

View File

@ -45,11 +45,11 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.group.name}"]
runner.executor = :docker
runner.token = project.group.reload!.runners_token
runner.group = project.group
end
end

View File

@ -39,7 +39,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -51,11 +51,11 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.group.name}"]
runner.executor = :docker
runner.token = project.group.reload!.runners_token
runner.group = project.group
end
end

View File

@ -36,7 +36,7 @@ product_group: :package_registry do
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -21,7 +21,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -21,7 +21,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{project.name}"]
runner.executor = :docker

View File

@ -15,7 +15,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate_via_api! do |resource|
Resource::ProjectRunner.fabricate_via_api! do |resource|
resource.project = project
resource.name = runner_name
resource.tags = [runner_name]

View File

@ -35,8 +35,44 @@ module QA
end
end
let(:smocker_host) { ENV["QA_SMOCKER_HOST"] }
let(:smocker) do
Vendor::Smocker::SmockerApi.new(
host: smocker_host,
public_port: 443,
admin_port: 8081,
tls: true
)
end
let(:mocks_path) { File.join(Runtime::Path.fixtures_path, "mocks", "import") }
before do
set_mocks
group.add_member(user, Resource::Members::AccessLevel::MAINTAINER)
end
def expect_project_import_finished_successfully
imported_project.reload! # import the project
status = nil
Support::Retrier.retry_until(max_duration: 240, sleep_interval: 1, raise_on_failure: false) do
status = imported_project.project_import_status[:import_status]
%w[finished failed].include?(status)
end
# finished status means success, all other statuses are considered to fail the test
expect(status).to eq('finished'), "Expected import to finish successfully, but status was: #{status}"
end
# Setup github mocked responses if mock server host is present
#
# @return [void]
def set_mocks
return Runtime::Logger.warn("Mock host is not set, skipping github response setup") unless smocker_host
smocker.reset
smocker.register(File.read(File.join(mocks_path, "github.yml")))
end
end
end

View File

@ -20,7 +20,7 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::ProjectRunner.fabricate! do |runner|
runner.project = project
runner.name = executor
runner.tags = [executor]

View File

@ -28,11 +28,11 @@ module QA
end
let(:runner) do
Resource::Runner.fabricate! do |runner|
Resource::GroupRunner.fabricate! do |runner|
runner.name = "qa-runner-#{Time.now.to_i}"
runner.tags = ["runner-for-#{package_project.group.name}"]
runner.executor = :docker
runner.token = package_project.group.reload!.runners_token
runner.group = package_project.group
end
end

View File

@ -37,8 +37,8 @@ module QA
end
let!(:runner) do
Resource::Runner.fabricate! do |runner|
runner.token = group.reload!.runners_token
Resource::GroupRunner.fabricate! do |runner|
runner.group = group
runner.name = random_string
runner.tags = [random_string]
end

View File

@ -17,36 +17,21 @@ module QA
body: '{}'
YAML
# @param wait [Integer] seconds to wait for server
# @yieldparam [SmockerApi] the api object ready for interaction
def self.init(**wait_args)
if @container.nil?
@container = Service::DockerRun::Smocker.new
@container.register!
@container.wait_for_running
end
yield new(@container, **wait_args)
end
def self.teardown!
@container&.remove!
@container = nil
end
def initialize(container, **wait_args)
@container = container
wait_for_ready(**wait_args)
def initialize(host:, public_port: 8080, admin_port: 8081, tls: false)
@host = host
@public_port = public_port
@admin_port = admin_port
@scheme = tls ? "https" : "http"
end
# @return [String] Base url of mock endpoint
def base_url
@container.base_url
@base_url ||= "#{scheme}://#{host}:#{public_port}"
end
# @return [String] Url of admin endpoint
def admin_url
@container.admin_url
@admin_url ||= "#{scheme}://#{host}:#{admin_port}"
end
# @param endpoint [String] path for mock endpoint
@ -130,6 +115,8 @@ module QA
private
attr_reader :host, :public_port, :admin_port, :scheme
def build_params(**args)
args.each_with_object([]) do |(k, v), memo|
memo << "#{k}=#{v}" if v

View File

@ -3,3 +3,4 @@
require_relative '../qa'
require_relative 'scenario_shared_examples'
require_relative('../../jh/qa/spec/spec_helper') if GitlabEdition.jh?

View File

@ -1,7 +1,7 @@
import { GlLabel, GlLoadingIcon, GlTooltip } from '@gitlab/ui';
import { range } from 'lodash';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
import { nextTick } from 'vue';
import setWindowLocation from 'helpers/set_window_location_helper';
import { createMockDirective, getBinding } from 'helpers/vue_mock_directive';
import { mountExtended } from 'helpers/vue_test_utils_helper';
@ -17,6 +17,8 @@ import { mockLabelList, mockIssue, mockIssueFullPath } from './mock_data';
jest.mock('~/lib/utils/url_utility');
jest.mock('~/boards/eventhub');
Vue.use(Vuex);
describe('Board card component', () => {
const user = {
id: 1,
@ -52,9 +54,8 @@ describe('Board card component', () => {
const performSearchMock = jest.fn();
const createStore = ({ isProjectBoard = false } = {}) => {
const createStore = () => {
store = new Vuex.Store({
...defaultStore,
actions: {
performSearch: performSearchMock,
},
@ -62,14 +63,10 @@ describe('Board card component', () => {
...defaultStore.state,
isShowingLabels: true,
},
getters: {
isGroupBoard: () => true,
isProjectBoard: () => isProjectBoard,
},
});
};
const createWrapper = ({ props = {}, isEpicBoard = false } = {}) => {
const createWrapper = ({ props = {}, isEpicBoard = false, isGroupBoard = true } = {}) => {
wrapper = mountExtended(BoardCardInner, {
store,
propsData: {
@ -97,6 +94,7 @@ describe('Board card component', () => {
scopedLabelsAvailable: false,
isEpicBoard,
issuableType: issuableTypes.issue,
isGroupBoard,
},
});
};
@ -164,8 +162,8 @@ describe('Board card component', () => {
});
it('does not render item reference path', () => {
createStore({ isProjectBoard: true });
createWrapper();
createStore();
createWrapper({ isGroupBoard: false });
expect(wrapper.find('.board-card-number').text()).not.toContain(mockIssueFullPath);
});

View File

@ -58,8 +58,6 @@ export default function createComponent({
...state,
},
getters: {
isGroupBoard: () => false,
isProjectBoard: () => true,
isEpicBoard: () => false,
...getters,
},
@ -104,6 +102,8 @@ export default function createComponent({
canAdminList: true,
isIssueBoard: true,
isEpicBoard: false,
isGroupBoard: false,
isProjectBoard: true,
...provide,
},
stubs,

View File

@ -29,9 +29,6 @@ describe('Board card', () => {
...initialState,
},
actions: mockActions,
getters: {
isProjectBoard: () => false,
},
});
};
@ -62,6 +59,8 @@ describe('Board card', () => {
scopedLabelsAvailable: false,
isEpicBoard: false,
issuableType: 'issue',
isProjectBoard: false,
isGroupBoard: true,
...provide,
},
});

View File

@ -34,7 +34,6 @@ describe('BoardContentSidebar', () => {
groupPathForActiveIssue: () => mockIssueGroupPath,
projectPathForActiveIssue: () => mockIssueProjectPath,
isSidebarOpen: () => true,
isGroupBoard: () => false,
...mockGetters,
},
actions: mockActions,
@ -55,6 +54,7 @@ describe('BoardContentSidebar', () => {
rootPath: '/',
groupId: 1,
issuableType: issuableTypes.issue,
isGroupBoard: false,
},
store,
stubs: {

View File

@ -71,6 +71,7 @@ describe('BoardContent', () => {
issuableType,
isIssueBoard,
isEpicBoard,
isGroupBoard: true,
isApolloBoard,
},
store,

View File

@ -53,10 +53,6 @@ describe('BoardForm', () => {
const setErrorMock = jest.fn();
const store = new Vuex.Store({
getters: {
isGroupBoard: () => true,
isProjectBoard: () => false,
},
actions: {
setBoard: setBoardMock,
setError: setErrorMock,
@ -73,6 +69,8 @@ describe('BoardForm', () => {
},
provide: {
boardBaseUrl: 'root',
isGroupBoard: true,
isProjectBoard: false,
},
mocks: {
$apollo: {

View File

@ -16,7 +16,8 @@ const mockActions = { addListNewIssue: addListNewIssuesSpy };
const createComponent = ({
state = { selectedProject: mockGroupProjects[0] },
actions = mockActions,
getters = { isGroupBoard: () => true, getBoardItemsByList: () => () => [] },
getters = { getBoardItemsByList: () => () => [] },
isGroupBoard = true,
} = {}) =>
shallowMount(BoardNewIssue, {
store: new Vuex.Store({
@ -32,6 +33,7 @@ const createComponent = ({
fullPath: mockGroupProjects[0].fullPath,
weightFeatureAvailable: false,
boardWeight: null,
isGroupBoard,
},
stubs: {
BoardNewItem,
@ -85,9 +87,9 @@ describe('Issue boards new issue form', () => {
beforeEach(() => {
wrapper = createComponent({
getters: {
isGroupBoard: () => true,
getBoardItemsByList: () => () => [mockIssue, mockIssue2],
},
isGroupBoard: true,
});
});
@ -129,7 +131,7 @@ describe('Issue boards new issue form', () => {
describe('when in project issue board', () => {
beforeEach(() => {
wrapper = createComponent({
getters: { isGroupBoard: () => false },
isGroupBoard: false,
});
});

View File

@ -33,6 +33,7 @@ describe('BoardTopBar', () => {
boardType: 'group',
releasesFetchPath: '/releases',
isIssueBoard: true,
isGroupBoard: true,
...provide,
},
stubs: { IssueBoardFilteredSearch },

View File

@ -10,7 +10,6 @@ import groupBoardsQuery from '~/boards/graphql/group_boards.query.graphql';
import projectBoardsQuery from '~/boards/graphql/project_boards.query.graphql';
import groupRecentBoardsQuery from '~/boards/graphql/group_recent_boards.query.graphql';
import projectRecentBoardsQuery from '~/boards/graphql/project_recent_boards.query.graphql';
import defaultStore from '~/boards/stores';
import createMockApollo from 'helpers/mock_apollo_helper';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import {
@ -28,23 +27,19 @@ import {
const throttleDuration = 1;
Vue.use(VueApollo);
Vue.use(Vuex);
describe('BoardsSelector', () => {
let wrapper;
let fakeApollo;
let store;
const createStore = ({ isGroupBoard = false, isProjectBoard = false } = {}) => {
const createStore = () => {
store = new Vuex.Store({
...defaultStore,
actions: {
setError: jest.fn(),
setBoardConfig: jest.fn(),
},
getters: {
isGroupBoard: () => isGroupBoard,
isProjectBoard: () => isProjectBoard,
},
state: {
board: mockBoard,
},
@ -86,6 +81,7 @@ describe('BoardsSelector', () => {
projectBoardsQueryHandler = projectBoardsQueryHandlerSuccess,
projectRecentBoardsQueryHandler = projectRecentBoardsQueryHandlerSuccess,
isGroupBoard = false,
isProjectBoard = false,
} = {}) => {
fakeApollo = createMockApollo([
[projectBoardsQuery, projectBoardsQueryHandler],
@ -110,6 +106,8 @@ describe('BoardsSelector', () => {
scopedIssueBoardFeatureEnabled: true,
weights: [],
boardType: isGroupBoard ? 'group' : 'project',
isGroupBoard,
isProjectBoard,
},
});
};
@ -121,8 +119,8 @@ describe('BoardsSelector', () => {
describe('template', () => {
beforeEach(() => {
createStore({ isProjectBoard: true });
createComponent();
createStore();
createComponent({ isProjectBoard: true });
});
describe('loading', () => {
@ -230,11 +228,11 @@ describe('BoardsSelector', () => {
${BoardType.group} | ${groupBoardsQueryHandlerSuccess} | ${projectBoardsQueryHandlerSuccess}
${BoardType.project} | ${projectBoardsQueryHandlerSuccess} | ${groupBoardsQueryHandlerSuccess}
`('fetches $boardType boards', async ({ boardType, queryHandler, notCalledHandler }) => {
createStore({
isProjectBoard: boardType === BoardType.project,
createStore();
createComponent({
isGroupBoard: boardType === BoardType.group,
isProjectBoard: boardType === BoardType.project,
});
createComponent({ isGroupBoard: boardType === BoardType.group });
await nextTick();

View File

@ -18,7 +18,7 @@ describe('IssueBoardFilter', () => {
isSignedIn,
releasesFetchPath: '/releases',
fullPath: 'gitlab-org',
boardType: 'group',
isGroupBoard: true,
},
});
};

View File

@ -12,42 +12,6 @@ import {
} from '../mock_data';
describe('Boards - Getters', () => {
describe('isGroupBoard', () => {
it('returns true when boardType on state is group', () => {
const state = {
boardType: 'group',
};
expect(getters.isGroupBoard(state)).toBe(true);
});
it('returns false when boardType on state is not group', () => {
const state = {
boardType: 'project',
};
expect(getters.isGroupBoard(state)).toBe(false);
});
});
describe('isProjectBoard', () => {
it('returns true when boardType on state is project', () => {
const state = {
boardType: 'project',
};
expect(getters.isProjectBoard(state)).toBe(true);
});
it('returns false when boardType on state is not project', () => {
const state = {
boardType: 'group',
};
expect(getters.isProjectBoard(state)).toBe(false);
});
});
describe('isSidebarOpen', () => {
it('returns true when activeId is not equal to 0', () => {
const state = {

View File

@ -62,6 +62,47 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Validators::CyclonedxSchemaValidator,
it { is_expected.to be_valid }
end
context 'when components have licenses' do
let(:components) do
[
{
"type" => "library",
"name" => "activesupport",
"version" => "5.1.4",
"licenses" => [
{ "license" => { "id" => "MIT" } }
]
}
]
end
it { is_expected.to be_valid }
end
context 'when components have a signature' do
let(:components) do
[
{
"type" => "library",
"name" => "activesupport",
"version" => "5.1.4",
"signature" => {
"algorithm" => "ES256",
"publicKey" => {
"kty" => "EC",
"crv" => "P-256",
"x" => "6BKxpty8cI-exDzCkh-goU6dXq3MbcY0cd1LaAxiNrU",
"y" => "mCbcvUzm44j3Lt2b5BPyQloQ91tf2D2V-gzeUxWaUdg"
},
"value" => "ybT1qz5zHNi4Ndc6y7Zhamuf51IqXkPkZwjH1XcC-KSuBiaQplTw6Jasf2MbCLg3CF7PAdnMO__WSLwvI5r2jA"
}
}
]
end
it { is_expected.to be_valid }
end
context "when components are not valid" do
let(:components) do
[