Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-13 09:08:30 +00:00
parent 33a43bde0e
commit 152d3b652d
45 changed files with 920 additions and 509 deletions

View file

@ -46,6 +46,7 @@ class Issue < ApplicationRecord
TYPES_FOR_LIST = %w(issue incident).freeze
belongs_to :project
belongs_to :namespace, inverse_of: :issues
belongs_to :duplicated_to, class_name: 'Issue'
belongs_to :closed_by, class_name: 'User'
@ -97,6 +98,7 @@ class Issue < ApplicationRecord
validates :project, presence: true
validates :issue_type, presence: true
validates :namespace, presence: true, if: -> { project.present? }
enum issue_type: WorkItems::Type.base_types
@ -183,6 +185,8 @@ class Issue < ApplicationRecord
scope :with_null_relative_position, -> { where(relative_position: nil) }
scope :with_non_null_relative_position, -> { where.not(relative_position: nil) }
before_validation :ensure_namespace_id
after_commit :expire_etag_cache, unless: :importing?
after_save :ensure_metrics, unless: :importing?
after_create_commit :record_create_action, unless: :importing?
@ -655,6 +659,10 @@ class Issue < ApplicationRecord
# Symptom of running out of space - schedule rebalancing
Issues::RebalancingWorker.perform_async(nil, *project.self_or_root_group_ids)
end
def ensure_namespace_id
self.namespace = project.project_namespace if project
end
end
Issue.prepend_mod_with('Issue')

View file

@ -74,7 +74,8 @@ class Namespace < ApplicationRecord
has_many :sync_events, class_name: 'Namespaces::SyncEvent'
has_one :cluster_enabled_grant, inverse_of: :namespace, class_name: 'Clusters::ClusterEnabledGrant'
has_many :work_items, inverse_of: :namespace, class_name: 'WorkItem'
has_many :work_items, inverse_of: :namespace
has_many :issues, inverse_of: :namespace
validates :owner, presence: true, if: ->(n) { n.owner_required? }
validates :name,

View file

@ -6,7 +6,7 @@ class WorkItem < Issue
self.table_name = 'issues'
self.inheritance_column = :_type_disabled
belongs_to :namespace, class_name: 'Namespace', foreign_key: :namespace_id, inverse_of: :work_items
belongs_to :namespace, inverse_of: :work_items
has_one :parent_link, class_name: '::WorkItems::ParentLink', foreign_key: :work_item_id
has_one :work_item_parent, through: :parent_link, class_name: 'WorkItem'

View file

@ -2731,15 +2731,6 @@
:weight: 1
:idempotent: true
:tags: []
- :name: pages_transfer
:worker_name: PagesTransferWorker
:feature_category: :pages
:has_external_dependencies: false
:urgency: :low
:resource_boundary: :unknown
:weight: 1
:idempotent: false
:tags: []
- :name: phabricator_import_import_tasks
:worker_name: Gitlab::PhabricatorImport::ImportTasksWorker
:feature_category: :importers

View file

@ -1,20 +0,0 @@
# frozen_string_literal: true
class PagesTransferWorker # rubocop:disable Scalability/IdempotentWorker
include ApplicationWorker
data_consistency :always
sidekiq_options retry: 3
TransferFailedError = Class.new(StandardError)
feature_category :pages
loggable_arguments 0, 1
def perform(method, args)
# noop
# This worker is not necessary anymore and will be removed
# https://gitlab.com/gitlab-org/gitlab/-/issues/340616
end
end

View file

@ -331,8 +331,6 @@
- 1
- - pages_invalidate_domain_cache
- 1
- - pages_transfer
- 1
- - personal_access_tokens
- 1
- - phabricator_import_import_tasks

View file

@ -0,0 +1,41 @@
# This is a template for a feature deprecation.
#
# Please refer to the deprecation guidelines to confirm your understanding of GitLab's definitions.
# https://docs.gitlab.com/ee/development/deprecation_guidelines/#terminology
#
# Deprecations must be announced at least three releases prior to removal.
#
# If an End of Support period applies, the announcement should be shared with GitLab Support
# in the `#spt_managers` on Slack and mention `@gitlab-com/support` in this MR.
#
# Breaking changes must happen in a major release.
#
# For more information please refer to the handbook documentation here:
# https://about.gitlab.com/handbook/marketing/blog/release-posts/#deprecations
#
# Please delete this line and above before submitting your merge request.
#
# REQUIRED FIELDS
#
- name: "Remove `job_age` parameter from `POST /jobs/request` Runner endpoint" # (required) The name of the feature to be deprecated
announcement_milestone: "15.2" # (required) The milestone when this feature was first announced as deprecated.
announcement_date: "2022-07-22" # (required) The date of the milestone release when this feature was first announced as deprecated. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
removal_milestone: "16.0" # (required) The milestone when this feature is planned to be removed
removal_date: "2023-05-22" # (required) The date of the milestone release when this feature is planned to be removed. This should almost always be the 22nd of a month (YYYY-MM-22), unless you did an out of band blog post.
breaking_change: true # (required) If this deprecation is a breaking change, set this value to true
reporter: jheimbuck_gl # (required) GitLab username of the person reporting the deprecation
stage: Verify # (required) String value of the stage that the feature was created in. e.g., Growth
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/334253 # (required) Link to the deprecation issue in GitLab
body: | # (required) Do not modify this line, instead modify the lines below.
The `job_age` parameter, returned from the `POST /jobs/request` API endpoint used in communication with GitLab Runner, was never used by any GitLab or Runner feature. This parameter will be removed in GitLab 16.0.
This could be a breaking change for anyone that developed their own runner that relies on this parameter being returned by the endpoint. This is not a breaking change for anyone using an officially released version of GitLab Runner, including public shared runners on GitLab.com.
#
# OPTIONAL FIELDS
#
end_of_support_milestone: # (optional) Use "XX.YY" format. The milestone when support for this feature will end.
end_of_support_date: # (optional) The date of the milestone release when support for this feature will end.
tiers: # (optional - may be required in the future) An array of tiers that the feature is available in currently. e.g., [Free, Silver, Gold, Core, Premium, Ultimate]
documentation_url: # (optional) This is a link to the current documentation page
image_url: # (optional) This is a link to a thumbnail image depicting the feature
video_url: # (optional) Use the youtube thumbnail URL with the structure of https://img.youtube.com/vi/UNIQUEID/hqdefault.jpg

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
class QueueUpdateDelayedProjectRemovalToNullForUserNamespace < Gitlab::Database::Migration[2.0]
MIGRATION = 'UpdateDelayedProjectRemovalToNullForUserNamespaces'
INTERVAL = 2.minutes
BATCH_SIZE = 10_000
disable_ddl_transaction!
restrict_gitlab_migration gitlab_schema: :gitlab_main
def up
queue_batched_background_migration(
MIGRATION,
:namespace_settings,
:namespace_id,
job_interval: INTERVAL,
batch_size: BATCH_SIZE
)
end
def down
delete_batched_background_migration(MIGRATION, :namespace_settings, :namespace_id, [])
end
end

View file

@ -0,0 +1 @@
24b07a6966c6fd7ab680cf5a9052b7c2f6d20944eaae5d06ef42934364dce222

View file

