Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
8cfe3415e9
commit
9134da0488
|
@ -955,6 +955,10 @@ rspec foss-impact:
|
|||
expire_in: 7d
|
||||
paths:
|
||||
- tmp/capybara/
|
||||
# Temporary allow failure because of the high rate of failure due to the job
|
||||
# running a lot more tests since https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96152.
|
||||
# This should be reverted once https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96797 is merged.
|
||||
allow_failure: true
|
||||
|
||||
fail-pipeline-early:
|
||||
extends:
|
||||
|
|
|
@ -3,26 +3,6 @@
|
|||
Layout/FirstArrayElementIndentation:
|
||||
Exclude:
|
||||
- 'lib/gitlab/email/message/in_product_marketing/trial.rb'
|
||||
- 'lib/gitlab/email/message/in_product_marketing/verify.rb'
|
||||
- 'lib/gitlab/import_export/base/relation_factory.rb'
|
||||
- 'lib/gitlab/import_export/json/streaming_serializer.rb'
|
||||
- 'lib/gitlab/kroki.rb'
|
||||
- 'lib/gitlab/object_hierarchy.rb'
|
||||
- 'lib/gitlab/pagination/keyset/simple_order_builder.rb'
|
||||
- 'lib/gitlab/project_authorizations.rb'
|
||||
- 'lib/gitlab/usage_data.rb'
|
||||
- 'lib/system_check/app/authorized_keys_permission_check.rb'
|
||||
- 'qa/qa/resource/protected_branch.rb'
|
||||
- 'qa/qa/specs/features/api/1_manage/group_access_token_spec.rb'
|
||||
- 'qa/qa/specs/features/api/1_manage/project_access_token_spec.rb'
|
||||
- 'qa/qa/specs/features/api/1_manage/user_access_termination_spec.rb'
|
||||
- 'qa/qa/specs/features/api/1_manage/user_inherited_access_spec.rb'
|
||||
- 'qa/qa/specs/features/api/3_create/gitaly/automatic_failover_and_recovery_spec.rb'
|
||||
- 'qa/qa/specs/features/api/3_create/gitaly/changing_repository_storage_spec.rb'
|
||||
- 'qa/qa/specs/features/api/3_create/gitaly/gitaly_mtls_spec.rb'
|
||||
- 'qa/qa/specs/features/api/3_create/gitaly/praefect_dataloss_spec.rb'
|
||||
- 'qa/qa/specs/features/api/3_create/repository/commit_to_templated_project_spec.rb'
|
||||
- 'qa/qa/specs/features/browser_ui/1_manage/group/transfer_project_spec.rb'
|
||||
- 'qa/qa/specs/features/browser_ui/2_plan/issue/custom_issue_template_spec.rb'
|
||||
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/cherry_pick/cherry_pick_commit_spec.rb'
|
||||
- 'qa/qa/specs/features/browser_ui/3_create/merge_request/create_merge_request_via_template_spec.rb'
|
||||
|
|
|
@ -1 +1 @@
|
|||
b4c1f29c487a41b2e69a31a99f6b0ac462c81ce4
|
||||
f39f02c9dd07a80ed1443d42bbf158bed901c777
|
||||
|
|
|
@ -190,7 +190,7 @@ export default {
|
|||
<gl-form-radio name="error-tracking-integrated" :value="true">
|
||||
{{ __('GitLab') }}
|
||||
<template #help>
|
||||
{{ __('Uses GitLab as a lightweight alternative to Sentry.') }}
|
||||
{{ __('Uses GitLab as an alternative to Sentry.') }}
|
||||
</template>
|
||||
</gl-form-radio>
|
||||
</gl-form-radio-group>
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
import { GlSprintf, GlBadge, GlResizeObserverDirective } from '@gitlab/ui';
|
||||
import { GlBreakpointInstance } from '@gitlab/ui/dist/utils';
|
||||
import { numberToHumanSize } from '~/lib/utils/number_utils';
|
||||
import { __ } from '~/locale';
|
||||
import { __, s__, sprintf } from '~/locale';
|
||||
import { formatDate } from '~/lib/utils/datetime_utility';
|
||||
import PackageTags from '~/packages_and_registries/shared/components/package_tags.vue';
|
||||
import { PACKAGE_TYPE_NUGET } from '~/packages_and_registries/package_registry/constants';
|
||||
import { getPackageTypeLabel } from '~/packages_and_registries/package_registry/utils';
|
||||
|
@ -25,6 +26,7 @@ export default {
|
|||
},
|
||||
inject: ['isGroupPage'],
|
||||
i18n: {
|
||||
lastDownloadedAt: s__('PackageRegistry|Last downloaded %{dateTime}'),
|
||||
packageInfo: __('v%{version} published %{timeAgo}'),
|
||||
},
|
||||
props: {
|
||||
|
@ -39,6 +41,11 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
packageLastDownloadedAtDisplay() {
|
||||
return sprintf(this.$options.i18n.lastDownloadedAt, {
|
||||
dateTime: formatDate(this.packageEntity.lastDownloadedAt, 'mmm d, yyyy'),
|
||||
});
|
||||
},
|
||||
packageTypeDisplay() {
|
||||
return getPackageTypeLabel(this.packageEntity.packageType);
|
||||
},
|
||||
|
@ -136,6 +143,15 @@ export default {
|
|||
<metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" />
|
||||
</template>
|
||||
|
||||
<template v-if="packageEntity.lastDownloadedAt" #metadata-last-downloaded-at>
|
||||
<metadata-item
|
||||
data-testid="package-last-downloaded-at"
|
||||
icon="download"
|
||||
:text="packageLastDownloadedAtDisplay"
|
||||
size="m"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<template #right-actions>
|
||||
<slot name="delete-button"></slot>
|
||||
</template>
|
||||
|
|
|
@ -4,6 +4,7 @@ query getPackageDetails($id: PackagesPackageID!) {
|
|||
name
|
||||
packageType
|
||||
version
|
||||
lastDownloadedAt
|
||||
createdAt
|
||||
updatedAt
|
||||
status
|
||||
|
|
|
@ -187,7 +187,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<section class="media-section" data-testid="widget-extension">
|
||||
<div class="media gl-p-5">
|
||||
<div class="gl-p-5 gl-align-items-center gl-display-flex">
|
||||
<status-icon
|
||||
:level="1"
|
||||
:name="widgetName"
|
||||
|
|
|
@ -94,6 +94,7 @@ module Mutations
|
|||
).execute
|
||||
return if result.success?
|
||||
|
||||
response[:runner] = nil
|
||||
response[:errors] = result.errors
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
@ -102,6 +103,7 @@ module Mutations
|
|||
result = ::Ci::Runners::UpdateRunnerService.new(runner).execute(attrs)
|
||||
return if result.success?
|
||||
|
||||
response[:runner] = nil
|
||||
response[:errors] = result.errors
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
|
|
|
@ -21,8 +21,8 @@ module Resolvers
|
|||
'Specify `"id_asc"` if query results\' order is important',
|
||||
milestone: '15.4'
|
||||
},
|
||||
description: "Sort order of results. Format: '<field_name>_<sort_direction>', " \
|
||||
"for example: 'id_desc' or 'name_asc'"
|
||||
description: "Sort order of results. Format: `<field_name>_<sort_direction>`, " \
|
||||
"for example: `id_desc` or `name_asc`"
|
||||
|
||||
def resolve_with_lookahead(**args)
|
||||
return unless runner.project_type?
|
||||
|
|
|
@ -12,8 +12,8 @@ module Resolvers
|
|||
|
||||
argument :sort, GraphQL::Types::String,
|
||||
required: false,
|
||||
description: "Sort order of results. Format: '<field_name>_<sort_direction>', " \
|
||||
"for example: 'id_desc' or 'name_asc'"
|
||||
description: "Sort order of results. Format: `<field_name>_<sort_direction>`, " \
|
||||
"for example: `id_desc` or `name_asc`"
|
||||
|
||||
def resolve(**args)
|
||||
ProjectsFinder
|
||||
|
|
|
@ -26,7 +26,7 @@ module Ci
|
|||
return legacy_dependent_jobs unless ::Feature.enabled?(:ci_requeue_with_dag_object_hierarchy, project)
|
||||
|
||||
ordered_by_dag(
|
||||
::Ci::Processable
|
||||
@processable.pipeline.processables
|
||||
.from_union(needs_dependent_jobs, stage_dependent_jobs)
|
||||
.skipped
|
||||
.ordered_by_stage
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: contribution_analytics_optimized_base_query
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/91468
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/367090
|
||||
milestone: '15.2'
|
||||
type: development
|
||||
group: group::optimize
|
||||
default_enabled: true
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: cycle_analytics
|
||||
event: views
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: snippet
|
||||
event: create
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: snippet
|
||||
event: update
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: wiki_pages
|
||||
event: create
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: wiki_pages
|
||||
event: update
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -10,6 +10,10 @@ value_type: number
|
|||
status: active
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: wiki_pages
|
||||
event: delete
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -12,6 +12,10 @@ milestone: "13.3"
|
|||
introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/38784"
|
||||
time_frame: all
|
||||
data_source: redis
|
||||
instrumentation_class: RedisMetric
|
||||
options:
|
||||
prefix: wiki_pages
|
||||
event: view
|
||||
distribution:
|
||||
- ce
|
||||
- ee
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveNotNullConstraintFromSbomSourceFingerprint < Gitlab::Database::Migration[2.0]
|
||||
enable_lock_retries!
|
||||
|
||||
def change
|
||||
change_column_null :sbom_sources, :fingerprint, true
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
f481a617b3fc4fa95daec75619029dc8ef3a02d55e86b940eda78d6a93e6e78b
|
|
@ -20979,7 +20979,7 @@ CREATE TABLE sbom_sources (
|
|||
updated_at timestamp with time zone NOT NULL,
|
||||
source_type smallint NOT NULL,
|
||||
source jsonb DEFAULT '{}'::jsonb NOT NULL,
|
||||
fingerprint bytea NOT NULL
|
||||
fingerprint bytea
|
||||
);
|
||||
|
||||
CREATE SEQUENCE sbom_sources_id_seq
|
||||
|
|
|
@ -320,7 +320,7 @@ four standard [pagination arguments](#connection-pagination-arguments):
|
|||
| <a id="queryprojectsmembership"></a>`membership` | [`Boolean`](#boolean) | Return only projects that the current user is a member of. |
|
||||
| <a id="queryprojectssearch"></a>`search` | [`String`](#string) | Search query, which can be for the project name, a path, or a description. |
|
||||
| <a id="queryprojectssearchnamespaces"></a>`searchNamespaces` | [`Boolean`](#boolean) | Include namespace in project search. |
|
||||
| <a id="queryprojectssort"></a>`sort` | [`String`](#string) | Sort order of results. Format: '<field_name>_<sort_direction>', for example: 'id_desc' or 'name_asc'. |
|
||||
| <a id="queryprojectssort"></a>`sort` | [`String`](#string) | Sort order of results. Format: `<field_name>_<sort_direction>`, for example: `id_desc` or `name_asc`. |
|
||||
| <a id="queryprojectstopics"></a>`topics` | [`[String!]`](#string) | Filter projects by topics. |
|
||||
|
||||
### `Query.queryComplexity`
|
||||
|
|
|
@ -1127,6 +1127,14 @@ Do not use words to describe the icon:
|
|||
- Avoid: `Select **Erase job log** (the trash icon).`
|
||||
- Use instead: `Select **Erase job log** (**{remove}**).` This generates as: Select **Erase job log** (**{remove}**).
|
||||
|
||||
When the button doesn't have any hover text, you can describe the icon.
|
||||
Follow up by creating a
|
||||
[UX bug issue](https://gitlab.com/gitlab-org/gitlab/-/issues/new?issuable_template=Bug)
|
||||
to add hover text to the button to improve accessibility.
|
||||
|
||||
- Avoid: `Select **{ellipsis_v}**.`
|
||||
- Use instead: `Select the vertical ellipsis (**{ellipsis_v}**).` This generates as: Select the vertical ellipsis (**{ellipsis_v}**).
|
||||
|
||||
## Videos
|
||||
|
||||
Adding GitLab YouTube video tutorials to the documentation is highly
|
||||
|
|
|
@ -20,6 +20,9 @@ by selecting buttons or dropdowns in the GitLab user interface. You can enter
|
|||
these commands in the descriptions or comments of issues, epics, merge requests,
|
||||
and commits.
|
||||
|
||||
Many quick actions are context-aware, requiring certain conditions be met. For example, to remove
|
||||
an issue due date with `/remove_due_date`, the issue must have a due date set.
|
||||
|
||||
Be sure to enter each quick action on a separate line to allow GitLab to
|
||||
properly detect and execute the commands.
|
||||
|
||||
|
@ -102,7 +105,7 @@ threads. Some quick actions might not be available to all subscription tiers.
|
|||
| `/remove_time_spent` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Remove time spent. |
|
||||
| `/remove_zoom` | **{check-circle}** Yes | **{dotted-circle}** No | **{dotted-circle}** No | Remove Zoom meeting from this issue. |
|
||||
| `/reopen` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Reopen. |
|
||||
| `/severity <severity>` | **{check-circle}** Yes | **{check-circle}** No | **{check-circle}** No | Set the severity. Options for `<severity>` are `S1` ... `S4`, `critical`, `high`, `medium`, `low`, `unknown`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334045) in GitLab 14.2. |
|
||||
| `/severity <severity>` | **{check-circle}** Yes | **{check-circle}** No | **{check-circle}** No | Set the severity. Issue type must be `Incident`. Options for `<severity>` are `S1` ... `S4`, `critical`, `high`, `medium`, `low`, `unknown`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/334045) in GitLab 14.2. |
|
||||
| `/shrug <comment>` | **{check-circle}** Yes | **{check-circle}** Yes | **{check-circle}** Yes | Append the comment with `¯\_(ツ)_/¯`. |
|
||||
| `/spend <time> [<date>]` | **{check-circle}** Yes | **{check-circle}** Yes | **{dotted-circle}** No | Add or subtract spent time. Optionally, specify the date that time was spent on. For example, `/spend 1mo 2w 3d 4h 5m 2018-08-26` or `/spend -1h 30m`. Learn more about [time tracking](time_tracking.md). |
|
||||
| `/submit_review` | **{dotted-circle}** No | **{check-circle}** Yes | **{dotted-circle}** No | Submit a pending review ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/8041) in GitLab 12.7). |
|
||||
|
|
|
@ -23,8 +23,7 @@ module Gitlab
|
|||
|
||||
::Gitlab::Ci::Reports::Sbom::Source.new(
|
||||
type: :dependency_scanning,
|
||||
data: data,
|
||||
fingerprint: fingerprint
|
||||
data: data
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -37,10 +36,6 @@ module Gitlab
|
|||
data.dig(*keys).present?
|
||||
end
|
||||
end
|
||||
|
||||
def fingerprint
|
||||
Digest::SHA256.hexdigest(data.to_json)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -91,7 +91,7 @@ module Gitlab
|
|||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def from_pipeline(pipeline)
|
||||
status = %w[success failed running canceled]
|
||||
builds = pipeline.builds.latest
|
||||
builds = pipeline.processables.latest
|
||||
.where(status: status).where.not(started_at: nil).order(:started_at)
|
||||
|
||||
from_builds(builds)
|
||||
|
|
|
@ -20,12 +20,16 @@ module Gitlab
|
|||
def ancestor_conditions(cte)
|
||||
middle_table[:name].eq(objects_table[:name]).and(
|
||||
middle_table[:build_id].eq(cte.table[:id])
|
||||
).and(
|
||||
objects_table[:commit_id].eq(cte.table[:commit_id])
|
||||
)
|
||||
end
|
||||
|
||||
def descendant_conditions(cte)
|
||||
middle_table[:build_id].eq(objects_table[:id]).and(
|
||||
middle_table[:name].eq(cte.table[:name])
|
||||
).and(
|
||||
objects_table[:commit_id].eq(cte.table[:commit_id])
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -5,12 +5,11 @@ module Gitlab
|
|||
module Reports
|
||||
module Sbom
|
||||
class Source
|
||||
attr_reader :source_type, :data, :fingerprint
|
||||
attr_reader :source_type, :data
|
||||
|
||||
def initialize(type:, data:, fingerprint:)
|
||||
def initialize(type:, data:)
|
||||
@source_type = type
|
||||
@data = data
|
||||
@fingerprint = fingerprint
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -49,10 +49,10 @@ module Gitlab
|
|||
[
|
||||
nil,
|
||||
list([
|
||||
s_('InProductMarketing|Start by %{performance_link}').html_safe % { performance_link: performance_link },
|
||||
s_('InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}').html_safe % { ci_template_link: ci_template_link },
|
||||
s_('InProductMarketing|And finally %{deploy_link} a Python application.').html_safe % { deploy_link: deploy_link }
|
||||
]),
|
||||
s_('InProductMarketing|Start by %{performance_link}').html_safe % { performance_link: performance_link },
|
||||
s_('InProductMarketing|Move on to easily creating a Pages website %{ci_template_link}').html_safe % { ci_template_link: ci_template_link },
|
||||
s_('InProductMarketing|And finally %{deploy_link} a Python application.').html_safe % { deploy_link: deploy_link }
|
||||
]),
|
||||
nil
|
||||
][series]
|
||||
end
|
||||
|
|
|
@ -15,19 +15,19 @@ module Gitlab
|
|||
UNIQUE_RELATIONS = %i[].freeze
|
||||
|
||||
USER_REFERENCES = %w[
|
||||
author_id
|
||||
assignee_id
|
||||
updated_by_id
|
||||
merged_by_id
|
||||
latest_closed_by_id
|
||||
user_id
|
||||
created_by_id
|
||||
last_edited_by_id
|
||||
merge_user_id
|
||||
resolved_by_id
|
||||
closed_by_id
|
||||
owner_id
|
||||
].freeze
|
||||
author_id
|
||||
assignee_id
|
||||
updated_by_id
|
||||
merged_by_id
|
||||
latest_closed_by_id
|
||||
user_id
|
||||
created_by_id
|
||||
last_edited_by_id
|
||||
merge_user_id
|
||||
resolved_by_id
|
||||
closed_by_id
|
||||
owner_id
|
||||
].freeze
|
||||
|
||||
TOKEN_RESET_MODELS = %i[Project Namespace Group Ci::Trigger Ci::Build Ci::Runner ProjectHook ErrorTracking::ProjectErrorTrackingSetting].freeze
|
||||
|
||||
|
|
|
@ -175,21 +175,22 @@ module Gitlab
|
|||
order_expression = arel_table[column].public_send(direction).public_send(nulls_position) # rubocop:disable GitlabSecurity/PublicSend
|
||||
reverse_order_expression = arel_table[column].public_send(reverse_direction).public_send(reverse_nulls_position) # rubocop:disable GitlabSecurity/PublicSend
|
||||
|
||||
::Gitlab::Pagination::Keyset::Order.build([
|
||||
::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: column,
|
||||
column_expression: arel_table[column],
|
||||
order_expression: order_expression,
|
||||
reversed_order_expression: reverse_order_expression,
|
||||
order_direction: direction,
|
||||
nullable: nulls_position,
|
||||
distinct: false
|
||||
),
|
||||
::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: klass.primary_key,
|
||||
order_expression: arel_order_classes[direction].new(arel_table[klass.primary_key.to_sym])
|
||||
)
|
||||
])
|
||||
::Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: column,
|
||||
column_expression: arel_table[column],
|
||||
order_expression: order_expression,
|
||||
reversed_order_expression: reverse_order_expression,
|
||||
order_direction: direction,
|
||||
nullable: nulls_position,
|
||||
distinct: false
|
||||
),
|
||||
::Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: klass.primary_key,
|
||||
order_expression: arel_order_classes[direction].new(arel_table[klass.primary_key.to_sym])
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
def read_from_replica_if_available(&block)
|
||||
|
|
|
@ -6,13 +6,13 @@ module Gitlab
|
|||
# Helper methods for Kroki
|
||||
module Kroki
|
||||
BLOCKDIAG_FORMATS = %w[
|
||||
blockdiag
|
||||
seqdiag
|
||||
actdiag
|
||||
nwdiag
|
||||
packetdiag
|
||||
rackdiag
|
||||
].freeze
|
||||
blockdiag
|
||||
seqdiag
|
||||
actdiag
|
||||
nwdiag
|
||||
packetdiag
|
||||
rackdiag
|
||||
].freeze
|
||||
DIAGRAMS_FORMATS = (::AsciidoctorExtensions::Kroki::SUPPORTED_DIAGRAM_NAMES - %w(mermaid)).freeze
|
||||
DIAGRAMS_FORMATS_WO_PLANTUML = (DIAGRAMS_FORMATS - %w(plantuml)).freeze
|
||||
|
||||
|
|
|
@ -138,9 +138,9 @@ module Gitlab
|
|||
.with
|
||||
.recursive(ancestors.to_arel, descendants.to_arel)
|
||||
.from_union([
|
||||
ancestors_scope,
|
||||
descendants_scope
|
||||
])
|
||||
ancestors_scope,
|
||||
descendants_scope
|
||||
])
|
||||
|
||||
read_only(relation)
|
||||
end
|
||||
|
|
|
@ -129,28 +129,31 @@ module Gitlab
|
|||
end
|
||||
|
||||
def primary_key_descending_order
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: model_class.primary_key,
|
||||
order_expression: arel_table[primary_key].desc
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: model_class.primary_key,
|
||||
order_expression: arel_table[primary_key].desc
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
def primary_key_order
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: model_class.primary_key,
|
||||
order_expression: order_values.first
|
||||
)
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
Gitlab::Pagination::Keyset::ColumnOrderDefinition.new(
|
||||
attribute_name: model_class.primary_key,
|
||||
order_expression: order_values.first
|
||||
)
|
||||
])
|
||||
end
|
||||
|
||||
def column_with_tie_breaker_order(tie_breaker_column_order = default_tie_breaker_column_order)
|
||||
Gitlab::Pagination::Keyset::Order.build([
|
||||
column(order_values.first),
|
||||
tie_breaker_column_order
|
||||
])
|
||||
Gitlab::Pagination::Keyset::Order.build(
|
||||
[
|
||||
column(order_values.first),
|
||||
tie_breaker_column_order
|
||||
])
|
||||
end
|
||||
|
||||
def column(order_value)
|
||||
|
|
|
@ -37,9 +37,9 @@ module Gitlab
|
|||
Namespace
|
||||
.unscoped
|
||||
.select([
|
||||
links[:project_id],
|
||||
least(cte_alias[:access_level], links[:group_access], 'access_level')
|
||||
])
|
||||
links[:project_id],
|
||||
least(cte_alias[:access_level], links[:group_access], 'access_level')
|
||||
])
|
||||
.from(cte_alias)
|
||||
.joins('INNER JOIN project_group_links ON project_group_links.group_id = namespaces.id')
|
||||
.joins('INNER JOIN projects ON projects.id = project_group_links.project_id')
|
||||
|
@ -79,9 +79,9 @@ module Gitlab
|
|||
|
||||
# Sub groups of any groups the user is a member of.
|
||||
cte << Group.select([
|
||||
namespaces[:id],
|
||||
greatest(members[:access_level], cte.table[:access_level], 'access_level')
|
||||
])
|
||||
namespaces[:id],
|
||||
greatest(members[:access_level], cte.table[:access_level], 'access_level')
|
||||
])
|
||||
.joins(join_cte(cte))
|
||||
.joins(join_members_on_namespaces)
|
||||
.except(:order)
|
||||
|
|
|
@ -21,18 +21,18 @@ module Gitlab
|
|||
MAX_GENERATION_TIME_FOR_SAAS = 40.hours
|
||||
|
||||
CE_MEMOIZED_VALUES = %i(
|
||||
issue_minimum_id
|
||||
issue_maximum_id
|
||||
project_minimum_id
|
||||
project_maximum_id
|
||||
user_minimum_id
|
||||
user_maximum_id
|
||||
deployment_minimum_id
|
||||
deployment_maximum_id
|
||||
auth_providers
|
||||
aggregated_metrics
|
||||
recorded_at
|
||||
).freeze
|
||||
issue_minimum_id
|
||||
issue_maximum_id
|
||||
project_minimum_id
|
||||
project_maximum_id
|
||||
user_minimum_id
|
||||
user_maximum_id
|
||||
deployment_minimum_id
|
||||
deployment_maximum_id
|
||||
auth_providers
|
||||
aggregated_metrics
|
||||
recorded_at
|
||||
).freeze
|
||||
|
||||
class << self
|
||||
include Gitlab::Utils::UsageData
|
||||
|
|
|
@ -3,13 +3,8 @@
|
|||
module Gitlab
|
||||
module UsageDataCounters
|
||||
COUNTERS = [
|
||||
WikiPageCounter,
|
||||
NoteCounter,
|
||||
SnippetCounter,
|
||||
SearchCounter,
|
||||
CycleAnalyticsCounter,
|
||||
ProductivityAnalyticsCounter,
|
||||
SourceCodeCounter,
|
||||
KubernetesAgentCounter,
|
||||
MergeRequestWidgetExtensionCounter
|
||||
].freeze
|
||||
|
@ -20,7 +15,12 @@ module Gitlab
|
|||
DesignsCounter,
|
||||
DiffsCounter,
|
||||
ServiceUsageDataCounter,
|
||||
WebIdeCounter
|
||||
WebIdeCounter,
|
||||
WikiPageCounter,
|
||||
SnippetCounter,
|
||||
CycleAnalyticsCounter,
|
||||
ProductivityAnalyticsCounter,
|
||||
SourceCodeCounter
|
||||
].freeze
|
||||
|
||||
UsageDataCounterError = Class.new(StandardError)
|
||||
|
|
|
@ -19,11 +19,12 @@ module SystemCheck
|
|||
end
|
||||
|
||||
def show_error
|
||||
try_fixing_it([
|
||||
"sudo chmod 700 #{File.dirname(authorized_keys.file)}",
|
||||
"touch #{authorized_keys.file}",
|
||||
"sudo chmod 600 #{authorized_keys.file}"
|
||||
])
|
||||
try_fixing_it(
|
||||
[
|
||||
"sudo chmod 700 #{File.dirname(authorized_keys.file)}",
|
||||
"touch #{authorized_keys.file}",
|
||||
"sudo chmod 600 #{authorized_keys.file}"
|
||||
])
|
||||
fix_and_rerun
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,36 @@ require "base64"
|
|||
class VersionCheck
|
||||
include ReactiveCaching
|
||||
|
||||
## Version Check Reactive Caching
|
||||
## This cache stores the external API response from https://version.gitlab.com
|
||||
##
|
||||
## Example API Response
|
||||
## {
|
||||
## "latest_version": "15.2.2",
|
||||
## "severity": "success"
|
||||
## }
|
||||
##
|
||||
## This response from this endpoint only changes in 2 scenarios:
|
||||
## 1. Customer upgrades their GitLab Instance
|
||||
## 2. GitLab releases a new version
|
||||
##
|
||||
## We use GitLab::VERSION as the identifier for the cached information.
|
||||
## This means if the user upgrades their version we will create a new cache record.
|
||||
## The old one will be invalidated and cleaned up at the end of the self.reactive_cache_lifetime.
|
||||
##
|
||||
## - self.reactive_cache_refresh_interval = 12.hours
|
||||
## We want to prevent as many external API calls as possible to save on resources.
|
||||
## Since an EXISTING cache record will only become "invalid" if GitLab releases a new version we
|
||||
## determined that 12 hour intervals is enough of a window to capture an available upgrade.
|
||||
##
|
||||
## - self.reactive_cache_lifetime = 7.days
|
||||
## We don't want the data to be missing every time a user revisits a page using this info.
|
||||
## Thus 7 days seems like a fair amount of time before we erase the cache.
|
||||
## This also will handle cleaning up old cache records as they will no longer be accessed after an upgrade.
|
||||
##
|
||||
|
||||
self.reactive_cache_refresh_interval = 12.hours
|
||||
self.reactive_cache_lifetime = 7.days
|
||||
self.reactive_cache_work_type = :external_dependency
|
||||
self.reactive_cache_worker_finder = ->(_id, *args) { from_cache }
|
||||
|
||||
|
|
|
@ -28398,6 +28398,9 @@ msgstr ""
|
|||
msgid "PackageRegistry|Invalid Package: failed metadata extraction"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Last downloaded %{dateTime}"
|
||||
msgstr ""
|
||||
|
||||
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
|
||||
msgstr ""
|
||||
|
||||
|
@ -43498,7 +43501,7 @@ msgstr ""
|
|||
msgid "UsersSelect|Unassigned"
|
||||
msgstr ""
|
||||
|
||||
msgid "Uses GitLab as a lightweight alternative to Sentry."
|
||||
msgid "Uses GitLab as an alternative to Sentry."
|
||||
msgstr ""
|
||||
|
||||
msgid "Using %{code_start}::%{code_end} denotes a %{link_start}scoped label set%{link_end}"
|
||||
|
|
|
@ -22,9 +22,7 @@ module QA
|
|||
commit.branch = branch_name
|
||||
commit.start_branch = project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: "new_file-#{SecureRandom.hex(8)}.md", content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: "new_file-#{SecureRandom.hex(8)}.md", content: 'new file' }])
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -40,9 +40,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }])
|
||||
end
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
|
|
@ -33,9 +33,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = @project_access_token.project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }])
|
||||
end
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
@ -67,9 +65,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = @different_project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: "text-#{SecureRandom.hex(8)}.txt", content: 'new file' }])
|
||||
end
|
||||
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/)
|
||||
end
|
||||
|
|
|
@ -69,9 +69,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = @project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: 'test.txt', content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
|
||||
end
|
||||
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError, /403 Forbidden - You are not allowed to push into this branch/)
|
||||
end
|
||||
|
|
|
@ -85,9 +85,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = sub_group_project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: 'test.txt', content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
|
||||
end
|
||||
end.not_to raise_error
|
||||
end
|
||||
|
@ -167,9 +165,7 @@ module QA
|
|||
commit.branch = "new_branch_#{SecureRandom.hex(8)}"
|
||||
commit.start_branch = parent_group_project.default_branch
|
||||
commit.commit_message = 'Add new file'
|
||||
commit.add_files([
|
||||
{ file_path: 'test.txt', content: 'new file' }
|
||||
])
|
||||
commit.add_files([{ file_path: 'test.txt', content: 'new file' }])
|
||||
end
|
||||
end.to raise_error(Resource::ApiFabricator::ResourceFabricationFailedError,
|
||||
/403 Forbidden - You are not allowed to push into this branch/)
|
||||
|
|
|
@ -16,18 +16,18 @@ module QA
|
|||
commit.project = project
|
||||
commit.update_files(
|
||||
[
|
||||
{
|
||||
file_path: '.gitlab-ci.yml',
|
||||
content: 'script'
|
||||
}
|
||||
{
|
||||
file_path: '.gitlab-ci.yml',
|
||||
content: 'script'
|
||||
}
|
||||
]
|
||||
)
|
||||
commit.add_files(
|
||||
[
|
||||
{
|
||||
file_path: 'foo',
|
||||
content: 'bar'
|
||||
}
|
||||
{
|
||||
file_path: 'foo',
|
||||
content: 'bar'
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
|
|
|
@ -27,9 +27,7 @@ module QA
|
|||
before do
|
||||
Resource::Repository::Commit.fabricate_via_api! do |commit|
|
||||
commit.project = project
|
||||
commit.add_files([
|
||||
{ file_path: 'README.md', content: readme_content }
|
||||
])
|
||||
commit.add_files([{ file_path: 'README.md', content: readme_content }])
|
||||
end
|
||||
|
||||
Flow::Login.sign_in
|
||||
|
|
|
@ -64,7 +64,7 @@ module RuboCop
|
|||
NON_METHOD_DEFINITIONS = %i[class_methods included prepended].to_set.freeze
|
||||
|
||||
def_node_matcher :translation_method?, <<~PATTERN
|
||||
(send _ {#{RESTRICT_ON_SEND.map(&:inspect).join(' ')}} str*)
|
||||
(send _ {#{RESTRICT_ON_SEND.map(&:inspect).join(' ')}} {dstr str}+)
|
||||
PATTERN
|
||||
|
||||
def on_send(node)
|
||||
|
|
|
@ -358,7 +358,7 @@ function rspec_fail_fast() {
|
|||
}
|
||||
|
||||
function rspec_matched_foss_tests() {
|
||||
local test_file_count_threshold=20
|
||||
local test_file_count_threshold=40
|
||||
local matching_tests_file=${1}
|
||||
local foss_matching_tests_file="${matching_tests_file}-foss"
|
||||
|
||||
|
|
|
@ -19,15 +19,12 @@ FactoryBot.define do
|
|||
}
|
||||
end
|
||||
|
||||
fingerprint { Digest::SHA256.hexdigest(data.to_json) }
|
||||
|
||||
skip_create
|
||||
|
||||
initialize_with do
|
||||
::Gitlab::Ci::Reports::Sbom::Source.new(
|
||||
type: type,
|
||||
data: data,
|
||||
fingerprint: fingerprint
|
||||
data: data
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -79,6 +79,18 @@ exports[`PackageTitle renders with tags 1`] = `
|
|||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-last-downloaded-at"
|
||||
icon="download"
|
||||
link=""
|
||||
size="m"
|
||||
text="Last downloaded Aug 17, 2021"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -164,6 +176,18 @@ exports[`PackageTitle renders without tags 1`] = `
|
|||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="gl-display-flex gl-align-items-center gl-mr-5"
|
||||
>
|
||||
<metadata-item-stub
|
||||
data-testid="package-last-downloaded-at"
|
||||
icon="download"
|
||||
link=""
|
||||
size="m"
|
||||
text="Last downloaded Aug 17, 2021"
|
||||
texttooltip=""
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ describe('PackageTitle', () => {
|
|||
const findPackageSize = () => wrapper.findByTestId('package-size');
|
||||
const findPipelineProject = () => wrapper.findByTestId('pipeline-project');
|
||||
const findPackageRef = () => wrapper.findByTestId('package-ref');
|
||||
const findPackageLastDownloadedAt = () => wrapper.findByTestId('package-last-downloaded-at');
|
||||
const findPackageTags = () => wrapper.findComponent(PackageTags);
|
||||
const findPackageBadges = () => wrapper.findAllByTestId('tag-badge');
|
||||
const findSubHeaderText = () => wrapper.findByTestId('sub-header');
|
||||
|
@ -227,4 +228,25 @@ describe('PackageTitle', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('package last downloaded at', () => {
|
||||
it('does not display the data if missing', async () => {
|
||||
await createComponent({
|
||||
...packageData(),
|
||||
lastDownloadedAt: null,
|
||||
});
|
||||
|
||||
expect(findPackageLastDownloadedAt().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('correctly shows the data if present', async () => {
|
||||
await createComponent();
|
||||
|
||||
expect(findPackageLastDownloadedAt().props()).toMatchObject({
|
||||
text: 'Last downloaded Aug 17, 2021',
|
||||
icon: 'download',
|
||||
size: 'm',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -127,6 +127,7 @@ export const packageData = (extend) => ({
|
|||
version: '1.0.0',
|
||||
createdAt: '2020-08-17T14:23:32Z',
|
||||
updatedAt: '2020-08-17T14:23:32Z',
|
||||
lastDownloadedAt: '2021-08-17T14:23:32Z',
|
||||
status: 'DEFAULT',
|
||||
mavenUrl: 'http://gdk.test:3000/api/v4/projects/1/packages/maven',
|
||||
npmUrl: 'http://gdk.test:3000/api/v4/projects/1/packages/npm',
|
||||
|
|
|
@ -45,7 +45,8 @@ RSpec.describe Mutations::Ci::Runner::Update do
|
|||
end
|
||||
|
||||
context 'when user can update runner', :enable_admin_mode do
|
||||
let(:admin_user) { create(:user, :admin) }
|
||||
let_it_be(:admin_user) { create(:user, :admin) }
|
||||
|
||||
let(:current_ctx) { { current_user: admin_user } }
|
||||
|
||||
context 'with valid arguments' do
|
||||
|
@ -134,8 +135,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
|
|||
response
|
||||
|
||||
expect(response[:errors]).to match_array(['user not allowed to assign runner'])
|
||||
expect(response[:runner]).to be_an_instance_of(Ci::Runner)
|
||||
expect(response[:runner]).not_to have_attributes(expected_attributes)
|
||||
expect(response[:runner]).to be_nil
|
||||
expect(runner.reload).not_to have_attributes(expected_attributes)
|
||||
expect(runner.projects).to match_array([project1])
|
||||
end
|
||||
|
@ -164,7 +164,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
|
|||
let(:mutation_params) do
|
||||
{
|
||||
id: runner.to_global_id,
|
||||
associated_projects: ['gid://gitlab/Project/-1']
|
||||
associated_projects: ["gid://gitlab/Project/#{non_existing_record_id}"]
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -191,6 +191,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
|
|||
end
|
||||
|
||||
it 'returns a descriptive error' do
|
||||
expect(response[:runner]).to be_nil
|
||||
expect(response[:errors]).to contain_exactly(
|
||||
'Maximum timeout needs to be at least 10 minutes',
|
||||
'Tags list can not be empty when runner is not allowed to pick untagged jobs'
|
||||
|
@ -202,6 +203,7 @@ RSpec.describe Mutations::Ci::Runner::Update do
|
|||
it 'returns a descriptive error' do
|
||||
mutation_params[:maintenance_note] = '1' * 1025
|
||||
|
||||
expect(response[:runner]).to be_nil
|
||||
expect(response[:errors]).to contain_exactly(
|
||||
'Maintenance note is too long (maximum is 1024 characters)'
|
||||
)
|
||||
|
|
|
@ -19,8 +19,7 @@ RSpec.describe Gitlab::Ci::Parsers::Sbom::Source::DependencyScanning do
|
|||
it 'returns expected source data' do
|
||||
is_expected.to have_attributes(
|
||||
source_type: :dependency_scanning,
|
||||
data: property_data,
|
||||
fingerprint: '4dbcb747e6f0fb3ed4f48d96b777f1d64acdf43e459fdfefad404e55c004a188'
|
||||
data: property_data
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,117 +1,187 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'fast_spec_helper'
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Pipeline::Duration do
|
||||
let(:calculated_duration) { calculate(data) }
|
||||
describe '.from_periods' do
|
||||
let(:calculated_duration) { calculate(data) }
|
||||
|
||||
shared_examples 'calculating duration' do
|
||||
it do
|
||||
expect(calculated_duration).to eq(duration)
|
||||
shared_examples 'calculating duration' do
|
||||
it do
|
||||
expect(calculated_duration).to eq(duration)
|
||||
end
|
||||
end
|
||||
|
||||
context 'test sample A' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6]]
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample B' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4],
|
||||
[0, 4]]
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample C' do
|
||||
let(:data) do
|
||||
[[0, 4],
|
||||
[2, 6],
|
||||
[5, 7],
|
||||
[8, 9]]
|
||||
end
|
||||
|
||||
let(:duration) { 8 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample D' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[2, 3],
|
||||
[4, 5],
|
||||
[6, 7]]
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample E' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[3, 9],
|
||||
[3, 4],
|
||||
[3, 5],
|
||||
[3, 8],
|
||||
[4, 5],
|
||||
[4, 7],
|
||||
[5, 8]]
|
||||
end
|
||||
|
||||
let(:duration) { 7 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample F' do
|
||||
let(:data) do
|
||||
[[1, 3],
|
||||
[2, 4],
|
||||
[2, 4],
|
||||
[2, 4],
|
||||
[5, 8]]
|
||||
end
|
||||
|
||||
let(:duration) { 6 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample G' do
|
||||
let(:data) do
|
||||
[[1, 3],
|
||||
[2, 4],
|
||||
[6, 7]]
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
def calculate(data)
|
||||
periods = data.shuffle.map do |(first, last)|
|
||||
described_class::Period.new(first, last)
|
||||
end
|
||||
|
||||
described_class.from_periods(periods.sort_by(&:first))
|
||||
end
|
||||
end
|
||||
|
||||
context 'test sample A' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[1, 2],
|
||||
[3, 4],
|
||||
[5, 6]]
|
||||
describe '.from_pipeline' do
|
||||
let_it_be(:start_time) { Time.current.change(usec: 0) }
|
||||
let_it_be(:current) { start_time + 1000 }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline) }
|
||||
let_it_be(:success_build) { create_build(:success, started_at: start_time, finished_at: start_time + 60) }
|
||||
let_it_be(:failed_build) { create_build(:failed, started_at: start_time + 60, finished_at: start_time + 120) }
|
||||
let_it_be(:canceled_build) { create_build(:canceled, started_at: start_time + 120, finished_at: start_time + 180) }
|
||||
let_it_be(:skipped_build) { create_build(:skipped, started_at: start_time) }
|
||||
let_it_be(:pending_build) { create_build(:pending) }
|
||||
let_it_be(:created_build) { create_build(:created) }
|
||||
let_it_be(:preparing_build) { create_build(:preparing) }
|
||||
let_it_be(:scheduled_build) { create_build(:scheduled) }
|
||||
let_it_be(:expired_scheduled_build) { create_build(:expired_scheduled) }
|
||||
let_it_be(:manual_build) { create_build(:manual) }
|
||||
|
||||
let!(:running_build) { create_build(:running, started_at: start_time) }
|
||||
|
||||
it 'returns the duration of the running build' do
|
||||
travel_to(current) do
|
||||
expect(described_class.from_pipeline(pipeline)).to eq 1000.seconds
|
||||
end
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
context 'when there is no running build' do
|
||||
let(:running_build) { nil }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample B' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4],
|
||||
[0, 4]]
|
||||
it 'returns the duration for all the builds' do
|
||||
travel_to(current) do
|
||||
expect(described_class.from_pipeline(pipeline)).to eq 180.seconds
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
context 'when there are bridge jobs' do
|
||||
let!(:success_bridge) { create_bridge(:success, started_at: start_time + 220, finished_at: start_time + 280) }
|
||||
let!(:failed_bridge) { create_bridge(:failed, started_at: start_time + 180, finished_at: start_time + 240) }
|
||||
let!(:skipped_bridge) { create_bridge(:skipped, started_at: start_time) }
|
||||
let!(:created_bridge) { create_bridge(:created) }
|
||||
let!(:manual_bridge) { create_bridge(:manual) }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
it 'returns the duration of the running build' do
|
||||
travel_to(current) do
|
||||
expect(described_class.from_pipeline(pipeline)).to eq 1000.seconds
|
||||
end
|
||||
end
|
||||
|
||||
context 'test sample C' do
|
||||
let(:data) do
|
||||
[[0, 4],
|
||||
[2, 6],
|
||||
[5, 7],
|
||||
[8, 9]]
|
||||
context 'when there is no running build' do
|
||||
let!(:running_build) { nil }
|
||||
|
||||
it 'returns the duration for all the builds and bridge jobs' do
|
||||
travel_to(current) do
|
||||
expect(described_class.from_pipeline(pipeline)).to eq 280.seconds
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
let(:duration) { 8 }
|
||||
private
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample D' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[2, 3],
|
||||
[4, 5],
|
||||
[6, 7]]
|
||||
def create_build(trait, **opts)
|
||||
create(:ci_build, trait, pipeline: pipeline, **opts)
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample E' do
|
||||
let(:data) do
|
||||
[[0, 1],
|
||||
[3, 9],
|
||||
[3, 4],
|
||||
[3, 5],
|
||||
[3, 8],
|
||||
[4, 5],
|
||||
[4, 7],
|
||||
[5, 8]]
|
||||
def create_bridge(trait, **opts)
|
||||
create(:ci_bridge, trait, pipeline: pipeline, **opts)
|
||||
end
|
||||
|
||||
let(:duration) { 7 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample F' do
|
||||
let(:data) do
|
||||
[[1, 3],
|
||||
[2, 4],
|
||||
[2, 4],
|
||||
[2, 4],
|
||||
[5, 8]]
|
||||
end
|
||||
|
||||
let(:duration) { 6 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
context 'test sample G' do
|
||||
let(:data) do
|
||||
[[1, 3],
|
||||
[2, 4],
|
||||
[6, 7]]
|
||||
end
|
||||
|
||||
let(:duration) { 4 }
|
||||
|
||||
it_behaves_like 'calculating duration'
|
||||
end
|
||||
|
||||
def calculate(data)
|
||||
periods = data.shuffle.map do |(first, last)|
|
||||
described_class::Period.new(first, last)
|
||||
end
|
||||
|
||||
described_class.from_periods(periods.sort_by(&:first))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,8 +12,7 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Source do
|
|||
'source_file' => { 'path' => 'package.json' },
|
||||
'package_manager' => { 'name' => 'npm' },
|
||||
'language' => { 'name' => 'JavaScript' }
|
||||
},
|
||||
fingerprint: '4dbcb747e6f0fb3ed4f48d96b777f1d64acdf43e459fdfefad404e55c004a188'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -22,8 +21,7 @@ RSpec.describe Gitlab::Ci::Reports::Sbom::Source do
|
|||
it 'has correct attributes' do
|
||||
expect(subject).to have_attributes(
|
||||
source_type: attributes[:type],
|
||||
data: attributes[:data],
|
||||
fingerprint: attributes[:fingerprint]
|
||||
data: attributes[:data]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,6 +9,20 @@ RSpec.describe VersionCheck do
|
|||
end
|
||||
end
|
||||
|
||||
context 'reactive cache properties' do
|
||||
describe '.reactive_cache_refresh_interval' do
|
||||
it 'returns 12.hours' do
|
||||
expect(described_class.reactive_cache_refresh_interval).to eq(12.hours)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.reactive_cache_lifetime' do
|
||||
it 'returns 7.days' do
|
||||
expect(described_class.reactive_cache_lifetime).to eq(7.days)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#calculate_reactive_cache' do
|
||||
context 'response code is 200' do
|
||||
before do
|
||||
|
|
|
@ -3813,7 +3813,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do
|
|||
describe '#upstream_root' do
|
||||
subject { pipeline.upstream_root }
|
||||
|
||||
let_it_be(:pipeline) { create(:ci_pipeline) }
|
||||
let_it_be_with_refind(:pipeline) { create(:ci_pipeline) }
|
||||
|
||||
context 'when pipeline is child of child pipeline' do
|
||||
let!(:root_ancestor) { create(:ci_pipeline) }
|
||||
|
|
|
@ -38,6 +38,15 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do
|
|||
C = n_("c")
|
||||
^^^^^^^ #{msg}
|
||||
CODE
|
||||
<<~'CODE',
|
||||
A = _('a' \
|
||||
^^^^^^^ [...]
|
||||
'b')
|
||||
CODE
|
||||
<<~'CODE',
|
||||
A = _("a#{s}")
|
||||
^^^^^^^^^^ [...]
|
||||
CODE
|
||||
<<~CODE,
|
||||
class MyClass
|
||||
def self.translations
|
||||
|
@ -100,6 +109,9 @@ RSpec.describe RuboCop::Cop::StaticTranslationDefinition do
|
|||
'CONSTANT_1 = __("a")',
|
||||
'CONSTANT_2 = s__("a")',
|
||||
'CONSTANT_3 = n__("a")',
|
||||
'CONSTANT_var = _(code)',
|
||||
'CONSTANT_int = _(1)',
|
||||
'CONSTANT_none = _()',
|
||||
<<~CODE,
|
||||
class MyClass
|
||||
def self.method
|
||||
|
|
|
@ -47,7 +47,11 @@ RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute' do
|
|||
|
||||
it 'reassigns associated projects and returns success response' do
|
||||
expect(execute).to be_success
|
||||
expect(runner.reload.projects.ids).to eq([owner_project.id] + project_ids)
|
||||
|
||||
runner.reload
|
||||
|
||||
expect(runner.owner_project).to eq(owner_project)
|
||||
expect(runner.projects.ids).to match_array([owner_project.id] + project_ids)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -56,7 +60,11 @@ RSpec.describe ::Ci::Runners::SetRunnerAssociatedProjectsService, '#execute' do
|
|||
|
||||
it 'reassigns associated projects and returns success response' do
|
||||
expect(execute).to be_success
|
||||
expect(runner.reload.projects.ids).to eq([owner_project.id] + project_ids)
|
||||
|
||||
runner.reload
|
||||
|
||||
expect(runner.owner_project).to eq(owner_project)
|
||||
expect(runner.projects.ids).to match_array([owner_project.id] + project_ids)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -2,18 +2,10 @@
|
|||
|
||||
module UsageDataHelpers
|
||||
SMAU_KEYS = %i(
|
||||
snippet_create
|
||||
snippet_update
|
||||
snippet_comment
|
||||
merge_request_comment
|
||||
commit_comment
|
||||
wiki_pages_create
|
||||
wiki_pages_update
|
||||
wiki_pages_delete
|
||||
navbar_searches
|
||||
cycle_analytics_views
|
||||
productivity_analytics_views
|
||||
source_code_pushes
|
||||
).freeze
|
||||
|
||||
COUNTS_KEYS = %i(
|
||||
|
|
Loading…
Reference in New Issue