Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f4186a753b
commit
ac1dca43ba
35 changed files with 374 additions and 68 deletions
|
@ -12,6 +12,24 @@ stages:
|
|||
- post-qa
|
||||
- pages
|
||||
|
||||
workflow:
|
||||
rules:
|
||||
# If `$FORCE_GITLAB_CI` is set, create a pipeline.
|
||||
- if: '$FORCE_GITLAB_CI'
|
||||
# For merge requests, create a pipeline.
|
||||
- if: '$CI_MERGE_REQUEST_IID'
|
||||
# For `master` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
|
||||
- if: '$CI_COMMIT_BRANCH == "master"'
|
||||
# For tags, create a pipeline.
|
||||
- if: '$CI_COMMIT_TAG'
|
||||
# If `$GITLAB_INTERNAL` isn't set, don't create a pipeline.
|
||||
- if: '$GITLAB_INTERNAL == null'
|
||||
when: never
|
||||
# For stable, auto-deploy, and security branches, create a pipeline.
|
||||
- if: '$CI_COMMIT_BRANCH =~ /^[\d-]+-stable(-ee)?$/'
|
||||
- if: '$CI_COMMIT_BRANCH =~ /^\d+-\d+-auto-deploy-\d+$/'
|
||||
- if: '$CI_COMMIT_BRANCH =~ /^security\//'
|
||||
|
||||
variables:
|
||||
RAILS_ENV: "test"
|
||||
NODE_ENV: "test"
|
||||
|
|
|
@ -45,10 +45,13 @@ export default {
|
|||
:class="{ active: isActive }"
|
||||
class="stage-nav-item d-flex pl-4 pr-4 m-0 mb-1 ml-2 rounded border-color-default border-style-solid border-width-1px"
|
||||
>
|
||||
<div class="stage-nav-item-cell stage-name p-0" :class="{ 'font-weight-bold': isActive }">
|
||||
<div
|
||||
class="stage-nav-item-cell stage-name w-50 pr-2"
|
||||
:class="{ 'font-weight-bold': isActive }"
|
||||
>
|
||||
{{ title }}
|
||||
</div>
|
||||
<div class="stage-nav-item-cell stage-median mr-4">
|
||||
<div class="stage-nav-item-cell stage-median w-50">
|
||||
<template v-if="isUserAllowed">
|
||||
<span v-if="hasValue">{{ value }}</span>
|
||||
<span v-else class="stage-empty">{{ __('Not enough data') }}</span>
|
||||
|
|
|
@ -51,11 +51,11 @@
|
|||
}
|
||||
|
||||
.stage-header {
|
||||
width: 18.5%;
|
||||
width: 20.5%;
|
||||
}
|
||||
|
||||
.median-header {
|
||||
width: 21.5%;
|
||||
width: 19.5%;
|
||||
}
|
||||
|
||||
.event-header {
|
||||
|
|
|
@ -28,4 +28,11 @@ module SnippetsActions
|
|||
def convert_line_endings(content)
|
||||
params[:line_ending] == 'raw' ? content : content.gsub(/\r\n/, "\n")
|
||||
end
|
||||
|
||||
def check_repository_error
|
||||
repository_error = snippet.errors.delete(:repository)
|
||||
|
||||
flash.now[:alert] = repository_error if repository_error
|
||||
recaptcha_check_with_fallback(repository_error.nil?) { render :edit }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -62,7 +62,7 @@ class Projects::SnippetsController < Projects::ApplicationController
|
|||
service_response = Snippets::UpdateService.new(project, current_user, update_params).execute(@snippet)
|
||||
@snippet = service_response.payload[:snippet]
|
||||
|
||||
recaptcha_check_with_fallback { render :edit }
|
||||
check_repository_error
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -12,6 +12,8 @@ module Repositories
|
|||
rescue_from Gitlab::GitAccess::ProjectCreationError, with: :render_422_with_exception
|
||||
rescue_from Gitlab::GitAccess::TimeoutError, with: :render_503_with_exception
|
||||
|
||||
before_action :snippet_request_allowed?
|
||||
|
||||
# GET /foo/bar.git/info/refs?service=git-upload-pack (git pull)
|
||||
# GET /foo/bar.git/info/refs?service=git-receive-pack (git push)
|
||||
def info_refs
|
||||
|
@ -116,6 +118,12 @@ module Repositories
|
|||
def log_user_activity
|
||||
Users::ActivityService.new(user).execute
|
||||
end
|
||||
|
||||
def snippet_request_allowed?
|
||||
if repo_type.snippet? && Feature.disabled?(:version_snippets, user)
|
||||
render plain: 'The project you were looking for could not be found.', status: :not_found
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ class SnippetsController < ApplicationController
|
|||
service_response = Snippets::UpdateService.new(nil, current_user, update_params).execute(@snippet)
|
||||
@snippet = service_response.payload[:snippet]
|
||||
|
||||
recaptcha_check_with_fallback { render :edit }
|
||||
check_repository_error
|
||||
end
|
||||
|
||||
def show
|
||||
|
|
|
@ -260,12 +260,14 @@ module Issuable
|
|||
|
||||
highest_priority = highest_label_priority(params).to_sql
|
||||
|
||||
select_columns = [
|
||||
"#{table_name}.*",
|
||||
"(#{highest_priority}) AS highest_priority"
|
||||
] + extra_select_columns
|
||||
# When using CTE make sure to select the same columns that are on the group_by clause.
|
||||
# This prevents errors when ignored columns are present in the database.
|
||||
issuable_columns = with_cte ? issue_grouping_columns(use_cte: with_cte) : "#{table_name}.*"
|
||||
|
||||
select(select_columns.join(', '))
|
||||
extra_select_columns = extra_select_columns.unshift("(#{highest_priority}) AS highest_priority")
|
||||
|
||||
select(issuable_columns)
|
||||
.select(extra_select_columns)
|
||||
.group(issue_grouping_columns(use_cte: with_cte))
|
||||
.reorder(Gitlab::Database.nulls_last_order('highest_priority', direction))
|
||||
end
|
||||
|
@ -301,7 +303,7 @@ module Issuable
|
|||
# Returns an array of arel columns
|
||||
def issue_grouping_columns(use_cte: false)
|
||||
if use_cte
|
||||
[arel_table[:state]] + attribute_names.map { |attr| arel_table[attr.to_sym] }
|
||||
attribute_names.map { |attr| arel_table[attr.to_sym] }
|
||||
else
|
||||
arel_table[:id]
|
||||
end
|
||||
|
|
|
@ -56,8 +56,13 @@ class PipelineSerializer < BaseSerializer
|
|||
:manual_actions,
|
||||
:scheduled_actions,
|
||||
:artifacts,
|
||||
:merge_request,
|
||||
:user,
|
||||
{
|
||||
merge_request: {
|
||||
source_project: [:route, { namespace: :route }],
|
||||
target_project: [:route, { namespace: :route }]
|
||||
}
|
||||
},
|
||||
{
|
||||
pending_builds: :project,
|
||||
project: [:route, { namespace: :route }],
|
||||
|
|
|
@ -52,7 +52,7 @@ module Snippets
|
|||
create_commit(snippet) if snippet.repository_exists?
|
||||
end
|
||||
rescue
|
||||
snippet.errors.add(:base, 'Error updating the snippet')
|
||||
snippet.errors.add(:repository, 'Error updating the snippet')
|
||||
|
||||
false
|
||||
end
|
||||
|
|
5
changelogs/unreleased/fix-api.yml
Normal file
5
changelogs/unreleased/fix-api.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Support finding namespace by ID or path on fork API
|
||||
merge_request: 20603
|
||||
author: leoleoasd
|
||||
type: fixed
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Show git error message updating snippet
|
||||
merge_request: 26570
|
||||
author:
|
||||
type: fixed
|
5
changelogs/unreleased/sh-optimize-pipeline-for-mrs.yml
Normal file
5
changelogs/unreleased/sh-optimize-pipeline-for-mrs.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Fix N+1 queries for PipelinesController#index.json
|
||||
merge_request: 26643
|
||||
author:
|
||||
type: performance
|
|
@ -35,10 +35,14 @@ the SSH configuration of your server by adding the line below to the `/etc/ssh/s
|
|||
AcceptEnv GIT_PROTOCOL
|
||||
```
|
||||
|
||||
Once configured, restart the SSH daemon. In Ubuntu, run:
|
||||
Once configured, restart the SSH daemon for the change to take effect:
|
||||
|
||||
```shell
|
||||
sudo service ssh restart
|
||||
# CentOS 6 / RHEL 6
|
||||
sudo service sshd restart
|
||||
|
||||
# All other supported distributions
|
||||
sudo systemctl restart ssh
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
|
|
@ -202,14 +202,8 @@ On different cloud vendors a best effort like for like can be used.
|
|||
and another for the Queues and Shared State classes respectively. We also recommend
|
||||
that you run the Redis Sentinel clusters separately as well for each Redis Cluster.
|
||||
|
||||
[^4]: For data objects such as LFS, Uploads, Artifacts, etc... We recommend a Cloud Object Storage
|
||||
where possible over NFS due to better performance and availability. Several types of objects
|
||||
are supported for S3 storage - [Job artifacts](../job_artifacts.md#using-object-storage),
|
||||
[LFS](../lfs/lfs_administration.md#storing-lfs-objects-in-remote-object-storage),
|
||||
[Uploads](../uploads.md#using-object-storage-core-only),
|
||||
[Merge Request Diffs](../merge_request_diffs.md#using-object-storage),
|
||||
[Packages](../packages/index.md#using-object-storage) (Optional Feature),
|
||||
[Dependency Proxy](../packages/dependency_proxy.md#using-object-storage) (Optional Feature).
|
||||
[^4]: For data objects such as LFS, Uploads, Artifacts, etc. We recommend a [Cloud Object Storage service](object_storage.md)
|
||||
over NFS where possible, due to better performance and availability.
|
||||
|
||||
[^5]: NFS can be used as an alternative for both repository data (replacing Gitaly) and
|
||||
object storage but this isn't typically recommended for performance reasons. Note however it is required for
|
||||
|
|
|
@ -736,10 +736,14 @@ To enable the read-only mode:
|
|||
|
||||
This will set the Container Registry into the read only mode.
|
||||
|
||||
1. Next, trigger the garbage collect command:
|
||||
1. Next, trigger one of the garbage collect commands:
|
||||
|
||||
```sh
|
||||
# Recycling unused tags
|
||||
sudo /opt/gitlab/embedded/bin/registry garbage-collect /var/opt/gitlab/registry/config.yml
|
||||
|
||||
# Removing unused layers not referenced by manifests
|
||||
sudo /opt/gitlab/embedded/bin/registry garbage-collect -m /var/opt/gitlab/registry/config.yml
|
||||
```
|
||||
|
||||
This will start the garbage collection, which might take some time to complete.
|
||||
|
|
|
@ -1207,7 +1207,9 @@ POST /projects/:id/fork
|
|||
| Attribute | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](README.md#namespaced-path-encoding) |
|
||||
| `namespace` | integer/string | yes | The ID or path of the namespace that the project will be forked to |
|
||||
| `namespace` | integer/string | no | (deprecated) The ID or path of the namespace that the project will be forked to |
|
||||
| `namespace_id` | integer | no | The ID of the namespace that the project will be forked to |
|
||||
| `namespace_path` | string | no | The path of the namespace that the project will be forked to |
|
||||
| `path` | string | no | The path that will be assigned to the resultant project after forking |
|
||||
| `name` | string | no | The name that will be assigned to the resultant project after forking |
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ The default image is currently
|
|||
`registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.5-golang-1.12-git-2.24-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34`.
|
||||
|
||||
It includes Ruby 2.6.5, Go 1.12, Git 2.24, Git LFS 2.9, Chrome 73, Node 12, Yarn 1.21,
|
||||
PostgreSQL 9.6, and Graphics Magick 1.3.33.
|
||||
PostgreSQL 9.6, and Graphics Magick 1.3.34.
|
||||
|
||||
The images used in our pipelines are configured in the
|
||||
[`gitlab-org/gitlab-build-images`](https://gitlab.com/gitlab-org/gitlab-build-images)
|
||||
|
@ -61,8 +61,8 @@ each pipeline includes default variables defined in
|
|||
## Common job definitions
|
||||
|
||||
Most of the jobs [extend from a few CI definitions](../ci/yaml/README.md#extends)
|
||||
that are scoped to a single
|
||||
[configuration parameter](../ci/yaml/README.md#configuration-parameters).
|
||||
defined in [`.gitlab/ci/global.gitlab-ci.yml`](https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab/ci/global.gitlab-ci.yml)
|
||||
that are scoped to a single [configuration parameter](../ci/yaml/README.md#configuration-parameters).
|
||||
|
||||
| Job definitions | Description |
|
||||
|------------------|-------------|
|
||||
|
@ -72,10 +72,27 @@ that are scoped to a single
|
|||
| `.default-cache` | Allows a job to use a default `cache` definition suitable for Ruby/Rails and frontend tasks. |
|
||||
| `.use-pg9` | Allows a job to use the `postgres:9.6.17` and `redis:alpine` services. |
|
||||
| `.use-pg10` | Allows a job to use the `postgres:10.12` and `redis:alpine` services. |
|
||||
| `.use-pg11` | Allows a job to use the `postgres:11.6` and `redis:alpine` services. |
|
||||
| `.use-pg9-ee` | Same as `.use-pg9` but also use the `docker.elastic.co/elasticsearch/elasticsearch:6.4.2` services. |
|
||||
| `.use-pg10-ee` | Same as `.use-pg10` but also use the `docker.elastic.co/elasticsearch/elasticsearch:6.4.2` services. |
|
||||
| `.use-pg11-ee` | Same as `.use-pg11` but also use the `docker.elastic.co/elasticsearch/elasticsearch:6.4.2` services. |
|
||||
| `.as-if-foss` | Simulate the FOSS project by setting the `FOSS_ONLY='1'` environment variable. |
|
||||
|
||||
## `workflow:rules`
|
||||
|
||||
We're using the [`workflow:rules` keyword](../ci/yaml/README.md#workflowrules) to
|
||||
define default rules to determine whether or not a pipeline is created.
|
||||
|
||||
These rules are defined in <https://gitlab.com/gitlab-org/gitlab/blob/master/.gitlab-ci.yml>
|
||||
and are as follows:
|
||||
|
||||
1. If `$FORCE_GITLAB_CI` is set, create a pipeline.
|
||||
1. For merge requests, create a pipeline.
|
||||
1. For `master` branch, create a pipeline (this includes on schedules, pushes, merges, etc.).
|
||||
1. For tags, create a pipeline.
|
||||
1. If `$GITLAB_INTERNAL` isn't set, don't create a pipeline.
|
||||
1. For stable, auto-deploy, and security branches, create a pipeline.
|
||||
|
||||
## `rules`, `if:` conditions and `changes:` patterns
|
||||
|
||||
We're using the [`rules` keyword](../ci/yaml/README.md#rules) extensively.
|
||||
|
|
|
@ -331,7 +331,7 @@ metrics:
|
|||
unit: "count"
|
||||
```
|
||||
|
||||
This will render into:
|
||||
This works by lowercasing the value of `label` and, if there are more words separated by spaces, replacing those spaces with an underscore (`_`). The transformed value is then checked against the labels of the time series returned by the Prometheus query. If a time series label is found that is equal to the transformed value, then the label value will be used and rendered in the legend like this:
|
||||
|
||||
![legend with label shorthand variable](img/prometheus_dashboard_label_variable_shorthand.png)
|
||||
|
||||
|
|
|
@ -12,6 +12,9 @@ module API
|
|||
expose :last_successful_update_at
|
||||
expose :last_error
|
||||
expose :only_protected_branches
|
||||
expose :keep_divergent_refs, if: -> (mirror, _options) do
|
||||
::Feature.enabled?(:keep_divergent_refs, mirror.project)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -142,6 +142,12 @@ module API
|
|||
end
|
||||
end
|
||||
|
||||
def check_namespace_access(namespace)
|
||||
return namespace if can?(current_user, :read_namespace, namespace)
|
||||
|
||||
not_found!('Namespace')
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def find_namespace(id)
|
||||
if id.to_s =~ /^\d+$/
|
||||
|
@ -153,13 +159,15 @@ module API
|
|||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def find_namespace!(id)
|
||||
namespace = find_namespace(id)
|
||||
|
||||
if can?(current_user, :read_namespace, namespace)
|
||||
namespace
|
||||
else
|
||||
not_found!('Namespace')
|
||||
check_namespace_access(find_namespace(id))
|
||||
end
|
||||
|
||||
def find_namespace_by_path(path)
|
||||
Namespace.find_by_full_path(path)
|
||||
end
|
||||
|
||||
def find_namespace_by_path!(path)
|
||||
check_namespace_access(find_namespace_by_path(path))
|
||||
end
|
||||
|
||||
def find_branch!(branch_name)
|
||||
|
|
|
@ -108,6 +108,10 @@ module API
|
|||
# check_ip - optional, only in EE version, may limit access to
|
||||
# group resources based on its IP restrictions
|
||||
post "/allowed" do
|
||||
if repo_type.snippet? && Feature.disabled?(:version_snippets, actor.user)
|
||||
break response_with_status(code: 404, success: false, message: 'The project you were looking for could not be found.')
|
||||
end
|
||||
|
||||
# It was moved to a separate method so that EE can alter its behaviour more
|
||||
# easily.
|
||||
check_allowed(params)
|
||||
|
|
|
@ -263,7 +263,9 @@ module API
|
|||
success Entities::Project
|
||||
end
|
||||
params do
|
||||
optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into'
|
||||
optional :namespace, type: String, desc: '(deprecated) The ID or name of the namespace that the project will be forked into'
|
||||
optional :namespace_id, type: Integer, desc: 'The ID of the namespace that the project will be forked into'
|
||||
optional :namespace_path, type: String, desc: 'The path of the namespace that the project will be forked into'
|
||||
optional :path, type: String, desc: 'The path that will be assigned to the fork'
|
||||
optional :name, type: String, desc: 'The name that will be assigned to the fork'
|
||||
end
|
||||
|
@ -273,7 +275,15 @@ module API
|
|||
not_found! unless can?(current_user, :fork_project, user_project)
|
||||
|
||||
fork_params = declared_params(include_missing: false)
|
||||
fork_params[:namespace] = find_namespace!(fork_params[:namespace]) if fork_params[:namespace].present?
|
||||
|
||||
fork_params[:namespace] =
|
||||
if fork_params[:namespace_id].present?
|
||||
find_namespace!(fork_params[:namespace_id])
|
||||
elsif fork_params[:namespace_path].present?
|
||||
find_namespace_by_path!(fork_params[:namespace_path])
|
||||
elsif fork_params[:namespace].present?
|
||||
find_namespace!(fork_params[:namespace])
|
||||
end
|
||||
|
||||
service = ::Projects::ForkService.new(user_project, current_user, fork_params)
|
||||
|
||||
|
|
|
@ -33,9 +33,11 @@ module API
|
|||
requires :url, type: String, desc: 'The URL for a remote mirror'
|
||||
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
|
||||
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
|
||||
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
|
||||
end
|
||||
post ':id/remote_mirrors' do
|
||||
create_params = declared_params(include_missing: false)
|
||||
create_params.delete(:keep_divergent_refs) unless ::Feature.enabled?(:keep_divergent_refs, user_project)
|
||||
|
||||
new_mirror = user_project.remote_mirrors.create(create_params)
|
||||
|
||||
|
@ -53,12 +55,15 @@ module API
|
|||
requires :mirror_id, type: String, desc: 'The ID of a remote mirror'
|
||||
optional :enabled, type: Boolean, desc: 'Determines if the mirror is enabled'
|
||||
optional :only_protected_branches, type: Boolean, desc: 'Determines if only protected branches are mirrored'
|
||||
optional :keep_divergent_refs, type: Boolean, desc: 'Determines if divergent refs are kept on the target'
|
||||
end
|
||||
put ':id/remote_mirrors/:mirror_id' do
|
||||
mirror = user_project.remote_mirrors.find(params[:mirror_id])
|
||||
|
||||
mirror_params = declared_params(include_missing: false)
|
||||
mirror_params[:id] = mirror_params.delete(:mirror_id)
|
||||
mirror_params.delete(:keep_divergent_refs) unless ::Feature.enabled?(:keep_divergent_refs, user_project)
|
||||
|
||||
update_params = { remote_mirrors_attributes: mirror_params }
|
||||
|
||||
result = ::Projects::UpdateService
|
||||
|
|
|
@ -8,7 +8,6 @@ module Gitlab
|
|||
authentication_mechanism: 'The authentication mechanism is not supported.',
|
||||
read_snippet: 'You are not allowed to read this snippet.',
|
||||
update_snippet: 'You are not allowed to update this snippet.',
|
||||
project_not_found: 'The project you were looking for could not be found.',
|
||||
snippet_not_found: 'The snippet you were looking for could not be found.',
|
||||
repository_not_found: 'The snippet repository you were looking for could not be found.'
|
||||
}.freeze
|
||||
|
@ -31,10 +30,6 @@ module Gitlab
|
|||
raise ForbiddenError, ERROR_MESSAGES[:authentication_mechanism]
|
||||
end
|
||||
|
||||
unless Feature.enabled?(:version_snippets, user)
|
||||
raise NotFoundError, ERROR_MESSAGES[:project_not_found]
|
||||
end
|
||||
|
||||
check_snippet_accessibility!
|
||||
|
||||
super
|
||||
|
|
|
@ -38,9 +38,9 @@ describe Projects::PipelinesController do
|
|||
expect(response).to match_response_schema('pipeline')
|
||||
|
||||
expect(json_response).to include('pipelines')
|
||||
expect(json_response['pipelines'].count).to eq 5
|
||||
expect(json_response['count']['all']).to eq '5'
|
||||
expect(json_response['count']['running']).to eq '1'
|
||||
expect(json_response['pipelines'].count).to eq 6
|
||||
expect(json_response['count']['all']).to eq '6'
|
||||
expect(json_response['count']['running']).to eq '2'
|
||||
expect(json_response['count']['pending']).to eq '1'
|
||||
expect(json_response['count']['finished']).to eq '3'
|
||||
|
||||
|
@ -61,7 +61,7 @@ describe Projects::PipelinesController do
|
|||
# There appears to be one extra query for Pipelines#has_warnings? for some reason
|
||||
expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['pipelines'].count).to eq 10
|
||||
expect(json_response['pipelines'].count).to eq 12
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -77,9 +77,9 @@ describe Projects::PipelinesController do
|
|||
expect(response).to match_response_schema('pipeline')
|
||||
|
||||
expect(json_response).to include('pipelines')
|
||||
expect(json_response['pipelines'].count).to eq 5
|
||||
expect(json_response['count']['all']).to eq '5'
|
||||
expect(json_response['count']['running']).to eq '1'
|
||||
expect(json_response['pipelines'].count).to eq 6
|
||||
expect(json_response['count']['all']).to eq '6'
|
||||
expect(json_response['count']['running']).to eq '2'
|
||||
expect(json_response['count']['pending']).to eq '1'
|
||||
expect(json_response['count']['finished']).to eq '3'
|
||||
|
||||
|
@ -99,8 +99,9 @@ describe Projects::PipelinesController do
|
|||
|
||||
# There appears to be one extra query for Pipelines#has_warnings? for some reason
|
||||
expect { get_pipelines_index_json }.not_to exceed_query_limit(control_count + 1)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(json_response['pipelines'].count).to eq 10
|
||||
expect(json_response['pipelines'].count).to eq 12
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -139,7 +140,7 @@ describe Projects::PipelinesController do
|
|||
it 'returns the pipelines when the user has access' do
|
||||
get_pipelines_index_json
|
||||
|
||||
expect(json_response['pipelines'].size).to eq(5)
|
||||
expect(json_response['pipelines'].size).to eq(6)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -155,18 +156,32 @@ describe Projects::PipelinesController do
|
|||
%w(pending running success failed canceled).each_with_index do |status, index|
|
||||
create_pipeline(status, project.commit("HEAD~#{index}"))
|
||||
end
|
||||
|
||||
create_pipeline_with_merge_request
|
||||
end
|
||||
|
||||
def create_pipeline(status, sha)
|
||||
def create_pipeline_with_merge_request
|
||||
# New merge requests must be created with different branches, so
|
||||
# let's just create new ones with random names.
|
||||
branch_name = "test-#{SecureRandom.hex}"
|
||||
project.repository.create_branch(branch_name, project.repository.root_ref)
|
||||
mr = create(:merge_request, source_project: project, target_project: project, source_branch: branch_name)
|
||||
create_pipeline(:running, project.commit('HEAD'), merge_request: mr)
|
||||
end
|
||||
|
||||
def create_pipeline(status, sha, merge_request: nil)
|
||||
user = create(:user)
|
||||
pipeline = create(:ci_empty_pipeline, status: status,
|
||||
project: project,
|
||||
sha: sha,
|
||||
user: user)
|
||||
user: user,
|
||||
merge_request: merge_request)
|
||||
|
||||
create_build(pipeline, 'build', 1, 'build', user)
|
||||
create_build(pipeline, 'test', 2, 'test', user)
|
||||
create_build(pipeline, 'deploy', 3, 'deploy', user)
|
||||
|
||||
pipeline
|
||||
end
|
||||
|
||||
def create_build(pipeline, stage, stage_idx, name, user = nil)
|
||||
|
|
|
@ -135,6 +135,38 @@ describe Repositories::GitHttpController do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'snippet feature flag disabled behavior' do
|
||||
before do
|
||||
stub_feature_flags(version_snippets: false)
|
||||
|
||||
request.headers.merge! auth_env(user.username, user.password, nil)
|
||||
end
|
||||
|
||||
describe 'GET #info_refs' do
|
||||
let(:params) { container_params.merge(service: 'git-upload-pack') }
|
||||
|
||||
it 'returns 404' do
|
||||
get :info_refs, params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST #git_upload_pack' do
|
||||
before do
|
||||
allow(controller).to receive(:authenticate_user).and_return(true)
|
||||
allow(controller).to receive(:verify_workhorse_api!).and_return(true)
|
||||
allow(controller).to receive(:access_check).and_return(nil)
|
||||
end
|
||||
|
||||
it 'returns 404' do
|
||||
post :git_upload_pack, params: params
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when repository container is a project' do
|
||||
it_behaves_like 'info_refs behavior' do
|
||||
let(:user) { project.owner }
|
||||
|
@ -158,6 +190,9 @@ describe Repositories::GitHttpController do
|
|||
let(:expected_class) { Gitlab::GitAccessSnippet }
|
||||
let(:expected_object) { personal_snippet }
|
||||
end
|
||||
it_behaves_like 'snippet feature flag disabled behavior' do
|
||||
let(:user) { personal_snippet.author }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when repository container is a project snippet' do
|
||||
|
@ -172,5 +207,8 @@ describe Repositories::GitHttpController do
|
|||
let(:expected_class) { Gitlab::GitAccessSnippet }
|
||||
let(:expected_object) { project_snippet }
|
||||
end
|
||||
it_behaves_like 'snippet feature flag disabled behavior' do
|
||||
let(:user) { project_snippet.author }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'Projects > Snippets > User updates a snippet' do
|
||||
let(:project) { create(:project) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, namespace: user.namespace) }
|
||||
let!(:snippet) { create(:project_snippet, project: project, author: user) }
|
||||
let(:user) { create(:user) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(snippets_vue: false)
|
||||
|
@ -13,16 +13,33 @@ describe 'Projects > Snippets > User updates a snippet' do
|
|||
sign_in(user)
|
||||
|
||||
visit(project_snippet_path(project, snippet))
|
||||
end
|
||||
|
||||
it 'updates a snippet' do
|
||||
page.within('.detail-page-header') do
|
||||
first(:link, 'Edit').click
|
||||
end
|
||||
end
|
||||
|
||||
it 'updates a snippet' do
|
||||
fill_in('project_snippet_title', with: 'Snippet new title')
|
||||
click_button('Save')
|
||||
|
||||
expect(page).to have_content('Snippet new title')
|
||||
end
|
||||
|
||||
context 'when the git operation fails' do
|
||||
before do
|
||||
allow_next_instance_of(Snippets::UpdateService) do |instance|
|
||||
allow(instance).to receive(:create_commit).and_raise(StandardError)
|
||||
end
|
||||
|
||||
fill_in('project_snippet_title', with: 'Snippet new title')
|
||||
|
||||
click_button('Save')
|
||||
end
|
||||
|
||||
it 'renders edit page and displays the error' do
|
||||
expect(page).to have_content('Error updating the snippet')
|
||||
expect(page).to have_content('Edit Snippet')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -8,7 +8,7 @@ describe 'User edits snippet', :js do
|
|||
let(:file_name) { 'test.rb' }
|
||||
let(:content) { 'puts "test"' }
|
||||
|
||||
let(:user) { create(:user) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
let(:snippet) { create(:personal_snippet, :public, file_name: file_name, content: content, author: user) }
|
||||
|
||||
before do
|
||||
|
@ -58,4 +58,21 @@ describe 'User edits snippet', :js do
|
|||
expect(page).to have_no_xpath("//i[@class='fa fa-lock']")
|
||||
expect(page).to have_xpath("//i[@class='fa fa-globe']")
|
||||
end
|
||||
|
||||
context 'when the git operation fails' do
|
||||
before do
|
||||
allow_next_instance_of(Snippets::UpdateService) do |instance|
|
||||
allow(instance).to receive(:create_commit).and_raise(StandardError)
|
||||
end
|
||||
|
||||
fill_in 'personal_snippet_title', with: 'New Snippet Title'
|
||||
|
||||
click_button('Save changes')
|
||||
end
|
||||
|
||||
it 'renders edit page and displays the error' do
|
||||
expect(page).to have_content('Error updating the snippet')
|
||||
expect(page).to have_content('Edit Snippet')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
3
spec/fixtures/api/schemas/remote_mirror.json
vendored
3
spec/fixtures/api/schemas/remote_mirror.json
vendored
|
@ -20,7 +20,8 @@
|
|||
"last_update_started_at": { "type": ["string", "null"] },
|
||||
"last_successful_update_at": { "type": ["string", "null"] },
|
||||
"last_error": { "type": ["string", "null"] },
|
||||
"only_protected_branches": { "type": "boolean" }
|
||||
"only_protected_branches": { "type": "boolean" },
|
||||
"keep_divergent_refs": { "type": ["boolean", "null"] }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
|
|
@ -31,12 +31,15 @@ describe Gitlab::GitAccessSnippet do
|
|||
end
|
||||
|
||||
describe 'when feature flag :version_snippets is disabled' do
|
||||
let(:user) { snippet.author }
|
||||
|
||||
before do
|
||||
stub_feature_flags(version_snippets: false)
|
||||
end
|
||||
|
||||
it 'does not allow push and pull access' do
|
||||
expect { pull_access_check }.to raise_project_not_found
|
||||
it 'allows push and pull access' do
|
||||
expect { pull_access_check }.not_to raise_error
|
||||
expect { push_access_check }.not_to raise_error
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -315,6 +315,18 @@ describe API::Internal::Base do
|
|||
end
|
||||
end
|
||||
|
||||
shared_examples 'snippets with disabled feature flag' do
|
||||
context 'when feature flag :version_snippets is disabled' do
|
||||
it 'returns 404' do
|
||||
stub_feature_flags(version_snippets: false)
|
||||
|
||||
subject
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'git push with personal snippet' do
|
||||
it 'responds with success' do
|
||||
push(key, personal_snippet)
|
||||
|
@ -325,6 +337,10 @@ describe API::Internal::Base do
|
|||
expect(json_response["gl_repository"]).to eq("snippet-#{personal_snippet.id}")
|
||||
expect(user.reload.last_activity_on).to be_nil
|
||||
end
|
||||
|
||||
it_behaves_like 'snippets with disabled feature flag' do
|
||||
subject { push(key, personal_snippet) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'git pull with personal snippet' do
|
||||
|
@ -337,6 +353,10 @@ describe API::Internal::Base do
|
|||
expect(json_response["gl_repository"]).to eq("snippet-#{personal_snippet.id}")
|
||||
expect(user.reload.last_activity_on).to eql(Date.today)
|
||||
end
|
||||
|
||||
it_behaves_like 'snippets with disabled feature flag' do
|
||||
subject { pull(key, personal_snippet) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'git push with project snippet' do
|
||||
|
@ -349,6 +369,10 @@ describe API::Internal::Base do
|
|||
expect(json_response["gl_repository"]).to eq("snippet-#{project_snippet.id}")
|
||||
expect(user.reload.last_activity_on).to be_nil
|
||||
end
|
||||
|
||||
it_behaves_like 'snippets with disabled feature flag' do
|
||||
subject { push(key, project_snippet) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'git pull with project snippet' do
|
||||
|
@ -361,6 +385,10 @@ describe API::Internal::Base do
|
|||
expect(json_response["gl_repository"]).to eq("snippet-#{project_snippet.id}")
|
||||
expect(user.reload.last_activity_on).to eql(Date.today)
|
||||
end
|
||||
|
||||
it_behaves_like 'snippets with disabled feature flag' do
|
||||
subject { pull(key, project_snippet) }
|
||||
end
|
||||
end
|
||||
|
||||
context "git pull" do
|
||||
|
|
|
@ -2871,6 +2871,66 @@ describe API::Projects do
|
|||
expect(json_response['namespace']['name']).to eq(group2.name)
|
||||
end
|
||||
|
||||
context 'when namespace_id is specified' do
|
||||
shared_examples_for 'forking to specified namespace_id' do
|
||||
it 'forks to specified namespace_id' do
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(json_response['owner']['id']).to eq(user2.id)
|
||||
expect(json_response['namespace']['id']).to eq(user2.namespace.id)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and namespace_id is specified alone' do
|
||||
before do
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forking to specified namespace_id'
|
||||
end
|
||||
|
||||
context 'and namespace_id and namespace are both specified' do
|
||||
before do
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id, namespace: admin.namespace.id }
|
||||
end
|
||||
|
||||
it_behaves_like 'forking to specified namespace_id'
|
||||
end
|
||||
|
||||
context 'and namespace_id and namespace_path are both specified' do
|
||||
before do
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace_id: user2.namespace.id, namespace_path: admin.namespace.path }
|
||||
end
|
||||
|
||||
it_behaves_like 'forking to specified namespace_id'
|
||||
end
|
||||
end
|
||||
|
||||
context 'when namespace_path is specified' do
|
||||
shared_examples_for 'forking to specified namespace_path' do
|
||||
it 'forks to specified namespace_path' do
|
||||
expect(response).to have_gitlab_http_status(:created)
|
||||
expect(json_response['owner']['id']).to eq(user2.id)
|
||||
expect(json_response['namespace']['path']).to eq(user2.namespace.path)
|
||||
end
|
||||
end
|
||||
|
||||
context 'and namespace_path is specified alone' do
|
||||
before do
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace_path: user2.namespace.path }
|
||||
end
|
||||
|
||||
it_behaves_like 'forking to specified namespace_path'
|
||||
end
|
||||
|
||||
context 'and namespace_path and namespace are both specified' do
|
||||
before do
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace_path: user2.namespace.path, namespace: admin.namespace.path }
|
||||
end
|
||||
|
||||
it_behaves_like 'forking to specified namespace_path'
|
||||
end
|
||||
end
|
||||
|
||||
it 'forks to owned subgroup' do
|
||||
full_path = "#{group2.path}/#{group3.path}"
|
||||
post api("/projects/#{project.id}/fork", user2), params: { namespace: full_path }
|
||||
|
|
|
@ -91,6 +91,10 @@ describe API::RemoteMirrors do
|
|||
let(:route) { ->(id) { "/projects/#{project.id}/remote_mirrors/#{id}" } }
|
||||
let(:mirror) { project.remote_mirrors.first }
|
||||
|
||||
before do
|
||||
stub_feature_flags(keep_divergent_refs: false)
|
||||
end
|
||||
|
||||
it 'requires `admin_remote_mirror` permission' do
|
||||
put api(route[mirror.id], developer)
|
||||
|
||||
|
@ -102,12 +106,31 @@ describe API::RemoteMirrors do
|
|||
|
||||
put api(route[mirror.id], user), params: {
|
||||
enabled: '0',
|
||||
only_protected_branches: 'true'
|
||||
only_protected_branches: 'true',
|
||||
keep_divergent_refs: 'true'
|
||||
}
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(json_response['enabled']).to eq(false)
|
||||
expect(json_response['only_protected_branches']).to eq(true)
|
||||
|
||||
# Deleted due to lack of feature availability
|
||||
expect(json_response['keep_divergent_refs']).to be_nil
|
||||
end
|
||||
|
||||
context 'with the `keep_divergent_refs` feature enabled' do
|
||||
before do
|
||||
stub_feature_flags(keep_divergent_refs: { enabled: true, project: project })
|
||||
end
|
||||
|
||||
it 'updates the `keep_divergent_refs` attribute' do
|
||||
project.add_maintainer(user)
|
||||
|
||||
put api(route[mirror.id], user), params: { keep_divergent_refs: 'true' }
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(json_response['keep_divergent_refs']).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
# TODO: Remove flag: https://gitlab.com/gitlab-org/gitlab/issues/38121
|
||||
|
|
|
@ -148,7 +148,7 @@ describe Snippets::UpdateService do
|
|||
response = subject
|
||||
|
||||
expect(response).to be_error
|
||||
expect(response.payload[:snippet].errors.full_messages).to eq ['Error updating the snippet']
|
||||
expect(response.payload[:snippet].errors.full_messages).to eq ['Repository Error updating the snippet']
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -173,7 +173,7 @@ describe Snippets::UpdateService do
|
|||
response = subject
|
||||
|
||||
expect(response).to be_error
|
||||
expect(response.payload[:snippet].errors.full_messages).to eq ['Error updating the snippet']
|
||||
expect(response.payload[:snippet].errors.full_messages).to eq ['Repository Error updating the snippet']
|
||||
end
|
||||
|
||||
it 'returns error if snippet does not have a snippet_repository' do
|
||||
|
|
Loading…
Reference in a new issue