Commit dfc4946f authored by Avielle Wolfe's avatar Avielle Wolfe Committed by Shinya Maeda

Return artifacts, not builds

1. It was weird that a key named `artifacts` returned builds
2. We need BuildArtifactEntity to represent each artifact of a job in
    order for a job to have more than one downloadable artifact
3. We need BuildArtifactEntity to have access to an artifact's file type
    in order to properly create the download path
parent 7f696037
...@@ -35,7 +35,7 @@ export default { ...@@ -35,7 +35,7 @@ export default {
<ul class="dropdown-menu dropdown-menu-right"> <ul class="dropdown-menu dropdown-menu-right">
<li v-for="(artifact, i) in artifacts" :key="i"> <li v-for="(artifact, i) in artifacts" :key="i">
<gl-link :href="artifact.path" rel="nofollow" download <gl-link :href="artifact.path" rel="nofollow" download
>Download {{ artifact.name }} artifacts</gl-link >Download {{ artifact.name }} artifact</gl-link
> >
</li> </li>
</ul> </ul>
......
...@@ -162,8 +162,8 @@ module GitlabRoutingHelper ...@@ -162,8 +162,8 @@ module GitlabRoutingHelper
# against the arguments. We can speed this up 10x by generating the strings directly. # against the arguments. We can speed this up 10x by generating the strings directly.
# /*namespace_id/:project_id/-/jobs/:job_id/artifacts/download(.:format) # /*namespace_id/:project_id/-/jobs/:job_id/artifacts/download(.:format)
def fast_download_project_job_artifacts_path(project, job) def fast_download_project_job_artifacts_path(project, job, params = {})
expose_fast_artifacts_path(project, job, :download) expose_fast_artifacts_path(project, job, :download, params)
end end
# /*namespace_id/:project_id/-/jobs/:job_id/artifacts/keep(.:format) # /*namespace_id/:project_id/-/jobs/:job_id/artifacts/keep(.:format)
...@@ -176,8 +176,13 @@ module GitlabRoutingHelper ...@@ -176,8 +176,13 @@ module GitlabRoutingHelper
expose_fast_artifacts_path(project, job, :browse) expose_fast_artifacts_path(project, job, :browse)
end end
def expose_fast_artifacts_path(project, job, action) def expose_fast_artifacts_path(project, job, action, params = {})
path = "#{project.full_path}/-/jobs/#{job.id}/artifacts/#{action}" path = "#{project.full_path}/-/jobs/#{job.id}/artifacts/#{action}"
unless params.empty?
path += "?#{params.to_query}"
end
Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, path) Gitlab::Utils.append_path(Gitlab.config.gitlab.relative_url_root, path)
end end
......
...@@ -112,6 +112,7 @@ module Ci ...@@ -112,6 +112,7 @@ module Ci
after_save :update_file_store, if: :saved_change_to_file? after_save :update_file_store, if: :saved_change_to_file?
scope :not_expired, -> { where('expire_at IS NULL OR expire_at > ?', Time.current) }
scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) } scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) }
scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) } scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) }
scope :for_sha, ->(sha, project_id) { joins(job: :pipeline).where(ci_pipelines: { sha: sha, project_id: project_id }) } scope :for_sha, ->(sha, project_id) { joins(job: :pipeline).where(ci_pipelines: { sha: sha, project_id: project_id }) }
...@@ -151,6 +152,7 @@ module Ci ...@@ -151,6 +152,7 @@ module Ci
end end
scope :expired, -> (limit) { where('expire_at < ?', Time.current).limit(limit) } scope :expired, -> (limit) { where('expire_at < ?', Time.current).limit(limit) }
scope :downloadable, -> { where(file_type: DOWNLOADABLE_TYPES) }
scope :locked, -> { where(locked: true) } scope :locked, -> { where(locked: true) }
scope :unlocked, -> { where(locked: [false, nil]) } scope :unlocked, -> { where(locked: [false, nil]) }
...@@ -246,6 +248,14 @@ module Ci ...@@ -246,6 +248,14 @@ module Ci
super || self.file_location.nil? super || self.file_location.nil?
end end
def expired?
expire_at.present? && expire_at < Time.current
end
def expiring?
expire_at.present? && expire_at > Time.current
end
def expire_in def expire_in
expire_at - Time.current if expire_at expire_at - Time.current if expire_at
end end
......
...@@ -41,10 +41,13 @@ module Ci ...@@ -41,10 +41,13 @@ module Ci
has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline has_many :latest_statuses_ordered_by_stage, -> { latest.order(:stage_idx, :stage) }, class_name: 'CommitStatus', foreign_key: :commit_id, inverse_of: :pipeline
has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline has_many :processables, class_name: 'Ci::Processable', foreign_key: :commit_id, inverse_of: :pipeline
has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline
has_many :job_artifacts, through: :builds
has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent
has_many :variables, class_name: 'Ci::PipelineVariable' has_many :variables, class_name: 'Ci::PipelineVariable'
has_many :deployments, through: :builds has_many :deployments, through: :builds
has_many :environments, -> { distinct }, through: :deployments has_many :environments, -> { distinct }, through: :deployments
has_many :latest_builds, -> { latest }, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'Ci::Build'
has_many :downloadable_artifacts, -> { not_expired.downloadable }, through: :latest_builds, source: :job_artifacts
# Merge requests for which the current pipeline is running against # Merge requests for which the current pipeline is running against
# the merge request's latest commit. # the merge request's latest commit.
...@@ -56,7 +59,6 @@ module Ci ...@@ -56,7 +59,6 @@ module Ci
has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus' has_many :cancelable_statuses, -> { cancelable }, foreign_key: :commit_id, class_name: 'CommitStatus'
has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :manual_actions, -> { latest.manual_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build' has_many :scheduled_actions, -> { latest.scheduled_actions.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :artifacts, -> { latest.with_artifacts_not_expired.includes(:project) }, foreign_key: :commit_id, class_name: 'Ci::Build'
has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id' has_many :auto_canceled_pipelines, class_name: 'Ci::Pipeline', foreign_key: 'auto_canceled_by_id'
has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id' has_many :auto_canceled_jobs, class_name: 'CommitStatus', foreign_key: 'auto_canceled_by_id'
......
...@@ -4,30 +4,28 @@ class BuildArtifactEntity < Grape::Entity ...@@ -4,30 +4,28 @@ class BuildArtifactEntity < Grape::Entity
include RequestAwareEntity include RequestAwareEntity
include GitlabRoutingHelper include GitlabRoutingHelper
expose :name do |job| alias_method :artifact, :object
job.name
end
expose :artifacts_expired?, as: :expired
expose :artifacts_expire_at, as: :expire_at
expose :path do |job| expose :name do |artifact|
fast_download_project_job_artifacts_path(project, job) "#{artifact.job.name}:#{artifact.file_type}"
end end
expose :keep_path, if: -> (*) { job.has_expiring_archive_artifacts? } do |job| expose :expire_at
fast_keep_project_job_artifacts_path(project, job) expose :expired?, as: :expired
end
expose :browse_path do |job| expose :path do |artifact|
fast_browse_project_job_artifacts_path(project, job) fast_download_project_job_artifacts_path(
artifact.project,
artifact.job,
file_type: artifact.file_type
)
end end
private expose :keep_path, if: -> (*) { artifact.expiring? } do |artifact|
fast_keep_project_job_artifacts_path(artifact.project, artifact.job)
alias_method :job, :object end
def project expose :browse_path do |artifact|
job.project fast_browse_project_job_artifacts_path(artifact.project, artifact.job)
end end
end end
...@@ -9,8 +9,7 @@ class PipelineDetailsEntity < PipelineEntity ...@@ -9,8 +9,7 @@ class PipelineDetailsEntity < PipelineEntity
expose :details do expose :details do
expose :artifacts do |pipeline, options| expose :artifacts do |pipeline, options|
rel = pipeline.artifacts rel = pipeline.downloadable_artifacts
rel = rel.eager_load_job_artifacts_archive if options.fetch(:preload_job_artifacts_archive, true)
BuildArtifactEntity.represent(rel, options) BuildArtifactEntity.represent(rel, options)
end end
......
...@@ -7,10 +7,6 @@ class PipelineSerializer < BaseSerializer ...@@ -7,10 +7,6 @@ class PipelineSerializer < BaseSerializer
# rubocop: disable CodeReuse/ActiveRecord # rubocop: disable CodeReuse/ActiveRecord
def represent(resource, opts = {}) def represent(resource, opts = {})
if resource.is_a?(ActiveRecord::Relation) if resource.is_a?(ActiveRecord::Relation)
# We don't want PipelineDetailsEntity to preload the job_artifacts_archive
# because we do it with preloaded_relations in a more optimal way
# if the given resource is a collection of multiple pipelines.
opts[:preload_job_artifacts_archive] = false
resource = resource.preload(preloaded_relations) resource = resource.preload(preloaded_relations)
end end
...@@ -44,35 +40,29 @@ class PipelineSerializer < BaseSerializer ...@@ -44,35 +40,29 @@ class PipelineSerializer < BaseSerializer
def preloaded_relations def preloaded_relations
[ [
:latest_statuses_ordered_by_stage,
:project,
:stages,
{
failed_builds: %i(project metadata)
},
:retryable_builds,
:cancelable_statuses, :cancelable_statuses,
:trigger_requests, :latest_statuses_ordered_by_stage,
:manual_actions, :manual_actions,
:retryable_builds,
:scheduled_actions, :scheduled_actions,
:artifacts, :stages,
:trigger_requests,
:user, :user,
{ {
downloadable_artifacts: {
project: [:route, { namespace: :route }],
job: []
},
failed_builds: %i(project metadata),
merge_request: { merge_request: {
source_project: [:route, { namespace: :route }], source_project: [:route, { namespace: :route }],
target_project: [:route, { namespace: :route }] target_project: [:route, { namespace: :route }]
} },
},
{
pending_builds: :project, pending_builds: :project,
project: [:route, { namespace: :route }], project: [:route, { namespace: :route }],
artifacts: { triggered_by_pipeline: [:project, :user],
project: [:route, { namespace: :route }], triggered_pipelines: [:project, :user]
job_artifacts_archive: [] }
}
},
{ triggered_by_pipeline: [:project, :user] },
{ triggered_pipelines: [:project, :user] }
] ]
end end
end end
---
title: Fix 404 when downloading a non-archive artifact
merge_request: 32811
author:
type: fixed
...@@ -20,7 +20,6 @@ module EE ...@@ -20,7 +20,6 @@ module EE
SECRET_DETECTION_REPORT_TYPES = %w[secret_detection].freeze SECRET_DETECTION_REPORT_TYPES = %w[secret_detection].freeze
DAST_REPORT_TYPES = %w[dast].freeze DAST_REPORT_TYPES = %w[dast].freeze
scope :not_expired, -> { where('expire_at IS NULL OR expire_at > ?', Time.current) }
scope :project_id_in, ->(ids) { where(project_id: ids) } scope :project_id_in, ->(ids) { where(project_id: ids) }
scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) } scope :with_files_stored_remotely, -> { where(file_store: ::JobArtifactUploader::Store::REMOTE) }
......
...@@ -14,7 +14,6 @@ module EE ...@@ -14,7 +14,6 @@ module EE
prepended do prepended do
include UsageStatistics include UsageStatistics
has_many :job_artifacts, through: :builds
has_many :vulnerabilities_occurrence_pipelines, class_name: 'Vulnerabilities::OccurrencePipeline' has_many :vulnerabilities_occurrence_pipelines, class_name: 'Vulnerabilities::OccurrencePipeline'
has_many :vulnerability_findings, source: :occurrence, through: :vulnerabilities_occurrence_pipelines, class_name: 'Vulnerabilities::Occurrence' has_many :vulnerability_findings, source: :occurrence, through: :vulnerabilities_occurrence_pipelines, class_name: 'Vulnerabilities::Occurrence'
...@@ -29,7 +28,7 @@ module EE ...@@ -29,7 +28,7 @@ module EE
# Legacy way to fetch security reports based on job name. This has been replaced by the reports feature. # Legacy way to fetch security reports based on job name. This has been replaced by the reports feature.
scope :with_legacy_security_reports, -> do scope :with_legacy_security_reports, -> do
joins(:artifacts).where(ci_builds: { name: %w[sast secret_detection dependency_scanning sast:container container_scanning dast] }) joins(:downloadable_artifacts).where(ci_builds: { name: %w[sast secret_detection dependency_scanning sast:container container_scanning dast] })
end end
scope :with_vulnerabilities, -> do scope :with_vulnerabilities, -> do
...@@ -199,10 +198,6 @@ module EE ...@@ -199,10 +198,6 @@ module EE
feature_names = REPORT_LICENSED_FEATURES.fetch(file_type) feature_names = REPORT_LICENSED_FEATURES.fetch(file_type)
feature_names.nil? || feature_names.any? { |feature| project.feature_available?(feature) } feature_names.nil? || feature_names.any? { |feature| project.feature_available?(feature) }
end end
def artifacts_with_files
@artifacts_with_files ||= artifacts.includes(:job_artifacts_metadata, :job_artifacts_archive).to_a
end
end end
end end
end end
...@@ -14,7 +14,6 @@ RSpec.describe Ci::Pipeline do ...@@ -14,7 +14,6 @@ RSpec.describe Ci::Pipeline do
it { is_expected.to have_many(:security_scans).through(:builds).class_name('Security::Scan') } it { is_expected.to have_many(:security_scans).through(:builds).class_name('Security::Scan') }
it { is_expected.to have_many(:downstream_bridges) } it { is_expected.to have_many(:downstream_bridges) }
it { is_expected.to have_many(:job_artifacts).through(:builds) }
it { is_expected.to have_many(:vulnerability_findings).through(:vulnerabilities_occurrence_pipelines).class_name('Vulnerabilities::Occurrence') } it { is_expected.to have_many(:vulnerability_findings).through(:vulnerabilities_occurrence_pipelines).class_name('Vulnerabilities::Occurrence') }
it { is_expected.to have_many(:vulnerabilities_occurrence_pipelines).class_name('Vulnerabilities::OccurrencePipeline') } it { is_expected.to have_many(:vulnerabilities_occurrence_pipelines).class_name('Vulnerabilities::OccurrencePipeline') }
......
...@@ -453,10 +453,12 @@ RSpec.describe 'Pipelines', :js do ...@@ -453,10 +453,12 @@ RSpec.describe 'Pipelines', :js do
context 'downloadable pipelines' do context 'downloadable pipelines' do
context 'with artifacts' do context 'with artifacts' do
let!(:with_artifacts) do let!(:with_artifacts) do
create(:ci_build, :artifacts, :success, build = create(:ci_build, :success,
pipeline: pipeline, pipeline: pipeline,
name: 'rspec tests', name: 'rspec tests',
stage: 'test') stage: 'test')
create(:ci_job_artifact, :codequality, job: build)
end end
before do before do
...@@ -470,7 +472,7 @@ RSpec.describe 'Pipelines', :js do ...@@ -470,7 +472,7 @@ RSpec.describe 'Pipelines', :js do
it 'has artifacts download dropdown' do it 'has artifacts download dropdown' do
find('.js-pipeline-dropdown-download').click find('.js-pipeline-dropdown-download').click
expect(page).to have_link(with_artifacts.name) expect(page).to have_link(with_artifacts.file_type)
end end
it 'has download attribute on download links' do it 'has download attribute on download links' do
......
...@@ -121,6 +121,16 @@ describe GitlabRoutingHelper do ...@@ -121,6 +121,16 @@ describe GitlabRoutingHelper do
it 'matches the Rails download path' do it 'matches the Rails download path' do
expect(fast_download_project_job_artifacts_path(project, job)).to eq(download_project_job_artifacts_path(project, job)) expect(fast_download_project_job_artifacts_path(project, job)).to eq(download_project_job_artifacts_path(project, job))
end end
context 'when given parameters' do
it 'adds them to the path' do
expect(
fast_download_project_job_artifacts_path(project, job, file_type: :dast)
).to eq(
download_project_job_artifacts_path(project, job, file_type: :dast)
)
end
end
end end
describe '#fast_keep_project_job_artifacts_path' do describe '#fast_keep_project_job_artifacts_path' do
......
...@@ -195,7 +195,7 @@ ci_pipelines: ...@@ -195,7 +195,7 @@ ci_pipelines:
- cancelable_statuses - cancelable_statuses
- manual_actions - manual_actions
- scheduled_actions - scheduled_actions
- artifacts - downloadable_artifacts
- pipeline_schedule - pipeline_schedule
- merge_requests_as_head_pipeline - merge_requests_as_head_pipeline
- merge_request - merge_request
...@@ -220,6 +220,7 @@ ci_pipelines: ...@@ -220,6 +220,7 @@ ci_pipelines:
- pipeline_config - pipeline_config
- security_scans - security_scans
- daily_build_group_report_results - daily_build_group_report_results
- latest_builds
pipeline_variables: pipeline_variables:
- pipeline - pipeline
stages: stages:
......
...@@ -23,6 +23,14 @@ describe Ci::JobArtifact do ...@@ -23,6 +23,14 @@ describe Ci::JobArtifact do
subject { build(:ci_job_artifact, :archive, size: 107464) } subject { build(:ci_job_artifact, :archive, size: 107464) }
end end
describe '.not_expired' do
it 'returns artifacts that have not expired' do
_expired_artifact = create(:ci_job_artifact, :expired)
expect(described_class.not_expired).to contain_exactly(artifact)
end
end
describe '.with_reports' do describe '.with_reports' do
let!(:artifact) { create(:ci_job_artifact, :archive) } let!(:artifact) { create(:ci_job_artifact, :archive) }
...@@ -118,6 +126,17 @@ describe Ci::JobArtifact do ...@@ -118,6 +126,17 @@ describe Ci::JobArtifact do
end end
end end
describe '.downloadable' do
subject { described_class.downloadable }
it 'filters for downloadable artifacts' do
downloadable_artifact = create(:ci_job_artifact, :codequality)
_not_downloadable_artifact = create(:ci_job_artifact, :trace)
expect(subject).to contain_exactly(downloadable_artifact)
end
end
describe '.archived_trace_exists_for?' do describe '.archived_trace_exists_for?' do
subject { described_class.archived_trace_exists_for?(job_id) } subject { described_class.archived_trace_exists_for?(job_id) }
...@@ -357,6 +376,62 @@ describe Ci::JobArtifact do ...@@ -357,6 +376,62 @@ describe Ci::JobArtifact do
end end
end end
describe 'expired?' do
subject { artifact.expired? }
context 'when expire_at is nil' do
let(:artifact) { build(:ci_job_artifact, expire_at: nil) }
it 'returns false' do
is_expected.to be_falsy
end
end
context 'when expire_at is in the past' do
let(:artifact) { build(:ci_job_artifact, expire_at: Date.yesterday) }
it 'returns true' do
is_expected.to be_truthy
end
end
context 'when expire_at is in the future' do
let(:artifact) { build(:ci_job_artifact, expire_at: Date.tomorrow) }
it 'returns false' do
is_expected.to be_falsey
end
end
end
describe '#expiring?' do
subject { artifact.expiring? }
context 'when expire_at is nil' do
let(:artifact) { build(:ci_job_artifact, expire_at: nil) }
it 'returns false' do
is_expected.to be_falsy
end
end
context 'when expire_at is in the past' do
let(:artifact) { build(:ci_job_artifact, expire_at: Date.yesterday) }
it 'returns false' do
is_expected.to be_falsy
end
end
context 'when expire_at is in the future' do
let(:artifact) { build(:ci_job_artifact, expire_at: Date.tomorrow) }
it 'returns true' do
is_expected.to be_truthy
end
end
end
describe '#expire_in' do describe '#expire_in' do
subject { artifact.expire_in } subject { artifact.expire_in }
......
...@@ -26,6 +26,7 @@ describe Ci::Pipeline, :mailer do ...@@ -26,6 +26,7 @@ describe Ci::Pipeline, :mailer do
it { is_expected.to have_many(:trigger_requests) } it { is_expected.to have_many(:trigger_requests) }
it { is_expected.to have_many(:variables) } it { is_expected.to have_many(:variables) }
it { is_expected.to have_many(:builds) } it { is_expected.to have_many(:builds) }
it { is_expected.to have_many(:job_artifacts).through(:builds) }
it { is_expected.to have_many(:auto_canceled_pipelines) } it { is_expected.to have_many(:auto_canceled_pipelines) }
it { is_expected.to have_many(:auto_canceled_jobs) } it { is_expected.to have_many(:auto_canceled_jobs) }
it { is_expected.to have_many(:sourced_pipelines) } it { is_expected.to have_many(:sourced_pipelines) }
...@@ -51,6 +52,27 @@ describe Ci::Pipeline, :mailer do ...@@ -51,6 +52,27 @@ describe Ci::Pipeline, :mailer do
expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project) expect(Project.reflect_on_association(:all_pipelines).has_inverse?).to eq(:project)
expect(Project.reflect_on_association(:ci_pipelines).has_inverse?).to eq(:project) expect(Project.reflect_on_association(:ci_pipelines).has_inverse?).to eq(:project)
end end
describe '#latest_builds' do
it 'has a one to many relationship with its latest builds' do
_old_build = create(:ci_build, :retried, pipeline: pipeline)
latest_build = create(:ci_build, :expired, pipeline: pipeline)
expect(pipeline.latest_builds).to contain_exactly(latest_build)
end
end
describe '#downloadable_artifacts' do
let(:build) { create(:ci_build, pipeline: pipeline) }
it 'returns downloadable artifacts that have not expired' do
downloadable_artifact = create(:ci_job_artifact, :codequality, job: build)
_expired_artifact = create(:ci_job_artifact, :junit, :expired, job: build)
_undownloadable_artifact = create(:ci_job_artifact, :trace, job: build)
expect(pipeline.downloadable_artifacts).to contain_exactly(downloadable_artifact)
end
end
end end
describe '#set_status' do describe '#set_status' do
......
...@@ -3,17 +3,18 @@ ...@@ -3,17 +3,18 @@
require 'spec_helper' require 'spec_helper'
describe BuildArtifactEntity do describe BuildArtifactEntity do
let(:job) { create(:ci_build, :artifacts, name: 'test:job', artifacts_expire_at: 1.hour.from_now) } let(:job) { create(:ci_build) }
let(:artifact) { create(:ci_job_artifact, :codequality, expire_at: 1.hour.from_now, job: job) }
let(:entity) do let(:entity) do
described_class.new(job, request: double) described_class.new(artifact, request: double)
end end
describe '#as_json' do describe '#as_json' do
subject { entity.as_json } subject { entity.as_json }
it 'contains job name' do it 'contains job name' do
expect(subject[:name]).to eq 'test:job' expect(subject[:name]).to eq "test:codequality"
end end
it 'exposes information about expiration of artifacts' do it 'exposes information about expiration of artifacts' do
...@@ -22,7 +23,7 @@ describe BuildArtifactEntity do ...@@ -22,7 +23,7 @@ describe BuildArtifactEntity do
it 'contains paths to the artifacts' do it 'contains paths to the artifacts' do
expect(subject[:path]) expect(subject[:path])
.to include "jobs/#{job.id}/artifacts/download" .to include "jobs/#{job.id}/artifacts/download?file_type=codequality"
expect(subject[:keep_path]) expect(subject[:keep_path])
.to include "jobs/#{job.id}/artifacts/keep" .to include "jobs/#{job.id}/artifacts/keep"
......
...@@ -173,44 +173,5 @@ describe PipelineDetailsEntity do ...@@ -173,44 +173,5 @@ describe PipelineDetailsEntity do
expect(subject[:triggered].first[:project]).not_to be_nil expect(subject[:triggered].first[:project]).not_to be_nil
end end
end end
context 'when pipeline has expiring archive artifacts' do
let(:pipeline) { create(:ci_empty_pipeline) }
let!(:build_1) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_1') }
let!(:build_2) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_2') }
let!(:build_3) { create(:ci_build, :artifacts, pipeline: pipeline, artifacts_expire_at: 2.days.from_now, name: 'build_3') }
let(:names) { subject[:details][:artifacts].map { |a| a[:name] } }
context 'and preload_job_artifacts_archive is not defined in the options' do
it 'defaults to true and eager loads the job_artifacts_archive' do
recorder = ActiveRecord::QueryRecorder.new do
expect(names).to match_array(%w[build_1 build_2 build_3])
end
expected_queries = Gitlab.ee? ? 42 : 29
# This makes only one query to fetch all job artifacts
expect(recorder.count).to eq(expected_queries)
end
end
context 'and preload_job_artifacts_archive is set to false' do
let(:entity) do
described_class.represent(pipeline, request: request, preload_job_artifacts_archive: false)
end
it 'does not eager load the job_artifacts_archive' do
recorder = ActiveRecord::QueryRecorder.new do
expect(names).to match_array(%w[build_1 build_2 build_3])
end
expected_queries = Gitlab.ee? ? 44 : 31
# This makes one query for each job artifact
expect(recorder.count).to eq(expected_queries)
end
end
end
end end
end end
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