Commit a2513470 authored by GitLab Bot's avatar GitLab Bot

Automatic merge of gitlab-org/gitlab master

parents 4ee20b8e 8a5d5b40
This diff is collapsed.
...@@ -204,8 +204,13 @@ class CommitStatus < ApplicationRecord ...@@ -204,8 +204,13 @@ class CommitStatus < ApplicationRecord
# 'rspec:linux: 1/10' => 'rspec:linux' # 'rspec:linux: 1/10' => 'rspec:linux'
common_name = name.to_s.gsub(%r{\d+[\s:\/\\]+\d+\s*}, '') common_name = name.to_s.gsub(%r{\d+[\s:\/\\]+\d+\s*}, '')
# 'rspec:linux: [aws, max memory]' => 'rspec:linux' if ::Gitlab::Ci::Features.one_dimensional_matrix_enabled?
common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '') # 'rspec:linux: [aws, max memory]' => 'rspec:linux', 'rspec:linux: [aws]' => 'rspec:linux'
common_name.gsub!(%r{: \[.*\]\s*\z}, '')
else
# 'rspec:linux: [aws, max memory]' => 'rspec:linux', 'rspec:linux: [aws]' => 'rspec:linux: [aws]'
common_name.gsub!(%r{: \[.*, .*\]\s*\z}, '')
end
common_name.strip! common_name.strip!
common_name common_name
......
...@@ -1384,8 +1384,6 @@ class MergeRequest < ApplicationRecord ...@@ -1384,8 +1384,6 @@ class MergeRequest < ApplicationRecord
end end
def has_coverage_reports? def has_coverage_reports?
return false unless Feature.enabled?(:coverage_report_view, project, default_enabled: true)
actual_head_pipeline&.has_coverage_reports? actual_head_pipeline&.has_coverage_reports?
end end
......
...@@ -3,7 +3,6 @@ module Ci ...@@ -3,7 +3,6 @@ module Ci
module Pipelines module Pipelines
class CreateArtifactService class CreateArtifactService
def execute(pipeline) def execute(pipeline)
return unless ::Gitlab::Ci::Features.coverage_report_view?(pipeline.project)
return unless pipeline.can_generate_coverage_reports? return unless pipeline.can_generate_coverage_reports?
return if pipeline.has_coverage_reports? return if pipeline.has_coverage_reports?
......
...@@ -36,5 +36,3 @@ ...@@ -36,5 +36,3 @@
.form-actions .form-actions
= f.submit _('Save changes'), class: "btn btn-success", data: { qa_selector: 'save_changes_button' } = f.submit _('Save changes'), class: "btn btn-success", data: { qa_selector: 'save_changes_button' }
= link_to _('Cancel'), admin_group_path(@group), class: "btn btn-cancel" = link_to _('Cancel'), admin_group_path(@group), class: "btn btn-cancel"
= render_if_exists 'ldap_group_links/ldap_syncrhonizations', group: @group
---
title: Remove coverage_report_view feature flag
merge_request: 43711
author: David Barr @davebarr
type: removed
---
title: Add internal API to download LFS objects
merge_request: 42161
author:
type: added
--- ---
name: coverage_report_view name: one_dimensional_matrix
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/21791 introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42170
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/211410 rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/256062
group: 'group::verify testing'
type: development type: development
default_enabled: true group: group::pipeline authoring
default_enabled: false
...@@ -3572,6 +3572,11 @@ job split into three separate jobs. ...@@ -3572,6 +3572,11 @@ job split into three separate jobs.
Use `matrix:` to configure different variables for jobs that are running in parallel. Use `matrix:` to configure different variables for jobs that are running in parallel.
There can be from 2 to 50 jobs. There can be from 2 to 50 jobs.
In GitLab 13.5 and later, you can have one-dimensional matrices with a single job.
The ability to have one-dimensional matrices is [deployed behind a feature flag](../../user/feature_flags.md),
disabled by default. It's disabled on GitLab.com. To use it in a GitLab self-managed
instance, ask a GitLab administrator to [enable the `one_dimensional_matrix:` feature flag](../../administration/feature_flags.md). **(CORE-ONLY)**
Every job gets the same `CI_NODE_TOTAL` [environment variable](../variables/README.md#predefined-environment-variables) value, and a unique `CI_NODE_INDEX` value. Every job gets the same `CI_NODE_TOTAL` [environment variable](../variables/README.md#predefined-environment-variables) value, and a unique `CI_NODE_INDEX` value.
```yaml ```yaml
......
...@@ -8,10 +8,7 @@ type: reference, howto ...@@ -8,10 +8,7 @@ type: reference, howto
# Test Coverage Visualization # Test Coverage Visualization
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9. > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/3708) in GitLab 12.9.
> - [Feature flag enabled](https://gitlab.com/gitlab-org/gitlab/-/issues/211410) in GitLab 13.4. > - [Feature flag removed](https://gitlab.com/gitlab-org/gitlab/-/issues/249811) in GitLab 13.5.
> - It's enabled on GitLab.com.
> - It can be disabled per-project.
> - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-code-coverage-visualization). **(CORE ONLY)**
With the help of [GitLab CI/CD](../../../ci/README.md), you can collect the test With the help of [GitLab CI/CD](../../../ci/README.md), you can collect the test
coverage information of your favorite testing or coverage-analysis tool, and visualize coverage information of your favorite testing or coverage-analysis tool, and visualize
...@@ -151,27 +148,3 @@ coverage-jdk11: ...@@ -151,27 +148,3 @@ coverage-jdk11:
reports: reports:
cobertura: build/cobertura.xml cobertura: build/cobertura.xml
``` ```
## Enable or disable code coverage visualization
This feature comes with the `:coverage_report_view` feature flag enabled by
default. It is enabled on GitLab.com. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can disable it for your instance. Test coverage visualization can be enabled or disabled per-project.
To disable it:
```ruby
# Instance-wide
Feature.disable(:coverage_report_view)
# or by project
Feature.disable(:coverage_report_view, Project.find(<project id>))
```
To enable it:
```ruby
# Instance-wide
Feature.enable(:coverage_report_view)
# or by project
Feature.enable(:coverage_report_view, Project.find(<project id>))
```
- group = local_assigns.fetch(:group)
- return unless Gitlab::Auth::Ldap::Config.group_sync_enabled? && group.persisted?
%h3.page-title LDAP synchronizations
= render 'ldap_group_links/form', group: group
= render 'ldap_group_links/ldap_group_links', group: group
...@@ -249,6 +249,7 @@ module API ...@@ -249,6 +249,7 @@ module API
end end
mount ::API::Internal::Base mount ::API::Internal::Base
mount ::API::Internal::Lfs
mount ::API::Internal::Pages mount ::API::Internal::Pages
mount ::API::Internal::Kubernetes mount ::API::Internal::Kubernetes
......
# frozen_string_literal: true
module API
module Internal
class Lfs < Grape::API::Instance
use Rack::Sendfile
before { authenticate_by_gitlab_shell_token! }
helpers do
def find_lfs_object(lfs_oid)
LfsObject.find_by_oid(lfs_oid)
end
end
namespace 'internal' do
namespace 'lfs' do
desc 'Get LFS URL for object ID' do
detail 'This feature was introduced in GitLab 13.5.'
end
params do
requires :oid, type: String, desc: 'The object ID to query'
requires :gl_repository, type: String, desc: "Project identifier (e.g. project-1)"
end
get "/" do
lfs_object = find_lfs_object(params[:oid])
not_found! unless lfs_object
_, project, repo_type = Gitlab::GlRepository.parse(params[:gl_repository])
not_found! unless repo_type.project? && project
not_found! unless lfs_object.project_allowed_access?(project)
file = lfs_object.file
not_found! unless file&.exists?
content_type 'application/octet-stream'
if file.file_storage?
sendfile file.path
else
workhorse_headers = Gitlab::Workhorse.send_url(file.url)
header workhorse_headers[0], workhorse_headers[1]
env['api.format'] = :binary
body nil
end
end
end
end
end
end
end
...@@ -14,7 +14,7 @@ module Gitlab ...@@ -14,7 +14,7 @@ module Gitlab
validations do validations do
validates :config, variables: { array_values: true } validates :config, variables: { array_values: true }
validates :config, length: { validates :config, length: {
minimum: 2, minimum: :minimum,
too_short: 'requires at least %{count} items' too_short: 'requires at least %{count} items'
} }
end end
...@@ -28,6 +28,10 @@ module Gitlab ...@@ -28,6 +28,10 @@ module Gitlab
.map { |key, value| [key.to_s, Array(value).map(&:to_s)] } .map { |key, value| [key.to_s, Array(value).map(&:to_s)] }
.to_h .to_h
end end
def minimum
::Gitlab::Ci::Features.one_dimensional_matrix_enabled? ? 1 : 2
end
end end
end end
end end
......
...@@ -46,10 +46,6 @@ module Gitlab ...@@ -46,10 +46,6 @@ module Gitlab
Feature.enabled?(:project_transactionless_destroy, project, default_enabled: false) Feature.enabled?(:project_transactionless_destroy, project, default_enabled: false)
end end
def self.coverage_report_view?(project)
::Feature.enabled?(:coverage_report_view, project, default_enabled: true)
end
def self.child_of_child_pipeline_enabled?(project) def self.child_of_child_pipeline_enabled?(project)
::Feature.enabled?(:ci_child_of_child_pipeline, project, default_enabled: true) ::Feature.enabled?(:ci_child_of_child_pipeline, project, default_enabled: true)
end end
...@@ -66,6 +62,10 @@ module Gitlab ...@@ -66,6 +62,10 @@ module Gitlab
def self.new_artifact_file_reader_enabled?(project) def self.new_artifact_file_reader_enabled?(project)
::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: true) ::Feature.enabled?(:ci_new_artifact_file_reader, project, default_enabled: true)
end end
def self.one_dimensional_matrix_enabled?
::Feature.enabled?(:one_dimensional_matrix, default_enabled: false)
end
end end
end end
end end
...@@ -109,8 +109,8 @@ RSpec.describe InvitesController, :snowplow do ...@@ -109,8 +109,8 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as experiment group' do it 'tracks the user as experiment group' do
request request
expect_snowplow_event(snowplow_event.merge(action: 'opened')) expect_snowplow_event(**snowplow_event.merge(action: 'opened'))
expect_snowplow_event(snowplow_event.merge(action: 'accepted')) expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end end
end end
...@@ -121,8 +121,8 @@ RSpec.describe InvitesController, :snowplow do ...@@ -121,8 +121,8 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as control group' do it 'tracks the user as control group' do
request request
expect_snowplow_event(snowplow_event.merge(action: 'opened')) expect_snowplow_event(**snowplow_event.merge(action: 'opened'))
expect_snowplow_event(snowplow_event.merge(action: 'accepted')) expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end end
end end
...@@ -173,7 +173,7 @@ RSpec.describe InvitesController, :snowplow do ...@@ -173,7 +173,7 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as experiment group' do it 'tracks the user as experiment group' do
request request
expect_snowplow_event(snowplow_event.merge(action: 'accepted')) expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end end
end end
...@@ -184,7 +184,7 @@ RSpec.describe InvitesController, :snowplow do ...@@ -184,7 +184,7 @@ RSpec.describe InvitesController, :snowplow do
it 'tracks the user as control group' do it 'tracks the user as control group' do
request request
expect_snowplow_event(snowplow_event.merge(action: 'accepted')) expect_snowplow_event(**snowplow_event.merge(action: 'accepted'))
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
require 'fast_spec_helper' require 'spec_helper'
require_dependency 'active_model' require_dependency 'active_model'
RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
...@@ -46,33 +46,140 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do ...@@ -46,33 +46,140 @@ RSpec.describe ::Gitlab::Ci::Config::Entry::Product::Matrix do
end end
end end
context 'when entry config has only one variable' do context 'with one_dimensional_matrix feature flag enabled' do
let(:config) do before do
[ stub_feature_flags(one_dimensional_matrix: true)
{ matrix.compose!
'VAR_1' => %w[test]
}
]
end end
describe '#valid?' do context 'when entry config has only one variable with multiple values' do
it { is_expected.not_to be_valid } let(:config) do
end [
{
'VAR_1' => %w[build test]
}
]
end
describe '#errors' do describe '#valid?' do
it 'returns error about too many jobs' do it { is_expected.to be_valid }
expect(matrix.errors) end
.to include('variables config requires at least 2 items')
describe '#errors' do
it 'returns no errors' do
expect(matrix.errors)
.to be_empty
end
end
describe '#value' do
before do
matrix.compose!
end
it 'returns the value without raising an error' do
expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
end
end end
context 'when entry config has only one variable with one value' do
let(:config) do
[
{
'VAR_1' => %w[test]
}
]
end
describe '#valid?' do
it { is_expected.to be_valid }
end
describe '#errors' do
it 'returns no errors' do
expect(matrix.errors)
.to be_empty
end
end
describe '#value' do
before do
matrix.compose!
end
it 'returns the value without raising an error' do
expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
end
end
end
end
end
context 'with one_dimensional_matrix feature flag disabled' do
before do
stub_feature_flags(one_dimensional_matrix: false)
matrix.compose!
end end
describe '#value' do context 'when entry config has only one variable with multiple values' do
before do let(:config) do
matrix.compose! [
{
'VAR_1' => %w[build test]
}
]
end end
it 'returns the value without raising an error' do describe '#valid?' do
expect(matrix.value).to eq([{ 'VAR_1' => ['test'] }]) it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'returns error about too many jobs' do
expect(matrix.errors)
.to include('variables config requires at least 2 items')
end
end
describe '#value' do
before do
matrix.compose!
end
it 'returns the value without raising an error' do
expect(matrix.value).to eq([{ 'VAR_1' => %w[build test] }])
end
end
context 'when entry config has only one variable with one value' do
let(:config) do
[
{
'VAR_1' => %w[test]
}
]
end
describe '#valid?' do
it { is_expected.not_to be_valid }
end
describe '#errors' do
it 'returns no errors' do
expect(matrix.errors)
.to include('variables config requires at least 2 items')
end
end
describe '#value' do
before do
matrix.compose!
end
it 'returns the value without raising an error' do
expect(matrix.value).to eq([{ 'VAR_1' => %w[test] }])
end
end
end end
end end
end end
......
# frozen_string_literal: true # frozen_string_literal: true
require 'fast_spec_helper' # After Feature one_dimensional_matrix is removed, this can be changed back to fast_spec_helper
require 'spec_helper'
require_dependency 'active_model' require_dependency 'active_model'
RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
...@@ -45,43 +46,71 @@ RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do ...@@ -45,43 +46,71 @@ RSpec.describe Gitlab::Ci::Config::Entry::Product::Variables do
end end
end end
context 'when entry value is not correct' do context 'with one_dimensional_matrix feature flag enabled' do
shared_examples 'invalid variables' do |message| context 'with only one variable' do
describe '#errors' do before do
it 'saves errors' do stub_feature_flags(one_dimensional_matrix: true)
expect(entry.errors).to include(message)
end
end end
let(:config) { { VAR: 'test' } }
describe '#valid?' do describe '#valid?' do
it 'is not valid' do it 'is valid' do
expect(entry).not_to be_valid expect(entry).to be_valid
end
end
describe '#errors' do
it 'does not append errors' do
expect(entry.errors).to be_empty
end end
end end
end end
end
context 'with array' do context 'with one_dimensional_matrix feature flag disabled' do
let(:config) { [:VAR, 'test'] } context 'when entry value is not correct' do
before do
stub_feature_flags(one_dimensional_matrix: false)
end
shared_examples 'invalid variables' do |message|
describe '#errors' do
it 'saves errors' do
expect(entry.errors).to include(message)
end
end
it_behaves_like 'invalid variables', /should be a hash of key value pairs/ describe '#valid?' do
end it 'is not valid' do
expect(entry).not_to be_valid
end
end
end
context 'with empty array' do context 'with array' do
let(:config) { { VAR: 'test', VAR2: [] } } let(:config) { [:VAR, 'test'] }
it_behaves_like 'invalid variables', /should be a hash of key value pairs/ it_behaves_like 'invalid variables', /should be a hash of key value pairs/
end end
context 'with nested array' do context 'with empty array' do
let(:config) { { VAR: 'test', VAR2: [1, [2]] } } let(:config) { { VAR: 'test', VAR2: [] } }
it_behaves_like 'invalid variables', /should be a hash of key value pairs/ it_behaves_like 'invalid variables', /should be a hash of key value pairs/
end end
context 'with only one variable' do context 'with nested array' do
let(:config) { { VAR: 'test' } } let(:config) { { VAR: 'test', VAR2: [1, [2]] } }
it_behaves_like 'invalid variables', /should be a hash of key value pairs/
end
it_behaves_like 'invalid variables', /variables config requires at least 2 items/ context 'with one_dimensional_matrix feature flag disabled' do
context 'with only one variable' do
let(:config) { { VAR: 'test' } }
it_behaves_like 'invalid variables', /variables config requires at least 2 items/
end
end
end end
end end
end end
......
...@@ -493,47 +493,104 @@ RSpec.describe CommitStatus do ...@@ -493,47 +493,104 @@ RSpec.describe CommitStatus do
end end
end end
describe '#group_name' do context 'with the one_dimensional_matrix feature flag disabled' do
let(:commit_status) do describe '#group_name' do
build(:commit_status, pipeline: pipeline, stage: 'test') before do
end stub_feature_flags(one_dimensional_matrix: false)
end
subject { commit_status.group_name }
tests = { let(:commit_status) do
'rspec:windows' => 'rspec:windows', build(:commit_status, pipeline: pipeline, stage: 'test')
'rspec:windows 0' => 'rspec:windows 0', end
'rspec:windows 0 test' => 'rspec:windows 0 test',
'rspec:windows 0 1' => 'rspec:windows', subject { commit_status.group_name }
'rspec:windows 0 1 name' => 'rspec:windows name',
'rspec:windows 0/1' => 'rspec:windows', tests = {
'rspec:windows 0/1 name' => 'rspec:windows name', 'rspec:windows' => 'rspec:windows',
'rspec:windows 0:1' => 'rspec:windows', 'rspec:windows 0' => 'rspec:windows 0',
'rspec:windows 0:1 name' => 'rspec:windows name', 'rspec:windows 0 test' => 'rspec:windows 0 test',
'rspec:windows 10000 20000' => 'rspec:windows', 'rspec:windows 0 1' => 'rspec:windows',
'rspec:windows 0 : / 1' => 'rspec:windows', 'rspec:windows 0 1 name' => 'rspec:windows name',
'rspec:windows 0 : / 1 name' => 'rspec:windows name', 'rspec:windows 0/1' => 'rspec:windows',
'0 1 name ruby' => 'name ruby', 'rspec:windows 0/1 name' => 'rspec:windows name',
'0 :/ 1 name ruby' => 'name ruby', 'rspec:windows 0:1' => 'rspec:windows',
'rspec: [aws]' => 'rspec: [aws]', 'rspec:windows 0:1 name' => 'rspec:windows name',
'rspec: [aws] 0/1' => 'rspec: [aws]', 'rspec:windows 10000 20000' => 'rspec:windows',
'rspec: [aws, max memory]' => 'rspec', 'rspec:windows 0 : / 1' => 'rspec:windows',
'rspec:linux: [aws, max memory, data]' => 'rspec:linux', 'rspec:windows 0 : / 1 name' => 'rspec:windows name',
'rspec: [inception: [something, other thing], value]' => 'rspec', '0 1 name ruby' => 'name ruby',
'rspec:windows 0/1: [name, other]' => 'rspec:windows', '0 :/ 1 name ruby' => 'name ruby',
'rspec:windows: [name, other] 0/1' => 'rspec:windows', 'rspec: [aws]' => 'rspec: [aws]',
'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows', 'rspec: [aws] 0/1' => 'rspec: [aws]',
'rspec:windows: [0/1, name]' => 'rspec:windows', 'rspec: [aws, max memory]' => 'rspec',
'rspec:windows: [, ]' => 'rspec:windows', 'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
'rspec:windows: [name]' => 'rspec:windows: [name]', 'rspec: [inception: [something, other thing], value]' => 'rspec',
'rspec:windows: [name,other]' => 'rspec:windows: [name,other]' 'rspec:windows 0/1: [name, other]' => 'rspec:windows',
} 'rspec:windows: [name, other] 0/1' => 'rspec:windows',
'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
'rspec:windows: [0/1, name]' => 'rspec:windows',
'rspec:windows: [, ]' => 'rspec:windows',
'rspec:windows: [name]' => 'rspec:windows: [name]',
'rspec:windows: [name,other]' => 'rspec:windows: [name,other]'
}
tests.each do |name, group_name|
it "'#{name}' puts in '#{group_name}'" do
commit_status.name = name
is_expected.to eq(group_name)
end
end
end
end
tests.each do |name, group_name| context 'with one_dimensional_matrix feature flag enabled' do
it "'#{name}' puts in '#{group_name}'" do describe '#group_name' do
commit_status.name = name before do
stub_feature_flags(one_dimensional_matrix: true)
end
is_expected.to eq(group_name) let(:commit_status) do
build(:commit_status, pipeline: pipeline, stage: 'test')
end
subject { commit_status.group_name }
tests = {
'rspec:windows' => 'rspec:windows',
'rspec:windows 0' => 'rspec:windows 0',
'rspec:windows 0 test' => 'rspec:windows 0 test',
'rspec:windows 0 1' => 'rspec:windows',
'rspec:windows 0 1 name' => 'rspec:windows name',
'rspec:windows 0/1' => 'rspec:windows',
'rspec:windows 0/1 name' => 'rspec:windows name',
'rspec:windows 0:1' => 'rspec:windows',
'rspec:windows 0:1 name' => 'rspec:windows name',
'rspec:windows 10000 20000' => 'rspec:windows',
'rspec:windows 0 : / 1' => 'rspec:windows',
'rspec:windows 0 : / 1 name' => 'rspec:windows name',
'0 1 name ruby' => 'name ruby',
'0 :/ 1 name ruby' => 'name ruby',
'rspec: [aws]' => 'rspec',
'rspec: [aws] 0/1' => 'rspec',
'rspec: [aws, max memory]' => 'rspec',
'rspec:linux: [aws, max memory, data]' => 'rspec:linux',
'rspec: [inception: [something, other thing], value]' => 'rspec',
'rspec:windows 0/1: [name, other]' => 'rspec:windows',
'rspec:windows: [name, other] 0/1' => 'rspec:windows',
'rspec:windows: [name, 0/1] 0/1' => 'rspec:windows',
'rspec:windows: [0/1, name]' => 'rspec:windows',
'rspec:windows: [, ]' => 'rspec:windows',
'rspec:windows: [name]' => 'rspec:windows',
'rspec:windows: [name,other]' => 'rspec:windows'
}
tests.each do |name, group_name|
it "'#{name}' puts in '#{group_name}'" do
commit_status.name = name
is_expected.to eq(group_name)
end
end end
end end
end end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Internal::Lfs do
include APIInternalBaseHelpers
let_it_be(:project) { create(:project) }
let_it_be(:lfs_object) { create(:lfs_object, :with_file) }
let_it_be(:lfs_objects_project) { create(:lfs_objects_project, project: project, lfs_object: lfs_object) }
let_it_be(:gl_repository) { "project-#{project.id}" }
let_it_be(:filename) { lfs_object.file.path }
let(:secret_token) { Gitlab::Shell.secret_token }
describe 'GET /internal/lfs' do
let(:valid_params) do
{ oid: lfs_object.oid, gl_repository: gl_repository, secret_token: secret_token }
end
context 'with invalid auth' do
let(:invalid_params) { valid_params.merge!(secret_token: 'invalid_tokne') }
it 'returns 401' do
get api("/internal/lfs"), params: invalid_params
end
end
context 'with valid auth' do
context 'LFS in local storage' do
it 'sends the file' do
get api("/internal/lfs"), params: valid_params
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('application/octet-stream')
expect(response.headers['Content-Length'].to_i).to eq(File.stat(filename).size)
expect(response.body).to eq(File.open(filename, 'rb', &:read))
end
# https://www.rubydoc.info/github/rack/rack/master/Rack/Sendfile
it 'delegates sending to Web server' do
get api("/internal/lfs"), params: valid_params, env: { 'HTTP_X_SENDFILE_TYPE' => 'X-Sendfile' }
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers['Content-Type']).to eq('application/octet-stream')
expect(response.headers['Content-Length'].to_i).to eq(0)
expect(response.headers['X-Sendfile']).to be_present
expect(response.body).to eq("")
end
it 'retuns 404 for unknown file' do
params = valid_params.merge(oid: SecureRandom.hex)
get api("/internal/lfs"), params: params
expect(response).to have_gitlab_http_status(:not_found)
end
it 'returns 404 if LFS object does not belong to project' do
other_lfs = create(:lfs_object, :with_file)
params = valid_params.merge(oid: other_lfs.oid)
get api("/internal/lfs"), params: params
expect(response).to have_gitlab_http_status(:not_found)
end
end
context 'LFS in object storage' do
let!(:lfs_object2) { create(:lfs_object, :with_file) }
let!(:lfs_objects_project2) { create(:lfs_objects_project, project: project, lfs_object: lfs_object2) }
let(:valid_params) do
{ oid: lfs_object2.oid, gl_repository: gl_repository, secret_token: secret_token }
end
before do
stub_lfs_object_storage(enabled: true)
lfs_object2.file.migrate!(LfsObjectUploader::Store::REMOTE)
end
it 'notifies Workhorse to send the file' do
get api("/internal/lfs"), params: valid_params
expect(response).to have_gitlab_http_status(:ok)
expect(response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]).to start_with("send-url:")
expect(response.headers['Content-Type']).to eq('application/octet-stream')
expect(response.headers['Content-Length'].to_i).to eq(0)
expect(response.body).to eq("")
end
end
end
end
end
...@@ -35,16 +35,6 @@ RSpec.describe ::Ci::Pipelines::CreateArtifactService do ...@@ -35,16 +35,6 @@ RSpec.describe ::Ci::Pipelines::CreateArtifactService do
end end
end end
context 'when feature is disabled' do
it 'does not create a pipeline artifact' do
stub_feature_flags(coverage_report_view: false)
subject
expect(Ci::PipelineArtifact.count).to eq(0)
end
end
context 'when pipeline artifact has already been created' do context 'when pipeline artifact has already been created' do
it 'do not raise an error and do not persist the same artifact twice' do it 'do not raise an error and do not persist the same artifact twice' do
expect { 2.times { described_class.new.execute(pipeline) } }.not_to raise_error(ActiveRecord::RecordNotUnique) expect { 2.times { described_class.new.execute(pipeline) } }.not_to raise_error(ActiveRecord::RecordNotUnique)
......
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