Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-09-16 18:10:35 +00:00
parent 282e71d660
commit 8e359577a7
97 changed files with 812 additions and 247 deletions

View File

@ -9,6 +9,7 @@ module VerifiesWithEmail
included do
prepend_before_action :verify_with_email, only: :create, unless: -> { two_factor_enabled? }
skip_before_action :required_signup_info, only: :successful_verification
end
def verify_with_email

View File

@ -32,6 +32,7 @@ class RegistrationsController < Devise::RegistrationsController
def create
set_user_state
token = set_custom_confirmation_token
super do |new_user|
accept_pending_invitations if new_user.persisted?
@ -39,6 +40,7 @@ class RegistrationsController < Devise::RegistrationsController
persist_accepted_terms_if_required(new_user)
set_role_required(new_user)
track_experiment_event(new_user)
send_custom_confirmation_instructions(new_user, token)
if pending_approval?
NotificationService.new.new_instance_access_request(new_user)
@ -118,8 +120,10 @@ class RegistrationsController < Devise::RegistrationsController
def after_inactive_sign_up_path_for(resource)
Gitlab::AppLogger.info(user_created_message)
return new_user_session_path(anchor: 'login-pane') if resource.blocked_pending_approval?
return dashboard_projects_path if Feature.enabled?(:soft_email_confirmation)
return identity_verification_redirect_path if custom_confirmation_enabled?(resource)
Feature.enabled?(:soft_email_confirmation) ? dashboard_projects_path : users_almost_there_path(email: resource.email)
users_almost_there_path(email: resource.email)
end
private
@ -236,6 +240,22 @@ class RegistrationsController < Devise::RegistrationsController
# signing up and becoming users
experiment(:logged_out_marketing_header, actor: new_user).track(:signed_up) if new_user.persisted?
end
def identity_verification_redirect_path
# overridden by EE module
end
def custom_confirmation_enabled?(resource)
# overridden by EE module
end
def set_custom_confirmation_token
# overridden by EE module
end
def send_custom_confirmation_instructions(user, token)
# overridden by EE module
end
end
RegistrationsController.prepend_mod_with('RegistrationsController')

View File

@ -18,3 +18,5 @@ module Types
end
end
end
Types::BranchProtections::BaseAccessLevelType.prepend_mod

View File

@ -25,3 +25,5 @@ module Types
end
end
end
Types::BranchRules::BranchProtectionType.prepend_mod_with('Types::BranchRules::BranchProtectionType')

View File

@ -13,3 +13,5 @@ module Emails
end
end
end
Emails::IdentityVerification.prepend_mod

View File

@ -220,6 +220,7 @@ module Packages
valid_until_field,
rfc822_field('NotAutomatic', !@distribution.automatic, !@distribution.automatic),
rfc822_field('ButAutomaticUpgrades', @distribution.automatic_upgrades, !@distribution.automatic && @distribution.automatic_upgrades),
rfc822_field('Acquire-By-Hash', 'yes'),
rfc822_field('Architectures', @distribution.architectures.map { |architecture| architecture.name }.sort.join(' ')),
rfc822_field('Components', @distribution.components.map { |component| component.name }.sort.join(' ')),
rfc822_field('Description', @distribution.description)

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module Packages
module Rpm
module RepositoryMetadata
class BaseBuilder
def execute
build_empty_structure
end
private
def build_empty_structure
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
xml.public_send(self.class::ROOT_TAG, self.class::ROOT_ATTRIBUTES) # rubocop:disable GitlabSecurity/PublicSend
end.to_xml
end
end
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Packages
module Rpm
module RepositoryMetadata
class BuildFilelistXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
ROOT_TAG = 'filelists'
ROOT_ATTRIBUTES = {
xmlns: 'http://linux.duke.edu/metadata/filelists',
packages: '0'
}.freeze
end
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module Packages
module Rpm
module RepositoryMetadata
class BuildOtherXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
ROOT_TAG = 'otherdata'
ROOT_ATTRIBUTES = {
xmlns: 'http://linux.duke.edu/metadata/other',
packages: '0'
}.freeze
end
end
end
end

View File

@ -0,0 +1,15 @@
# frozen_string_literal: true
module Packages
module Rpm
module RepositoryMetadata
class BuildPrimaryXml < ::Packages::Rpm::RepositoryMetadata::BaseBuilder
ROOT_TAG = 'metadata'
ROOT_ATTRIBUTES = {
xmlns: 'http://linux.duke.edu/metadata/common',
'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm',
packages: '0'
}.freeze
end
end
end
end

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
module Packages
module Rpm
module RepositoryMetadata
class BuildRepomdXml
attr_reader :data
ROOT_ATTRIBUTES = {
xmlns: 'http://linux.duke.edu/metadata/repo',
'xmlns:rpm': 'http://linux.duke.edu/metadata/rpm'
}.freeze
# Expected `data` structure
#
# data = {
# filelists: {
# checksum: { type: "sha256", value: "123" },
# location: { href: "repodata/123-filelists.xml.gz" },
# ...
# },
# ...
# }
def initialize(data)
@data = data
end
def execute
build_repomd
end
private
def build_repomd
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
xml.repomd(ROOT_ATTRIBUTES) do
xml.revision Time.now.to_i
build_data_info(xml)
end
end.to_xml
end
def build_data_info(xml)
data.each do |filename, info|
xml.data(type: filename) do
build_file_info(info, xml)
end
end
end
def build_file_info(info, xml)
info.each do |key, attributes|
value = attributes.delete(:value)
xml.public_send(key, value, attributes) # rubocop:disable GitlabSecurity/PublicSend
end
end
end
end
end
end

View File

@ -27,10 +27,12 @@ module Users
attr_reader :user
def verification_rate_limited?
Gitlab::ApplicationRateLimiter.throttled?(:email_verification, scope: token)
Gitlab::ApplicationRateLimiter.throttled?(:email_verification, scope: user[attr])
end
def valid?
return false unless token.present?
Devise.secure_compare(user[attr], digest)
end
@ -59,11 +61,11 @@ module Users
case reason
when :rate_limited
format(s_("IdentityVerification|You've reached the maximum amount of tries. "\
'Wait %{interval} or resend a new code and try again.'), interval: email_verification_interval)
'Wait %{interval} or send a new code and try again.'), interval: email_verification_interval)
when :expired
s_('IdentityVerification|The code has expired. Resend a new code and try again.')
s_('IdentityVerification|The code has expired. Send a new code and try again.')
when :invalid
s_('IdentityVerification|The code is incorrect. Enter it again, or resend a new code.')
s_('IdentityVerification|The code is incorrect. Enter it again, or send a new code.')
end
end

View File

@ -8,4 +8,4 @@
%p.gl-pt-2
- redirect_url_start = '<a href="%{url}"">'.html_safe % { url: @redirect_url }
- redirect_url_end = '</a>'.html_safe
= html_escape(s_("IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment or %{redirect_url_start}click here%{redirect_url_end} to refresh.")) % { redirect_url_start: redirect_url_start, redirect_url_end: redirect_url_end }
= html_escape(s_("IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}.")) % { redirect_url_start: redirect_url_start, redirect_url_end: redirect_url_end }

View File

@ -1,8 +0,0 @@
---
name: identity_verification
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/95722
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/371389
milestone: '15.4'
type: development
group: group::anti-abuse
default_enabled: false

View File

@ -10,6 +10,10 @@ value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: merge_request
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: design_management_designs
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: design_management_designs
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: design_management_designs
event: delete
distribution:
- ce
- ee

View File

@ -1,4 +1,5 @@
---
data_category: optional
key_path: counts.diff_searches
description: Total count of merge request diff searches
product_section: dev
@ -11,7 +12,10 @@ milestone: '14.2'
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/66522
time_frame: all
data_source: redis
data_category: optional
instrumentation_class: RedisMetric
options:
prefix: diff
event: searches
distribution:
- ce
- ee

View File

@ -11,6 +11,10 @@ value_type: number
status: active
time_frame: all
data_source: redis
instrumentation_class: RedisMetric
options:
prefix: service_usage_data
event: download_payload_click
distribution:
- ce
- ee

View File

@ -0,0 +1,59 @@
# frozen_string_literal: true
class RemoveUnusedAggregationColumns < Gitlab::Database::Migration[2.0]
disable_ddl_transaction!
def up
with_lock_retries do
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_processed_records
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_runtimes_in_seconds
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_issues_updated_at
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_mrs_updated_at
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_issues_id
remove_column :analytics_cycle_analytics_aggregations, :last_full_run_merge_requests_id
end
end
def down
with_lock_retries do
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_processed_records,
:integer,
array: true,
default: [],
null: false,
if_not_exists: true)
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_runtimes_in_seconds,
:integer,
array: true,
default: [],
null: false,
if_not_exists: true)
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_issues_updated_at,
:datetime_with_timezone,
if_not_exists: true)
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_mrs_updated_at,
:datetime_with_timezone,
if_not_exists: true)
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_issues_id,
:integer,
if_not_exists: true)
add_column(:analytics_cycle_analytics_aggregations,
:last_full_run_merge_requests_id,
:integer,
if_not_exists: true)
end
add_check_constraint(:analytics_cycle_analytics_aggregations,
'CARDINALITY(last_full_run_runtimes_in_seconds) <= 10',
'chk_rails_7810292ec9')
add_check_constraint(:analytics_cycle_analytics_aggregations,
'CARDINALITY(last_full_run_processed_records) <= 10',
'chk_rails_8b9e89687c')
end
end

View File

@ -0,0 +1 @@
0bc8cd07786c950037731a0443e0d7da9c9692da39f13787b24769dbd122ba88

View File

