Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-02-14 18:13:23 +00:00
parent 1123408ec8
commit 4db74ea147
26 changed files with 568 additions and 150 deletions

View file

@ -291,6 +291,12 @@ Gitlab/AvoidUploadedFileFromParams:
- 'spec/**/*'
- 'ee/spec/**/*'
Gitlab/EventStoreSubscriber:
Enabled: true
Exclude:
- 'spec/**/*'
- 'ee/spec/**/*'
GitlabSecurity/PublicSend:
Enabled: true
Exclude:

View file

@ -41,6 +41,16 @@ export default {
required: false,
default: false,
},
inputFieldName: {
type: String,
required: false,
default: 'upload_file',
},
shouldUpdateInputOnFileDrop: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -84,6 +94,30 @@ export default {
return;
}
// NOTE: This is a temporary solution to integrate dropzone into a Rails
// form. On file drop if `shouldUpdateInputOnFileDrop` is true, the file
// input value is updated. So that when the form is submitted the file
// value would be send together with the form data. This solution should
// be removed when License file upload page is fully migrated:
// https://gitlab.com/gitlab-org/gitlab/-/issues/352501
// NOTE: as per https://caniuse.com/mdn-api_htmlinputelement_files, IE11
// is not able to set input.files property, thought the user would still
// be able to use the file picker dialogue option, by clicking the
// "openFileUpload" button
if (this.shouldUpdateInputOnFileDrop) {
// Since FileList cannot be easily manipulated, to match requirement of
// singleFileSelection, we're throwing an error if multiple files were
// dropped on the dropzone
// NOTE: we can drop this logic together with
// `shouldUpdateInputOnFileDrop` flag
if (this.singleFileSelection && files.length > 1) {
this.$emit('error');
return;
}
this.$refs.fileUpload.files = files;
}
this.$emit('change', this.singleFileSelection ? files[0] : files);
},
ondragenter(e) {
@ -116,6 +150,7 @@ export default {
<slot>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
@click="openFileUpload"
>
<div
@ -147,7 +182,7 @@ export default {
<input
ref="fileUpload"
type="file"
name="upload_file"
:name="inputFieldName"
:accept="validFileMimetypes"
class="hide"
:multiple="!singleFileSelection"

View file

@ -15,6 +15,7 @@ class ContainerRepository < ApplicationRecord
MIGRATION_STATES = (IDLE_MIGRATION_STATES + ACTIVE_MIGRATION_STATES).freeze
TooManyImportsError = Class.new(StandardError)
NativeImportError = Class.new(StandardError)
belongs_to :project
@ -85,9 +86,7 @@ class ContainerRepository < ApplicationRecord
end
state :pre_import_done do
validates :migration_pre_import_started_at,
:migration_pre_import_done_at,
presence: true
validates :migration_pre_import_done_at, presence: true
end
state :importing do
@ -113,7 +112,7 @@ class ContainerRepository < ApplicationRecord
end
event :finish_pre_import do
transition pre_importing: :pre_import_done
transition %i[pre_importing import_aborted] => :pre_import_done
end
event :start_import do
@ -121,7 +120,7 @@ class ContainerRepository < ApplicationRecord
end
event :finish_import do
transition importing: :import_done
transition %i[importing import_aborted] => :import_done
end
event :already_migrated do
@ -155,7 +154,7 @@ class ContainerRepository < ApplicationRecord
end
end
before_transition pre_importing: :pre_import_done do |container_repository|
before_transition %i[pre_importing import_aborted] => :pre_import_done do |container_repository|
container_repository.migration_pre_import_done_at = Time.zone.now
end
@ -170,7 +169,7 @@ class ContainerRepository < ApplicationRecord
end
end
before_transition importing: :import_done do |container_repository|
before_transition %i[importing import_aborted] => :import_done do |container_repository|
container_repository.migration_import_done_at = Time.zone.now
end
@ -272,13 +271,29 @@ class ContainerRepository < ApplicationRecord
finish_pre_import && start_import
end
def retry_migration
return if migration_import_done_at
def retry_aborted_migration
return unless migration_state == 'import_aborted'
if migration_pre_import_done_at
import_status = gitlab_api_client.import_status(self.path)
case import_status
when 'native'
raise NativeImportError
when 'import_in_progress'
nil
when 'import_complete'
finish_import
when 'import_failed'
retry_import
else
when 'pre_import_in_progress'
nil
when 'pre_import_complete'
finish_pre_import_and_start_import
when 'pre_import_failed'
retry_pre_import
else
# If the import_status request fails, use the timestamp to guess current state
migration_pre_import_done_at ? retry_import : retry_pre_import
end
end

View file

@ -9,11 +9,10 @@
%a{ href: help_page_path('user/usage_quotas.md'), target: '_blank', rel: 'noopener noreferrer' }
= s_('UsageQuota|Learn more about usage quotas') + '.'
.top-area.scrolling-tabs-container.inner-page-scroll-tabs
%ul.nav.nav-tabs.nav-links.scrolling-tabs.separator.js-usage-quota-tabs{ role: 'tablist' }
%li.nav-item
%a.nav-link#storage-quota{ data: { toggle: "tab", action: '#storage-quota-tab' }, href: '#storage-quota-tab', 'aria-controls': '#storage-quota-tab', 'aria-selected': 'true' }
= s_('UsageQuota|Storage')
= gl_tabs_nav do
= gl_tab_link_to '#storage-quota-tab', item_active: true do
= s_('UsageQuota|Storage')
.tab-content
.tab-pane#storage-quota-tab
.tab-pane.active#storage-quota-tab
#js-project-storage-count-app{ data: { project_path: @project.full_path } }

View file

@ -32,7 +32,7 @@ module ContainerRegistry
private
def handle_aborted_migration
return unless next_aborted_repository&.retry_migration
return unless next_aborted_repository&.retry_aborted_migration
log_extra_metadata_on_done(:container_repository_id, next_aborted_repository.id)
log_extra_metadata_on_done(:import_type, 'retry')

View file

@ -4,77 +4,69 @@ group: Distribution
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
---
# How to self-host the docs site **(FREE SELF)**
# How to host the GitLab product documentation **(FREE SELF)**
If you have a self-managed instance of GitLab, you may not be able to access the
product documentation as hosted on `docs.gitlab.com` from your GitLab instance.
Be aware of the following items if you self-host the product documentation:
- You must host the product documentation site under a subdirectory that matches
your installed GitLab version (for example, `14.5/`). The
[Docker images](https://gitlab.com/gitlab-org/gitlab-docs/container_registry/631635)
hosted by the GitLab Docs team provide this by default. We use a
[script](https://gitlab.com/gitlab-org/gitlab-docs/-/blob/2995d1378175803b22fb8806ba77adf63e79f32c/scripts/normalize-links.sh#L28-82)
to normalize the links and prefix them with the respective version.
- The version dropdown will display additional versions that don't exist, selecting
those versions will display a 404 Not Found page.
- Results when using the search box will display results from `docs.gitlab.com`
and not the local documentation.
- When you use the Docker images to serve the product documentation site, by
default the landing page redirects to the respective version (for example, `/14.5/`),
which causes the landing page <https://docs.gitlab.com> to not be displayed.
If you are not able to access the GitLab product documentation at `docs.gitlab.com`,
you can host the documentation yourself instead.
## Documentation self-hosting options
You can self-host the GitLab product documentation locally using one of these
methods:
To host the GitLab product documentation, you can use:
- Docker
- A Docker container
- GitLab Pages
- From your own webserver
- Your own web server
The examples on this page are based on GitLab 14.5.
After you create a website by using one of these methods, you redirect the UI links
in the product to point to your website.
NOTE:
The website you create must be hosted under a subdirectory that matches
your installed GitLab version (for example, `14.5/`). The
[Docker images](https://gitlab.com/gitlab-org/gitlab-docs/container_registry/631635)
use this version by default.
The following examples use GitLab 14.5.
### Self-host the product documentation with Docker
The Docker images use a built-in webserver listening on port `4000`, so you need
to expose that.
You can run the GitLab product documentation website in a Docker container:
In the server that you host GitLab, or any other server that your GitLab instance
can talk to, you can use Docker to pull the docs site:
1. Expose port `4000`. The Docker image uses this port for the web server.
1. On the server where you host GitLab, or on any other server that your GitLab instance
can communicate with, pull the docs site:
```shell
docker run -it --rm -p 4000:4000 registry.gitlab.com/gitlab-org/gitlab-docs:14.5
```
```shell
docker run -it --rm -p 4000:4000 registry.gitlab.com/gitlab-org/gitlab-docs:14.5
```
If you use [Docker compose](../install/docker.md#install-gitlab-using-docker-compose)
to host your GitLab instance, add the following to `docker-compose.yaml`:
If you host your GitLab instance using [Docker compose](../install/docker.md#install-gitlab-using-docker-compose),
add the following to `docker-compose.yaml`:
```yaml
version: '3.6'
services:
docs:
image: registry.gitlab.com/gitlab-org/gitlab-docs:14.5
hostname: 'https://gitlab.example.com'
ports:
- '4000:4000'
```
```yaml
version: '3.6'
services:
docs:
image: registry.gitlab.com/gitlab-org/gitlab-docs:14.5
hostname: 'https://gitlab.example.com'
ports:
- '4000:4000'
```
### Self-host the product documentation with GitLab Pages
You use GitLab Pages to host the GitLab product documentation locally.
You can use GitLab Pages to host the GitLab product documentation.
Prerequisite:
- The Pages site URL must not use a subfolder. Due to the nature of how the docs
- Ensure the Pages site URL does not use a subfolder. Because of how the docs
site is pre-compiled, the CSS and JavaScript files are relative to the
main domain or subdomain. For example, URLs like `https://example.com/docs/`
are not supported.
To host the product documentation site with GitLab Pages:
1. [Create a new blank project](../user/project/working_with_projects.md#create-a-blank-project).
1. [Create a blank project](../user/project/working_with_projects.md#create-a-blank-project).
1. Create a new or edit your existing `.gitlab-ci.yml` file, and add the following
`pages` job, while ensuring the version is the same as your GitLab installation:
@ -97,13 +89,13 @@ To host the product documentation site with GitLab Pages:
| [Project website](../user/project/pages/getting_started_part_one.md#project-website-examples) | Not supported | Supported |
| [User or group website](../user/project/pages/getting_started_part_one.md#user-and-group-website-examples) | Supported | Supported |
### Self-host the product documentation on your own webserver
### Self-host the product documentation on your own web server
Because the product documentation site is static, you can grab the directory from
the container (in `/usr/share/nginx/html`) and use your own web server to host
it wherever you want.
Because the product documentation site is static, from the container, you can take the contents
of `/usr/share/nginx/html` and use your own web server to host
the docs wherever you want.
Use the following commands, and replace `<destination>` with the directory where the
Run the following commands, replacing `<destination>` with the directory where the
documentation files will be copied to:
```shell
@ -114,18 +106,30 @@ docker rm -f gitlab-docs
## Redirect the `/help` links to the new docs page
After your local product documentation site is running, [redirect the help
links](../user/admin_area/settings/help_page.md#redirect-help-pages) in the GitLab
application to your local site.
After your local product documentation site is running,
[redirect the help links](../user/admin_area/settings/help_page.md#redirect-help-pages)
in the GitLab application to your local site.
Be sure to use the fully qualified domain name as the docs URL. For example, if you
used the [Docker method](#self-host-the-product-documentation-with-docker), enter `http://0.0.0.0:4000`.
You don't need to append the version, as GitLab will detect it and append it to
any documentation URL requests, as needed. For example, if your GitLab version is
14.5, the GitLab Docs URL becomes `http://0.0.0.0:4000/14.5/`. The link
inside GitLab displays as `<instance_url>/help/user/admin_area/settings/help_page#destination-requirements`,
but when you select it, you are redirected to
You don't need to append the version. GitLab detects it and appends it to
documentation URL requests as needed. For example, if your GitLab version is
14.5:
- The GitLab Docs URL becomes `http://0.0.0.0:4000/14.5/`.
- The link in GitLab displays as `<instance_url>/help/user/admin_area/settings/help_page#destination-requirements`.
- When you select the link, you are redirected to
`http://0.0.0.0:4000/14.5/ee/user/admin_area/settings/help_page/#destination-requirements`.
To test the setting, select a **Learn more** link within the GitLab application.
## Known issues
If you self-host the product documentation:
- The version dropdown displays additional versions that don't exist. Selecting
these versions displays a `404 Not Found` page.
- The search displays results from `docs.gitlab.com` and not the local site.
- By default, the landing page redirects to the
respective version (for example, `/14.5/`). This causes the landing page <https://docs.gitlab.com> to not be displayed.

View file

@ -62,8 +62,8 @@ can reserve your catch-all mailbox for other purposes.
### Dedicated email address
This solution is relatively simple to set up: you just need to create an email
address dedicated to receive your users' replies to GitLab notifications. However,
To set up this solution, you must create a dedicated email
address to receive your users' replies to GitLab notifications. However,
this method only supports replies, and not the other features of [incoming email](#incoming-email).
## Accepted headers
@ -75,7 +75,7 @@ Email is processed correctly when a configured email address is present in one o
- `Envelope-To` or `X-Envelope-To`
In GitLab 14.6 and later, [Service Desk](../user/project/service_desk.md)
also checks these additional headers.
also checks accepted headers.
Usually, the "To" field contains the email address of the primary receiver.
However, it might not include the configured GitLab email address if:
@ -84,6 +84,14 @@ However, it might not include the configured GitLab email address if:
- The address was included when using "Reply all".
- The email was forwarded.
## Rejected headers
To prevent unwanted issue creation from automatic email systems, GitLab ignores all incoming email
containing the following headers:
- `Auto-Submitted` with a value other than `no`
- `X-Autoreply` with a value of `yes`
## Set it up
If you want to use Gmail / Google Apps for incoming email, make sure you have

View file

@ -97,6 +97,7 @@ The [Quality Engineering - Enablement team](https://about.gitlab.com/handbook/en
- Network latency on the test environments between components on all Cloud Providers were measured at <5ms. Note that this is shared as an observation and not as an implicit recommendation.
- We aim to have a "test smart" approach where architectures tested have a good range that can also apply to others. Testing focuses on 10k Omnibus on GCP as the testing has shown this is a good bellwether for the other architectures and cloud providers as well as Cloud Native Hybrids.
- Testing is done publicly and all results are shared.
- For more information about performance testing at GitLab, read [how our QA team leverages GitLabs performance testing tool (and you can too)](https://about.gitlab.com/blog/2020/02/18/how-were-building-up-performance-testing-of-gitlab/).
The following table details the testing done against the reference architectures along with the frequency and results. Additional testing is continuously evaluated, and the table is updated accordingly.

View file

@ -15,7 +15,7 @@ Server hooks run custom logic on the GitLab server. Users can use them to run Gi
- Enforcing specific commit policies.
- Performing tasks based on the state of the repository.
Server hooks use `pre-receive`, `post-receive`, and `update`
Server hooks use `pre-receive`, `post-receive`, and `update`
[Git server-side hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks#_server_side_hooks).
GitLab administrators configure server hooks on the file system of the GitLab server. If you don't have file system access,
@ -124,8 +124,8 @@ The following Git environment variables are supported for `pre-receive` and `pos
|:-----------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `GIT_ALTERNATE_OBJECT_DIRECTORIES` | Alternate object directories in the quarantine environment. See [Git `receive-pack` documentation](https://git-scm.com/docs/git-receive-pack#_quarantine_environment). |
| `GIT_OBJECT_DIRECTORY` | GitLab project path in the quarantine environment. See [Git `receive-pack` documentation](https://git-scm.com/docs/git-receive-pack#_quarantine_environment). |
| `GIT_PUSH_OPTION_COUNT` | Number of push options. See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
| `GIT_PUSH_OPTION_<i>` | Value of push options where `i` is from `0` to `GIT_PUSH_OPTION_COUNT - 1`. See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
| `GIT_PUSH_OPTION_COUNT` | Number of [push options](../user/project/push_options.md). See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
| `GIT_PUSH_OPTION_<i>` | Value of [push options](../user/project/push_options.md) where `i` is from `0` to `GIT_PUSH_OPTION_COUNT - 1`. See [Git `pre-receive` documentation](https://git-scm.com/docs/githooks#pre-receive). |
## Custom error messages

View file

@ -683,6 +683,10 @@ Do not use profanity. Doing so may negatively affect other users and contributor
Use lowercase for **push rules**.
## register
Use **register** instead of **sign up** when talking about creating an account.
## Reporter
When writing about the Reporter role:
@ -780,6 +784,10 @@ Use **sign in** instead of **sign on** or **log on** or **log in**. If the user
You can use **single sign-on**.
## sign up
Use **register** instead of **sign up** when talking about creating an account.
## simply, simple
Do not use **simply** or **simple**. If the user doesn't find the process to be simple, we lose their trust. ([Vale](../testing.md#vale) rule: [`Simplicity.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Simplicity.yml))

View file

@ -567,6 +567,7 @@ sudo -u git -H git config --global gc.auto 0
sudo -u git -H git config --global repack.writeBitmaps true
# Enable push options
# Refer to https://docs.gitlab.com/ee/user/project/push_options.html for more information.
sudo -u git -H git config --global receive.advertisePushOptions true
# Enable fsyncObjectFiles to reduce risk of repository corruption if the server crashes
@ -1143,7 +1144,7 @@ You can configure the Prometheus server in `config/gitlab.yml`:
# example
prometheus:
enabled: true
server_address: '10.1.2.3:9090'
server_address: '10.1.2.3:9090'
```
## Troubleshooting

View file

@ -59,8 +59,10 @@ Otherwise, to upload your license:
1. On the left sidebar, select **Settings**.
1. In the **License file** area, select **Upload a license**.
1. Upload a license:
- For a file, select **Upload `.gitlab-license` file**, **Choose file**, and
select the license file from your local machine.
- For a file, either:
- Select **Upload `.gitlab-license` file**, then **Choose File** and
select the license file from your local machine.
- Drag and drop the license file to the **Drag your license file here** area.
- For plain text, select **Enter license key** and paste the contents in
**License key**.
1. Select the **Terms of Service** checkbox.

View file

@ -137,3 +137,4 @@ For a web developer writing a webpage for your company's website:
- [Suggest code changes](reviews/suggestions.md)
- [Commits](commits.md)
- [CI/CD pipelines](../../../ci/index.md)
- [Push options](../push_options.md) for merge requests

View file

@ -57,8 +57,8 @@ GitLab administrators can configure a new default branch name at the
### Instance-level custom initial branch name **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221013) in GitLab 13.2.
> - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/325163) in GitLab 13.12.
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/221013) in GitLab 13.2 [with a flag](../../../../administration/feature_flags.md) named `global_default_branch_name`. Enabled by default.
> - [Generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/325163) in GitLab 13.12. Feature flag `global_default_branch_name` removed.
GitLab [administrators](../../../permissions.md) of self-managed instances can
customize the initial branch for projects hosted on that instance. Individual

View file

@ -33,7 +33,7 @@ To fork an existing project in GitLab:
![Choose namespace](img/forking_workflow_choose_namespace_v13_10.png)
- Experimental method. If your GitLab administrator has
[enabled the experimental fork project form](#enable-or-disable-the-fork-project-form), read
enabled the experimental fork project form, read
[Create a fork with the fork project form](#create-a-fork-with-the-fork-project-form).
Only namespaces where you have at least the Developer role for are shown.
@ -84,14 +84,14 @@ You can unlink your fork from its upstream project in the [advanced settings](..
## Create a fork with the fork project form **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15013) in GitLab 13.11.
> - It's [deployed behind a feature flag](../../../user/feature_flags.md), disabled by default.
> - It's disabled on GitLab.com.
> - It's not recommended for production use.
> - To use it in GitLab self-managed instances, ask a GitLab administrator to [enable it](#enable-or-disable-the-fork-project-form). **(FREE SELF)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/15013) in GitLab 13.11 [with a flag](../../../administration/feature_flags.md) named `fork_project_form`. Disabled by default.
> - [Enabled on self-managed and GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64967) in GitLab 13.8.
This experimental version of the fork project form is available only if your GitLab
administrator has [enabled it](#enable-or-disable-the-fork-project-form):
FLAG:
On self-managed GitLab, by default this feature is available. To hide the feature, ask an administrator to [disable the feature flag](../../../administration/feature_flags.md) named `fork_project_form`.
On GitLab.com, this feature is available.
This version of the fork project form is experimental:
![Choose namespace](img/fork_form_v13_10.png)
@ -102,23 +102,3 @@ To use it, follow the instructions at [Creating a fork](#creating-a-fork) and pr
- The project slug.
- Optional. The project description.
- The visibility level for your fork.
### Enable or disable the fork project form **(FREE SELF)**
The new [fork project form](#create-a-fork-with-the-fork-project-form) is under
development and not ready for production use. It is deployed behind a feature flag
that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can enable it.
To enable it:
```ruby
Feature.enable(:fork_project_form)
```
To disable it:
```ruby
Feature.disable(:fork_project_form)
```

View file

@ -333,3 +333,10 @@ Note that:
Behind the scenes, Service Desk works by the special Support Bot user creating issues. This user
does not count toward the license limit count.
## Troubleshooting Service Desk
### Emails to Service Desk do not create issues
Your emails might be ignored because they contain one of the
[email headers that GitLab ignores](../../administration/incoming_email.md#rejected-headers).

View file

@ -45,6 +45,11 @@ module ContainerRegistry
IMPORT_RESPONSES.fetch(response.status, :error)
end
def import_status(path)
body_hash = response_body(faraday.get(import_url_for(path)))
body_hash['status'] || 'error'
end
private
def start_import_for(path, pre:)

View file

@ -21660,9 +21660,18 @@ msgstr ""
msgid "Licenses|Displays licenses detected in the project, based on the %{linkStart}latest successful%{linkEnd} scan"
msgstr ""
msgid "Licenses|Drag your license file here or %{linkStart}click to upload%{linkEnd}."
msgstr ""
msgid "Licenses|Drop your license file to start the upload."
msgstr ""
msgid "Licenses|Error fetching the license list. Please check your network connection and try again."
msgstr ""
msgid "Licenses|Error: You are trying to upload something other than a file"
msgstr ""
msgid "Licenses|License Compliance"
msgstr ""
@ -21681,6 +21690,9 @@ msgstr ""
msgid "Licenses|Specified policies in this project"
msgstr ""
msgid "Licenses|The file could not be uploaded."
msgstr ""
msgid "Licenses|The license list details information about the licenses used within your project."
msgstr ""
@ -40731,6 +40743,9 @@ msgstr ""
msgid "Webhooks|An issue is created, updated, closed, or reopened."
msgstr ""
msgid "Webhooks|Are you sure you want to delete this group hook?"
msgstr ""
msgid "Webhooks|Are you sure you want to delete this project hook?"
msgstr ""

View file

@ -0,0 +1,71 @@
# frozen_string_literal: true
module RuboCop
module Cop
module Gitlab
# Cop that checks the implementation of Gitlab::EventStore::Subscriber
#
# A worker that implements Gitlab::EventStore::Subscriber
# must implement the method #handle_event(event) and
# must not override the method #perform(*args)
#
# # bad
# class MySubscriber
# include Gitlab::EventStore::Subscriber
#
# def perform(*args)
# end
# end
#
# # bad
# class MySubscriber
# include Gitlab::EventStore::Subscriber
# end
#
# # good
# class MySubscriber
# include Gitlab::EventStore::Subscriber
#
# def handle_event(event)
# end
# end
#
class EventStoreSubscriber < RuboCop::Cop::Cop
SUBSCRIBER_MODULE_NAME = 'Gitlab::EventStore::Subscriber'
FORBID_PERFORM_OVERRIDE = "Do not override `perform` in a `#{SUBSCRIBER_MODULE_NAME}`."
REQUIRE_HANDLE_EVENT = "A `#{SUBSCRIBER_MODULE_NAME}` must implement `#handle_event(event)`."
def_node_matcher :includes_subscriber?, <<~PATTERN
(send nil? :include (const (const (const nil? :Gitlab) :EventStore) :Subscriber))
PATTERN
def on_send(node)
return unless includes_subscriber?(node)
self.is_subscriber ||= true
self.include_subscriber_node ||= node
end
def on_def(node)
if is_subscriber && node.method_name == :perform
add_offense(node, message: FORBID_PERFORM_OVERRIDE)
end
self.implements_handle_event ||= true if node.method_name == :handle_event
end
def on_investigation_end
super
if is_subscriber && !implements_handle_event
add_offense(include_subscriber_node, message: REQUIRE_HANDLE_EVENT)
end
end
private
attr_accessor :is_subscriber, :include_subscriber_node, :implements_handle_event
end
end
end
end

View file

@ -6,6 +6,7 @@ exports[`Upload dropzone component correctly overrides description and drop mess
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -86,6 +87,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -170,6 +172,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -254,6 +257,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -339,6 +343,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -424,6 +429,7 @@ exports[`Upload dropzone component when dragging renders correct template when d
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"
@ -509,6 +515,7 @@ exports[`Upload dropzone component when no slot provided renders default dropzon
>
<button
class="card upload-dropzone-card upload-dropzone-border gl-w-full gl-h-full gl-align-items-center gl-justify-content-center gl-p-3"
type="button"
>
<div
class="gl-display-flex gl-align-items-center gl-justify-content-center gl-text-center gl-flex-direction-column"

View file

@ -16,6 +16,7 @@ describe('Upload dropzone component', () => {
const findDropzoneArea = () => wrapper.find('[data-testid="dropzone-area"]');
const findIcon = () => wrapper.find(GlIcon);
const findUploadText = () => wrapper.find('[data-testid="upload-text"]').text();
const findFileInput = () => wrapper.find('input[type="file"]');
function createComponent({ slots = {}, data = {}, props = {} } = {}) {
wrapper = shallowMount(UploadDropzone, {
@ -197,4 +198,60 @@ describe('Upload dropzone component', () => {
expect(wrapper.element).toMatchSnapshot();
});
describe('file input form name', () => {
it('applies inputFieldName as file input name', () => {
createComponent({ props: { inputFieldName: 'test_field_name' } });
expect(findFileInput().attributes('name')).toBe('test_field_name');
});
it('uses default file input name if no inputFieldName provided', () => {
createComponent();
expect(findFileInput().attributes('name')).toBe('upload_file');
});
});
describe('updates file input files value', () => {
// NOTE: the component assigns dropped files from the drop event to the
// input.files property. There's a restriction that nothing but a FileList
// can be assigned to this property. While FileList can't be created
// manually: it has no constructor. And currently there's no good workaround
// for jsdom. So we have to stub the file input in vm.$refs to ensure that
// the files property is updated. This enforces following tests to know a
// bit too much about the SUT internals See this thread for more details on
// FileList in jsdom: https://github.com/jsdom/jsdom/issues/1272
function stubFileInputOnWrapper() {
const fakeFileInput = { files: [] };
wrapper.vm.$refs.fileUpload = fakeFileInput;
}
it('assigns dragged files to the input files property', async () => {
const mockFile = { name: 'test', type: 'image/jpg' };
const mockEvent = mockDragEvent({ files: [mockFile] });
createComponent({ props: { shouldUpdateInputOnFileDrop: true } });
stubFileInputOnWrapper();
wrapper.trigger('dragenter', mockEvent);
await nextTick();
wrapper.trigger('drop', mockEvent);
await nextTick();
expect(wrapper.vm.$refs.fileUpload.files).toEqual([mockFile]);
});
it('throws an error when multiple files are dropped on a single file input dropzone', async () => {
const mockFile = { name: 'test', type: 'image/jpg' };
const mockEvent = mockDragEvent({ files: [mockFile, mockFile] });
createComponent({ props: { shouldUpdateInputOnFileDrop: true, singleFileSelection: true } });
stubFileInputOnWrapper();
wrapper.trigger('dragenter', mockEvent);
await nextTick();
wrapper.trigger('drop', mockEvent);
await nextTick();
expect(wrapper.vm.$refs.fileUpload.files).toEqual([]);
expect(wrapper.emitted('error')).toHaveLength(1);
});
});
});

View file

@ -77,7 +77,7 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
end
end
describe '#pre_import_repository' do
describe '#import_repository' do
subject { client.import_repository(path) }
where(:status_code, :expected_result) do
@ -101,6 +101,26 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
end
end
describe '#import_status' do
subject { client.import_status(path) }
before do
stub_import_status(path, status)
end
context 'with a status' do
let(:status) { 'this_is_a_test' }
it { is_expected.to eq(status) }
end
context 'with no status' do
let(:status) { nil }
it { is_expected.to eq('error') }
end
end
describe '.supports_gitlab_api?' do
subject { described_class.supports_gitlab_api? }
@ -171,4 +191,14 @@ RSpec.describe ContainerRegistry::GitlabApiClient do
.with(headers: { 'Accept' => described_class::JSON_TYPE })
.to_return(status: status_code, body: '')
end
def stub_import_status(path, status)
stub_request(:get, "#{registry_api_url}/gitlab/v1/import/#{path}/")
.with(headers: { 'Accept' => described_class::JSON_TYPE })
.to_return(
status: 200,
body: { status: status }.to_json,
headers: { content_type: 'application/json' }
)
end
end

View file

@ -218,7 +218,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { repository.finish_pre_import }
it_behaves_like 'transitioning from allowed states', %w[pre_importing]
it_behaves_like 'transitioning from allowed states', %w[pre_importing import_aborted]
it 'sets migration_pre_import_done_at' do
expect { subject }.to change { repository.reload.migration_pre_import_done_at }
@ -263,7 +263,7 @@ RSpec.describe ContainerRepository, :aggregate_failures do
subject { repository.finish_import }
it_behaves_like 'transitioning from allowed states', %w[importing]
it_behaves_like 'transitioning from allowed states', %w[importing import_aborted]
it_behaves_like 'queueing the next import'
it 'sets migration_import_done_at and queues the next import' do
@ -334,46 +334,120 @@ RSpec.describe ContainerRepository, :aggregate_failures do
end
end
it_behaves_like 'transitioning from allowed states', %w[pre_importing]
it_behaves_like 'transitioning from allowed states', %w[pre_importing import_aborted]
it_behaves_like 'transitioning to importing'
end
end
describe '#retry_migration' do
subject { repository.retry_migration }
describe '#retry_aborted_migration' do
subject { repository.retry_aborted_migration }
it 'retries the pre_import' do
expect(repository).to receive(:retry_pre_import).and_return(true)
expect(repository).not_to receive(:retry_import)
expect(subject).to eq(true)
end
context 'when migration is done pre-importing' do
before do
repository.update_columns(migration_pre_import_done_at: Time.zone.now)
end
it 'returns' do
expect(repository).to receive(:retry_import).and_return(true)
expect(repository).not_to receive(:retry_pre_import)
expect(subject).to eq(true)
end
end
context 'when migration is already complete' do
before do
repository.update_columns(migration_import_done_at: Time.zone.now)
end
it 'returns' do
expect(repository).not_to receive(:retry_pre_import)
expect(repository).not_to receive(:retry_import)
shared_examples 'no action' do
it 'does nothing' do
expect { subject }.not_to change { repository.reload.migration_state }
expect(subject).to eq(nil)
end
end
shared_examples 'retrying the pre_import' do
it 'retries the pre_import' do
expect(repository).to receive(:migration_pre_import).and_return(:ok)
expect { subject }.to change { repository.reload.migration_state }.to('pre_importing')
end
end
shared_examples 'retrying the import' do
it 'retries the import' do
expect(repository).to receive(:migration_import).and_return(:ok)
expect { subject }.to change { repository.reload.migration_state }.to('importing')
end
end
context 'when migration_state is not aborted' do
it_behaves_like 'no action'
end
context 'when migration_state is aborted' do
before do
repository.abort_import
allow(repository.gitlab_api_client)
.to receive(:import_status).with(repository.path).and_return(client_response)
end
context 'native response' do
let(:client_response) { 'native' }
it 'raises an error' do
expect { subject }.to raise_error(described_class::NativeImportError)
end
end
context 'import_in_progress response' do
let(:client_response) { 'import_in_progress' }
it_behaves_like 'no action'
end
context 'import_complete response' do
let(:client_response) { 'import_complete' }
it 'finishes the import' do
expect { subject }.to change { repository.reload.migration_state }.to('import_done')
end
end
context 'import_failed response' do
let(:client_response) { 'import_failed' }
it_behaves_like 'retrying the import'
end
context 'pre_import_in_progress response' do
let(:client_response) { 'pre_import_in_progress' }
it_behaves_like 'no action'
end
context 'pre_import_complete response' do
let(:client_response) { 'pre_import_complete' }
it 'finishes the pre_import and starts the import' do
expect(repository).to receive(:finish_pre_import).and_call_original
expect(repository).to receive(:migration_import).and_return(:ok)
expect { subject }.to change { repository.reload.migration_state }.to('importing')
end
end
context 'pre_import_failed response' do
let(:client_response) { 'pre_import_failed' }
it_behaves_like 'retrying the pre_import'
end
context 'error response' do
let(:client_response) { 'error' }
context 'migration_pre_import_done_at is NULL' do
it_behaves_like 'retrying the pre_import'
end
context 'migration_pre_import_done_at is not NULL' do
before do
repository.update_columns(
migration_pre_import_started_at: 5.minutes.ago,
migration_pre_import_done_at: Time.zone.now
)
end
it_behaves_like 'retrying the import'
end
end
end
end
describe '#tag' do

View file

@ -0,0 +1,82 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require_relative '../../../../rubocop/cop/gitlab/event_store_subscriber'
RSpec.describe RuboCop::Cop::Gitlab::EventStoreSubscriber do
subject(:cop) { described_class.new }
context 'when an event store subscriber overrides #perform' do
it 'registers an offense' do
expect_offense(<<~WORKER)
class SomeWorker
include Gitlab::EventStore::Subscriber
def perform(*args)
^^^^^^^^^^^^^^^^^^ Do not override `perform` in a `Gitlab::EventStore::Subscriber`.
end
def handle_event(event); end
end
WORKER
end
end
context 'when an event store subscriber does not override #perform' do
it 'does not register an offense' do
expect_no_offenses(<<~WORKER)
class SomeWorker
include Gitlab::EventStore::Subscriber
def handle_event(event); end
end
WORKER
end
end
context 'when an event store subscriber does not implement #handle_event' do
it 'registers an offense' do
expect_offense(<<~WORKER)
class SomeWorker
include Gitlab::EventStore::Subscriber
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ A `Gitlab::EventStore::Subscriber` must implement `#handle_event(event)`.
end
WORKER
end
end
context 'when a Sidekiq worker overrides #perform' do
it 'does not register an offense' do
expect_no_offenses(<<~WORKER)
class SomeWorker
include ApplicationWorker
def perform(*args); end
end
WORKER
end
end
context 'when a Sidekiq worker implements #handle_event' do
it 'does not register an offense' do
expect_no_offenses(<<~WORKER)
class SomeWorker
include ApplicationWorker
def handle_event(event); end
end
WORKER
end
end
context 'a non worker class' do
it 'does not register an offense' do
expect_no_offenses(<<~MODEL)
class Model < ApplicationRecord
include ActiveSupport::Concern
end
MODEL
end
end
end

View file

@ -0,0 +1,9 @@
# frozen_string_literal: true
RSpec.configure do |config|
config.after do |example|
[::ApplicationRecord, ::Ci::ApplicationRecord].each do |base_class|
base_class.gitlab_transactions_stack.clear if base_class.respond_to?(:gitlab_transactions_stack)
end
end
end

View file

@ -113,6 +113,7 @@ RSpec.describe ContainerRegistry::Migration::EnqueuerWorker, :aggregate_failures
allow(worker).to receive(:next_aborted_repository) do
next_aborted_repository = method.call
allow(next_aborted_repository).to receive(:migration_import).and_return(:ok)
allow(next_aborted_repository.gitlab_api_client).to receive(:import_status).and_return('import_failed')
next_aborted_repository
end