@ -131,7 +131,8 @@ Example response:
## Group Audit Events
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34078) in GitLab 12.5.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34078) in GitLab 12.5.
> - [Support for keyset pagination added](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2.
The Group Audit Events API allows you to retrieve [group audit events](../administration/audit_events.md#group-events).
This API cannot retrieve project audit events.
@ -139,6 +140,10 @@ This API cannot retrieve project audit events.
A user with a Owner role (or above) can retrieve group audit events of all users.
A user with a Developer or Maintainer role is limited to group audit events based on their individual actions.
This endpoint optionally supports [keyset pagination](index.md#keyset-based-pagination):
- When requesting consecutive pages of results, we recommend you use keyset pagination.
### Retrieve all group audit events
```plaintext

View file

@ -520,10 +520,11 @@ pagination headers.
Keyset-based pagination is supported only for selected resources and ordering
options:
| Resource | Options | Availability |
|:-------------------------|:---------------------------------|:----------------------------------------|
| [Projects](projects.md) | `order_by=id` only | Authenticated and unauthenticated users |
| [Groups](groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only |
| Resource | Options | Availability |
|:---------------------------------------------------------|:---------------------------------|:------------------------------------------------------------------------------------------------------------|
| [Projects](projects.md) | `order_by=id` only | Authenticated and unauthenticated users |
| [Groups](groups.md) | `order_by=name`, `sort=asc` only | Unauthenticated users only |
| [Group audit events](audit_events.md#group-audit-events) | `order_by=id`, `sort=desc` only | Authenticated users only ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/333968) in GitLab 15.2 |
### Pagination response headers

View file

@ -25,26 +25,37 @@ mean FIPS 140-2.
## Current status
GitLab Inc has not committed to making GitLab FIPS-compliant at this time. We are
performing initial investigations to see how much work such an effort would be.
Read [Epic &5104](https://gitlab.com/groups/gitlab-org/-/epics/5104) for more
information on the status of the investigation.
GitLab is actively working towards FIPS compliance.
## FIPS compliance at GitLab
In a FIPS context, compliance is a form of self-certification - if we say we are
"FIPS compliant", we mean that we *believe* we are. There are no external
certifications to acquire, but if we are aware of non-compliant areas
in GitLab, we cannot self-certify in good faith.
The known areas of non-compliance are tracked in [Epic &5104](https://gitlab.com/groups/gitlab-org/-/epics/5104).
To be compliant, all components (GitLab itself, Gitaly, etc) must be compliant,
along with the communication between those components, and any storage used by
them. Where functionality cannot be brought into compliance, it must be disabled
when FIPS mode is enabled.
### Leveraged Cryptographic modules
| Cryptographic module name | CMVP number | Instance type | Software component used |
|----------------------------------------------------------|-------------------------------------------------------------------------------------------------|---------------|-------------------------|
| Ubuntu 20.04 AWS Kernel Crypto API Cryptographic Module | [4132](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/4132) | EC2 | Linux kernel |
| Ubuntu 20.04 OpenSSL Cryptographic Module | [3966](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3966) | EC2 | Gitaly, Rails (Puma/Sidekiq) |
| Ubuntu 20.04 Libgcrypt Cryptographic Module | [3902](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3902) | EC2 instances | `gpg`, `sshd` |
| Amazon Linux 2 Kernel Crypto API Cryptographic Module | [3709](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3709) | EKS nodes | Linux kernel |
| Amazon Linux 2 OpenSSL Cryptographic Module | [3553](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3553) | EKS nodes | NGINX |
| RedHat Enterprise Linux 8 OpenSSL Cryptographic Module | [3852](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3852) | EKS nodes | UBI containers: Workhorse, Pages, Container Registry, Rails (Puma/Sidekiq), Security Analyzers |
| RedHat Enterprise Linux 8 Libgcrypt Cryptographic Module | [3784](https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3784) | EKS nodes | UBI containers: GitLab Shell, `gpg` |
### Supported Operating Systems
The supported hybrid environments are:
- Omnibus: Ubuntu 20.04 FIPS
- EKS: Amazon Linux 2
## FIPS validation at GitLab
Unlike FIPS compliance, FIPS validation is a formal declaration of compliance by
@ -55,89 +66,24 @@ A list of FIPS-validated modules can be found at the
NIST (National Institute of Standards and Technology)
[cryptographic module validation program](https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules).
## Setting up a FIPS-enabled development environment
## Install GitLab with FIPS compliance
The simplest approach is to set up a virtual machine running
[Red Hat Enterprise Linux 8](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening#switching-the-system-to-fips-mode_using-the-system-wide-cryptographic-policies).
This guide is specifically for public users or GitLab team members with a requirement
to run a production instance of GitLab that is FIPS compliant. This guide outlines
a hybrid deployment using elements from both Omnibus and our Cloud Native GitLab installations.
Red Hat provide free licenses to developers, and permit the CD image to be
downloaded from the [Red Hat developer's portal](https://developers.redhat.com).
Registration is required.
### Prerequisites
After the virtual machine is set up, you can follow the [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit)
installation instructions, including the [advanced instructions for RHEL](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/advanced.md#red-hat-enterprise-linux).
Note that `asdf` is not used for dependency management because it's essential to
use the RedHat-provided Go compiler and other system dependencies.
- Amazon Web Services account. Our first target environment is running on AWS, and uses other FIPS Compliant AWS resources.
- Ability to run Ubuntu 20.04 machines for GitLab. Our first target environment uses the hybrid architecture.
### Enable FIPS mode
After GDK and its dependencies are installed, run this command (as
root) and restart the virtual machine:
```shell
fips-mode-setup --enable
```
You can check whether it's taken effect by running:
```shell
fips-mode-setup --check
```
In this environment, OpenSSL refuses to perform cryptographic operations
forbidden by the FIPS standards. This enables you to reproduce FIPS-related bugs,
and validate fixes.
You should be able to open a web browser inside the virtual machine and log in
to the GitLab instance.
You can disable FIPS mode again by running this command, then restarting the
virtual machine:
```shell
fips-mode-setup --disable
```
#### Detect FIPS enablement in code
You can query `Gitlab::FIPS` in Ruby code to determine if the instance is FIPS-enabled:
```ruby
def default_min_key_size(name)
if Gitlab::FIPS.enabled?
Gitlab::SSHPublicKey.supported_sizes(name).select(&:positive?).min || -1
else
0
end
end
```
#### Unsupported features in FIPS mode
Some GitLab features may not work when FIPS mode is enabled. The following features are known to not work in FIPS mode; however, there may be additional features not listed here that also do not work properly in FIPS mode:
- [License compliance](../user/compliance/license_compliance/index.md)
- [Dependency scanning](../user/application_security/dependency_scanning/index.md) support for Gradle
- [Solutions for vulnerabilities](../user/application_security/vulnerabilities/index.md#resolve-a-vulnerability) for yarn projects
## Nightly Omnibus FIPS builds
The Distribution team has created [nightly FIPS Omnibus builds](https://packages.gitlab.com/gitlab/nightly-fips-builds). These
GitLab builds are compiled to use the system OpenSSL instead of the Omnibus-embedded version of OpenSSL.
See [the section on how FIPS builds are created](#how-fips-builds-are-created).
## Runner
See the [documentation on installing a FIPS-compliant GitLab Runner](https://docs.gitlab.com/runner/install/#fips-compliant-gitlab-runner).
## Set up a FIPS-enabled cluster
### Set up a FIPS-enabled cluster
You can use the [GitLab Environment Toolkit](https://gitlab.com/gitlab-org/gitlab-environment-toolkit) to spin
up a FIPS-enabled cluster for development and testing. These instructions use Amazon Web Services (AWS)
because that is the first target environment, but you can adapt them for other providers.
up a FIPS-enabled cluster for development and testing. As mentioned in the prerequisites, these instructions use Amazon Web Services (AWS)
because that is the first target environment.
### Set up your environment
#### Set up your environment
To get started, your AWS account must subscribe to a FIPS-enabled Amazon
Machine Image (AMI) in the [AWS Marketplace console](https://aws.amazon.com/premiumsupport/knowledge-center/launch-ec2-marketplace-subscription/).
@ -146,13 +92,13 @@ This example assumes that the `Ubuntu Pro 20.04 FIPS LTS` AMI by
`Canonical Group Limited` has been added your account. This operating
system is used for virtual machines running in Amazon EC2.
### Omnibus
#### Omnibus
The simplest way to get a FIPS-enabled GitLab cluster is to use an Omnibus reference architecture.
See the [GET Quick Start Guide](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/docs/environment_quick_start_guide.md)
for more details. The following instructions build on the Quick Start and are also necessary for [Cloud Native Hybrid](#cloud-native-hybrid) installations.
#### Terraform: Use a FIPS AMI
##### Terraform: Use a FIPS AMI
1. Follow the guide to set up Terraform and Ansible.
1. After [step 2b](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/-/blob/main/docs/environment_quick_start_guide.md#2b-setup-config),
@ -197,7 +143,7 @@ an instance, this would result in data loss: not only would disks be
destroyed, but also GitLab secrets would be lost. There is a [Terraform lifecycle rule](https://gitlab.com/gitlab-org/gitlab-environment-toolkit/blob/2aaeaff8ac8067f23cd7b6bb5bf131061649089d/terraform/modules/gitlab_aws_instance/main.tf#L40)
to ignore AMI changes.
#### Ansible: Specify the FIPS Omnibus builds
##### Ansible: Specify the FIPS Omnibus builds
The standard Omnibus GitLab releases build their own OpenSSL library, which is
not FIPS-validated. However, we have nightly builds that create Omnibus packages
@ -211,11 +157,11 @@ in this way:
all:
vars:
...
gitlab_repo_script_url: "https://packages.gitlab.com/install/repositories/gitlab/nightly-fips-builds/script.deb.sh"
gitlab_repo_script_url: "https://packages.gitlab.com/install/repositories/gitlab/gitlab-fips/script.deb.sh"
gitlab_edition: "gitlab-fips"
```
### Cloud Native Hybrid
#### Cloud Native Hybrid
A Cloud Native Hybrid install uses both Omnibus and Cloud Native GitLab
(CNG) images. The previous instructions cover the Omnibus part, but two
@ -224,7 +170,7 @@ additional steps are needed to enable FIPS in CNG:
1. Use a custom Amazon Elastic Kubernetes Service (EKS) AMI.
1. Use GitLab containers built with RedHat's Universal Base Image (UBI).
#### Build a custom EKS AMI
##### Build a custom EKS AMI
Because Amazon does not yet publish a FIPS-enabled AMI, you have to
build one yourself with Packer.
@ -267,7 +213,7 @@ be different.
Building a RHEL-based system with FIPS enabled should be possible, but
there is [an outstanding issue preventing the Packer build from completing](https://github.com/aws-samples/amazon-eks-custom-amis/issues/51).
#### Terraform: Use a custom EKS AMI
##### Terraform: Use a custom EKS AMI
Now you can set the custom EKS AMI.
@ -294,7 +240,7 @@ Now you can set the custom EKS AMI.
}
```
#### Ansible: Use UBI images
##### Ansible: Use UBI images
CNG uses a Helm Chart to manage which container images to deploy. By default, GET
deploys the latest released versions that use Debian-based containers.
@ -414,6 +360,97 @@ You can find more information on FIPS performance benchmarking in the following
- [Benchmark performance of FIPS reference architecture](https://gitlab.com/gitlab-org/gitlab/-/issues/364051#note_1010450415)
## Setting up a FIPS-enabled development environment
The simplest approach is to set up a virtual machine running
[Red Hat Enterprise Linux 8](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/security_hardening/using-the-system-wide-cryptographic-policies_security-hardening#switching-the-system-to-fips-mode_using-the-system-wide-cryptographic-policies).
Red Hat provide free licenses to developers, and permit the CD image to be
downloaded from the [Red Hat developer's portal](https://developers.redhat.com).
Registration is required.
After the virtual machine is set up, you can follow the [GDK](https://gitlab.com/gitlab-org/gitlab-development-kit)
installation instructions, including the [advanced instructions for RHEL](https://gitlab.com/gitlab-org/gitlab-development-kit/-/blob/main/doc/advanced.md#red-hat-enterprise-linux).
Note that `asdf` is not used for dependency management because it's essential to
use the RedHat-provided Go compiler and other system dependencies.
### Enable FIPS mode
After GDK and its dependencies are installed, run this command (as
root) and restart the virtual machine:
```shell
fips-mode-setup --enable
```
You can check whether it's taken effect by running:
```shell
fips-mode-setup --check
```
In this environment, OpenSSL refuses to perform cryptographic operations
forbidden by the FIPS standards. This enables you to reproduce FIPS-related bugs,
and validate fixes.
You should be able to open a web browser inside the virtual machine and log in
to the GitLab instance.
You can disable FIPS mode again by running this command, then restarting the
virtual machine:
```shell
fips-mode-setup --disable
```
#### Detect FIPS enablement in code
You can query `Gitlab::FIPS` in Ruby code to determine if the instance is FIPS-enabled:
```ruby
def default_min_key_size(name)
if Gitlab::FIPS.enabled?
Gitlab::SSHPublicKey.supported_sizes(name).select(&:positive?).min || -1
else
0
end
end
```
#### Unsupported features in FIPS mode
Some GitLab features may not work when FIPS mode is enabled. The following features
are known to not work in FIPS mode. However, there may be additional features not
listed here that also do not work properly in FIPS mode:
- [Container Scanning](../user/application_security/container_scanning/index.md) support for scanning images in repositories that require authentication.
- [Code Quality](../ci/testing/code_quality.md) does not support operating in FIPS-compliant mode.
- [Dependency scanning](../user/application_security/dependency_scanning/index.md) support for Gradle.
- [Dynamic Application Security Testing (DAST)](../user/application_security/dast/index.md)
does not support operating in FIPS-compliant mode.
- [License compliance](../user/compliance/license_compliance/index.md).
- [Solutions for vulnerabilities](../user/application_security/vulnerabilities/index.md#resolve-a-vulnerability)
for yarn projects.
- [Static Application Security Testing (SAST)](../user/application_security/sast/index.md)
supports a reduced set of [analyzers](../user/application_security/sast/#fips-enabled-images)
when operating in FIPS-compliant mode.
Additionally, these package repositories are disabled in FIPS mode:
- [Conan package repository](../user/packages/conan_repository/index.md).
- [Debian package repository](../user/packages/debian_repository/index.md).
## Nightly Omnibus FIPS builds
The Distribution team has created [nightly FIPS Omnibus builds](https://packages.gitlab.com/gitlab/nightly-fips-builds). These
GitLab builds are compiled to use the system OpenSSL instead of the Omnibus-embedded version of OpenSSL.
See [the section on how FIPS builds are created](#how-fips-builds-are-created).
## Runner
See the [documentation on installing a FIPS-compliant GitLab Runner](https://docs.gitlab.com/runner/install/#fips-compliant-gitlab-runner).
## Verify FIPS
The following sections describe ways you can verify if FIPS is enabled.

View file

@ -313,11 +313,11 @@ run:
```shell
# Validate all queries
bundle exec rake gitlab::graphql:validate
bundle exec rake gitlab:graphql:validate
# Validate one query
bundle exec rake gitlab::graphql:validate[path/to/query.graphql]
bundle exec rake gitlab:graphql:validate[path/to/query.graphql]
# Validate a directory
bundle exec rake gitlab::graphql:validate[path/to/queries]
bundle exec rake gitlab:graphql:validate[path/to/queries]
```
This prints out a report with an entry for each query, explaining why
@ -335,11 +335,11 @@ Usage:
```shell
# Analyze all queries
bundle exec rake gitlab::graphql:analyze
bundle exec rake gitlab:graphql:analyze
# Analyze one query
bundle exec rake gitlab::graphql:analyze[path/to/query.graphql]
bundle exec rake gitlab:graphql:analyze[path/to/query.graphql]
# Analyze a directory
bundle exec rake gitlab::graphql:analyze[path/to/queries]
bundle exec rake gitlab:graphql:analyze[path/to/queries]
```
This prints out a report for each query, including the complexity

View file

@ -753,3 +753,223 @@ If this happens, examine the following:
- Confirm there is sufficient disk space for the Gzip operation.
- If NFS is being used, check if the mount option `timeout` is set. The
default is `600`, and changing this to smaller values results in this error.
### Backup fails with `File name too long` error
During backup, you can get the `File name too long` error ([issue #354984](https://gitlab.com/gitlab-org/gitlab/-/issues/354984)). For example:
```plaintext
Problem: <class 'OSError: [Errno 36] File name too long:
```
This problem stops the backup script from completing. To fix this problem, you must truncate the filenames causing the problem. A maximum of 246 characters, including the file extension, is permitted.
WARNING:
The steps in this section can potentially lead to **data loss**. All steps must be followed strictly in the order given.
Truncating filenames to resolve the error involves:
- Cleaning up remote uploaded files that aren't tracked in the database.
- Truncating the filenames in the database.
- Rerunning the backup task.
#### Clean up remote uploaded files
A [known issue](https://gitlab.com/gitlab-org/gitlab-ce/issues/45425) caused object store uploads to remain after a parent resource was deleted. This issue was [resolved](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18698).
To fix these files, you must clean up all remote uploaded files that are in the storage but not tracked in the `uploads` database table.
1. List all the object store upload files that can be moved to a lost and found directory if they don't exist in the GitLab database:
```shell
bundle exec rake gitlab:cleanup:remote_upload_files RAILS_ENV=production
```
1. If you are sure you want to delete these files and remove all non-referenced uploaded files, run:
WARNING:
The following action is **irreversible**.
```shell
bundle exec rake gitlab:cleanup:remote_upload_files RAILS_ENV=production DRY_RUN=false
```
#### Truncate the filenames referenced by the database
You must truncate the files referenced by the database that are causing the problem. The filenames referenced by the database are stored:
- In the `uploads` table.
- In the references found. Any reference found from other database tables and columns.
- On the filesystem.
Truncate the filenames in the `uploads` table:
1. Enter the database console:
For Omnibus GitLab 14.2 and later:
```shell
sudo gitlab-rails dbconsole --database main
```
For Omnibus GitLab 14.1 and earlier:
```shell
sudo gitlab-rails dbconsole
```
For installations from source, GitLab 14.2 and later:
```shell
sudo -u git -H bundle exec rails dbconsole -e production --database main
```
For installations from source, GitLab 14.1 and earlier:
```shell
sudo -u git -H bundle exec rails dbconsole -e production
```
1. Search the `uploads` table for filenames longer than 246 characters:
The following query selects the `uploads` records with filenames longer than 246 characters in batches of 0 to 10000. This improves the performance on large GitLab instances with tables having thousand of records.
```sql
CREATE TEMP TABLE uploads_with_long_filenames AS
SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, id, path
FROM uploads AS u
WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
CREATE INDEX ON uploads_with_long_filenames(row_id);
SELECT
u.id,
u.path,
-- Current filename
(regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] AS current_filename,
-- New filename
CONCAT(
LEFT(SPLIT_PART((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
COALESCE(SUBSTRING((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
) AS new_filename,
-- New path
CONCAT(
COALESCE((regexp_match(u.path, '(.*\/).*'))[1], ''),
CONCAT(
LEFT(SPLIT_PART((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
COALESCE(SUBSTRING((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
)
) AS new_path
FROM uploads_with_long_filenames AS u
WHERE u.row_id > 0 AND u.row_id <= 10000;
```
Output example:
```postgresql
-[ RECORD 1 ]----+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
id | 34
path | public/@hashed/loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisit.txt
current_filename | loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisit.txt
new_filename | loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelits.txt
new_path | public/@hashed/loremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelitsedvulputatemisitloremipsumdolorsitametconsecteturadipiscingelitseddoeiusmodtemporincididuntutlaboreetdoloremagnaaliquaauctorelits.txt
```
Where:
- `current_filename`: a filename that is currently more than 246 characters long.
- `new_filename`: a filename that has been truncated to 246 characters maximum.
- `new_path`: new path considering the new_filename (truncated).
Once you validate the batch results, you must change the batch size (`row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
1. Rename the files found in the `uploads` table from long filenames to new truncated filenames. The following query rolls back the update so you can check the results safely within a transaction wrapper:
```sql
CREATE TEMP TABLE uploads_with_long_filenames AS
SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, path, id
FROM uploads AS u
WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
CREATE INDEX ON uploads_with_long_filenames(row_id);
BEGIN;
WITH updated_uploads AS (
UPDATE uploads
SET
path =
CONCAT(
COALESCE((regexp_match(updatable_uploads.path, '(.*\/).*'))[1], ''),
CONCAT(
LEFT(SPLIT_PART((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
COALESCE(SUBSTRING((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
)
)
FROM
uploads_with_long_filenames AS updatable_uploads
WHERE
uploads.id = updatable_uploads.id
AND updatable_uploads.row_id > 0 AND updatable_uploads.row_id <= 10000
RETURNING uploads.*
)
SELECT id, path FROM updated_uploads;
ROLLBACK;
```
Once you validate the batch update results, you must change the batch size (`row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
1. Validate that the new filenames from the previous query are the expected ones. If you are sure you want to truncate the records found in the previous step to 246 characters, run the following:
WARNING:
The following action is **irreversible**.
```sql
CREATE TEMP TABLE uploads_with_long_filenames AS
SELECT ROW_NUMBER() OVER(ORDER BY id) row_id, path, id
FROM uploads AS u
WHERE LENGTH((regexp_match(u.path, '[^\\/:*?"<>|\r\n]+$'))[1]) > 246;
CREATE INDEX ON uploads_with_long_filenames(row_id);
UPDATE uploads
SET
path =
CONCAT(
COALESCE((regexp_match(updatable_uploads.path, '(.*\/).*'))[1], ''),
CONCAT(
LEFT(SPLIT_PART((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1], '.', 1), 242),
COALESCE(SUBSTRING((regexp_match(updatable_uploads.path, '[^\\/:*?"<>|\r\n]+$'))[1] FROM '\.(?:.(?!\.))+$'))
)
)
FROM
uploads_with_long_filenames AS updatable_uploads
WHERE
uploads.id = updatable_uploads.id
AND updatable_uploads.row_id > 0 AND updatable_uploads.row_id <= 10000;
```
Once you finish the batch update, you must change the batch size (`updatable_uploads.row_id`) using the following sequence of numbers (10000 to 20000). Repeat this process until you reach the last record in the `uploads` table.
Truncate the filenames in the references found:
1. Check if those records are referenced somewhere. One way to do this is to dump the database and search for the parent directory name and filename:
1. To dump your database, you can use the following command as an example:
```shell
pg_dump -h /var/opt/gitlab/postgresql/ -d gitlabhq_production > gitlab-dump.tmp
```
1. Then you can search for the references using the `grep` command. Combining the parent directory and the filename can be a good idea. For example:
```shell
grep public/alongfilenamehere.txt gitlab-dump.tmp
```
1. Replace those long filenames using the new filenames obtained from querying the `uploads` table.
Truncate the filenames on the filesystem. You must manually rename the files in your filesystem to the new filenames obtained from querying the `uploads` table.
#### Re-run the backup task
After following all the previous steps, re-run the backup task.

View file

@ -45,6 +45,27 @@ sole discretion of GitLab Inc.
<div class="announcement-milestone">
## Announced in 15.2
<div class="deprecation removal-160 breaking-change">
### Remove `job_age` parameter from `POST /jobs/request` Runner endpoint
Planned removal: GitLab <span class="removal-milestone">16.0</span> (2023-05-22)
WARNING:
This is a [breaking change](https://docs.gitlab.com/ee/development/contributing/#breaking-changes).
Review the details carefully before upgrading.
The `job_age` parameter, returned from the `POST /jobs/request` API endpoint used in communication with GitLab Runner, was never used by any GitLab or Runner feature. This parameter will be removed in GitLab 16.0.
This could be a breaking change for anyone that developed their own runner that relies on this parameter being returned by the endpoint. This is not a breaking change for anyone using an officially released version of GitLab Runner, including public shared runners on GitLab.com.
</div>
</div>
<div class="announcement-milestone">
## Announced in 15.1
<div class="deprecation removal-160 breaking-change">

View file

@ -99,7 +99,8 @@ The **Overview** dashboard shows the following key metrics that measure team per
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340150) lead time for changes DORA metric in GitLab 14.5.
> - DORA API-based deployment metrics for value stream analytics for groups were [moved](https://gitlab.com/gitlab-org/gitlab/-/issues/337256) from GitLab Ultimate to GitLab Premium in GitLab 14.3.
> - DORA and key metrics were [separated into distinct rows in the UI](https://gitlab.com/gitlab-org/gitlab/-/issues/359060) in GitLab 15.0.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/355304) time to restore service tile in GitLab 15.0.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357071) change failure rate tile in GitLab 15.0.
The value stream analytics **Overview** dashboard displays the following [DORA](../../../user/analytics/index.md) metrics:

View file

@ -49,6 +49,7 @@ module API
offset_limit = limit_for_scope(request_scope)
if (Gitlab::Pagination::Keyset.available_for_type?(relation) ||
cursor_based_keyset_pagination_supported?(relation)) &&
cursor_based_keyset_pagination_enforced?(relation) &&
offset_limit_exceeded?(offset_limit)
return error!("Offset pagination has a maximum allowed offset of #{offset_limit} " \
@ -63,6 +64,10 @@ module API
Gitlab::Pagination::CursorBasedKeyset.available_for_type?(relation)
end
def cursor_based_keyset_pagination_enforced?(relation)
Gitlab::Pagination::CursorBasedKeyset.enforced_for_type?(relation)
end
def keyset_pagination_enabled?
params[:pagination] == 'keyset'
end

View file

@ -0,0 +1,44 @@
# frozen_string_literal: true
module Gitlab
module BackgroundMigration
# This class is used to update the delayed_project_removal column
# for user namespaces of the namespace_settings table.
class UpdateDelayedProjectRemovalToNullForUserNamespaces < Gitlab::BackgroundMigration::BatchedMigrationJob
# Migration only version of `namespace_settings` table
class NamespaceSetting < ::ApplicationRecord
self.table_name = 'namespace_settings'
end
def perform
each_sub_batch(
operation_name: :set_delayed_project_removal_to_null_for_user_namespace
) do |sub_batch|
set_delayed_project_removal_to_null_for_user_namespace(sub_batch)
end
end
private
def set_delayed_project_removal_to_null_for_user_namespace(relation)
NamespaceSetting.connection.execute(
<<~SQL
UPDATE namespace_settings
SET delayed_project_removal = NULL
WHERE
namespace_settings.namespace_id IN (
SELECT
namespace_settings.namespace_id
FROM
namespace_settings
INNER JOIN namespaces ON namespaces.id = namespace_settings.namespace_id
WHERE
namespaces.id IN (#{relation.select(:namespace_id).to_sql})
AND namespaces.type = 'User'
AND namespace_settings.delayed_project_removal = FALSE)
SQL
)
end
end
end
end

View file

@ -106,6 +106,7 @@ module Gitlab
description: description,
state_id: Issue.available_states[issue.state],
author_id: gitlab_user_id(project, issue.author),
namespace_id: project.project_namespace_id,
milestone: milestone,
created_at: issue.created_at,
updated_at: issue.updated_at

View file

@ -51,6 +51,7 @@ module Gitlab
title: issue.truncated_title,
author_id: author_id,
project_id: project.id,
namespace_id: project.project_namespace_id,
description: description,
milestone_id: milestone_finder.id_for(issue),
state_id: ::Issue.available_states[issue.state],

View file

@ -18,6 +18,7 @@ module Gitlab
{
iid: params[:iid],
project_id: project.id,
namespace_id: project.project_namespace_id,
description: description,
title: title,
state_id: map_status(jira_issue.status.statusCategory),

View file

@ -4,9 +4,18 @@ module Gitlab
module Pagination
module CursorBasedKeyset
SUPPORTED_ORDERING = {
Group => { name: :asc }
Group => { name: :asc },
AuditEvent => { id: :desc }
}.freeze
# Relation types that are enforced in this list
# enforce the use of keyset pagination, thus erroring out requests
# made with offset pagination above a certain limit.
#
# In many cases this could introduce a breaking change
# so enforcement is optional.
ENFORCED_TYPES = [Group].freeze
def self.available_for_type?(relation)
SUPPORTED_ORDERING.key?(relation.klass)
end
@ -16,6 +25,10 @@ module Gitlab
order_satisfied?(relation, cursor_based_request_context)
end
def self.enforced_for_type?(relation)
ENFORCED_TYPES.include?(relation.klass)
end
def self.order_satisfied?(relation, cursor_based_request_context)
order_by_from_request = cursor_based_request_context.order_by

View file

@ -55,9 +55,10 @@ RSpec.describe API::Helpers::PaginationStrategies do
allow(subject).to receive(:keyset_pagination_enabled?).and_return(false)
end
context 'when keyset pagination is available for the relation' do
context 'when keyset pagination is available and enforced for the relation' do
before do
allow(Gitlab::Pagination::Keyset).to receive(:available_for_type?).and_return(true)
allow(Gitlab::Pagination::CursorBasedKeyset).to receive(:enforced_for_type?).and_return(true)
end
context 'when a request scope is given' do
@ -70,6 +71,18 @@ RSpec.describe API::Helpers::PaginationStrategies do
subject.paginator(relation, request_scope)
end
context 'when keyset pagination is not enforced' do
before do
allow(Gitlab::Pagination::CursorBasedKeyset).to receive(:enforced_for_type?).and_return(false)
end
it 'returns no errors' do
expect(subject).not_to receive(:error!)
subject.paginator(relation, request_scope)
end
end
end
context 'when the scope limit is not exceeded' do

View file

@ -0,0 +1,49 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::BackgroundMigration::UpdateDelayedProjectRemovalToNullForUserNamespaces,
:migration do
let(:namespaces_table) { table(:namespaces) }
let(:namespace_settings_table) { table(:namespace_settings) }
subject(:perform_migration) do
described_class.new(
start_id: 1,
end_id: 30,
batch_table: :namespace_settings,
batch_column: :namespace_id,
sub_batch_size: 2,
pause_ms: 0,
connection: ActiveRecord::Base.connection
).perform
end
before do
namespaces_table.create!(id: 1, name: 'group_namespace', path: 'path-1', type: 'Group')
namespaces_table.create!(id: 2, name: 'user_namespace', path: 'path-2', type: 'User')
namespaces_table.create!(id: 3, name: 'user_three_namespace', path: 'path-3', type: 'User')
namespaces_table.create!(id: 4, name: 'group_four_namespace', path: 'path-4', type: 'Group')
namespaces_table.create!(id: 5, name: 'group_five_namespace', path: 'path-5', type: 'Group')
namespace_settings_table.create!(namespace_id: 1, delayed_project_removal: false)
namespace_settings_table.create!(namespace_id: 2, delayed_project_removal: false)
namespace_settings_table.create!(namespace_id: 3, delayed_project_removal: nil)
namespace_settings_table.create!(namespace_id: 4, delayed_project_removal: true)
namespace_settings_table.create!(namespace_id: 5, delayed_project_removal: nil)
end
it 'updates `delayed_project_removal` column to null for user namespaces', :aggregate_failures do
expect(ActiveRecord::QueryRecorder.new { perform_migration }.count).to eq(7)
expect(migrated_attribute(1)).to be_falsey
expect(migrated_attribute(2)).to be_nil
expect(migrated_attribute(3)).to be_nil
expect(migrated_attribute(4)).to be_truthy
expect(migrated_attribute(5)).to be_nil
end
def migrated_attribute(namespace_id)
namespace_settings_table.find(namespace_id).delayed_project_removal
end
end

View file

@ -328,6 +328,7 @@ RSpec.describe Gitlab::BitbucketImport::Importer do
expect(project.issues.where(state_id: Issue.available_states[:closed]).size).to eq(5)
expect(project.issues.where(state_id: Issue.available_states[:opened]).size).to eq(2)
expect(project.issues.map(&:namespace_id).uniq).to match_array([project.project_namespace_id])
end
describe 'wiki import' do

View file

@ -45,16 +45,26 @@ RSpec.describe Gitlab::EncodingHelper do
end
context 'with corrupted diff' do
let(:project) { create(:project, :empty_repo) }
let(:repository) { project.repository }
let(:content) { fixture_file('encoding/Japanese.md') }
let(:corrupted_diff) do
with_empty_bare_repository do |repo|
content = File.read(Rails.root.join(
'spec/fixtures/encoding/Japanese.md').to_s)
commit_a = commit(repo, 'Japanese.md', content)
commit_b = commit(repo, 'Japanese.md',
content.sub('[TODO: Link]', '[現在作業中です: Link]'))
commit_a = repository.create_file(
project.creator,
'Japanese.md',
content,
branch_name: 'HEAD',
message: 'Create Japanese.md'
)
commit_b = repository.update_file(
project.creator,
'Japanese.md',
content.sub('[TODO: Link]', '[現在作業中です: Link]'),
branch_name: 'HEAD',
message: 'Update Japanese.md'
)
repo.diff(commit_a, commit_b).each_line.map(&:content).join
end
repository.diff(commit_a, commit_b).map(&:diff).join
end
let(:cleaned_diff) do
@ -69,26 +79,6 @@ RSpec.describe Gitlab::EncodingHelper do
it 'does not corrupt data but remove invalid characters' do
expect(encoded_diff).to eq(cleaned_diff)
end
def commit(repo, path, content)
oid = repo.write(content, :blob)
index = repo.index
index.read_tree(repo.head.target.tree) unless repo.empty?
index.add(path: path, oid: oid, mode: 0100644)
user = { name: 'Test', email: 'test@example.com' }
Rugged::Commit.create(
repo,
tree: index.write_tree(repo),
author: user,
committer: user,
message: "Update #{path}",
parents: repo.empty? ? [] : [repo.head.target].compact,
update_ref: 'HEAD'
)
end
end
end

View file

@ -4,9 +4,6 @@ require "spec_helper"
RSpec.describe Gitlab::Git::Branch, :seed_helper do
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
let(:rugged) do
Rugged::Repository.new(File.join(TestEnv.repos_path, repository.relative_path))
end
subject { repository.branches }
@ -81,20 +78,6 @@ RSpec.describe Gitlab::Git::Branch, :seed_helper do
end
let(:user) { create(:user) }
let(:committer) { { email: user.email, name: user.name } }
let(:params) do
parents = [rugged.head.target]
tree = parents.first.tree
{
message: +'commit message',
author: committer,
committer: committer,
tree: tree,
parents: parents
}
end
let(:stale_sha) { travel_to(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago - 5.days) { create_commit } }
let(:active_sha) { travel_to(Gitlab::Git::Branch::STALE_BRANCH_THRESHOLD.ago + 5.days) { create_commit } }
let(:future_sha) { travel_to(100.days.since) { create_commit } }
@ -137,7 +120,11 @@ RSpec.describe Gitlab::Git::Branch, :seed_helper do
it { expect(repository.branches.size).to eq(SeedRepo::Repo::BRANCHES.size) }
def create_commit
params[:message].delete!(+"\r")
Rugged::Commit.create(rugged, params.merge(committer: committer.merge(time: Time.now)))
repository.multi_action(
user,
branch_name: 'HEAD',
message: 'commit message',
actions: []
).newrev
end
end

View file

@ -3,68 +3,8 @@
require "spec_helper"
RSpec.describe Gitlab::Git::Commit, :seed_helper do
include GitHelpers
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
let(:rugged_repo) do
Rugged::Repository.new(File.join(TestEnv.repos_path, TEST_REPO_PATH))
end
let(:commit) { described_class.find(repository, SeedRepo::Commit::ID) }
let(:rugged_commit) { rugged_repo.lookup(SeedRepo::Commit::ID) }
describe "Commit info" do
before do
@committer = {
email: 'mike@smith.com',
name: "Mike Smith",
time: Time.new(2000, 1, 1, 0, 0, 0, "+08:00")
}
@author = {
email: 'john@smith.com',
name: "John Smith",
time: Time.new(2000, 1, 1, 0, 0, 0, "-08:00")
}
@parents = [rugged_repo.head.target]
@gitlab_parents = @parents.map { |c| described_class.find(repository, c.oid) }
@tree = @parents.first.tree
sha = Rugged::Commit.create(
rugged_repo,
author: @author,
committer: @committer,
tree: @tree,
parents: @parents,
message: "Refactoring specs",
update_ref: "HEAD"
)
@raw_commit = rugged_repo.lookup(sha)
@commit = described_class.find(repository, sha)
end
it { expect(@commit.short_id).to eq(@raw_commit.oid[0..10]) }
it { expect(@commit.id).to eq(@raw_commit.oid) }
it { expect(@commit.sha).to eq(@raw_commit.oid) }
it { expect(@commit.safe_message).to eq(@raw_commit.message) }
it { expect(@commit.created_at).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.date).to eq(@raw_commit.committer[:time]) }
it { expect(@commit.author_email).to eq(@author[:email]) }
it { expect(@commit.author_name).to eq(@author[:name]) }
it { expect(@commit.committer_name).to eq(@committer[:name]) }
it { expect(@commit.committer_email).to eq(@committer[:email]) }
it { expect(@commit.different_committer?).to be_truthy }
it { expect(@commit.parents).to eq(@gitlab_parents) }
it { expect(@commit.parent_id).to eq(@parents.first.oid) }
it { expect(@commit.no_commit_message).to eq("No commit message") }
after do
# Erase the new commit so other tests get the original repo
repository.write_ref("refs/heads/master", SeedRepo::LastCommit::ID)
end
end
describe "Commit info from gitaly commit" do
let(:subject) { (+"My commit").force_encoding('ASCII-8BIT') }
@ -132,7 +72,7 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
shared_examples '.find' do
it "returns first head commit if without params" do
expect(described_class.last(repository).id).to eq(
rugged_repo.head.target.oid
repository.commit.sha
)
end
@ -622,19 +562,6 @@ RSpec.describe Gitlab::Git::Commit, :seed_helper do
end
end
skip 'move this test to gitaly-ruby' do
RSpec.describe '#init_from_rugged' do
let(:gitlab_commit) { described_class.new(repository, rugged_commit) }
subject { gitlab_commit }
describe '#id' do
subject { super().id }
it { is_expected.to eq(SeedRepo::Commit::ID) }
end
end
end
describe '#init_from_hash' do
let(:commit) { described_class.new(repository, sample_commit_hash) }

View file

@ -3,8 +3,6 @@
require 'spec_helper'
RSpec.describe Gitlab::Git::ObjectPool do
include RepoHelpers
let(:pool_repository) { create(:pool_repository) }
let(:source_repository) { pool_repository.source_project.repository }
@ -80,8 +78,6 @@ RSpec.describe Gitlab::Git::ObjectPool do
end
describe '#fetch' do
let(:source_repository_path) { File.join(TestEnv.repos_path, source_repository.relative_path) }
let(:source_repository_rugged) { Rugged::Repository.new(source_repository_path) }
let(:commit_count) { source_repository.commit_count }
context "when the object's pool repository exists" do
@ -106,7 +102,13 @@ RSpec.describe Gitlab::Git::ObjectPool do
end
it 'fetches objects from the source repository' do
new_commit_id = new_commit_edit_old_file(source_repository_rugged).oid
new_commit_id = source_repository.create_file(
pool_repository.source_project.owner,
'a.file',
'This is a file',
branch_name: source_repository.root_ref,
message: 'Add a file'
)
expect(subject.repository.exists?).to be false

View file

@ -352,12 +352,30 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
repository.create_branch('left-branch')
repository.create_branch('right-branch')
left.times do
new_commit_edit_new_file_on_branch(repository_rugged, 'encoding/CHANGELOG', 'left-branch', 'some more content for a', 'some stuff')
left.times do |i|
repository.multi_action(
user,
branch_name: 'left-branch',
message: 'some more content for a',
actions: [{
action: i == 0 ? :create : :update,
file_path: 'encoding/CHANGELOG',
content: 'some stuff'
}]
)
end
right.times do
new_commit_edit_new_file_on_branch(repository_rugged, 'encoding/CHANGELOG', 'right-branch', 'some more content for b', 'some stuff')
right.times do |i|
repository.multi_action(
user,
branch_name: 'right-branch',
message: 'some more content for b',
actions: [{
action: i == 0 ? :create : :update,
file_path: 'encoding/CHANGELOG',
content: 'some stuff'
}]
)
end
end
@ -392,12 +410,30 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
repository.create_branch('left-branch')
repository.create_branch('right-branch')
left.times do
new_commit_edit_new_file_on_branch(repository_rugged, 'encoding/CHANGELOG', 'left-branch', 'some more content for a', 'some stuff')
left.times do |i|
repository.multi_action(
user,
branch_name: 'left-branch',
message: 'some more content for a',
actions: [{
action: i == 0 ? :create : :update,
file_path: 'encoding/CHANGELOG',
content: 'some stuff'
}]
)
end
right.times do
new_commit_edit_new_file_on_branch(repository_rugged, 'encoding/CHANGELOG', 'right-branch', 'some more content for b', 'some stuff')
right.times do |i|
repository.multi_action(
user,
branch_name: 'right-branch',
message: 'some more content for b',
actions: [{
action: i == 0 ? :create : :update,
file_path: 'encoding/CHANGELOG',
content: 'some stuff'
}]
)
end
end
@ -557,14 +593,31 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
describe '#search_files_by_content' do
let(:repository) { mutable_repository }
let(:repository_rugged) { mutable_repository_rugged }
let(:ref) { 'search-files-by-content-branch' }
let(:content) { 'foobarbazmepmep' }
before do
repository.create_branch(ref)
new_commit_edit_new_file_on_branch(repository_rugged, 'encoding/CHANGELOG', ref, 'committing something', content)
new_commit_edit_new_file_on_branch(repository_rugged, 'anotherfile', ref, 'committing something', content)
repository.multi_action(
user,
branch_name: ref,
message: 'committing something',
actions: [{
action: :create,
file_path: 'encoding/CHANGELOG',
content: content
}]
)
repository.multi_action(
user,
branch_name: ref,
message: 'committing something',
actions: [{
action: :create,
file_path: 'anotherfile',
content: content
}]
)
end
after do
@ -667,14 +720,42 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
before do
# Add new commits so that there's a renamed file in the commit history
@commit_with_old_name_id = new_commit_edit_old_file(repository_rugged).oid
@rename_commit_id = new_commit_move_file(repository_rugged).oid
@commit_with_new_name_id = new_commit_edit_new_file(repository_rugged, "encoding/CHANGELOG", "Edit encoding/CHANGELOG", "I'm a new changelog with different text").oid
@commit_with_old_name_id = repository.multi_action(
user,
branch_name: repository.root_ref,
message: 'Update CHANGELOG',
actions: [{
action: :update,
file_path: 'CHANGELOG',
content: 'CHANGELOG'
}]
).newrev
@rename_commit_id = repository.multi_action(
user,
branch_name: repository.root_ref,
message: 'Move CHANGELOG to encoding/',
actions: [{
action: :move,
previous_path: 'CHANGELOG',
file_path: 'encoding/CHANGELOG',
content: 'CHANGELOG'
}]
).newrev
@commit_with_new_name_id = repository.multi_action(
user,
branch_name: repository.root_ref,
message: 'Edit encoding/CHANGELOG',
actions: [{
action: :update,
file_path: 'encoding/CHANGELOG',
content: "I'm a new changelog with different text"
}]
).newrev
end
after do
# Erase our commits so other tests get the original repo
repository.write_ref("refs/heads/master", SeedRepo::LastCommit::ID)
repository.write_ref(repository.root_ref, SeedRepo::LastCommit::ID)
end
context "where 'follow' == true" do
@ -1804,12 +1885,18 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
context 'when the branch exists' do
context 'when the commit does not exist locally' do
let(:source_branch) { 'new-branch-for-fetch-source-branch' }
let(:source_path) { File.join(TestEnv.repos_path, source_repository.relative_path) }
let(:source_rugged) { Rugged::Repository.new(source_path) }
let(:new_oid) { new_commit_edit_old_file(source_rugged).oid }
before do
source_repository.write_ref(source_branch, new_oid)
let!(:new_oid) do
source_repository.multi_action(
user,
branch_name: source_branch,
message: 'Add a file',
actions: [{
action: :create,
file_path: 'a.file',
content: 'This is a file.'
}]
).newrev
end
it 'writes the ref' do
@ -2276,11 +2363,23 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
end
context 'when the diff contains a rename' do
let(:end_sha) { new_commit_move_file(repository_rugged).oid }
let(:end_sha) do
repository.multi_action(
user,
branch_name: repository.root_ref,
message: 'Move CHANGELOG to encoding/',
actions: [{
action: :move,
previous_path: 'CHANGELOG',
file_path: 'encoding/CHANGELOG',
content: 'CHANGELOG'
}]
).newrev
end
after do
# Erase our commits so other tests get the original repo
repository.write_ref('refs/heads/master', SeedRepo::LastCommit::ID)
repository.write_ref(repository.root_ref, SeedRepo::LastCommit::ID)
end
it 'does not include the renamed file in the sparse checkout' do
@ -2336,10 +2435,7 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
let(:project) { create(:project, :repository) }
let(:pool_repository) { create(:pool_repository) }
let(:repository) { project.repository }
let(:repository_path) { File.join(TestEnv.repos_path, repository.relative_path) }
let(:object_pool) { pool_repository.object_pool }
let(:object_pool_path) { File.join(TestEnv.repos_path, object_pool.repository.relative_path) }
let(:object_pool_rugged) { Rugged::Repository.new(object_pool_path) }
before do
object_pool.create # rubocop:disable Rails/SaveBang
@ -2349,25 +2445,24 @@ RSpec.describe Gitlab::Git::Repository, :seed_helper do
expect { repository.disconnect_alternates }.not_to raise_error
end
it 'removes the alternates file' do
object_pool.link(repository)
alternates_file = File.join(repository_path, "objects", "info", "alternates")
expect(File.exist?(alternates_file)).to be_truthy
repository.disconnect_alternates
expect(File.exist?(alternates_file)).to be_falsey
end
it 'can still access objects in the object pool' do
object_pool.link(repository)
new_commit = new_commit_edit_old_file(object_pool_rugged)
expect(repository.commit(new_commit.oid).id).to eq(new_commit.oid)
new_commit_id = object_pool.repository.multi_action(
project.owner,
branch_name: object_pool.repository.root_ref,
message: 'Add a file',
actions: [{
action: :create,
file_path: 'a.file',
content: 'This is a file.'
}]
).newrev
expect(repository.commit(new_commit_id).id).to eq(new_commit_id)
repository.disconnect_alternates
expect(repository.commit(new_commit.oid).id).to eq(new_commit.oid)
expect(repository.commit(new_commit_id).id).to eq(new_commit_id)
end
end

View file

@ -3,6 +3,8 @@
require "spec_helper"
RSpec.describe Gitlab::Git::Tree, :seed_helper do
let_it_be(:user) { create(:user) }
let(:repository) { Gitlab::Git::Repository.new('default', TEST_REPO_PATH, '', 'group/project') }
shared_examples :repo do
@ -85,52 +87,30 @@ RSpec.describe Gitlab::Git::Tree, :seed_helper do
context :flat_path do
let(:filename) { 'files/flat/path/correct/content.txt' }
let(:sha) { create_file(filename) }
let(:path) { 'files/flat' }
# rubocop: disable Rails/FindBy
# This is not ActiveRecord where..first
let(:subdir_file) { entries.first }
# rubocop: enable Rails/FindBy
let(:repository_rugged) { Rugged::Repository.new(File.join(SEED_STORAGE_PATH, TEST_REPO_PATH)) }
let!(:sha) do
repository.multi_action(
user,
branch_name: 'HEAD',
message: "Create #{filename}",
actions: [{
action: :create,
file_path: filename,
contents: 'test'
}]
).newrev
end
after do
ensure_seeds
end
it { expect(subdir_file.flat_path).to eq('files/flat/path/correct') }
end
def create_file(path)
oid = repository_rugged.write('test', :blob)
index = repository_rugged.index
index.add(path: filename, oid: oid, mode: 0100644)
options = commit_options(
repository_rugged,
index,
repository_rugged.head.target,
'HEAD',
'Add new file')
Rugged::Commit.create(repository_rugged, options)
end
# Build the options hash that's passed to Rugged::Commit#create
def commit_options(repo, index, target, ref, message)
options = {}
options[:tree] = index.write_tree(repo)
options[:author] = {
email: "test@example.com",
name: "Test Author",
time: Time.gm(2014, "mar", 3, 20, 15, 1)
}
options[:committer] = {
email: "test@example.com",
name: "Test Author",
time: Time.gm(2014, "mar", 3, 20, 15, 1)
}
options[:message] ||= message
options[:parents] = repo.empty? ? [] : [target].compact
options[:update_ref] = ref
options
end
end
describe '#file?' do

View file

@ -131,6 +131,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi
title: 'My Issue',
author_id: user.id,
project_id: project.id,
namespace_id: project.project_namespace_id,
description: 'This is my issue',
milestone_id: milestone.id,
state_id: 1,
@ -160,6 +161,7 @@ RSpec.describe Gitlab::GithubImport::Importer::IssueImporter, :clean_gitlab_redi
title: 'My Issue',
author_id: project.creator_id,
project_id: project.id,
namespace_id: project.project_namespace_id,
description: "*Created by: alice*\n\nThis is my issue",
milestone_id: milestone.id,
state_id: 1,

View file

@ -75,6 +75,7 @@ RSpec.describe Gitlab::JiraImport::IssueSerializer do
expect(subject).to eq(
iid: iid,
project_id: project.id,
namespace_id: project.project_namespace_id,
description: expected_description.strip,
title: "[#{key}] #{summary}",
state_id: 1,

View file

@ -15,6 +15,22 @@ RSpec.describe Gitlab::Pagination::CursorBasedKeyset do
end
end
describe '.enforced_for_type?' do
subject { described_class.enforced_for_type?(relation) }
context 'when relation is Group' do
let(:relation) { Group.all }
it { is_expected.to be true }
end
context 'when relation is AuditEvent' do
let(:relation) { AuditEvent.all }
it { is_expected.to be false }
end
end
describe '.available?' do
let(:request_context) { double('request_context', params: { order_by: order_by, sort: sort }) }
let(:cursor_based_request_context) { Gitlab::Pagination::Keyset::CursorBasedRequestContext.new(request_context) }

View file

@ -0,0 +1,32 @@
# frozen_string_literal: true
require 'spec_helper'
require_migration!
RSpec.describe QueueUpdateDelayedProjectRemovalToNullForUserNamespace do
let(:migration) { described_class::MIGRATION }
describe '#up' do
it 'schedules background jobs for each batch of namespace settings' do
migrate!
expect(migration).to(
have_scheduled_batched_migration(
table_name: :namespace_settings,
column_name: :namespace_id,
interval: described_class::INTERVAL,
batch_size: described_class::BATCH_SIZE
)
)
end
end
describe '#down' do
it 'deletes all batched migration records' do
migrate!
schema_migrate_down!
expect(migration).not_to have_scheduled_batched_migration
end
end
end

View file

@ -131,6 +131,37 @@ RSpec.describe Issue do
create(:issue)
end
end
context 'issue namespace' do
let(:issue) { build(:issue, project: reusable_project) }
it 'sets the namespace_id' do
expect(issue).to be_valid
expect(issue.namespace).to eq(reusable_project.project_namespace)
end
context 'when issue is created' do
it 'sets the namespace_id' do
issue.save!
expect(issue.reload.namespace).to eq(reusable_project.project_namespace)
end
end
context 'when existing issue is saved' do
let(:issue) { create(:issue) }
before do
issue.update!(namespace_id: nil)
end
it 'sets the namespace id' do
issue.update!(title: "#{issue.title} and something extra")
expect(issue.namespace).to eq(issue.project.project_namespace)
end
end
end
end
context 'order by upvotes' do

View file

@ -255,21 +255,10 @@ RSpec.describe Repository do
end
context 'with a commit with invalid UTF-8 path' do
def create_commit_with_invalid_utf8_path
rugged = rugged_repo(repository)
blob_id = Rugged::Blob.from_buffer(rugged, "some contents")
tree_builder = Rugged::Tree::Builder.new(rugged)
tree_builder.insert({ oid: blob_id, name: "hello\x80world", filemode: 0100644 })
tree_id = tree_builder.write
user = { email: "jcai@gitlab.com", time: Time.current.to_time, name: "John Cai" }
Rugged::Commit.create(rugged, message: 'some commit message', parents: [rugged.head.target.oid], tree: tree_id, committer: user, author: user)
end
it 'does not raise an error' do
commit = create_commit_with_invalid_utf8_path
response = create_file_in_repo(project, 'master', 'master', "hello\x80world", 'some contents')
expect { repository.list_last_commits_for_tree(commit, '.', offset: 0) }.not_to raise_error
expect { repository.list_last_commits_for_tree(response[:result], '.', offset: 0) }.not_to raise_error
end
end
end

View file

@ -3,6 +3,8 @@
require 'spec_helper'
RSpec.describe WorkItem do
let_it_be(:reusable_project) { create(:project) }
describe 'associations' do
it { is_expected.to belong_to(:namespace) }
it { is_expected.to have_one(:work_item_parent).class_name('WorkItem') }
@ -55,5 +57,55 @@ RSpec.describe WorkItem do
create(:work_item)
end
end
context 'work item namespace' do
let(:work_item) { build(:work_item, project: reusable_project) }
it 'sets the namespace_id' do
expect(work_item).to be_valid
expect(work_item.namespace).to eq(reusable_project.project_namespace)
end
context 'when work item is saved' do
it 'sets the namespace_id' do
work_item.save!
expect(work_item.reload.namespace).to eq(reusable_project.project_namespace)
end
end
context 'when existing work item is saved' do
let(:work_item) { create(:work_item) }
before do
work_item.update!(namespace_id: nil)
end
it 'sets the namespace id' do
work_item.update!(title: "#{work_item.title} and something extra")
expect(work_item.namespace).to eq(work_item.project.project_namespace)
end
end
end
end
describe 'validations' do
subject { work_item.valid? }
describe 'issue_type' do
let(:work_item) { build(:work_item, issue_type: issue_type) }
context 'when a valid type' do
let(:issue_type) { :issue }
it { is_expected.to eq(true) }
end
context 'empty type' do
let(:issue_type) { nil }
it { is_expected.to eq(false) }
end
end
end
end

View file

@ -47,6 +47,7 @@ RSpec.describe Issues::MoveService do
it 'creates a new issue in a new project' do
expect(new_issue.project).to eq new_project
expect(new_issue.namespace_id).to eq new_project.project_namespace_id
end
it 'copies issue title' do

View file

@ -59,22 +59,6 @@ RSpec.describe Projects::AfterRenameService do
end
end
context 'gitlab pages' do
before do
allow(project_storage).to receive(:rename_repo) { true }
end
context 'when the project does not have pages deployed' do
it 'does nothing with the pages directory' do
allow(project).to receive(:pages_deployed?).and_return(false)
expect(PagesTransferWorker).not_to receive(:perform_async)
service_execute
end
end
end
context 'attachments' do
before do
expect(project_storage).to receive(:rename_repo) { true }

View file

@ -715,20 +715,6 @@ RSpec.describe Projects::TransferService do
end
end
context 'moving pages' do
let_it_be(:project) { create(:project, namespace: user.namespace) }
before do
group.add_owner(user)
end
it 'does not schedule a job when no pages are deployed' do
expect(PagesTransferWorker).not_to receive(:perform_async)
execute_transfer
end
end
context 'handling issue contacts' do
let_it_be(:root_group) { create(:group) }

View file

@ -137,80 +137,4 @@ eos
file_content: content
).execute
end
def commit_options(repo, index, target, ref, message)
options = {}
options[:tree] = index.write_tree(repo)
options[:author] = {
email: "test@example.com",
name: "Test Author",
time: Time.gm(2014, "mar", 3, 20, 15, 1)
}
options[:committer] = {
email: "test@example.com",
name: "Test Author",
time: Time.gm(2014, "mar", 3, 20, 15, 1)
}
options[:message] ||= message
options[:parents] = repo.empty? ? [] : [target].compact
options[:update_ref] = ref
options
end
# Writes a new commit to the repo and returns a Rugged::Commit. Replaces the
# contents of CHANGELOG with a single new line of text.
def new_commit_edit_old_file(repo)
oid = repo.write("I replaced the changelog with this text", :blob)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(path: "CHANGELOG", oid: oid, mode: 0100644)
options = commit_options(
repo,
index,
repo.head.target,
"HEAD",
"Edit CHANGELOG in its original location"
)
sha = Rugged::Commit.create(repo, options)
repo.lookup(sha)
end
# Writes a new commit to the repo and returns a Rugged::Commit. Replaces the
# contents of the specified file_path with new text.
def new_commit_edit_new_file(repo, file_path, commit_message, text, branch = repo.head)
oid = repo.write(text, :blob)
index = repo.index
index.read_tree(branch.target.tree)
index.add(path: file_path, oid: oid, mode: 0100644)
options = commit_options(repo, index, branch.target, branch.canonical_name, commit_message)
sha = Rugged::Commit.create(repo, options)
repo.lookup(sha)
end
# Writes a new commit to the repo and returns a Rugged::Commit. Replaces the
# contents of encoding/CHANGELOG with new text.
def new_commit_edit_new_file_on_branch(repo, file_path, branch_name, commit_message, text)
branch = repo.branches[branch_name]
new_commit_edit_new_file(repo, file_path, commit_message, text, branch)
end
# Writes a new commit to the repo and returns a Rugged::Commit. Moves the
# CHANGELOG file to the encoding/ directory.
def new_commit_move_file(repo)
blob_oid = repo.head.target.tree.detect { |i| i[:name] == "CHANGELOG" }[:oid]
file_content = repo.lookup(blob_oid).content
oid = repo.write(file_content, :blob)
index = repo.index
index.read_tree(repo.head.target.tree)
index.add(path: "encoding/CHANGELOG", oid: oid, mode: 0100644)
index.remove("CHANGELOG")
options = commit_options(repo, index, repo.head.target, "HEAD", "Move CHANGELOG to encoding/")
sha = Rugged::Commit.create(repo, options)
repo.lookup(sha)
end
end

View file

@ -355,14 +355,6 @@ module TestEnv
"#{forked_repo_path}.bundle"
end
def with_empty_bare_repository(name = nil)
path = Rails.root.join('tmp/tests', name || 'empty-bare-repository').to_s
yield(Rugged::Repository.init_at(path, :bare))
ensure
FileUtils.rm_rf(path)
end
def seed_db
Gitlab::DatabaseImporters::WorkItems::BaseTypeImporter.upsert_types
end

View file

@ -1,10 +1,6 @@
# frozen_string_literal: true
require 'fileutils'
RSpec.shared_examples 'can collect git garbage' do |update_statistics: true|
include GitHelpers
let!(:lease_uuid) { SecureRandom.uuid }
let!(:lease_key) { "resource_housekeeping:#{resource.id}" }
let(:params) { [resource.id, task, lease_key, lease_uuid] }
@ -246,39 +242,6 @@ RSpec.shared_examples 'can collect git garbage' do |update_statistics: true|
subject.perform(resource.id, 'prune', lease_key, lease_uuid)
end
# Create a new commit on a random new branch
def create_objects(resource)
rugged = rugged_repo(resource.repository)
old_commit = rugged.branches.first.target
new_commit_sha = Rugged::Commit.create(
rugged,
message: "hello world #{SecureRandom.hex(6)}",
author: { email: 'foo@bar', name: 'baz' },
committer: { email: 'foo@bar', name: 'baz' },
tree: old_commit.tree,
parents: [old_commit]
)
repository.write_ref("refs/heads/#{SecureRandom.hex(6)}", new_commit_sha)
end
def packs(resource)
Dir["#{path_to_repo}/objects/pack/*.pack"]
end
def packed_refs(resource)
path = File.join(path_to_repo, 'packed-refs')
FileUtils.touch(path)
File.read(path)
end
def path_to_repo
@path_to_repo ||= File.join(TestEnv.repos_path, resource.repository.relative_path)
end
def bitmap_path(pack)
pack.sub(/\.pack\z/, '.bitmap')
end
end
context 'with bitmaps enabled' do

View file

@ -365,7 +365,6 @@ RSpec.describe 'Every Sidekiq worker' do
'Packages::Rubygems::ExtractionWorker' => 3,
'PagesDomainSslRenewalWorker' => 3,
'PagesDomainVerificationWorker' => 3,
'PagesTransferWorker' => 3,
'PagesWorker' => 3,
'PersonalAccessTokens::Groups::PolicyWorker' => 3,
'PersonalAccessTokens::Instance::PolicyWorker' => 3,