Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-19 18:10:34 +00:00
parent 8cfe3415e9
commit 9134da0488
64 changed files with 494 additions and 291 deletions

View File

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

View File

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

View File

@ -1 +1 @@
b4c1f29c487a41b2e69a31a99f6b0ac462c81ce4
f39f02c9dd07a80ed1443d42bbf158bed901c777

View File

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

View File

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

View File

@ -4,6 +4,7 @@ query getPackageDetails($id: PackagesPackageID!) {
name
packageType
version
lastDownloadedAt
createdAt
updatedAt
status

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1 @@
f481a617b3fc4fa95daec75619029dc8ef3a02d55e86b940eda78d6a93e6e78b

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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