@ -10817,18 +10817,12 @@ CREATE TABLE analytics_cycle_analytics_aggregations (
group_id bigint NOT NULL,
incremental_runtimes_in_seconds integer[] DEFAULT '{}'::integer[] NOT NULL,
incremental_processed_records integer[] DEFAULT '{}'::integer[] NOT NULL,
last_full_run_runtimes_in_seconds integer[] DEFAULT '{}'::integer[] NOT NULL,
last_full_run_processed_records integer[] DEFAULT '{}'::integer[] NOT NULL,
last_incremental_issues_id integer,
last_incremental_merge_requests_id integer,
last_full_run_issues_id integer,
last_full_run_merge_requests_id integer,
last_incremental_run_at timestamp with time zone,
last_incremental_issues_updated_at timestamp with time zone,
last_incremental_merge_requests_updated_at timestamp with time zone,
last_full_run_at timestamp with time zone,
last_full_run_issues_updated_at timestamp with time zone,
last_full_run_mrs_updated_at timestamp with time zone,
last_consistency_check_updated_at timestamp with time zone,
enabled boolean DEFAULT true NOT NULL,
full_runtimes_in_seconds integer[] DEFAULT '{}'::integer[] NOT NULL,
@ -10846,8 +10840,6 @@ CREATE TABLE analytics_cycle_analytics_aggregations (
last_consistency_check_merge_requests_end_event_timestamp timestamp with time zone,
last_consistency_check_merge_requests_issuable_id bigint,
CONSTRAINT chk_rails_1ef688e577 CHECK ((cardinality(incremental_runtimes_in_seconds) <= 10)),
CONSTRAINT chk_rails_7810292ec9 CHECK ((cardinality(last_full_run_processed_records) <= 10)),
CONSTRAINT chk_rails_8b9e89687c CHECK ((cardinality(last_full_run_runtimes_in_seconds) <= 10)),
CONSTRAINT chk_rails_e16bf3913a CHECK ((cardinality(incremental_processed_records) <= 10)),
CONSTRAINT full_processed_records_size CHECK ((cardinality(full_processed_records) <= 10)),
CONSTRAINT full_runtimes_in_seconds_size CHECK ((cardinality(full_runtimes_in_seconds) <= 10))

View File

@ -10132,6 +10132,7 @@ Branch protection details for a branch rule.
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="branchprotectionallowforcepush"></a>`allowForcePush` | [`Boolean!`](#boolean) | Toggle force push to the branch for users with write access. |
| <a id="branchprotectioncodeownerapprovalrequired"></a>`codeOwnerApprovalRequired` | [`Boolean!`](#boolean) | Enforce code owner approvals before allowing a merge. |
| <a id="branchprotectionmergeaccesslevels"></a>`mergeAccessLevels` | [`MergeAccessLevelConnection`](#mergeaccesslevelconnection) | Details about who can merge when this branch is the source branch. (see [Connections](#connections)) |
| <a id="branchprotectionpushaccesslevels"></a>`pushAccessLevels` | [`PushAccessLevelConnection`](#pushaccesslevelconnection) | Details about who can push when this branch is the source branch. (see [Connections](#connections)) |
@ -13857,6 +13858,8 @@ Represents the merge access level of a branch protection.
| ---- | ---- | ----------- |
| <a id="mergeaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
| <a id="mergeaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
| <a id="mergeaccesslevelgroup"></a>`group` | [`Group`](#group) | Group associated with this access level. |
| <a id="mergeaccessleveluser"></a>`user` | [`UserCore`](#usercore) | User associated with this access level. |
### `MergeRequest`
@ -17173,6 +17176,8 @@ Represents the push access level of a branch protection.
| ---- | ---- | ----------- |
| <a id="pushaccesslevelaccesslevel"></a>`accessLevel` | [`Int!`](#int) | GitLab::Access level. |
| <a id="pushaccesslevelaccessleveldescription"></a>`accessLevelDescription` | [`String!`](#string) | Human readable representation for this access level. |
| <a id="pushaccesslevelgroup"></a>`group` | [`Group`](#group) | Group associated with this access level. |
| <a id="pushaccessleveluser"></a>`user` | [`UserCore`](#usercore) | User associated with this access level. |
### `PushRules`

View File

@ -210,48 +210,27 @@ To reach the definition of done, the merge request must create no regressions an
- Verified as working in production on GitLab.com.
- Verified as working for self-managed instances.
If a regression occurs, we prefer you revert the change. We break the definition of done into two phases: [MR Merge](#mr-merge) and [Production use](#production-use).
If a regression occurs, we prefer you revert the change.
Your contribution is *incomplete* until you have made sure it meets all of these
requirements.
### MR Merge
### Functionality
1. Clear title and description explaining the relevancy of the contribution.
1. Working and clean code that is commented where needed.
1. The change is evaluated to [limit the impact of far-reaching work](https://about.gitlab.com/handbook/engineering/development/#reducing-the-impact-of-far-reaching-work).
1. Testing:
- [Unit, integration, and system tests](../testing_guide/index.md) that all pass
on the CI server.
- Peer member testing is optional but recommended when the risk of a change is high.
This includes when the changes are [far-reaching](https://about.gitlab.com/handbook/engineering/development/#reducing-the-impact-of-far-reaching-work)
or are for [components critical for security](../code_review.md#security).
- Description includes any steps or setup required to ensure reviewers can view the changes you've made (for example, include any information about feature flags).
- Regressions and bugs are covered with tests that reduce the risk of the issue happening
again.
- For tests that use Capybara, read
[how to write reliable, asynchronous integration tests](https://thoughtbot.com/blog/write-reliable-asynchronous-integration-tests-with-capybara).
- [Black-box tests/end-to-end tests](../testing_guide/testing_levels.md#black-box-tests-at-the-system-level-aka-end-to-end-tests)
added if required. Please contact [the quality team](https://about.gitlab.com/handbook/engineering/quality/#teams)
with any questions.
- The change is tested in a review app where possible and if appropriate.
1. In case of UI changes:
- Use available components from the GitLab Design System,
[Pajamas](https://design.gitlab.com/).
- The MR must include *Before* and *After* screenshots if UI changes are made.
- If the MR changes CSS classes, please include the list of affected pages, which
can be found by running `grep css-class ./app -R`.
1. [Performance guidelines](../merge_request_performance_guidelines.md) have been followed.
1. [Secure coding guidelines](https://gitlab.com/gitlab-com/gl-security/security-guidelines) have been followed.
1. [Application and rate limit guidelines](../merge_request_application_and_rate_limit_guidelines.md) have been followed.
1. [Documented](../documentation/index.md) in the `/doc` directory.
1. If your MR touches code that executes shell commands, reads or opens files, or
handles paths to files on disk, make sure it adheres to the
[shell command guidelines](../shell_commands.md)
1. [Code changes should include observability instrumentation](../code_review.md#observability-instrumentation).
1. If your code needs to handle file storage, see the [uploads documentation](../uploads/index.md).
1. If your merge request adds one or more migrations:
- Make sure to execute all migrations on a fresh database before the MR is reviewed.
If the review leads to large changes in the MR, execute the migrations again
after the review is complete.
- Write tests for more complex migrations.
1. If your merge request adds one or more migrations, make sure to execute all migrations on a fresh database
before the MR is reviewed.
If the review leads to large changes in the MR, execute the migrations again
after the review is complete.
1. If your merge request adds new validations to existing models, to make sure the
data processing is backwards compatible:
@ -270,12 +249,37 @@ requirements.
[self-managed instances](../../subscriptions/self_managed/index.md), so keep
that in mind for any data implications with your merge request.
### Testing
1. [Unit, integration, and system tests](../testing_guide/index.md) that all pass
on the CI server.
1. Peer member testing is optional but recommended when the risk of a change is high.
This includes when the changes are [far-reaching](https://about.gitlab.com/handbook/engineering/development/#reducing-the-impact-of-far-reaching-work)
or are for [components critical for security](../code_review.md#security).
1. Regressions and bugs are covered with tests that reduce the risk of the issue happening
again.
1. For tests that use Capybara, read
[how to write reliable, asynchronous integration tests](https://thoughtbot.com/blog/write-reliable-asynchronous-integration-tests-with-capybara).
1. [Black-box tests/end-to-end tests](../testing_guide/testing_levels.md#black-box-tests-at-the-system-level-aka-end-to-end-tests)
added if required. Please contact [the quality team](https://about.gitlab.com/handbook/engineering/quality/#teams)
with any questions.
1. The change is tested in a review app where possible and if appropriate.
1. Code affected by a feature flag is covered by [automated tests with the feature flag enabled and disabled](../feature_flags/index.md#feature-flags-in-tests), or both
states are tested as part of peer member testing or as part of the rollout plan.
1. [Performance guidelines](../merge_request_performance_guidelines.md) have been followed.
1. [Secure coding guidelines](https://gitlab.com/gitlab-com/gl-security/security-guidelines) have been followed.
1. [Application and rate limit guidelines](../merge_request_application_and_rate_limit_guidelines.md) have been followed.
1. [Documented](../documentation/index.md) in the `/doc` directory.
1. If your merge request adds one or more migrations, write tests for more complex migrations.
### UI changes
1. Use available components from the GitLab Design System,
[Pajamas](https://design.gitlab.com/).
1. The MR must include *Before* and *After* screenshots if UI changes are made.
1. If the MR changes CSS classes, please include the list of affected pages, which
can be found by running `grep css-class ./app -R`.
### Description of changes
1. Clear title and description explaining the relevancy of the contribution.
1. Description includes any steps or setup required to ensure reviewers can view the changes you've made (for example, include any information about feature flags).
1. [Changelog entry added](../changelog.md), if necessary.
1. If your merge request introduces changes that require additional steps when
installing GitLab from source, add them to `doc/install/installation.md` in
@ -285,10 +289,13 @@ requirements.
`doc/update/upgrading_from_source.md` in the same merge request. If these
instructions are specific to a version, add them to the "Version specific
upgrading instructions" section.
1. Reviewed by relevant reviewers, and all concerns are addressed for Availability, Regressions, and Security. Documentation reviews should take place as soon as possible, but they should not block a merge request.
### Approval
1. The [MR acceptance checklist](../code_review.md#acceptance-checklist) has been checked as confirmed in the MR.
1. Create an issue in the [infrastructure issue tracker](https://gitlab.com/gitlab-com/gl-infra/reliability/-/issues) to inform the Infrastructure department when your contribution is changing default settings or introduces a new setting, if relevant.
1. An agreed-upon [rollout plan](https://about.gitlab.com/handbook/engineering/development/processes/rollout-plans/).
1. Reviewed by relevant reviewers, and all concerns are addressed for Availability, Regressions, and Security. Documentation reviews should take place as soon as possible, but they should not block a merge request.
1. Your merge request has at least 1 approval, but depending on your changes
you might need additional approvals. Refer to the [Approval guidelines](../code_review.md#approval-guidelines).
- You don't have to select any specific approvers, but you can if you really want
@ -297,6 +304,8 @@ requirements.
### Production use
The following items are checked after the merge request has been merged:
1. Confirmed to be working in staging before implementing the change in production, where possible.
1. Confirmed to be working in the production with no new [Sentry](https://about.gitlab.com/handbook/engineering/monitoring/#sentry) errors after the contribution is deployed.
1. Confirmed that the [rollout plan](https://about.gitlab.com/handbook/engineering/development/processes/rollout-plans/) has been completed.

View File

@ -4,7 +4,7 @@ group: unassigned
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
---
# `Gemfile` guidelines
# Gemfile guidelines
When adding a new entry to `Gemfile` or upgrading an existing dependency pay
attention to the following rules.

View File

@ -535,6 +535,7 @@ and [Helm Chart deployments](https://docs.gitlab.com/charts/). They come with ap
hook type. Global server hooks can no longer be a single hook file in the root of the custom hooks directory. For example, you must use `<custom_hooks_dir>/<hook_name>.d/*` rather
than `<custom_hooks_dir>/<hook_name>`.
- [Incorrect deletion of object storage files on Geo secondary sites]((https://gitlab.com/gitlab-org/gitlab/-/issues/371397)) can occur in certain situations. See [Geo: Incorrect object storage LFS file deletion on secondary site issue in GitLab 15.0.0 to 15.3.2](#geo-incorrect-object-storage-lfs-file-deletion-on-secondary-sites-in-gitlab-1500-to-1532).
- The `FF_GITLAB_REGISTRY_HELPER_IMAGE` [feature flag](../administration/feature_flags.md#enable-or-disable-the-feature) is removed and helper images are always pulled from GitLab Registry.
### 14.10.0

View File

@ -46,7 +46,7 @@ module API
def present_index_file!(file_type)
relation = "::Packages::Debian::#{project_or_group.class.name}ComponentFile".constantize
component_file = relation
relation = relation
.preload_distribution
.with_container(project_or_group)
.with_codename_or_suite(params[:distribution])
@ -55,9 +55,10 @@ module API
.with_architecture_name(params[:architecture])
.with_compression_type(nil)
.order_created_asc
.last!
present_carrierwave_file!(component_file.file)
relation = relation.with_file_sha256(params[:file_sha256]) if params[:file_sha256]
present_carrierwave_file!(relation.last!.file)
end
end
@ -135,6 +136,17 @@ module API
get 'Packages' do
present_index_file!(:di_packages)
end
# GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/by-hash/SHA256/:file_sha256
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The installer (udeb) binary files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
end
route_setting :authentication, authenticate_non_public: true
get 'by-hash/SHA256/:file_sha256' do
present_index_file!(:di_packages)
end
end
namespace 'source', requirements: COMPONENT_ARCHITECTURE_REQUIREMENTS do
@ -148,6 +160,17 @@ module API
get 'Sources' do
present_index_file!(:sources)
end
# GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/source/by-hash/SHA256/:file_sha256
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The source files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
end
route_setting :authentication, authenticate_non_public: true
get 'by-hash/SHA256/:file_sha256' do
present_index_file!(:sources)
end
end
params do
@ -165,6 +188,17 @@ module API
get 'Packages' do
present_index_file!(:packages)
end
# GET {projects|groups}/:id/packages/debian/dists/*distribution/:component/binary-:architecture/by-hash/SHA256/:file_sha256
# https://wiki.debian.org/DebianRepository/Format?action=show&redirect=RepositoryFormat#indices_acquisition_via_hashsums_.28by-hash.29
desc 'The binary files index by hash' do
detail 'This feature was introduced in GitLab 15.4'
end
route_setting :authentication, authenticate_non_public: true
get 'by-hash/SHA256/:file_sha256' do
present_index_file!(:packages)
end
end
end
end

View File

@ -45,6 +45,11 @@ module API
desc 'Upload a RPM package'
post do
authorize_create_package!(authorized_user_project)
if authorized_user_project.actual_limits.exceeded?(:rpm_max_file_size, params[:file].size)
bad_request!('File is too large')
end
not_found!
end

View File

@ -10,16 +10,16 @@ module Gitlab
CycleAnalyticsCounter,
ProductivityAnalyticsCounter,
SourceCodeCounter,
MergeRequestCounter,
DesignsCounter,
KubernetesAgentCounter,
DiffsCounter,
ServiceUsageDataCounter,
MergeRequestWidgetExtensionCounter
].freeze
COUNTERS_MIGRATED_TO_INSTRUMENTATION_CLASSES = [
PackageEventCounter,
MergeRequestCounter,
DesignsCounter,
DiffsCounter,
ServiceUsageDataCounter,
WebIdeCounter
].freeze

View File

@ -19821,18 +19821,36 @@ msgstr ""
msgid "Identities"
msgstr ""
msgid "IdentityVerification|A new code has been sent."
msgstr ""
msgid "IdentityVerification|Before you create your first project, we need you to verify your identity with a valid payment method. You will not be charged during this step. If we ever need to charge you, we will let you know."
msgstr ""
msgid "IdentityVerification|Before you create your group, we need you to verify your identity with a valid payment method. You will not be charged during this step. If we ever need to charge you, we will let you know."
msgstr ""
msgid "IdentityVerification|Before you finish creating your account, we need to verify your identity. On the verification page, enter the following code."
msgstr ""
msgid "IdentityVerification|Before you sign in, we need to verify your identity. Enter the following code on the sign-in page."
msgstr ""
msgid "IdentityVerification|Confirm your email address"
msgstr ""
msgid "IdentityVerification|Create a project"
msgstr ""
msgid "IdentityVerification|Didn't receive a code?"
msgstr ""
msgid "IdentityVerification|Enter a code."
msgstr ""
msgid "IdentityVerification|Enter a valid code."
msgstr ""
msgid "IdentityVerification|For added security, you'll need to verify your identity in a few quick steps."
msgstr ""
@ -19881,16 +19899,22 @@ msgstr ""
msgid "IdentityVerification|Resend code"
msgstr ""
msgid "IdentityVerification|Send a new code"
msgstr ""
msgid "IdentityVerification|Send code"
msgstr ""
msgid "IdentityVerification|Something went wrong. Please try again."
msgstr ""
msgid "IdentityVerification|Step 1: Verify phone number"
msgstr ""
msgid "IdentityVerification|The code has expired. Resend a new code and try again."
msgid "IdentityVerification|The code has expired. Send a new code and try again."
msgstr ""
msgid "IdentityVerification|The code is incorrect. Enter it again, or resend a new code."
msgid "IdentityVerification|The code is incorrect. Enter it again, or send a new code."
msgstr ""
msgid "IdentityVerification|Verification code"
@ -19902,6 +19926,9 @@ msgstr ""
msgid "IdentityVerification|Verify code"
msgstr ""
msgid "IdentityVerification|Verify email address"
msgstr ""
msgid "IdentityVerification|Verify payment method"
msgstr ""
@ -19914,10 +19941,13 @@ msgstr ""
msgid "IdentityVerification|You will receive a text containing a code. Standard charges may apply."
msgstr ""
msgid "IdentityVerification|You've reached the maximum amount of tries. Wait %{interval} or resend a new code and try again."
msgid "IdentityVerification|You've reached the maximum amount of resends. Wait %{interval} and try again."
msgstr ""
msgid "IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment or %{redirect_url_start}click here%{redirect_url_end} to refresh."
msgid "IdentityVerification|You've reached the maximum amount of tries. Wait %{interval} or send a new code and try again."
msgstr ""
msgid "IdentityVerification|Your account has been successfully verified. You'll be redirected to your account in just a moment. You can also %{redirect_url_start}refresh the page%{redirect_url_end}."
msgstr ""
msgid "IdentityVerification|Your verification code expires after %{expires_in_minutes} minutes."

View File

@ -129,6 +129,10 @@ RSpec.describe ConfirmationsController do
subject(:perform_request) { post(:create, params: { user: { email: user.email } }) }
before do
stub_feature_flags(identity_verification: false)
end
context 'when reCAPTCHA is disabled' do
before do
stub_application_setting(recaptcha_enabled: false)

View File

@ -122,6 +122,7 @@ RSpec.describe RegistrationsController do
context 'when `send_user_confirmation_email` is true' do
before do
stub_application_setting(send_user_confirmation_email: true)
stub_feature_flags(identity_verification: false)
end
it 'sends a confirmation email' do
@ -134,6 +135,10 @@ RSpec.describe RegistrationsController do
end
context 'email confirmation' do
before do
stub_feature_flags(identity_verification: false)
end
context 'when send_user_confirmation_email is false' do
it 'signs the user in' do
stub_application_setting(send_user_confirmation_email: false)

View File

@ -38,6 +38,12 @@ FactoryBot.define do
file_fixture { 'spec/fixtures/packages/debian/distribution/D-I-Packages' }
end
trait(:older_sha256) do
created_at { '2020-01-24T08:00:00Z' }
file_sha256 { '157a1ad2b9102038560eea56771913b312ebf25093f5ef3b9842021c639c880d' }
file_fixture { 'spec/fixtures/packages/debian/distribution/OtherSHA256' }
end
trait(:object_storage) do
file_store { Packages::PackageFileUploader::Store::REMOTE }
end

View File

@ -6,6 +6,7 @@ FactoryBot.define do
project
transient do
ee { false }
default_push_level { true }
default_merge_level { true }
default_access_level { true }
@ -17,14 +18,11 @@ FactoryBot.define do
ProtectedBranches::CacheService.new(protected_branch.project).refresh
end
after(:build) do |protected_branch, evaluator|
if evaluator.default_access_level && evaluator.default_push_level
protected_branch.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
end
after(:build) do |obj, ctx|
next if ctx.ee || !ctx.default_access_level
if evaluator.default_access_level && evaluator.default_merge_level
protected_branch.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER)
end
obj.push_access_levels.new(access_level: Gitlab::Access::MAINTAINER) if ctx.default_push_level
obj.merge_access_levels.new(access_level: Gitlab::Access::MAINTAINER) if ctx.default_merge_level
end
trait :create_branch_on_repository do

View File

@ -34,7 +34,7 @@ RSpec.describe "Admin Runners" do
context "when there are runners" do
context "with an instance runner" do
let!(:instance_runner) { create(:ci_runner, :instance) }
let_it_be(:instance_runner) { create(:ci_runner, :instance) }
before do
visit admin_runners_path
@ -86,10 +86,12 @@ RSpec.describe "Admin Runners" do
end
describe 'search' do
before do
before_all do
create(:ci_runner, :instance, description: 'runner-foo')
create(:ci_runner, :instance, description: 'runner-bar')
end
before do
visit admin_runners_path
end
@ -130,10 +132,12 @@ RSpec.describe "Admin Runners" do
end
describe 'filter by paused' do
before do
before_all do
create(:ci_runner, :instance, description: 'runner-active')
create(:ci_runner, :instance, description: 'runner-paused', active: false)
end
before do
visit admin_runners_path
end
@ -164,15 +168,17 @@ RSpec.describe "Admin Runners" do
end
describe 'filter by status' do
let!(:never_contacted) do
let_it_be(:never_contacted) do
create(:ci_runner, :instance, description: 'runner-never-contacted', contacted_at: nil)
end
before do
before_all do
create(:ci_runner, :instance, description: 'runner-1', contacted_at: Time.zone.now)
create(:ci_runner, :instance, description: 'runner-2', contacted_at: Time.zone.now)
create(:ci_runner, :instance, description: 'runner-offline', contacted_at: 1.week.ago)
end
before do
visit admin_runners_path
end
@ -238,7 +244,7 @@ RSpec.describe "Admin Runners" do
end
describe 'filter by type' do
before do
before_all do
create(:ci_runner, :project, description: 'runner-project', projects: [project])
create(:ci_runner, :group, description: 'runner-group', groups: [group])
end
@ -345,7 +351,7 @@ RSpec.describe "Admin Runners" do
end
describe 'filter by tag' do
before do
before_all do
create(:ci_runner, :instance, description: 'runner-blue', tag_list: ['blue'])
create(:ci_runner, :instance, description: 'runner-red', tag_list: ['red'])
end
@ -464,7 +470,7 @@ RSpec.describe "Admin Runners" do
end
describe "Runner show page", :js do
let(:runner) do
let_it_be(:runner) do
create(
:ci_runner,
description: 'runner-foo',
@ -520,9 +526,9 @@ RSpec.describe "Admin Runners" do
end
describe "Runner edit page" do
let(:project_runner) { create(:ci_runner, :project) }
let!(:project1) { create(:project) }
let!(:project2) { create(:project) }
let_it_be(:project1) { create(:project) }
let_it_be(:project2) { create(:project) }
let_it_be(:project_runner) { create(:ci_runner, :project) }
before do
visit edit_admin_runner_path(project_runner)

View File

@ -246,6 +246,7 @@ RSpec.describe 'Group or Project invitations', :aggregate_failures do
before do
stub_feature_flags(soft_email_confirmation: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return 0
stub_feature_flags(identity_verification: false)
end
it 'signs up and redirects to the group activity page' do

View File

@ -118,7 +118,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
# Expect an error message
expect_log_message('Failed Attempt', reason: 'rate_limited')
expect(page).to have_content("You've reached the maximum amount of tries. "\
'Wait 10 minutes or resend a new code and try again.')
'Wait 10 minutes or send a new code and try again.')
# Wait for 10 minutes
travel 10.minutes
@ -138,7 +138,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
# Expect an error message
expect_log_message('Failed Attempt', reason: 'invalid')
expect(page).to have_content('The code is incorrect. Enter it again, or resend a new code.')
expect(page).to have_content('The code is incorrect. Enter it again, or send a new code.')
end
it 'verifies expired codes' do
@ -155,7 +155,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
# Expect an error message
expect_log_message('Failed Attempt', reason: 'expired')
expect(page).to have_content('The code has expired. Resend a new code and try again.')
expect(page).to have_content('The code has expired. Send a new code and try again.')
end
end
end
@ -255,7 +255,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
perform_enqueued_jobs do
# The user is prompted for a verification code
gitlab_sign_in(user)
expect(page).to have_content('Help us protect your account')
expect(page).to have_content(s_('IdentityVerification|Help us protect your account'))
code = expect_instructions_email_and_extract_code
# We toggle the feature flag off
@ -266,12 +266,13 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
new_code = expect_instructions_email_and_extract_code
verify_code(code)
expect(page).to have_content('The code is incorrect. Enter it again, or resend a new code.')
expect(page)
.to have_content(s_('IdentityVerification|The code is incorrect. Enter it again, or send a new code.'))
travel Users::EmailVerification::ValidateTokenService::TOKEN_VALID_FOR_MINUTES.minutes + 1.second
verify_code(new_code)
expect(page).to have_content('The code has expired. Resend a new code and try again.')
expect(page).to have_content(s_('IdentityVerification|The code has expired. Send a new code and try again.'))
click_link 'Resend code'
another_code = expect_instructions_email_and_extract_code
@ -296,7 +297,7 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
it 'the unlock link still works' do
# The user is locked and unlock instructions are sent
expect(page).to have_content('Invalid login or password.')
expect(page).to have_content(_('Invalid login or password.'))
user.reload
expect(user.locked_at).not_to be_nil
expect(user.unlock_token).not_to be_nil
@ -334,15 +335,15 @@ RSpec.describe 'Email Verification On Login', :clean_gitlab_redis_rate_limiting
def expect_instructions_email_and_extract_code
mail = find_email_for(user)
expect(mail.to).to match_array([user.email])
expect(mail.subject).to eq('Verify your identity')
expect(mail.subject).to eq(s_('IdentityVerification|Verify your identity'))
code = mail.body.parts.first.to_s[/\d{#{Users::EmailVerification::GenerateTokenService::TOKEN_LENGTH}}/o]
reset_delivered_emails!
code
end
def verify_code(code)
fill_in 'Verification code', with: code
click_button 'Verify code'
fill_in s_('IdentityVerification|Verification code'), with: code
click_button s_('IdentityVerification|Verify code')
end
def expect_log_message(event = nil, times = 1, reason: '', message: nil)

View File

@ -105,6 +105,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
before do
stub_application_setting(send_user_confirmation_email: true)
allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
stub_feature_flags(identity_verification: false)
end
context 'within the grace period' do
@ -954,6 +955,7 @@ RSpec.describe 'Login', :clean_gitlab_redis_sessions do
before do
stub_application_setting(send_user_confirmation_email: true)
stub_feature_flags(soft_email_confirmation: true)
stub_feature_flags(identity_verification: false)
allow(User).to receive(:allow_unconfirmed_access_for).and_return grace_period
end

View File

@ -203,6 +203,7 @@ RSpec.describe 'Signup' do
context 'when soft email confirmation is not enabled' do
before do
stub_feature_flags(soft_email_confirmation: false)
stub_feature_flags(identity_verification: false)
end
it 'creates the user account and sends a confirmation email, and pre-fills email address after confirming' do

View File

@ -0,0 +1 @@
Other SHA256

View File

@ -16,17 +16,17 @@ describe('getAverageByMonth', () => {
expect(getAverageByMonth(mockCountsData2)).toStrictEqual(countsMonthlyChartData2);
});
it('it transforms a data point to the first of the month', () => {
it('transforms a data point to the first of the month', () => {
const item = mockCountsData1[0];
const firstOfTheMonth = item.recordedAt.replace(/-[0-9]{2}$/, '-01');
expect(getAverageByMonth([item])).toStrictEqual([[firstOfTheMonth, item.count]]);
});
it('it uses sane defaults', () => {
it('uses sane defaults', () => {
expect(getAverageByMonth()).toStrictEqual([]);
});
it('it errors when passing null', () => {
it('errors when passing null', () => {
expect(() => {
getAverageByMonth(null);
}).toThrow();

View File

@ -53,7 +53,7 @@ describe('Batch comments preview dropdown', () => {
});
describe('clicking draft', () => {
it('it toggles active file when viewDiffsFileByFile is true', async () => {
it('toggles active file when viewDiffsFileByFile is true', async () => {
factory({
viewDiffsFileByFile: true,
sortedDrafts: [{ id: 1, file_hash: 'hash' }],

View File

@ -118,7 +118,7 @@ describe('Batch comments draft preview item component', () => {
);
});
it('it renders thread resolved text', () => {
it('renders thread resolved text', () => {
expect(vm.$el.querySelector('.draft-note-resolution').textContent).toContain(
'Thread will be resolved',
);

View File

@ -24,7 +24,7 @@ describe('Batch comments review bar component', () => {
wrapper.destroy();
});
it('it adds review-bar-visible class to body when review bar is mounted', async () => {
it('adds review-bar-visible class to body when review bar is mounted', async () => {
expect(document.body.classList.contains(REVIEW_BAR_VISIBLE_CLASS_NAME)).toBe(false);
createComponent();
@ -32,7 +32,7 @@ describe('Batch comments review bar component', () => {
expect(document.body.classList.contains(REVIEW_BAR_VISIBLE_CLASS_NAME)).toBe(true);
});
it('it removes review-bar-visible class to body when review bar is destroyed', async () => {
it('removes review-bar-visible class to body when review bar is destroyed', async () => {
createComponent();
wrapper.destroy();

View File

@ -92,7 +92,7 @@ describe('Batch comments submit dropdown', () => {
canApprove | exists | existsText
${true} | ${true} | ${'shows'}
${false} | ${false} | ${'hides'}
`('it $existsText approve checkbox if can_approve is $canApprove', ({ canApprove, exists }) => {
`('$existsText approve checkbox if can_approve is $canApprove', ({ canApprove, exists }) => {
factory({ canApprove });
expect(wrapper.findByTestId('approve_merge_request').exists()).toBe(exists);

View File

@ -90,7 +90,7 @@ describe('Issue boards new issue form', () => {
});
});
it('it uses the first issue ID as moveAfterId', async () => {
it('uses the first issue ID as moveAfterId', async () => {
findBoardNewItem().vm.$emit('form-submit', { title: 'Foo' });
await nextTick();

View File

@ -142,7 +142,7 @@ describe('ClustersMainViewComponent', () => {
createWrapper({ certificateBasedClustersEnabled: false });
});
it('it displays only the Agent tab', () => {
it('displays only the Agent tab', () => {
expect(findAllTabs()).toHaveLength(1);
const agentTab = findGlTabAtIndex(0);

View File

@ -17,7 +17,7 @@ describe('getCurrentHoverElement', () => {
value
${'test'}
${undefined}
`('it returns cached current key', ({ value }) => {
`('returns cached current key', ({ value }) => {
if (value) {
cachedData.set('current', value);
}
@ -52,7 +52,7 @@ describe('addInteractionClass', () => {
${1} | ${0} | ${0}
${1} | ${0} | ${0}
`(
'it sets code navigation attributes for line $line and character $char',
'sets code navigation attributes for line $line and character $char',
({ line, char, index }) => {
addInteractionClass({ path: 'index.js', d: { start_line: line, start_char: char } });

View File

@ -176,7 +176,7 @@ describe('ValueStreamMetrics', () => {
await waitForPromises();
});
it('it should render an error message', () => {
it('should render an error message', () => {
expect(createFlash).toHaveBeenCalledWith({
message: `There was an error while fetching value stream analytics ${fakeReqName} data.`,
});

View File

@ -314,7 +314,7 @@ describe('deprecatedJQueryDropdown', () => {
});
describe('with a trackSuggestionsClickedLabel', () => {
it('it includes data-track attributes', () => {
it('includes data-track attributes', () => {
const dropdown = dropdownWithOptions({
trackSuggestionClickedLabel: 'some_value_for_label',
});
@ -333,7 +333,7 @@ describe('deprecatedJQueryDropdown', () => {
expect(link).toHaveAttr('data-track-property', 'suggestion-category');
});
it('it defaults property to no_category when category not provided', () => {
it('defaults property to no_category when category not provided', () => {
const dropdown = dropdownWithOptions({
trackSuggestionClickedLabel: 'some_value_for_label',
});

View File

@ -682,7 +682,7 @@ describe('diffs/components/app', () => {
${'123'} | ${2}
${'312'} | ${1}
`(
'it calls navigateToDiffFileIndex with $index when $link is clicked',
'calls navigateToDiffFileIndex with $index when $link is clicked',
async ({ currentDiffFileId, targetFile }) => {
createComponent({ fileByFileUserPreference: true }, ({ state }) => {
state.diffs.diffFiles.push({ file_hash: '123' }, { file_hash: '312' });

View File

@ -106,7 +106,7 @@ describe('Diffs tree list component', () => {
${'index.js'} | ${1}
${'app/*.js'} | ${1}
${'*.js, *.rb'} | ${2}
`('it returns $itemSize item for $extension', async ({ extension, itemSize }) => {
`('returns $itemSize item for $extension', async ({ extension, itemSize }) => {
wrapper.find('[data-testid="diff-tree-search"]').setValue(extension);
await nextTick();

View File

@ -68,7 +68,7 @@ describe('Source Editor Toolbar', () => {
});
describe('buttons update', () => {
it('it properly updates buttons on Apollo cache update', async () => {
it('properly updates buttons on Apollo cache update', async () => {
const item = buildButton('first', {
group: EDITOR_TOOLBAR_RIGHT_GROUP,
});

View File

@ -382,7 +382,7 @@ describe('Source Editor Instance', () => {
},
);
it('it does not remove entry from the global registry to keep for potential future re-use', () => {
it('does not remove entry from the global registry to keep for potential future re-use', () => {
const extensionStore = new Map();
seInstance = new SourceEditorInstance({}, extensionStore);
const extensions = seInstance.use(fullExtensionsArray);

View File

@ -4,13 +4,13 @@ import { getFrequentlyUsedEmojis, addToFrequentlyUsed } from '~/emoji/components
jest.mock('~/lib/utils/cookies');
describe('getFrequentlyUsedEmojis', () => {
it('it returns null when no saved emojis set', () => {
it('returns null when no saved emojis set', () => {
jest.spyOn(Cookies, 'get').mockReturnValue(null);
expect(getFrequentlyUsedEmojis()).toBe(null);
});
it('it returns frequently used emojis object', () => {
it('returns frequently used emojis object', () => {
jest.spyOn(Cookies, 'get').mockReturnValue('thumbsup,thumbsdown');
expect(getFrequentlyUsedEmojis()).toEqual({

View File

@ -363,7 +363,7 @@ describe('Environment table', () => {
});
describe('sortedEnvironments', () => {
it('it should sort children as well', () => {
it('should sort children as well', () => {
const mockItems = [
{
name: 'production',

View File

@ -65,7 +65,7 @@ describe('~/environments/components/new.vue', () => {
input | value
${() => name} | ${'test'}
${() => url} | ${'https://example.org'}
`('it changes the value of the input to $value', async ({ input, value }) => {
`('changes the value of the input to $value', async ({ input, value }) => {
await input().setValue(value);
expect(input().element.value).toBe(value);

View File

@ -164,19 +164,19 @@ describe('ErrorTrackingList', () => {
expect(findSortDropdown().exists()).toBe(true);
});
it('it searches by query', () => {
it('searches by query', () => {
findSearchBox().vm.$emit('input', 'search');
findSearchBox().trigger('keyup.enter');
expect(actions.searchByQuery.mock.calls[0][1]).toBe('search');
});
it('it sorts by fields', () => {
it('sorts by fields', () => {
const findSortItem = () => findSortDropdown().find('.dropdown-item');
findSortItem().trigger('click');
expect(actions.sortByField).toHaveBeenCalled();
});
it('it filters by status', () => {
it('filters by status', () => {
const findStatusFilter = () => findStatusFilterDropdown().find('.dropdown-item');
findStatusFilter().trigger('click');
expect(actions.filterByStatus).toHaveBeenCalled();

View File

@ -557,11 +557,11 @@ describe('DropLab DropDown', () => {
DropDown.prototype.show.call(testContext.dropdown);
});
it('it should set .list display to block', () => {
it('should set .list display to block', () => {
expect(testContext.list.style.display).toBe('block');
});
it('it should set .hidden to false', () => {
it('should set .hidden to false', () => {
expect(testContext.dropdown.hidden).toBe(false);
});
@ -591,11 +591,11 @@ describe('DropLab DropDown', () => {
DropDown.prototype.hide.call(testContext.dropdown);
});
it('it should set .list display to none', () => {
it('should set .list display to none', () => {
expect(testContext.list.style.display).toBe('none');
});
it('it should set .hidden to true', () => {
it('should set .hidden to true', () => {
expect(testContext.dropdown.hidden).toBe(true);
});
});
@ -648,11 +648,11 @@ describe('DropLab DropDown', () => {
DropDown.prototype.destroy.call(testContext.dropdown);
});
it('it should call .hide', () => {
it('should call .hide', () => {
expect(testContext.dropdown.hide).toHaveBeenCalled();
});
it('it should call .removeEventListener', () => {
it('should call .removeEventListener', () => {
expect(testContext.list.removeEventListener).toHaveBeenCalledWith(
'click',
testContext.eventWrapper.clickEvent,

View File

@ -274,7 +274,7 @@ describe('GroupItemComponent', () => {
${'itemscope'} | ${'itemscope'}
${'itemtype'} | ${'https://schema.org/Organization'}
${'itemprop'} | ${'subOrganization'}
`('it does set correct $attr', ({ attr, value } = {}) => {
`('does set correct $attr', ({ attr, value } = {}) => {
expect(wrapper.attributes(attr)).toBe(value);
});
@ -283,7 +283,7 @@ describe('GroupItemComponent', () => {
${'img'} | ${'logo'}
${'[data-testid="group-name"]'} | ${'name'}
${'[data-testid="group-description"]'} | ${'description'}
`('it does set correct $selector', ({ selector, propValue } = {}) => {
`('does set correct $selector', ({ selector, propValue } = {}) => {
expect(wrapper.find(selector).attributes('itemprop')).toBe(propValue);
});
});

View File

@ -106,7 +106,7 @@ describe('CreateMergeRequestDropdown', () => {
loading | hasClass
${true} | ${false}
${false} | ${true}
`('it toggle loading spinner when loading is $loading', ({ loading, hasClass }) => {
`('toggle loading spinner when loading is $loading', ({ loading, hasClass }) => {
dropdown.setLoading(loading);
expect(document.querySelector('.js-spinner').classList.contains('gl-display-none')).toEqual(

View File

@ -6,7 +6,7 @@ describe('isNavigatingAway', () => {
setNavigatingForTestsOnly(false);
});
it.each([false, true])('it returns the navigation flag with value %s', (flag) => {
it.each([false, true])('returns the navigation flag with value %s', (flag) => {
setNavigatingForTestsOnly(flag);
expect(isNavigatingAway()).toEqual(flag);
});

View File

@ -63,7 +63,7 @@ describe('initPrefetchLinks', () => {
expect(newLink.addEventListener).toHaveBeenCalled();
});
it('it is not fired when less then 100ms over link', () => {
it('is not fired when less then 100ms over link', () => {
const mouseOverEvent = new Event('mouseover');
const mouseOutEvent = new Event('mouseout');

View File

@ -333,7 +333,7 @@ describe('MergeRequestTabs', () => {
${'show'} | ${false} | ${'shows'}
${'diffs'} | ${true} | ${'hides'}
${'commits'} | ${true} | ${'hides'}
`('it $hidesText expand button on $tab tab', ({ tab, hides }) => {
`('$hidesText expand button on $tab tab', ({ tab, hides }) => {
window.gon = { features: { movedMrSidebar: true } };
const expandButton = document.createElement('div');

View File

@ -430,7 +430,7 @@ describe('Dashboard Panel', () => {
expect(findTimeChart().props().projectPath).toBe(mockProjectPath);
});
it('it renders a time series chart with no errors', () => {
it('renders a time series chart with no errors', () => {
expect(wrapper.findComponent(MonitorTimeSeriesChart).exists()).toBe(true);
});
});

View File

@ -407,7 +407,7 @@ describe('Dashboard', () => {
await nextTick();
});
it('it does not show loading icons in any group', async () => {
it('does not show loading icons in any group', async () => {
setupStoreWithData(store);
await nextTick();
@ -614,7 +614,7 @@ describe('Dashboard', () => {
const findFirstDraggableRemoveButton = () =>
findDraggablePanels().at(0).find('.js-draggable-remove');
it('it enables draggables', async () => {
it('enables draggables', async () => {
findRearrangeButton().vm.$emit('click');
await nextTick();
@ -656,7 +656,7 @@ describe('Dashboard', () => {
expect(findDraggablePanels().length).toEqual(metricsDashboardPanelCount - 1);
});
it('it disables draggables when clicked again', async () => {
it('disables draggables when clicked again', async () => {
findRearrangeButton().vm.$emit('click');
await nextTick();

View File

@ -19,7 +19,7 @@ describe('ResolveWithIssueButton', () => {
wrapper.destroy();
});
it('it should have a link with the provided link property as href', () => {
it('should have a link with the provided link property as href', () => {
const button = wrapper.findComponent(GlButton);
expect(button.attributes().href).toBe(url);

View File

@ -71,7 +71,7 @@ describe('NugetInstallation', () => {
});
});
it('it has docs link', () => {
it('has docs link', () => {
expect(findSetupDocsLink().attributes()).toMatchObject({
href: NUGET_HELP_PATH,
target: '_blank',

View File

@ -24,13 +24,13 @@ describe('packages_filter', () => {
wrapper = null;
});
it('it binds all of his attrs to filtered search token', () => {
it('binds all of his attrs to filtered search token', () => {
mountComponent({ attrs: { foo: 'bar' } });
expect(findFilteredSearchToken().attributes('foo')).toBe('bar');
});
it('it binds all of his events to filtered search token', () => {
it('binds all of his events to filtered search token', () => {
const clickListener = jest.fn();
mountComponent({ listeners: { click: clickListener } });

View File

@ -178,7 +178,7 @@ describe('PackagesApp', () => {
${PACKAGE_TYPE_PYPI} | ${true}
${PACKAGE_TYPE_NPM} | ${false}
`(
`It is $visible that the component is visible when the package is $packageType`,
`is $visible that the component is visible when the package is $packageType`,
async ({ packageType, visible }) => {
createComponent({
resolver: jest.fn().mockResolvedValue(

View File

@ -554,7 +554,7 @@ describe('Pipeline graph wrapper', () => {
mock.restore();
});
it('it calls reportPerformance with expected arguments', () => {
it('calls reportPerformance with expected arguments', () => {
expect(markAndMeasure).toHaveBeenCalled();
expect(reportPerformance).toHaveBeenCalled();
expect(reportPerformance).toHaveBeenCalledWith(metricsPath, metricsData);

View File

@ -59,7 +59,7 @@ describe('pipeline graph job item', () => {
});
});
it('it should render status and name', () => {
it('should render status and name', () => {
expect(wrapper.find('.ci-status-icon-success').exists()).toBe(true);
expect(wrapper.find('a').exists()).toBe(false);
@ -72,7 +72,7 @@ describe('pipeline graph job item', () => {
});
describe('action icon', () => {
it('it should render the action icon', () => {
it('should render the action icon', () => {
createWrapper({ job: mockJob });
const actionComponent = findActionComponent();
@ -82,7 +82,7 @@ describe('pipeline graph job item', () => {
expect(actionComponent.attributes('disabled')).not.toBe('disabled');
});
it('it should render disabled action icon when user cannot run the action', () => {
it('should render disabled action icon when user cannot run the action', () => {
createWrapper({ job: mockJobWithUnauthorizedAction });
const actionComponent = findActionComponent();

View File

@ -143,7 +143,7 @@ describe('AssigneeAvatarLink component', () => {
issuableType | userId
${'merge_request'} | ${undefined}
${'issue'} | ${'1'}
`('it sets data-user-id as $userId for $issuableType', ({ issuableType, userId }) => {
`('sets data-user-id as $userId for $issuableType', ({ issuableType, userId }) => {
createComponent({
issuableType,
});

View File

@ -845,7 +845,7 @@ describe('MrWidgetOptions', () => {
${'closed'} | ${false} | ${'hides'}
${'merged'} | ${true} | ${'shows'}
${'open'} | ${true} | ${'shows'}
`('it $showText merge error when state is $state', ({ state, show }) => {
`('$showText merge error when state is $state', ({ state, show }) => {
createComponent({ ...mockData, state, merge_error: 'Error!' });
expect(wrapper.find('[data-testid="merge_error"]').exists()).toBe(show);

View File

@ -49,7 +49,7 @@ describe('Pagination links component', () => {
});
describe('rendering', () => {
it('it renders the gl-paginated-list', () => {
it('renders the gl-paginated-list', () => {
expect(wrapper.find('ul.list-group').exists()).toBe(true);
expect(wrapper.findAll('li.list-group-item').length).toBe(2);
});

View File

@ -93,7 +93,7 @@ describe('ManageViaMr component', () => {
createComponent({ apolloProvider, featureName, featureType, isFeatureConfigured: true });
});
it('it does not render a button', () => {
it('does not render a button', () => {
expect(findButton().exists()).toBe(false);
});
});
@ -104,7 +104,7 @@ describe('ManageViaMr component', () => {
createComponent({ apolloProvider, featureName, featureType, isFeatureConfigured: false });
});
it('it does render a button', () => {
it('does render a button', () => {
expect(findButton().exists()).toBe(true);
});

View File

@ -9,5 +9,5 @@ RSpec.describe GitlabSchema.types['MergeAccessLevel'] do
specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
specify { is_expected.to have_graphql_fields(fields) }
specify { is_expected.to have_graphql_fields(fields).at_least }
end

View File

@ -9,5 +9,5 @@ RSpec.describe GitlabSchema.types['BranchProtection'] do
specify { is_expected.to require_graphql_authorizations(:read_protected_branch) }
specify { is_expected.to have_graphql_fields(fields) }
specify { is_expected.to have_graphql_fields(fields).at_least }
end

View File

@ -2,8 +2,8 @@
require "spec_helper"
RSpec.describe Gitlab::Git::Commit, :seed_helper do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
RSpec.describe Gitlab::Git::Commit do
let(:repository) { create(:project, :repository).repository.raw }
let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) }
describe "Commit info from gitaly commit" do
@ -121,14 +121,6 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
it "returns nil for id containing NULL" do
expect(described_class.find(repository, "HE\x00AD")).to be_nil
end
context 'with broken repo' do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_BROKEN_REPO_PATH, '', 'group/project') }
it 'returns nil' do
expect(described_class.find(repository, SeedRepo::Commit::ID)).to be_nil
end
end
end
describe '.find with Gitaly enabled' do
@ -154,7 +146,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
describe '#id' do
subject { super().id }
it { is_expected.to eq(SeedRepo::LastCommit::ID) }
it { is_expected.to eq(TestEnv::BRANCH_SHA['master']) }
end
end
@ -223,7 +215,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
it { is_expected.to include(TestEnv::BRANCH_SHA['master']) }
end
context 'path is nil' do
@ -242,28 +234,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
expect(subject.size).to eq(10)
end
it { is_expected.to include(SeedRepo::EmptyCommit::ID) }
end
context 'ref is branch name' do
subject do
commits = described_class.where(
repo: repository,
ref: 'master',
path: 'files',
limit: 3,
offset: 1
)
commits.map { |c| c.id }
end
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("d14d6c0abdd253381df51a723d58691b2ee1ab08") }
it { is_expected.not_to include("eb49186cfa5c4338011f5f590fac11bd66c5c631") }
it { is_expected.to include(TestEnv::BRANCH_SHA['master']) }
end
context 'ref is commit id' do
@ -323,13 +294,12 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
context 'requesting a commit range' do
let(:from) { 'v1.0.0' }
let(:to) { 'v1.2.0' }
let(:to) { 'v1.1.0' }
let(:commits_in_range) do
%w[
570e7b2abdd848b95f2f578043fc23bd6f6fd24d
5937ac0a7beb003549fc5fd26fc247adbce4a52e
eb49186cfa5c4338011f5f590fac11bd66c5c631
]
end
@ -338,9 +308,9 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
context 'limited' do
let(:limit) { 2 }
let(:limit) { 1 }
it { expect(commit_ids).to eq(commits_in_range.last(2)) }
it { expect(commit_ids).to eq(commits_in_range.last(1)) }
end
end
end
@ -383,16 +353,8 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
commits.map(&:id)
end
it 'has 34 elements' do
expect(subject.size).to eq(34)
end
it 'includes the expected commits' do
expect(subject).to include(
SeedRepo::Commit::ID,
SeedRepo::Commit::PARENT_ID,
SeedRepo::FirstCommit::ID
)
it 'has maximum elements' do
expect(subject.size).to eq(50)
end
end
@ -408,13 +370,13 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
commits.map(&:id)
end
it 'has 24 elements' do
expect(subject.size).to eq(24)
it 'has 36 elements' do
expect(subject.size).to eq(36)
end
it 'includes the expected commits' do
expect(subject).to include(SeedRepo::Commit::ID, SeedRepo::FirstCommit::ID)
expect(subject).not_to include(SeedRepo::LastCommit::ID)
expect(subject).not_to include(TestEnv::BRANCH_SHA['master'])
end
end
end
@ -650,8 +612,8 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
subject { commit.ref_names(repository) }
it 'has 2 element' do
expect(subject.size).to eq(2)
it 'has 3 elements' do
expect(subject.size).to eq(3)
end
it { is_expected.to include("master") }
@ -681,6 +643,8 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
it 'gets messages in one batch', :request_store do
repository # preload repository so that the project factory does not pollute request counts
expect { subject.map(&:itself) }.to change { Gitlab::GitalyClient.get_request_count }.by(1)
end
end

View File

@ -17,11 +17,12 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
describe '/api/v4/jobs' do
let(:group) { create(:group, :nested) }
let_it_be(:group) { create(:group, :nested) }
let_it_be(:user) { create(:user) }
let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
let(:user) { create(:user) }
let(:pipeline) { create(:ci_pipeline, project: project, ref: 'master') }
let(:job) do
create(:ci_build, :pending, :queued, :artifacts, :extended_options,
pipeline: pipeline, name: 'spinach', stage: 'test', stage_idx: 0)
@ -354,6 +355,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when GIT_DEPTH is not specified and there is no default git depth for the project' do
let(:project) { create(:project, namespace: group, shared_runners_enabled: false) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
before do
project.update!(ci_default_git_depth: nil)
end
@ -411,7 +415,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
context 'when job is made for merge request' do
let(:pipeline) { create(:ci_pipeline, source: :merge_request_event, project: project, ref: 'feature', merge_request: merge_request) }
let!(:job) { create(:ci_build, :pending, :queued, pipeline: pipeline, name: 'spinach', ref: 'feature', stage: 'test', stage_idx: 0) }
let(:merge_request) { create(:merge_request) }
let_it_be(:merge_request) { create(:merge_request) }
it 'sets branch as ref_type' do
request_job
@ -728,7 +733,9 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
describe 'timeout support' do
context 'when project specifies job timeout' do
let(:project) { create(:project, shared_runners_enabled: false, build_timeout: 1234) }
let_it_be(:project) { create(:project, shared_runners_enabled: false, build_timeout: 1234) }
let(:runner) { create(:ci_runner, :project, projects: [project]) }
it 'contains info about timeout taken from project' do
request_job
@ -926,8 +933,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state do
end
context 'when the runner is of group type' do
let(:group) { create(:group) }
let(:runner) { create(:ci_runner, :group, groups: [group]) }
let_it_be(:group) { create(:group) }
let_it_be(:runner) { create(:ci_runner, :group, groups: [group]) }
it_behaves_like 'storing arguments in the application context for the API' do
let(:expected_params) { { root_namespace: group.full_path_components.first, client_id: "runner/#{runner.id}" } }

View File

@ -36,18 +36,36 @@ RSpec.describe API::DebianGroupPackages do
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Packages file/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/binary-:architecture/by-hash/SHA256/:file_sha256' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/by-hash/SHA256/#{component_file_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/source/Sources' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/source/Sources" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Sources file/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/source/by-hash/SHA256/:file_sha256' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/source/by-hash/SHA256/#{component_file_sources_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/Packages' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/Packages" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete D-I Packages file/
end
describe 'GET groups/:id/-/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/by-hash/SHA256/:file_sha256' do
let(:url) { "/groups/#{container.id}/-/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{component_file_di_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET groups/:id/-/packages/debian/pool/:codename/:project_id/:letter/:package_name/:package_version/:file_name' do
using RSpec::Parameterized::TableSyntax

View File

@ -36,18 +36,36 @@ RSpec.describe API::DebianProjectPackages do
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Packages file/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/binary-:architecture/by-hash/SHA256/:file_sha256' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/binary-#{architecture.name}/by-hash/SHA256/#{component_file_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/source/Sources' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/source/Sources" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete Sources file/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/source/by-hash/SHA256/:file_sha256' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/source/by-hash/SHA256/#{component_file_sources_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/Packages' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/Packages" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /Description: This is an incomplete D-I Packages file/
end
describe 'GET projects/:id/packages/debian/dists/*distribution/:component/debian-installer/binary-:architecture/by-hash/SHA256/:file_sha256' do
let(:url) { "/projects/#{container.id}/packages/debian/dists/#{distribution.codename}/#{component.name}/debian-installer/binary-#{architecture.name}/by-hash/SHA256/#{component_file_di_older_sha256.file_sha256}" }
it_behaves_like 'Debian packages read endpoint', 'GET', :success, /^Other SHA256$/
end
describe 'GET projects/:id/packages/debian/pool/:codename/:letter/:package_name/:package_version/:file_name' do
using RSpec::Parameterized::TableSyntax

View File

@ -3,6 +3,9 @@ require 'spec_helper'
RSpec.describe API::RpmProjectPackages do
include HttpBasicAuthHelpers
include WorkhorseHelpers
include_context 'workhorse headers'
using RSpec::Parameterized::TableSyntax
@ -141,8 +144,9 @@ RSpec.describe API::RpmProjectPackages do
describe 'POST /api/v4/projects/:project_id/packages/rpm' do
let(:url) { "/projects/#{project.id}/packages/rpm" }
let(:file_upload) { fixture_file_upload('spec/fixtures/packages/rpm/hello-0.0.1-1.fc29.x86_64.rpm') }
subject { post api(url), headers: headers }
subject { post api(url), params: { file: file_upload }, headers: headers }
context 'with user token' do
context 'with valid project' do
@ -179,6 +183,41 @@ RSpec.describe API::RpmProjectPackages do
it_behaves_like params[:shared_examples_name], params[:expected_status]
end
end
context 'when user can upload file' do
before do
project.add_developer(user)
end
let(:headers) { basic_auth_header(user.username, personal_access_token.token).merge(workhorse_headers) }
context 'when file size too large' do
before do
allow_next_instance_of(UploadedFile) do |uploaded_file|
allow(uploaded_file).to receive(:size).and_return(project.actual_limits.rpm_max_file_size + 1)
end
end
it 'returns an error' do
upload_file(params: { file: file_upload }, request_headers: headers)
expect(response).to have_gitlab_http_status(:bad_request)
expect(response.body).to match(/File is too large/)
end
end
end
def upload_file(params: {}, request_headers: headers)
url = "/projects/#{project.id}/packages/rpm"
workhorse_finalize(
api(url),
method: :post,
file_key: :file,
params: params,
headers: request_headers,
send_rewritten_field: true
)
end
end
it_behaves_like 'a deploy token for RPM requests'

View File

@ -18,7 +18,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it 'sends an email' do
mail = find_email_for(user)
expect(mail.to).to match_array([user.email])
expect(mail.subject).to eq('Verify your identity')
expect(mail.subject).to eq(s_('IdentityVerification|Verify your identity'))
end
end
@ -50,7 +50,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it 'adds a verification error message' do
expect(response.body)
.to include("You&#39;ve reached the maximum amount of tries. "\
'Wait 10 minutes or resend a new code and try again.')
'Wait 10 minutes or send a new code and try again.')
end
end
@ -62,7 +62,8 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it_behaves_like 'prompt for email verification'
it 'adds a verification error message' do
expect(response.body).to include(('The code is incorrect. Enter it again, or resend a new code.'))
expect(response.body)
.to include((s_('IdentityVerification|The code is incorrect. Enter it again, or send a new code.')))
end
end
@ -75,7 +76,8 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it_behaves_like 'prompt for email verification'
it 'adds a verification error message' do
expect(response.body).to include(('The code has expired. Resend a new code and try again.'))
expect(response.body)
.to include((s_('IdentityVerification|The code has expired. Send a new code and try again.')))
end
end
@ -112,7 +114,8 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
it 'redirects to the login form and shows an alert message' do
expect(response).to redirect_to(new_user_session_path)
expect(flash[:alert]).to eq('Maximum login attempts exceeded. Wait 10 minutes and try again.')
expect(flash[:alert])
.to eq(s_('IdentityVerification|Maximum login attempts exceeded. Wait 10 minutes and try again.'))
end
end
@ -217,6 +220,7 @@ RSpec.describe 'VerifiesWithEmail', :clean_gitlab_redis_sessions, :clean_gitlab_
describe 'successful_verification' do
before do
allow(user).to receive(:role_required?).and_return(true) # It skips the required signup info before_action
sign_in(user)
end

View File

@ -0,0 +1,22 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::RepositoryMetadata::BaseBuilder do
describe '#execute' do
subject { described_class.new.execute }
before do
stub_const("#{described_class}::ROOT_TAG", 'test')
stub_const("#{described_class}::ROOT_ATTRIBUTES", { foo1: 'bar1', foo2: 'bar2' })
end
it 'generate valid xml' do
result = Nokogiri::XML::Document.parse(subject)
expect(result.children.count).to eq(1)
expect(result.children.first.attributes.count).to eq(2)
expect(result.children.first.attributes['foo1'].value).to eq('bar1')
expect(result.children.first.attributes['foo2'].value).to eq('bar2')
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::RepositoryMetadata::BuildFilelistXml do
describe '#execute' do
subject { described_class.new.execute }
context "when generate empty xml" do
let(:expected_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<filelists xmlns="http://linux.duke.edu/metadata/filelists" packages="0"/>
XML
end
it 'generate expected xml' do
expect(subject).to eq(expected_xml)
end
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::RepositoryMetadata::BuildOtherXml do
describe '#execute' do
subject { described_class.new.execute }
context "when generate empty xml" do
let(:expected_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<otherdata xmlns="http://linux.duke.edu/metadata/other" packages="0"/>
XML
end
it 'generate expected xml' do
expect(subject).to eq(expected_xml)
end
end
end
end

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::RepositoryMetadata::BuildPrimaryXml do
describe '#execute' do
subject { described_class.new.execute }
context "when generate empty xml" do
let(:expected_xml) do
<<~XML
<?xml version="1.0" encoding="UTF-8"?>
<metadata xmlns="http://linux.duke.edu/metadata/common" xmlns:rpm="http://linux.duke.edu/metadata/rpm" packages="0"/>
XML
end
it 'generate expected xml' do
expect(subject).to eq(expected_xml)
end
end
end
end

View File

@ -0,0 +1,66 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Packages::Rpm::RepositoryMetadata::BuildRepomdXml do
describe '#execute' do
subject { described_class.new(data).execute }
let(:data) do
{
filelists: {
checksum: { type: "sha256", value: "123" },
'open-checksum': { type: "sha256", value: "123" },
location: { href: "repodata/123-filelists.xml.gz" },
timestamp: { value: 1644602784 },
size: { value: 11111 },
'open-size': { value: 11111 }
},
primary: {
checksum: { type: "sha256", value: "234" },
'open-checksum': { type: "sha256", value: "234" },
location: { href: "repodata/234-primary.xml.gz" },
timestamp: { value: 1644602784 },
size: { value: 22222 },
'open-size': { value: 22222 }
},
other: {
checksum: { type: "sha256", value: "345" },
'open-checksum': { type: "sha256", value: "345" },
location: { href: "repodata/345-other.xml.gz" },
timestamp: { value: 1644602784 },
size: { value: 33333 },
'open-size': { value: 33333 }
}
}
end
let(:creation_timestamp) { 111111 }
before do
allow(Time).to receive(:now).and_return(creation_timestamp)
end
it 'generate valid xml' do
# Have one root attribute
result = Nokogiri::XML::Document.parse(subject)
expect(result.children.count).to eq(1)
# Root attribute name is 'repomd'
root = result.children.first
expect(root.name).to eq('repomd')
# Have the same count of 'data' tags as count of keys in 'data'
expect(result.css('data').count).to eq(data.count)
end
it 'has all data info' do
result = Nokogiri::XML::Document.parse(subject).remove_namespaces!
data.each do |tag_name, tag_attributes|
tag_attributes.each_key do |key|
expect(result.at("//repomd/data[@type=\"#{tag_name}\"]/#{key}")).not_to be_nil
end
end
end
end
end

View File

@ -25,7 +25,8 @@ RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_red
context 'when rate limited' do
before do
allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?).and_return(true)
allow(Gitlab::ApplicationRateLimiter).to receive(:throttled?)
.with(:email_verification, scope: encrypted_token).and_return(true)
end
it 'returns a failure status' do
@ -33,8 +34,8 @@ RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_red
{
status: :failure,
reason: :rate_limited,
message: "You've reached the maximum amount of tries. "\
'Wait 10 minutes or resend a new code and try again.'
message: format(s_("IdentityVerification|You've reached the maximum amount of tries. "\
'Wait %{interval} or send a new code and try again.'), interval: '10 minutes')
}
)
end
@ -48,7 +49,7 @@ RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_red
{
status: :failure,
reason: :expired,
message: 'The code has expired. Resend a new code and try again.'
message: s_('IdentityVerification|The code has expired. Send a new code and try again.')
}
)
end
@ -62,7 +63,22 @@ RSpec.describe Users::EmailVerification::ValidateTokenService, :clean_gitlab_red
{
status: :failure,
reason: :invalid,
message: 'The code is incorrect. Enter it again, or resend a new code.'
message: s_('IdentityVerification|The code is incorrect. Enter it again, or send a new code.')
}
)
end
end
context 'when encrypted token was not set and a blank token is provided' do
let(:encrypted_token) { nil }
let(:token) { '' }
it 'returns a failure status' do
expect(service.execute).to eq(
{
status: :failure,
reason: :invalid,
message: s_('IdentityVerification|The code is incorrect. Enter it again, or send a new code.')
}
)
end

View File

@ -6,7 +6,6 @@ module UsageDataHelpers
snippet_update
snippet_comment
merge_request_comment
merge_request_create
commit_comment
wiki_pages_create
wiki_pages_update
@ -15,9 +14,6 @@ module UsageDataHelpers
cycle_analytics_views
productivity_analytics_views
source_code_pushes
design_management_designs_create
design_management_designs_update
design_management_designs_delete
).freeze
COUNTS_KEYS = %i(
@ -122,7 +118,6 @@ module UsageDataHelpers
uploads
web_hooks
user_preferences_user_gitpod_enabled
service_usage_data_download_payload_click
).push(*SMAU_KEYS)
USAGE_DATA_KEYS = %i(

View File

@ -1,9 +0,0 @@
# frozen_string_literal: true
RSpec.configure do |config|
config.include SeedHelper, :seed_helper
config.before(:all, :seed_helper) do
ensure_seeds
end
end

View File

@ -18,8 +18,11 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let_it_be(:private_architecture_all, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'all') }
let_it_be(:private_architecture, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'existing-arch') }
let_it_be(:private_component_file) { create("debian_#{container_type}_component_file", component: private_component, architecture: private_architecture) }
let_it_be(:private_component_sources) { create("debian_#{container_type}_component_file", :sources, component: private_component) }
let_it_be(:private_component_file_sources) { create("debian_#{container_type}_component_file", :sources, component: private_component) }
let_it_be(:private_component_file_di) { create("debian_#{container_type}_component_file", :di_packages, component: private_component, architecture: private_architecture) }
let_it_be(:private_component_file_older_sha256) { create("debian_#{container_type}_component_file", :older_sha256, component: private_component, architecture: private_architecture) }
let_it_be(:private_component_file_sources_older_sha256) { create("debian_#{container_type}_component_file", :sources, :older_sha256, component: private_component) }
let_it_be(:private_component_file_di_older_sha256) { create("debian_#{container_type}_component_file", :di_packages, :older_sha256, component: private_component, architecture: private_architecture) }
let_it_be(:public_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, container: public_container, codename: 'existing-codename') }
let_it_be(:public_distribution_key, freeze: true) { create("debian_#{container_type}_distribution_key", distribution: public_distribution) }
@ -29,6 +32,9 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let_it_be(:public_component_file) { create("debian_#{container_type}_component_file", component: public_component, architecture: public_architecture) }
let_it_be(:public_component_file_sources) { create("debian_#{container_type}_component_file", :sources, component: public_component) }
let_it_be(:public_component_file_di) { create("debian_#{container_type}_component_file", :di_packages, component: public_component, architecture: public_architecture) }
let_it_be(:public_component_file_older_sha256) { create("debian_#{container_type}_component_file", :older_sha256, component: public_component, architecture: public_architecture) }
let_it_be(:public_component_file_sources_older_sha256) { create("debian_#{container_type}_component_file", :sources, :older_sha256, component: public_component) }
let_it_be(:public_component_file_di_older_sha256) { create("debian_#{container_type}_component_file", :di_packages, :older_sha256, component: public_component, architecture: public_architecture) }
if container_type == :group
let_it_be(:private_project) { create(:project, :private, group: private_container) }
@ -52,6 +58,9 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let(:distribution) { { private: private_distribution, public: public_distribution }[visibility_level] }
let(:architecture) { { private: private_architecture, public: public_architecture }[visibility_level] }
let(:component) { { private: private_component, public: public_component }[visibility_level] }
let(:component_file_older_sha256) { { private: private_component_file_older_sha256, public: public_component_file_older_sha256 }[visibility_level] }
let(:component_file_sources_older_sha256) { { private: private_component_file_sources_older_sha256, public: public_component_file_sources_older_sha256 }[visibility_level] }
let(:component_file_di_older_sha256) { { private: private_component_file_di_older_sha256, public: public_component_file_di_older_sha256 }[visibility_level] }
let(:package) { { private: private_package, public: public_package }[visibility_level] }
let(:letter) { package.name[0..2] == 'lib' ? package.name[0..3] : package.name[0] }

View File

@ -190,6 +190,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
Codename: unstable
Date: Sat, 25 Jan 2020 15:17:18 +0000
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
Acquire-By-Hash: yes
Architectures: all amd64 arm64
Components: contrib main
MD5Sum:
@ -249,6 +250,7 @@ RSpec.shared_examples 'Generate Debian Distribution and component files' do
Codename: unstable
Date: Sat, 25 Jan 2020 15:17:18 +0000
Valid-Until: Mon, 27 Jan 2020 15:17:18 +0000
Acquire-By-Hash: yes
MD5Sum:
SHA256:
EOF

View File

@ -30,15 +30,15 @@ module OmniAuth
@raw_info ||= access_token.get(user_endpoint_url).parsed
end
def callback_url
options.redirect_url || (full_host + callback_path)
end
private
def user_endpoint_url
options.client_options.site.match(API_SUFFIX_REGEX) ? 'user' : 'api/v4/user'
end
def callback_url
options.redirect_url || (full_host + script_name + callback_path)
end
end
end
end

View File

@ -77,4 +77,26 @@ describe OmniAuth::Strategies::GitLab do
end
end
end
describe '#callback_url' do
let(:base_url) { 'https://example.com' }
context 'no script name present' do
it 'has the correct default callback path' do
allow(subject).to receive(:full_host) { base_url }
allow(subject).to receive(:script_name) { '' }
allow(subject).to receive(:query_string) { '' }
expect(subject.callback_url).to eq(base_url + '/auth/gitlab/callback')
end
end
context 'script name' do
it 'should set the callback path with script_name' do
allow(subject).to receive(:full_host) { base_url }
allow(subject).to receive(:script_name) { '/v1' }
allow(subject).to receive(:query_string) { '' }
expect(subject.callback_url).to eq(base_url + '/v1/auth/gitlab/callback')
end
end
end
end