Commit 1ea1db49 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent 22e9af3c
...@@ -83,6 +83,7 @@ package-lock.json ...@@ -83,6 +83,7 @@ package-lock.json
jsdoc/ jsdoc/
**/tmp/rubocop_cache/** **/tmp/rubocop_cache/**
.overcommit.yml .overcommit.yml
.overcommit.yml.backup
.projections.json .projections.json
/qa/.rakeTasks /qa/.rakeTasks
webpack-dev-server.json webpack-dev-server.json
......
...@@ -15,6 +15,13 @@ ...@@ -15,6 +15,13 @@
# #
# Uncomment the following lines to make the configuration take effect. # Uncomment the following lines to make the configuration take effect.
# Make sure to run `cd tooling/overcommit && make && cd -`
gemfile: 'tooling/overcommit/gems.rb'
PostCheckout:
BundleInstall:
enabled: true
PreCommit: PreCommit:
AuthorName: AuthorName:
enabled: false enabled: false
...@@ -35,6 +42,19 @@ PreCommit: ...@@ -35,6 +42,19 @@ PreCommit:
# on_warn: fail # Treat all warnings as failures # on_warn: fail # Treat all warnings as failures
ScssLint: ScssLint:
enabled: true enabled: true
CommitMsg:
TextWidth:
enabled: true
min_subject_width: 8 # three 2-letter words with 2 spaces
max_subject_width: 72
quiet: false
EmptyMessage:
enabled: true
required: true
description: 'Checking for empty commit message'
#PostCheckout: #PostCheckout:
# ALL: # Special hook name that customizes all hooks of this type # ALL: # Special hook name that customizes all hooks of this type
# quiet: true # Change all post-checkout hooks to only display output on failure # quiet: true # Change all post-checkout hooks to only display output on failure
......
...@@ -347,6 +347,8 @@ RSpec/HaveGitlabHttpStatus: ...@@ -347,6 +347,8 @@ RSpec/HaveGitlabHttpStatus:
- 'ee/spec/features/**/*' - 'ee/spec/features/**/*'
- 'spec/controllers/*.rb' - 'spec/controllers/*.rb'
- 'ee/spec/controllers/*.rb' - 'ee/spec/controllers/*.rb'
- 'spec/requests/*.rb'
- 'ee/spec/requests/*.rb'
Style/MultilineWhenThen: Style/MultilineWhenThen:
Enabled: false Enabled: false
......
...@@ -21,7 +21,7 @@ module PrometheusAdapter ...@@ -21,7 +21,7 @@ module PrometheusAdapter
raise NotImplemented raise NotImplemented
end end
# This is a heavy-weight check if a prometheus is properly configured and accesible from GitLab. # This is a heavy-weight check if a prometheus is properly configured and accessible from GitLab.
# This actually sends a request to an external service and often it could take a long time, # This actually sends a request to an external service and often it could take a long time,
# Please consider using `configured?` instead if the process is running on unicorn/puma threads. # Please consider using `configured?` instead if the process is running on unicorn/puma threads.
def can_query? def can_query?
......
...@@ -2207,7 +2207,7 @@ class Project < ApplicationRecord ...@@ -2207,7 +2207,7 @@ class Project < ApplicationRecord
end end
def reference_counter(type: Gitlab::GlRepository::PROJECT) def reference_counter(type: Gitlab::GlRepository::PROJECT)
Gitlab::ReferenceCounter.new(type.identifier_for_repositorable(self)) Gitlab::ReferenceCounter.new(type.identifier_for_container(self))
end end
def badges def badges
......
...@@ -65,7 +65,7 @@ class ProjectWiki ...@@ -65,7 +65,7 @@ class ProjectWiki
# Returns the Gitlab::Git::Wiki object. # Returns the Gitlab::Git::Wiki object.
def wiki def wiki
@wiki ||= begin @wiki ||= begin
gl_repository = Gitlab::GlRepository::WIKI.identifier_for_repositorable(project) gl_repository = Gitlab::GlRepository::WIKI.identifier_for_container(project)
raw_repository = Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', gl_repository, full_path) raw_repository = Gitlab::Git::Repository.new(project.repository_storage, disk_path + '.git', gl_repository, full_path)
create_repo!(raw_repository) unless raw_repository.exists? create_repo!(raw_repository) unless raw_repository.exists?
......
...@@ -1183,7 +1183,7 @@ class Repository ...@@ -1183,7 +1183,7 @@ class Repository
def initialize_raw_repository def initialize_raw_repository
Gitlab::Git::Repository.new(project.repository_storage, Gitlab::Git::Repository.new(project.repository_storage,
disk_path + '.git', disk_path + '.git',
repo_type.identifier_for_repositorable(project), repo_type.identifier_for_container(project),
project.full_path) project.full_path)
end end
end end
......
---
title: Filter merge requests by approvals (API)
merge_request: 21379
author:
type: added
---
title: Add separate classes for user related entities for email, membership, status
merge_request: 23748
author: Rajendra Kadam
type: added
...@@ -173,9 +173,11 @@ praefect['virtual_storages'] = { ...@@ -173,9 +173,11 @@ praefect['virtual_storages'] = {
} }
} }
# Replace POSTGRESQL_SERVER below with a real IP/host address of the database.
praefect['database_host'] = 'POSTGRESQL_SERVER' praefect['database_host'] = 'POSTGRESQL_SERVER'
praefect['database_port'] = 5432 praefect['database_port'] = 5432
praefect['database_user'] = 'praefect' praefect['database_user'] = 'praefect'
# Replace PRAEFECT_SQL_PASSWORD below with a real password of the database.
praefect['database_password'] = 'PRAEFECT_SQL_PASSWORD' praefect['database_password'] = 'PRAEFECT_SQL_PASSWORD'
praefect['database_dbname'] = 'praefect_production' praefect['database_dbname'] = 'praefect_production'
......
...@@ -38,7 +38,7 @@ GET /merge_requests?search=foo&in=title ...@@ -38,7 +38,7 @@ GET /merge_requests?search=foo&in=title
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------------- | -------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | | ------------------------------- | -------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` | | `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
| `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `order_by` | string | no | Return requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
| `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` | | `sort` | string | no | Return requests sorted in `asc` or `desc` order. Default is `desc` |
...@@ -54,6 +54,7 @@ Parameters: ...@@ -54,6 +54,7 @@ Parameters:
| `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me` | | `author_id` | integer | no | Returns merge requests created by the given user `id`. Combine with `scope=all` or `scope=assigned_to_me` |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. | | `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. | | `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ | | `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch | | `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch | | `target_branch` | string | no | Return merge requests with the given target branch |
...@@ -211,7 +212,7 @@ will be the same. In the case of a merge request from a fork, ...@@ -211,7 +212,7 @@ will be the same. In the case of a merge request from a fork,
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ | | ------------------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id` | integer | yes | The ID of a project | | `id` | integer | yes | The ID of a project |
| `iids[]` | integer array | no | Return the request having the given `iid` | | `iids[]` | integer array | no | Return the request having the given `iid` |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` | | `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
...@@ -229,6 +230,7 @@ Parameters: ...@@ -229,6 +230,7 @@ Parameters:
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ | | `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ | | `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. | | `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ | | `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch | | `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch | | `target_branch` | string | no | Return merge requests with the given target branch |
...@@ -373,7 +375,7 @@ GET /groups/:id/merge_requests?my_reaction_emoji=star ...@@ -373,7 +375,7 @@ GET /groups/:id/merge_requests?my_reaction_emoji=star
Parameters: Parameters:
| Attribute | Type | Required | Description | | Attribute | Type | Required | Description |
| ------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ | | ------------------------------- | -------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `id` | integer | yes | The ID of a group | | `id` | integer | yes | The ID of a group |
| `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` | | `state` | string | no | Return all merge requests or just those that are `opened`, `closed`, `locked`, or `merged` |
| `order_by` | string | no | Return merge requests ordered by `created_at` or `updated_at` fields. Default is `created_at` | | `order_by` | string | no | Return merge requests ordered by `created_at` or `updated_at` fields. Default is `created_at` |
...@@ -390,6 +392,7 @@ Parameters: ...@@ -390,6 +392,7 @@ Parameters:
| `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ | | `author_id` | integer | no | Returns merge requests created by the given user `id` _([Introduced][ce-13060] in GitLab 9.5)_ |
| `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ | | `assignee_id` | integer | no | Returns merge requests assigned to the given user `id`. `None` returns unassigned merge requests. `Any` returns merge requests with an assignee. _([Introduced][ce-13060] in GitLab 9.5)_ |
| `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. | | `approver_ids` **(STARTER)** | integer array | no | Returns merge requests which have specified all the users with the given `id`s as individual approvers. `None` returns merge requests without approvers. `Any` returns merge requests with an approver. |
| `approved_by_ids` **(STARTER)** | integer array | no | Returns merge requests which have been approved by all the users with the given `id`s (Max: 5). `None` returns merge requests with no approvals. `Any` returns merge requests with an approval. |
| `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ | | `my_reaction_emoji` | string | no | Return merge requests reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced][ce-14016] in GitLab 10.0)_ |
| `source_branch` | string | no | Return merge requests with the given source branch | | `source_branch` | string | no | Return merge requests with the given source branch |
| `target_branch` | string | no | Return merge requests with the given target branch | | `target_branch` | string | no | Return merge requests with the given target branch |
......
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
This is also the style used by linting tools such as This is also the style used by linting tools such as
[RuboCop](https://github.com/rubocop-hq/rubocop) and [Hound CI](https://houndci.com). [RuboCop](https://github.com/rubocop-hq/rubocop) and [Hound CI](https://houndci.com).
You can run RuboCop by hand or install a tool like [Overcommit](https://github.com/sds/overcommit) to run it for you. You can run RuboCop by hand or install a tool like [Overcommit](https://github.com/sds/overcommit) to run it for you.
Overcommit will automatically run the configured checks (like Rubocop) on every modified file before commit. You can use the example overcommit configuration found in `.overcommit.yml.example` as a quickstart.
Overcommit will automatically run the configured checks (like Rubocop) on every modified file before commit.
You can use the example overcommit configuration found in `.overcommit.yml.example` as a quickstart.
This saves you time as you don't have to wait for the same errors to be detected by the CI. This saves you time as you don't have to wait for the same errors to be detected by the CI.
--- ---
......
...@@ -94,6 +94,19 @@ project. ...@@ -94,6 +94,19 @@ project.
![Releases list](img/releases.png) ![Releases list](img/releases.png)
### Number of Releases
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/36667) in GitLab 12.8.
The incremental number of Releases is displayed on the project's details page. When clicked,
it takes you to the list of Releases.
![Number of Releases](img/releases_count_v12_8.png "Incremental counter of Releases")
For private projects, the number of Releases is displayed to users with Reporter
[permissions](../../permissions.md#releases-permissions) or higher. For public projects,
it is displayed to every user regardless of their permission level.
## Editing a release ## Editing a release
> [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/26016) in GitLab 12.6. > [Introduced](https://gitlab.com/gitlab-org/gitlab/issues/26016) in GitLab 12.6.
......
...@@ -60,4 +60,8 @@ changes will be added to the repository and branch you're merging into. ...@@ -60,4 +60,8 @@ changes will be added to the repository and branch you're merging into.
![New merge request](img/forking_workflow_merge_request.png) ![New merge request](img/forking_workflow_merge_request.png)
## Removing a fork relationship
You can unlink your fork from its upstream project in the [advanced settings](../settings/index.md#removing-a-fork-relationship).
[gitlab flow]: https://about.gitlab.com/blog/2014/09/29/gitlab-flow/ "GitLab Flow blog post" [gitlab flow]: https://about.gitlab.com/blog/2014/09/29/gitlab-flow/ "GitLab Flow blog post"
...@@ -97,7 +97,8 @@ In case your development workflow dictates to have an issue for every merge ...@@ -97,7 +97,8 @@ In case your development workflow dictates to have an issue for every merge
request, you can quickly create a branch right on the issue page which will be request, you can quickly create a branch right on the issue page which will be
tied with the issue itself. You can see a **Create merge request** dropdown tied with the issue itself. You can see a **Create merge request** dropdown
below the issue description unless there is already a branch with the same below the issue description unless there is already a branch with the same
name or a referenced merge request. name or a referenced merge request or your project (still) has an active
[fork relationship](../settings/index.md#advanced-settings).
![Create Button](img/web_editor_new_branch_from_issue_create_button_v12_6.png) ![Create Button](img/web_editor_new_branch_from_issue_create_button_v12_6.png)
......
# Project settings # Project settings
NOTE: **Note:** NOTE: **Note:**
Only project Maintainers and Admin users have the [permissions] to access a project Only project Maintainers and Admin users have the [permissions](../../permissions.md#project-members-permissions)
settings. to access a project settings.
You can adjust your [project](../index.md) settings by navigating You can adjust your [project](../index.md) settings by navigating
to your project's homepage and clicking **Settings**. to your project's homepage and clicking **Settings**.
...@@ -106,12 +106,13 @@ Learn how to [export a project](import_export.md#importing-the-project) in GitLa ...@@ -106,12 +106,13 @@ Learn how to [export a project](import_export.md#importing-the-project) in GitLa
### Advanced settings ### Advanced settings
Here you can run housekeeping, archive, rename, transfer, or remove a project. Here you can run housekeeping, archive, rename, transfer, [remove a fork relationship](#removing-a-fork-relationship), or remove a project.
#### Archiving a project #### Archiving a project
NOTE: **Note:** NOTE: **Note:**
Only project Owners and Admin users have the [permissions] to archive a project. Only project Owners and Admin users have the [permissions](../../permissions.md#project-members-permissions)
to archive a project.
Archiving a project makes it read-only for all users and indicates that it is Archiving a project makes it read-only for all users and indicates that it is
no longer actively maintained. Projects that have been archived can also be no longer actively maintained. Projects that have been archived can also be
...@@ -130,7 +131,7 @@ To archive a project: ...@@ -130,7 +131,7 @@ To archive a project:
#### Renaming a repository #### Renaming a repository
NOTE: **Note:** NOTE: **Note:**
Only project Maintainers and Admin users have the [permissions] to rename a Only project Maintainers and Admin users have the [permissions](../../permissions.md#project-members-permissions) to rename a
repository. Not to be confused with a project's name where it can also be repository. Not to be confused with a project's name where it can also be
changed from the [general project settings](#general-project-settings). changed from the [general project settings](#general-project-settings).
...@@ -150,11 +151,12 @@ old URL will not be able to push or pull. Read more about what happens with the ...@@ -150,11 +151,12 @@ old URL will not be able to push or pull. Read more about what happens with the
#### Transferring an existing project into another namespace #### Transferring an existing project into another namespace
NOTE: **Note:** NOTE: **Note:**
Only project Owners and Admin users have the [permissions] to transfer a project. Only project Owners and Admin users have the [permissions](../../permissions.md#project-members-permissions)
to transfer a project.
You can transfer an existing project into a [group](../../group/index.md) if: You can transfer an existing project into a [group](../../group/index.md) if:
1. You have at least **Maintainer** [permissions] to that group. 1. You have at least **Maintainer** [permissions](../../permissions.md#project-members-permissions) to that group.
1. The project is in a subgroup you own. 1. The project is in a subgroup you own.
1. You are at least a **Maintainer** of the project under your personal namespace. 1. You are at least a **Maintainer** of the project under your personal namespace.
Similarly, if you are an owner of a group, you can transfer any of its projects Similarly, if you are an owner of a group, you can transfer any of its projects
...@@ -175,8 +177,6 @@ NOTE: **Note:** ...@@ -175,8 +177,6 @@ NOTE: **Note:**
GitLab administrators can use the admin interface to move any project to any GitLab administrators can use the admin interface to move any project to any
namespace if needed. namespace if needed.
[permissions]: ../../permissions.md#project-members-permissions
#### Remove a project #### Remove a project
NOTE: **Note:** NOTE: **Note:**
...@@ -202,6 +202,24 @@ To restore a project that is marked for deletion: ...@@ -202,6 +202,24 @@ To restore a project that is marked for deletion:
1. Navigate to your project, and select **{settings}** **Settings > General > Advanced**. 1. Navigate to your project, and select **{settings}** **Settings > General > Advanced**.
1. In the Restore project section, click the **Restore project** button. 1. In the Restore project section, click the **Restore project** button.
#### Removing a fork relationship
Forking is a great way to [contribute to a project](../repository/forking_workflow.md)
of which you are not a member.
If you want to use the fork for yourself and do not need to send
[merge requests](../merge_requests.md) to the upstream project,
you can safely remove the fork relationship.
To do so:
1. Navigate to your project's **Settings > General > Advanced**.
1. Under **Remove fork relationship**, click the likewise-labeled button.
1. Confirm the action by typing the project's path as instructed.
NOTE: **Note:**
Only project maintainers have the [permissions](../../permissions.md#project-members-permissions)
to remove a fork relationship.
## Operations settings ## Operations settings
### Error Tracking ### Error Tracking
......
...@@ -2,31 +2,6 @@ ...@@ -2,31 +2,6 @@
module API module API
module Entities module Entities
class Membership < Grape::Entity
expose :source_id
expose :source_name do |member|
member.source.name
end
expose :source_type
expose :access_level
end
class Identity < Grape::Entity
expose :provider, :extern_uid
end
class UserStatus < Grape::Entity
expose :emoji
expose :message
expose :message_html do |entity|
MarkupHelper.markdown_field(entity, :message)
end
end
class Email < Grape::Entity
expose :id, :email
end
class Hook < Grape::Entity class Hook < Grape::Entity
expose :id, :url, :created_at, :push_events, :tag_push_events, :merge_requests_events, :repository_update_events expose :id, :url, :created_at, :push_events, :tag_push_events, :merge_requests_events, :repository_update_events
expose :enable_ssl_verification expose :enable_ssl_verification
......
# frozen_string_literal: true
module API
module Entities
class Email < Grape::Entity
expose :id, :email
end
end
end
# frozen_string_literal: true
module API
module Entities
class Identity < Grape::Entity
expose :provider, :extern_uid
end
end
end
# frozen_string_literal: true
module API
module Entities
class Membership < Grape::Entity
expose :source_id
expose :source_name do |member|
member.source.name
end
expose :source_type
expose :access_level
end
end
end
# frozen_string_literal: true
module API
module Entities
class UserStatus < Grape::Entity
expose :emoji
expose :message
expose :message_html do |entity|
MarkupHelper.markdown_field(entity, :message)
end
end
end
end
...@@ -116,7 +116,7 @@ module API ...@@ -116,7 +116,7 @@ module API
# Project id to pass between components that don't share/don't have # Project id to pass between components that don't share/don't have
# access to the same filesystem mounts # access to the same filesystem mounts
def gl_repository def gl_repository
repo_type.identifier_for_repositorable(project) repo_type.identifier_for_container(project)
end end
def gl_project_path def gl_project_path
......
...@@ -7,12 +7,13 @@ module Gitlab ...@@ -7,12 +7,13 @@ module Gitlab
PROJECT = RepoType.new( PROJECT = RepoType.new(
name: :project, name: :project,
access_checker_class: Gitlab::GitAccess, access_checker_class: Gitlab::GitAccess,
repository_accessor: -> (project) { project.repository } repository_resolver: -> (project) { project.repository }
).freeze ).freeze
WIKI = RepoType.new( WIKI = RepoType.new(
name: :wiki, name: :wiki,
access_checker_class: Gitlab::GitAccessWiki, access_checker_class: Gitlab::GitAccessWiki,
repository_accessor: -> (project) { project.wiki.repository } repository_resolver: -> (project) { project.wiki.repository },
suffix: :wiki
).freeze ).freeze
TYPES = { TYPES = {
...@@ -27,15 +28,14 @@ module Gitlab ...@@ -27,15 +28,14 @@ module Gitlab
def self.parse(gl_repository) def self.parse(gl_repository)
type_name, _id = gl_repository.split('-').first type_name, _id = gl_repository.split('-').first
type = types[type_name] type = types[type_name]
subject_id = type&.fetch_id(gl_repository)
unless subject_id unless type
raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\"" raise ArgumentError, "Invalid GL Repository \"#{gl_repository}\""
end end
project = Project.find_by_id(subject_id) container = type.fetch_container!(gl_repository)
[project, type] [container, type]
end end
def self.default_type def self.default_type
......
...@@ -5,16 +5,25 @@ module Gitlab ...@@ -5,16 +5,25 @@ module Gitlab
class RepoType class RepoType
attr_reader :name, attr_reader :name,
:access_checker_class, :access_checker_class,
:repository_accessor :repository_resolver,
:container_resolver,
:suffix
def initialize(name:, access_checker_class:, repository_accessor:) def initialize(
name:,
access_checker_class:,
repository_resolver:,
container_resolver: default_container_resolver,
suffix: nil)
@name = name @name = name
@access_checker_class = access_checker_class @access_checker_class = access_checker_class
@repository_accessor = repository_accessor @repository_resolver = repository_resolver
@container_resolver = container_resolver
@suffix = suffix
end end
def identifier_for_repositorable(repositorable) def identifier_for_container(container)
"#{name}-#{repositorable.id}" "#{name}-#{container.id}"
end end
def fetch_id(identifier) def fetch_id(identifier)
...@@ -22,6 +31,14 @@ module Gitlab ...@@ -22,6 +31,14 @@ module Gitlab
match[:id] if match match[:id] if match
end end
def fetch_container!(identifier)
id = fetch_id(identifier)
raise ArgumentError, "Invalid GL Repository \"#{identifier}\"" unless id
container_resolver.call(id)
end
def wiki? def wiki?
self == WIKI self == WIKI
end end
...@@ -31,11 +48,21 @@ module Gitlab ...@@ -31,11 +48,21 @@ module Gitlab
end end
def path_suffix def path_suffix
project? ? "" : ".#{name}" suffix ? ".#{suffix}" : ''
end end
def repository_for(repositorable) def repository_for(container)
repository_accessor.call(repositorable) repository_resolver.call(container)
end
def valid?(repository_path)
repository_path.end_with?(path_suffix)
end
private
def default_container_resolver
-> (id) { Project.find_by_id(id) }
end end
end end
end end
......
...@@ -4,8 +4,9 @@ module Gitlab ...@@ -4,8 +4,9 @@ module Gitlab
module RepoPath module RepoPath
NotFoundError = Class.new(StandardError) NotFoundError = Class.new(StandardError)
def self.parse(repo_path) def self.parse(path)
project_path = repo_path.sub(/\.git\z/, '').sub(%r{\A/}, '') repo_path = path.sub(/\.git\z/, '').sub(%r{\A/}, '')
redirected_path = nil
# Detect the repo type based on the path, the first one tried is the project # Detect the repo type based on the path, the first one tried is the project
# type, which does not have a suffix. # type, which does not have a suffix.
...@@ -14,10 +15,13 @@ module Gitlab ...@@ -14,10 +15,13 @@ module Gitlab
# type. # type.
# We'll always try to find a project with an empty suffix (for the # We'll always try to find a project with an empty suffix (for the
# `Gitlab::GlRepository::PROJECT` type. # `Gitlab::GlRepository::PROJECT` type.
next unless project_path.end_with?(type.path_suffix) next unless type.valid?(repo_path)
project, was_redirected = find_project(project_path.chomp(type.path_suffix)) # Removing the suffix (.wiki, .design, ...) from the project path
redirected_path = project_path if was_redirected full_path = repo_path.chomp(type.path_suffix)
project, was_redirected = find_project(full_path)
redirected_path = repo_path if was_redirected
# If we found a matching project, then the type was matched, no need to # If we found a matching project, then the type was matched, no need to
# continue looking. # continue looking.
......
...@@ -24,7 +24,7 @@ module Gitlab ...@@ -24,7 +24,7 @@ module Gitlab
attrs = { attrs = {
GL_ID: Gitlab::GlId.gl_id(user), GL_ID: Gitlab::GlId.gl_id(user),
GL_REPOSITORY: repo_type.identifier_for_repositorable(repository.project), GL_REPOSITORY: repo_type.identifier_for_container(repository.project),
GL_USERNAME: user&.username, GL_USERNAME: user&.username,
ShowAllRefs: show_all_refs, ShowAllRefs: show_all_refs,
Repository: repository.gitaly_repository.to_h, Repository: repository.gitaly_repository.to_h,
......
...@@ -2,33 +2,45 @@ ...@@ -2,33 +2,45 @@
require 'spec_helper' require 'spec_helper'
describe Gitlab::GlRepository::RepoType do describe Gitlab::GlRepository::RepoType do
set(:project) { create(:project) } let_it_be(:project) { create(:project) }
describe Gitlab::GlRepository::PROJECT do describe Gitlab::GlRepository::PROJECT do
it_behaves_like 'a repo type' do it_behaves_like 'a repo type' do
let(:expected_identifier) { "project-#{project.id}" } let(:expected_identifier) { "project-#{project.id}" }
let(:expected_id) { project.id.to_s } let(:expected_id) { project.id.to_s }
let(:expected_suffix) { "" } let(:expected_suffix) { '' }
let(:expected_repository) { project.repository } let(:expected_repository) { project.repository }
let(:expected_container) { project }
end end
it "knows its type" do it 'knows its type' do
expect(described_class).not_to be_wiki expect(described_class).not_to be_wiki
expect(described_class).to be_project expect(described_class).to be_project
end end
it 'checks if repository path is valid' do
expect(described_class.valid?(project.repository.full_path)).to be_truthy
expect(described_class.valid?(project.wiki.repository.full_path)).to be_truthy
end
end end
describe Gitlab::GlRepository::WIKI do describe Gitlab::GlRepository::WIKI do
it_behaves_like 'a repo type' do it_behaves_like 'a repo type' do
let(:expected_identifier) { "wiki-#{project.id}" } let(:expected_identifier) { "wiki-#{project.id}" }
let(:expected_id) { project.id.to_s } let(:expected_id) { project.id.to_s }
let(:expected_suffix) { ".wiki" } let(:expected_suffix) { '.wiki' }
let(:expected_repository) { project.wiki.repository } let(:expected_repository) { project.wiki.repository }
let(:expected_container) { project }
end end
it "knows its type" do it 'knows its type' do
expect(described_class).to be_wiki expect(described_class).to be_wiki
expect(described_class).not_to be_project expect(described_class).not_to be_project
end end
it 'checks if repository path is valid' do
expect(described_class.valid?(project.repository.full_path)).to be_falsey
expect(described_class.valid?(project.wiki.repository.full_path)).to be_truthy
end
end end
end end
...@@ -4,7 +4,7 @@ require 'spec_helper' ...@@ -4,7 +4,7 @@ require 'spec_helper'
describe ::Gitlab::GlRepository do describe ::Gitlab::GlRepository do
describe '.parse' do describe '.parse' do
set(:project) { create(:project, :repository) } let_it_be(:project) { create(:project, :repository) }
it 'parses a project gl_repository' do it 'parses a project gl_repository' do
expect(described_class.parse("project-#{project.id}")).to eq([project, Gitlab::GlRepository::PROJECT]) expect(described_class.parse("project-#{project.id}")).to eq([project, Gitlab::GlRepository::PROJECT])
...@@ -14,8 +14,12 @@ describe ::Gitlab::GlRepository do ...@@ -14,8 +14,12 @@ describe ::Gitlab::GlRepository do
expect(described_class.parse("wiki-#{project.id}")).to eq([project, Gitlab::GlRepository::WIKI]) expect(described_class.parse("wiki-#{project.id}")).to eq([project, Gitlab::GlRepository::WIKI])
end end
it 'throws an argument error on an invalid gl_repository' do it 'throws an argument error on an invalid gl_repository type' do
expect { described_class.parse("badformat-#{project.id}") }.to raise_error(ArgumentError) expect { described_class.parse("badformat-#{project.id}") }.to raise_error(ArgumentError)
end end
it 'throws an argument error on an invalid gl_repository id' do
expect { described_class.parse("project-foo") }.to raise_error(ArgumentError)
end
end end
end end
...@@ -3992,7 +3992,7 @@ describe Project do ...@@ -3992,7 +3992,7 @@ describe Project do
end end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the project repo is in use' do it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the project repo is in use' do
Gitlab::ReferenceCounter.new(Gitlab::GlRepository::PROJECT.identifier_for_repositorable(project)).increase Gitlab::ReferenceCounter.new(Gitlab::GlRepository::PROJECT.identifier_for_container(project)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in) expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
...@@ -4000,7 +4000,7 @@ describe Project do ...@@ -4000,7 +4000,7 @@ describe Project do
end end
it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do it 'schedules HashedStorage::ProjectMigrateWorker with delayed start when the wiki repo is in use' do
Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_repositorable(project)).increase Gitlab::ReferenceCounter.new(Gitlab::GlRepository::WIKI.identifier_for_container(project)).increase
expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in) expect(HashedStorage::ProjectMigrateWorker).to receive(:perform_in)
......
...@@ -268,7 +268,7 @@ describe API::Internal::Base do ...@@ -268,7 +268,7 @@ describe API::Internal::Base do
end end
context 'with env passed as a JSON' do context 'with env passed as a JSON' do
let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_repositorable(project) } let(:gl_repository) { Gitlab::GlRepository::WIKI.identifier_for_container(project) }
it 'sets env in RequestStore' do it 'sets env in RequestStore' do
obj_dir_relative = './objects' obj_dir_relative = './objects'
...@@ -1054,9 +1054,9 @@ describe API::Internal::Base do ...@@ -1054,9 +1054,9 @@ describe API::Internal::Base do
def gl_repository_for(project_or_wiki) def gl_repository_for(project_or_wiki)
case project_or_wiki case project_or_wiki
when ProjectWiki when ProjectWiki
Gitlab::GlRepository::WIKI.identifier_for_repositorable(project_or_wiki.project) Gitlab::GlRepository::WIKI.identifier_for_container(project_or_wiki.project)
when Project when Project
Gitlab::GlRepository::PROJECT.identifier_for_repositorable(project_or_wiki) Gitlab::GlRepository::PROJECT.identifier_for_container(project_or_wiki)
else else
nil nil
end end
......
...@@ -848,7 +848,7 @@ describe 'Git HTTP requests' do ...@@ -848,7 +848,7 @@ describe 'Git HTTP requests' do
end end
it "redirects" do it "redirects" do
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(:found)
end end
end end
end end
...@@ -890,7 +890,7 @@ describe 'Git HTTP requests' do ...@@ -890,7 +890,7 @@ describe 'Git HTTP requests' do
it "responds with status 200" do it "responds with status 200" do
clone_get(path, env) do |response| clone_get(path, env) do |response|
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
end end
......
...@@ -15,12 +15,12 @@ describe JwtController do ...@@ -15,12 +15,12 @@ describe JwtController do
context 'existing service' do context 'existing service' do
subject! { get '/jwt/auth', params: parameters } subject! { get '/jwt/auth', params: parameters }
it { expect(response).to have_gitlab_http_status(200) } it { expect(response).to have_gitlab_http_status(:ok) }
context 'returning custom http code' do context 'returning custom http code' do
let(:service) { double(execute: { http_status: 505 }) } let(:service) { double(execute: { http_status: 505 }) }
it { expect(response).to have_gitlab_http_status(505) } it { expect(response).to have_gitlab_http_status(:http_version_not_supported) }
end end
end end
...@@ -43,7 +43,7 @@ describe JwtController do ...@@ -43,7 +43,7 @@ describe JwtController do
subject! { get '/jwt/auth', params: parameters, headers: headers } subject! { get '/jwt/auth', params: parameters, headers: headers }
it { expect(response).to have_gitlab_http_status(401) } it { expect(response).to have_gitlab_http_status(:unauthorized) }
end end
context 'using personal access tokens' do context 'using personal access tokens' do
...@@ -58,7 +58,7 @@ describe JwtController do ...@@ -58,7 +58,7 @@ describe JwtController do
subject! { get '/jwt/auth', params: parameters, headers: headers } subject! { get '/jwt/auth', params: parameters, headers: headers }
it 'authenticates correctly' do it 'authenticates correctly' do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect(service_class).to have_received(:new).with(nil, user, ActionController::Parameters.new(parameters).permit!) expect(service_class).to have_received(:new).with(nil, user, ActionController::Parameters.new(parameters).permit!)
end end
end end
...@@ -96,7 +96,7 @@ describe JwtController do ...@@ -96,7 +96,7 @@ describe JwtController do
context 'without personal token' do context 'without personal token' do
it 'rejects the authorization attempt' do it 'rejects the authorization attempt' do
expect(response).to have_gitlab_http_status(401) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end end
end end
...@@ -106,7 +106,7 @@ describe JwtController do ...@@ -106,7 +106,7 @@ describe JwtController do
let(:headers) { { authorization: credentials(user.username, access_token.token) } } let(:headers) { { authorization: credentials(user.username, access_token.token) } }
it 'accepts the authorization attempt' do it 'accepts the authorization attempt' do
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
...@@ -116,7 +116,7 @@ describe JwtController do ...@@ -116,7 +116,7 @@ describe JwtController do
get '/jwt/auth', params: parameters, headers: headers get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
end end
...@@ -127,7 +127,7 @@ describe JwtController do ...@@ -127,7 +127,7 @@ describe JwtController do
it 'rejects the authorization attempt' do it 'rejects the authorization attempt' do
get '/jwt/auth', params: parameters, headers: headers get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(401) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).not_to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end end
end end
...@@ -139,7 +139,7 @@ describe JwtController do ...@@ -139,7 +139,7 @@ describe JwtController do
end end
get '/jwt/auth', params: parameters, headers: headers get '/jwt/auth', params: parameters, headers: headers
expect(response).to have_gitlab_http_status(401) expect(response).to have_gitlab_http_status(:unauthorized)
expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP') expect(response.body).to include('You must use a personal access token with \'api\' scope for Git over HTTP')
end end
end end
...@@ -150,7 +150,7 @@ describe JwtController do ...@@ -150,7 +150,7 @@ describe JwtController do
it 'accepts the authorization attempt' do it 'accepts the authorization attempt' do
get '/jwt/auth', params: parameters get '/jwt/auth', params: parameters
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
it 'allows read access' do it 'allows read access' do
...@@ -163,7 +163,7 @@ describe JwtController do ...@@ -163,7 +163,7 @@ describe JwtController do
context 'unknown service' do context 'unknown service' do
subject! { get '/jwt/auth', params: { service: 'unknown' } } subject! { get '/jwt/auth', params: { service: 'unknown' } }
it { expect(response).to have_gitlab_http_status(404) } it { expect(response).to have_gitlab_http_status(:not_found) }
end end
def credentials(login, password) def credentials(login, password)
......
...@@ -227,7 +227,7 @@ describe 'Git LFS API and storage' do ...@@ -227,7 +227,7 @@ describe 'Git LFS API and storage' do
end end
it 'responds with redirect' do it 'responds with redirect' do
expect(response).to have_gitlab_http_status(302) expect(response).to have_gitlab_http_status(:found)
end end
it 'responds with the file location' do it 'responds with the file location' do
...@@ -1011,7 +1011,7 @@ describe 'Git LFS API and storage' do ...@@ -1011,7 +1011,7 @@ describe 'Git LFS API and storage' do
it 'responds with status 403' do it 'responds with status 403' do
subject subject
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end
end end
...@@ -1027,7 +1027,7 @@ describe 'Git LFS API and storage' do ...@@ -1027,7 +1027,7 @@ describe 'Git LFS API and storage' do
it 'responds with status 200' do it 'responds with status 200' do
subject subject
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
object = LfsObject.find_by_oid(sample_oid) object = LfsObject.find_by_oid(sample_oid)
expect(object).to be_present expect(object).to be_present
...@@ -1070,7 +1070,7 @@ describe 'Git LFS API and storage' do ...@@ -1070,7 +1070,7 @@ describe 'Git LFS API and storage' do
it 'rejects slashes in the tempfile name (path traversal)' do it 'rejects slashes in the tempfile name (path traversal)' do
put_finalize('../bar', with_tempfile: true) put_finalize('../bar', with_tempfile: true)
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end
end end
......
...@@ -23,7 +23,7 @@ describe 'Git LFS File Locking API' do ...@@ -23,7 +23,7 @@ describe 'Git LFS File Locking API' do
it 'returns a forbidden 403 response' do it 'returns a forbidden 403 response' do
post_lfs_json url, body, headers post_lfs_json url, body, headers
expect(response).to have_gitlab_http_status(403) expect(response).to have_gitlab_http_status(:forbidden)
end end
end end
end end
...@@ -51,7 +51,7 @@ describe 'Git LFS File Locking API' do ...@@ -51,7 +51,7 @@ describe 'Git LFS File Locking API' do
it 'return an error message' do it 'return an error message' do
post_lfs_json url, body, headers post_lfs_json url, body, headers
expect(response).to have_gitlab_http_status(409) expect(response).to have_gitlab_http_status(:conflict)
expect(json_response.keys).to match_array(%w(lock message documentation_url)) expect(json_response.keys).to match_array(%w(lock message documentation_url))
expect(json_response['message']).to match(/already locked/) expect(json_response['message']).to match(/already locked/)
...@@ -68,7 +68,7 @@ describe 'Git LFS File Locking API' do ...@@ -68,7 +68,7 @@ describe 'Git LFS File Locking API' do
it 'creates the lock' do it 'creates the lock' do
post_lfs_json url, body, headers post_lfs_json url, body, headers
expect(response).to have_gitlab_http_status(201) expect(response).to have_gitlab_http_status(:created)
expect(json_response['lock'].keys).to match_array(%w(id path locked_at owner)) expect(json_response['lock'].keys).to match_array(%w(id path locked_at owner))
end end
...@@ -87,7 +87,7 @@ describe 'Git LFS File Locking API' do ...@@ -87,7 +87,7 @@ describe 'Git LFS File Locking API' do
do_get url, nil, headers do_get url, nil, headers
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect(json_response['locks'].size).to eq(2) expect(json_response['locks'].size).to eq(2)
expect(json_response['locks'].first.keys).to match_array(%w(id path locked_at owner)) expect(json_response['locks'].first.keys).to match_array(%w(id path locked_at owner))
...@@ -106,7 +106,7 @@ describe 'Git LFS File Locking API' do ...@@ -106,7 +106,7 @@ describe 'Git LFS File Locking API' do
post_lfs_json url, nil, headers post_lfs_json url, nil, headers
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect(json_response['ours'].size).to eq(1) expect(json_response['ours'].size).to eq(1)
expect(json_response['ours'].first['path']).to eq('README') expect(json_response['ours'].first['path']).to eq('README')
...@@ -126,7 +126,7 @@ describe 'Git LFS File Locking API' do ...@@ -126,7 +126,7 @@ describe 'Git LFS File Locking API' do
it 'deletes the lock' do it 'deletes the lock' do
post_lfs_json url, nil, headers post_lfs_json url, nil, headers
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
it 'returns the deleted lock' do it 'returns the deleted lock' do
...@@ -142,7 +142,7 @@ describe 'Git LFS File Locking API' do ...@@ -142,7 +142,7 @@ describe 'Git LFS File Locking API' do
project.add_maintainer(maintainer) project.add_maintainer(maintainer)
post_lfs_json url, { force: true }, headers post_lfs_json url, { force: true }, headers
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
......
...@@ -75,7 +75,7 @@ describe 'OpenID Connect requests' do ...@@ -75,7 +75,7 @@ describe 'OpenID Connect requests' do
it 'userinfo response is unauthorized' do it 'userinfo response is unauthorized' do
request_user_info! request_user_info!
expect(response).to have_gitlab_http_status 403 expect(response).to have_gitlab_http_status(:forbidden)
expect(response.body).to be_blank expect(response.body).to be_blank
end end
end end
...@@ -177,7 +177,7 @@ describe 'OpenID Connect requests' do ...@@ -177,7 +177,7 @@ describe 'OpenID Connect requests' do
it 'correctly returns the configuration' do it 'correctly returns the configuration' do
get '/.well-known/openid-configuration' get '/.well-known/openid-configuration'
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect(json_response['issuer']).to eq('http://localhost') expect(json_response['issuer']).to eq('http://localhost')
expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys') expect(json_response['jwks_uri']).to eq('http://www.example.com/oauth/discovery/keys')
expect(json_response['scopes_supported']).to eq(%w[api read_user read_repository write_repository sudo openid profile email]) expect(json_response['scopes_supported']).to eq(%w[api read_user read_repository write_repository sudo openid profile email])
......
...@@ -53,7 +53,7 @@ describe 'Rack Attack global throttles' do ...@@ -53,7 +53,7 @@ describe 'Rack Attack global throttles' do
# At first, allow requests under the rate limit. # At first, allow requests under the rate limit.
requests_per_period.times do requests_per_period.times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
# the last straw # the last straw
...@@ -63,7 +63,7 @@ describe 'Rack Attack global throttles' do ...@@ -63,7 +63,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests after throttling and then waiting for the next period' do it 'allows requests after throttling and then waiting for the next period' do
requests_per_period.times do requests_per_period.times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
expect_rejection { get url_that_does_not_require_authentication } expect_rejection { get url_that_does_not_require_authentication }
...@@ -71,7 +71,7 @@ describe 'Rack Attack global throttles' do ...@@ -71,7 +71,7 @@ describe 'Rack Attack global throttles' do
Timecop.travel(period.from_now) do Timecop.travel(period.from_now) do
requests_per_period.times do requests_per_period.times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
expect_rejection { get url_that_does_not_require_authentication } expect_rejection { get url_that_does_not_require_authentication }
...@@ -81,7 +81,7 @@ describe 'Rack Attack global throttles' do ...@@ -81,7 +81,7 @@ describe 'Rack Attack global throttles' do
it 'counts requests from different IPs separately' do it 'counts requests from different IPs separately' do
requests_per_period.times do requests_per_period.times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
expect_next_instance_of(Rack::Attack::Request) do |instance| expect_next_instance_of(Rack::Attack::Request) do |instance|
...@@ -90,14 +90,14 @@ describe 'Rack Attack global throttles' do ...@@ -90,14 +90,14 @@ describe 'Rack Attack global throttles' do
# would be over limit for the same IP # would be over limit for the same IP
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
context 'when the request is to the api internal endpoints' do context 'when the request is to the api internal endpoints' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
get url_api_internal, params: { secret_token: Gitlab::Shell.secret_token } get url_api_internal, params: { secret_token: Gitlab::Shell.secret_token }
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
...@@ -109,7 +109,7 @@ describe 'Rack Attack global throttles' do ...@@ -109,7 +109,7 @@ describe 'Rack Attack global throttles' do
it 'does not cont as unauthenticated' do it 'does not cont as unauthenticated' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
post request_jobs_url, params: { token: runner.token } post request_jobs_url, params: { token: runner.token }
expect(response).to have_http_status 204 expect(response).to have_gitlab_http_status(:no_content)
end end
end end
end end
...@@ -117,7 +117,7 @@ describe 'Rack Attack global throttles' do ...@@ -117,7 +117,7 @@ describe 'Rack Attack global throttles' do
it 'logs RackAttack info into structured logs' do it 'logs RackAttack info into structured logs' do
requests_per_period.times do requests_per_period.times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
arguments = { arguments = {
...@@ -143,7 +143,7 @@ describe 'Rack Attack global throttles' do ...@@ -143,7 +143,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
get url_that_does_not_require_authentication get url_that_does_not_require_authentication
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
...@@ -243,7 +243,7 @@ describe 'Rack Attack global throttles' do ...@@ -243,7 +243,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
post protected_path_that_does_not_require_authentication, params: post_params post protected_path_that_does_not_require_authentication, params: post_params
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
...@@ -257,7 +257,7 @@ describe 'Rack Attack global throttles' do ...@@ -257,7 +257,7 @@ describe 'Rack Attack global throttles' do
it 'rejects requests over the rate limit' do it 'rejects requests over the rate limit' do
requests_per_period.times do requests_per_period.times do
post protected_path_that_does_not_require_authentication, params: post_params post protected_path_that_does_not_require_authentication, params: post_params
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params } expect_rejection { post protected_path_that_does_not_require_authentication, params: post_params }
...@@ -272,7 +272,7 @@ describe 'Rack Attack global throttles' do ...@@ -272,7 +272,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
post protected_path_that_does_not_require_authentication, params: post_params post protected_path_that_does_not_require_authentication, params: post_params
expect(response).to have_http_status 200 expect(response).to have_gitlab_http_status(:ok)
end end
end end
end end
...@@ -329,7 +329,7 @@ describe 'Rack Attack global throttles' do ...@@ -329,7 +329,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
post(*request_args) post(*request_args)
expect(response).not_to have_http_status 429 expect(response).not_to have_gitlab_http_status(:too_many_requests)
end end
end end
end end
...@@ -369,7 +369,7 @@ describe 'Rack Attack global throttles' do ...@@ -369,7 +369,7 @@ describe 'Rack Attack global throttles' do
it 'allows requests over the rate limit' do it 'allows requests over the rate limit' do
(1 + requests_per_period).times do (1 + requests_per_period).times do
post url_that_requires_authentication post url_that_requires_authentication
expect(response).not_to have_http_status 429 expect(response).not_to have_gitlab_http_status(:too_many_requests)
end end
end end
end end
......
...@@ -19,7 +19,7 @@ describe 'Loading a user avatar' do ...@@ -19,7 +19,7 @@ describe 'Loading a user avatar' do
it 'only performs three SQL queries' do it 'only performs three SQL queries' do
get user.avatar_url # Skip queries on first application load get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect { get user.avatar_url }.not_to exceed_query_limit(3) expect { get user.avatar_url }.not_to exceed_query_limit(3)
end end
end end
...@@ -29,7 +29,7 @@ describe 'Loading a user avatar' do ...@@ -29,7 +29,7 @@ describe 'Loading a user avatar' do
it 'only performs two SQL queries' do it 'only performs two SQL queries' do
get user.avatar_url # Skip queries on first application load get user.avatar_url # Skip queries on first application load
expect(response).to have_gitlab_http_status(200) expect(response).to have_gitlab_http_status(:ok)
expect { get user.avatar_url }.not_to exceed_query_limit(2) expect { get user.avatar_url }.not_to exceed_query_limit(2)
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
describe AkismetService do
let(:fake_akismet_client) { double(:akismet_client) }
let_it_be(:text) { "Would you like to buy some tinned meat product?" }
let_it_be(:spam_owner) { create(:user) }
subject do
options = { ip_address: '1.2.3.4', user_agent: 'some user_agent', referrer: 'some referrer' }
described_class.new(spam_owner.name, spam_owner.email, text, options)
end
before do
stub_application_setting(akismet_enabled: true)
allow(subject).to receive(:akismet_client).and_return(fake_akismet_client)
end
shared_examples 'no activity if Akismet is not enabled' do |method_call|
# if the method name is `submit`, it requires an argument, so add it
before do
stub_application_setting(akismet_enabled: false)
end
it 'is automatically false' do
expect(subject.send(method_call)).to be_falsey
end
it 'performs no check' do
expect(fake_akismet_client).not_to receive(:public_send)
subject.send(method_call)
end
end
shared_examples 'false if Akismet is not available' do |method_call|
context 'if Akismet is not available' do
before do
allow(fake_akismet_client).to receive(:public_send).and_raise(StandardError.new("oh noes!"))
end
specify do
expect(subject.send(method_call)).to be_falsey
end
it 'logs an error' do
logger_spy = double(:logger)
expect(Rails).to receive(:logger).and_return(logger_spy)
expect(logger_spy).to receive(:error).with(/skipping/)
subject.send(method_call)
end
end
end
describe '#spam?' do
it_behaves_like 'no activity if Akismet is not enabled', :spam?, :check
context 'if Akismet is enabled' do
context 'the text is spam' do
before do
allow(fake_akismet_client).to receive(:check).and_return([true, false])
end
specify do
expect(subject.spam?).to be_truthy
end
end
context 'the text is blatant spam' do
before do
allow(fake_akismet_client).to receive(:check).and_return([false, true])
end
specify do
expect(subject.spam?).to be_truthy
end
end
context 'the text is not spam' do
before do
allow(fake_akismet_client).to receive(:check).and_return([false, false])
end
specify do
expect(subject.spam?).to be_falsey
end
end
context 'if Akismet is not available' do
before do
allow(fake_akismet_client).to receive(:check).and_raise(StandardError.new("oh noes!"))
end
specify do
expect(subject.spam?).to be_falsey
end
it 'logs an error' do
logger_spy = double(:logger)
expect(Rails).to receive(:logger).and_return(logger_spy)
expect(logger_spy).to receive(:error).with(/skipping check/)
subject.spam?
end
end
end
end
describe '#submit_ham' do
it_behaves_like 'no activity if Akismet is not enabled', :submit_ham
it_behaves_like 'false if Akismet is not available', :submit_ham
context 'if Akismet is available' do
specify do
expect(fake_akismet_client).to receive(:public_send).with(:ham, any_args)
expect(subject.submit_ham).to be_truthy
end
end
end
describe '#submit_spam' do
it_behaves_like 'no activity if Akismet is not enabled', :submit_spam
it_behaves_like 'false if Akismet is not available', :submit_spam
context 'if Akismet is available' do
specify do
expect(fake_akismet_client).to receive(:public_send).with(:spam, any_args)
expect(subject.submit_spam).to be_truthy
end
end
end
end
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
require 'spec_helper' require 'spec_helper'
describe Ci::CreatePipelineService do describe Ci::CreatePipelineService do
context '.pre/.post stages' do describe '.pre/.post stages' do
let_it_be(:user) { create(:admin) } let_it_be(:user) { create(:admin) }
let_it_be(:project) { create(:project, :repository, creator: user) } let_it_be(:project) { create(:project, :repository, creator: user) }
......
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_examples 'a repo type' do RSpec.shared_examples 'a repo type' do
describe "#identifier_for_repositorable" do describe '#identifier_for_container' do
subject { described_class.identifier_for_repositorable(project) } subject { described_class.identifier_for_container(project) }
it { is_expected.to eq(expected_identifier) } it { is_expected.to eq(expected_identifier) }
end end
describe "#fetch_id" do describe '#fetch_id' do
it "finds an id match in the identifier" do it 'finds an id match in the identifier' do
expect(described_class.fetch_id(expected_identifier)).to eq(expected_id) expect(described_class.fetch_id(expected_identifier)).to eq(expected_id)
end end
it 'does not break on other identifiers' do it 'does not break on other identifiers' do
expect(described_class.fetch_id("wiki-noid")).to eq(nil) expect(described_class.fetch_id('wiki-noid')).to eq(nil)
end end
end end
describe "#path_suffix" do describe '#fetch_container!' do
it 'returns the container' do
expect(described_class.fetch_container!(expected_identifier)).to eq expected_container
end
it 'raises an exception if the identifier is invalid' do
expect { described_class.fetch_container!('project-noid') }.to raise_error ArgumentError
end
end
describe '#path_suffix' do
subject { described_class.path_suffix } subject { described_class.path_suffix }
it { is_expected.to eq(expected_suffix) } it { is_expected.to eq(expected_suffix) }
end end
describe "#repository_for" do describe '#repository_for' do
it "finds the repository for the repo type" do it 'finds the repository for the repo type' do
expect(described_class.repository_for(project)).to eq(expected_repository) expect(described_class.repository_for(project)).to eq(expected_repository)
end end
end end
......
.PHONY: install
install:
if [ -e ../../.overcommit.yml ]; then cp -f ../../.overcommit.yml ../../.overcommit.yml.backup; fi
cp ../../.overcommit.yml.example ../../.overcommit.yml
bundle install
cd ../../ && overcommit -i
GEM
remote: https://rubygems.org/
specs:
ast (2.4.0)
childprocess (3.0.0)
ffi (1.12.1)
gitlab-styles (3.1.0)
rubocop (~> 0.74.0)
rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.4.1)
rubocop-rails (~> 2.0)
rubocop-rspec (~> 1.36)
haml (5.1.2)
temple (>= 0.8.0)
tilt
haml_lint (0.34.1)
haml (>= 4.0, < 5.2)
rainbow
rubocop (>= 0.50.0)
sysexits (~> 1.1)
iniparse (1.4.4)
jaro_winkler (1.5.4)
overcommit (0.52.1)
childprocess (>= 0.6.3, < 4)
iniparse (~> 1.4)
parallel (1.19.1)
parser (2.7.0.2)
ast (~> 2.4.0)
rack (2.1.1)
rainbow (3.0.0)
rake (12.3.3)
rb-fsevent (0.10.3)
rb-inotify (0.10.1)
ffi (~> 1.0)
rubocop (0.74.0)
jaro_winkler (~> 1.5.1)
parallel (~> 1.10)
parser (>= 2.6)
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 1.7)
rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51)
rubocop-performance (1.4.1)
rubocop (>= 0.71.0)
rubocop-rails (2.4.1)
rack (>= 1.1)
rubocop (>= 0.72.0)
rubocop-rspec (1.37.1)
rubocop (>= 0.68.1)
ruby-progressbar (1.10.1)
sass (3.5.7)
sass-listen (~> 4.0.0)
sass-listen (4.0.0)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
scss_lint (0.56.0)
rake (>= 0.9, < 13)
sass (~> 3.5.3)
sysexits (1.2.0)
temple (0.8.2)
tilt (2.0.10)
unicode-display_width (1.6.1)
PLATFORMS
ruby
DEPENDENCIES
gitlab-styles (~> 3.1.0)
haml_lint (~> 0.34.0)
overcommit
scss_lint (~> 0.56.0)
BUNDLED WITH
2.1.2
# frozen_string_literal: true
# Make sure to run `bundle install --gemfile=tooling/overcommit/gems.rb` when you update this file.
source 'https://rubygems.org'
gem 'overcommit'
gem 'gitlab-styles', '~> 3.1.0', require: false
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.34.0', require: false
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment