Squashed commit of the following:

commit c35ca6594eb1d29cac46362d09036f3d128143ed
Merge: 87da74fb98a 13ea4b387d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 27 13:25:22 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 87da74fb98aef1f664553ca2b8406ca154e4c19f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 20:27:45 2018 +0900

    Remove unncessary GENERAL_ARCHIVE_FILE_TYPE

commit 5a3cfc1fdc8e81dd5647e275f87c0da2d93235b4
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 20:19:44 2018 +0900

    Expand  entities in JobRequest::Artifacts

commit 660f885ebb25a19182e601181050683d2b6134f6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 20:06:14 2018 +0900

    Add tests

commit 60bca3dcfd055647a9f43523b79d5eebdc4bdc5a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 19:30:52 2018 +0900

    Simplify build runner presenter

commit 81d1951d5562bec4086d719748360f3f24df4168
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 19:18:53 2018 +0900

    Simplify `scope :test_reports` in job_artifacts

commit 15d1d76ca1cb97501c82471eb1c927290071dcfb
Merge: f3327b2912d ffbfd18ce2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 19:01:53 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit f3327b2912d0b169e7a059dca7b4d15e77567075
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 26 19:01:44 2018 +0900

    Fix "or string" to "or a string". Use be_valid

commit 9aaae6d60f7537f55f862f4d61de7a0d3a3b6bc2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 21:25:57 2018 +0900

    Fix spec file name - build_runner_presenter_spec.rb

commit 41c64c190e2e2efa7ab91a0daa0598da2d755f05
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 21:18:12 2018 +0900

    Rename to Ci::BuildRunnerPresenter

commit e9762299eb66c8f88734f80d05d38b9616a8fde8
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 21:14:44 2018 +0900

    Split methods into three in Ci::Builds::RunnerPresenter

commit 6e73070313a782eb63d4fbcbe324d9acaf67334b
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 20:23:53 2018 +0900

    Remove redandant as: :artifacts

commit 063f647e4829d9c71a71d227f9946bb47b93691f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 20:04:58 2018 +0900

    Fix specs

commit a45975afd9b9391390c1adafbeab72c970e97b64
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 18:18:53 2018 +0900

    Created a separate presenter

commit 431ad666e080124c90e13cbaf0d4f0969aa7b2f2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 18:10:04 2018 +0900

    Simplified config presenter

commit 2e106569ea258f5f7556a8b454a6dd0e9cbe6902
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 17:25:05 2018 +0900

    Skip file_format setting if the file_type is trace

commit 0572bd8357a2e9ea16118a0bd85264e3fb799322
Merge: 30ae33daa1d 6cb30f8325
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 17:13:55 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 30ae33daa1d4afcb57e6335fba62a3c5fc98468a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 25 17:13:23 2018 +0900

    Fix spec

commit ccb6eb75187030ff0fd3c6e69f89eeca79d2a929
Merge: 1ebaaaf2094 34c57e09b9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Tue Jul 24 14:27:48 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 1ebaaaf2094c47c03e16745d2f8af736ec102b76
Merge: bfdf565800b dc7b4b7bb9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 23 14:22:29 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit bfdf565800b58e838a760aa01d2fadb64e2d768f
Merge: 681bd6a878a 44dbeccbe1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 19:10:47 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit 681bd6a878ad2a77c278f5619b51c542d7382aa2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:19:46 2018 +0900

    Specify DOWNTIME=false

commit 59c4e31390e0d616d69babf8ac857e98f2dc774e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:14:44 2018 +0900

    Wrap long lines

commit 3d85788edbe73fc74c72854508e47fe259d99236
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 18:05:31 2018 +0900

    Checking filr_format and file_type paring

commit 3c92a22faf6278e7a2d1ee13bd978bc659b72452
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:07:21 2018 +0900

    Fix build presenter spec

commit 36e69897b0524cdee6060c928c03af734afae664
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 16:02:09 2018 +0900

    Erase test reports at the proper timing

commit 402ae97ecf7f9e3fe541f2d6abef6e47ab740452
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:46:56 2018 +0900

    Make GENERAL_ARCHIVE_FILE_TYPE as a single entry

commit 75f75b3f5988398fff0660ca5f04aec756ab03bb
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 15:42:16 2018 +0900

    Implement config artifact presenter

commit 9ecaee914defba5f12a7a06375ea2876b4328d7f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 14:27:54 2018 +0900

    Introduce ARCHIVE_LEGACY_TRACES_MIGRATION_VERSION check

commit 34ea9610ab9a249a576ee435f365b9e1fcca7f00
Merge: d88523ca884 b60364c0f3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 20 13:46:52 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit d88523ca88420354f61bd36f533c62a6ca474423
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 21:00:40 2018 +0900

    Revert unnecessary change

commit d9beb10ede5e4e8abe388fadbd6412640293917a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:57:03 2018 +0900

    Remove scattering around erase_test_reports!

commit c79f361ca01f8dbc0d395edee5fab7f5a0697934
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:53:00 2018 +0900

    Rever archive_metadata refactoring  (For simplifying)

commit 55bc71a404d8cf5fa87e187f6e88da92ab95afa9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:45:19 2018 +0900

    Use array_of_strings_or_string in Command

commit 8a576b18c8ab8ead2344e2885aaf2fde11af0328
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 20:40:06 2018 +0900

    Fix spec

commit a2cda62fb922184aaf0e78699e06846c96565e0d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:27:11 2018 +0900

    Fix presenter spec

commit 95502e605af9bcf1a61dbeb26f9be4d181f8a7ba
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:23:41 2018 +0900

    Fix artifact migratable

commit a3930853c93862007ba6814511bc32042c7f4986
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 18:15:41 2018 +0900

    Increment migration version to use `file_format` when archiving traces

commit e31121cb5e617b0f05e375c2150ece0e38e5e0d6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 17:57:15 2018 +0900

    Impolement job_artifact.test_reports method

commit e54707fdf97392839cb2c4711160bd3bc89da196
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:49:27 2018 +0900

    Fix erase method

commit 20e95824341af1ebc5877d28dc5eba26f73eddf9
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 16:28:00 2018 +0900

    Fix spec

commit 7ade498101d02573b20a2405ebe0bdb8efd8aa3b
Merge: e7be6b2b362 98eccfc44c
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 19 12:37:22 2018 +0900

    Merge branch 'master-ce' into artifact-format-v2

commit e7be6b2b3624ba44d56143084731cb9a6168f974
Merge: 5a8d4930e01 9bdc9b1ae6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:43:36 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 5a8d4930e0127aae311bfa3da70d9ab9637791e3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 18 15:43:28 2018 +0900

    Evaluate artifact_format

commit c3ce06aa9bc6481b37a16d175adf0fd1c37a1bc0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 22:27:46 2018 +0900

    Fix sending junit.xml

commit e5ce3668ee65217aba610d5311efd5e82bacddf3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 19:02:06 2018 +0900

    Add spec for Gitlab::Ci::Config::Entry::Artifacts

commit ede107caf13fb215045576dcce18e20eec776df1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:58:28 2018 +0900

    Revert refactoring

commit 15531ba9feff669b2ac05936e0feaee1856c1571
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:57:31 2018 +0900

    Revert refactoring

commit 14821f3babcc210bc52e4e825adc8333752fbc88
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:55:41 2018 +0900

    Add spec for file format. Add spec for config_artifacts

commit 882faeab57ab39d18f72abd9b65d286db92e1011
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:20:28 2018 +0900

    Add file_format to factory

commit 3cd0513e254db15141cd748f6209179f462974f2
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:12:52 2018 +0900

    Rename migration file properly

commit f511933b5f618fc47d1512554878913922dfba61
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 17:09:57 2018 +0900

    Revert artifacts_archive_file refactoring

commit e295e8cbdee065ee3af6dd82f512729554237cad
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 16:03:26 2018 +0900

    Dry up the converion in Entry::Reports

commit b0ffa42f6410be4718e7a36cb21f7b585421750e
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:50:42 2018 +0900

    Set file_format at callers

commit f3dc7a2e02901c79a9e572514a1b731c680e43cc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 15:47:51 2018 +0900

    Use presenter for presenting artifacts hash to runner

commit e5299526138be90d65cf13368134e734b46f7597
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:59:09 2018 +0900

    Support deleting junit artifact. Make wording explicit

commit cc81c34acf23323257d190c23030d0a89265bccc
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 14:35:12 2018 +0900

    Add changelog

commit abde0f2ab5c5c1d99b2f94a049984877bb5a4d77
Merge: 4c87e5b388f fabf6a5634
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Mon Jul 16 13:22:22 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 4c87e5b388fb098fb6da71e17a47fa204033e4ac
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 17:33:07 2018 +0900

    Fix static analysis

commit bc96346be6990b75da9a36055814b24b5b805707
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 16:43:02 2018 +0900

    Fix Config::Entry::Artifacts

commit aac284613b9db43e3021198dc5b43b81806f1bce
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 14:40:20 2018 +0900

    Generalized by DEFAULT_FILE_FORMAT

commit a79299fdbb0ed74000ca37cff8fef8268cd29b13
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:55:02 2018 +0900

    Cleanup API::Entities::JobRequest::Artifacts

commit 1650249214768c23f6f46ec62c0c54448017eeb5
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:25:52 2018 +0900

    Simplified file_type relations

commit 981da91bc4c255ff992870e4e4c4393696f5bece
Merge: e79808425eb 924146a8d6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 13 13:18:20 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit e79808425eb63c322a997e71d606d97b85e42048
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 18:16:52 2018 +0900

    Remove unnecessary change

commit a531bd7487955143489d286a0fb2e5d0984acc52
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 17:40:35 2018 +0900

    Fix errors typo

commit 57d6f21821c8ad934874c1aac3f627335c64c80d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:32:35 2018 +0900

    Use the correct type name

commit da4ca63f25a27a1268317952061c81a28516653f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:29:21 2018 +0900

    Refactor job_artifacts_metadata to job_artifacts_archive_metadata

commit 4098a8f10f92a6efa48080f8925809e251066f9d
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:23:55 2018 +0900

    Add job_artifacts_junit relation

commit 5342f07e100253713dbf50eb303da1977484077f
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:14:03 2018 +0900

    Fix raw to raw?

commit 15e0abcb22d9db3d8ef955e647f0a5d0a49c26b6
Merge: 31252fe8d75 ba38931d90
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 12 13:12:38 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 31252fe8d751319c5390f898f66f0af4a8581013
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 19:05:51 2018 +0900

    Temporaly use type Hash for reports

commit 583165c0349f40e7be16a8039dbffb4139f94921
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:27:21 2018 +0900

    Revert unnecessary change

commit eb48369b8311b538f46f59a31f4a6d3f8c9e68e1
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:21:46 2018 +0900

    Use file_format raw for trace

commit fb69ae8349d58499ad21965c0d1cf95e2b79a8e3
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:20:10 2018 +0900

    Check the presence of the file_format

commit c0840224bc8789d35da032c2a0ee48aa9f2232aa
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:16:19 2018 +0900

    Add format_restriction validation

commit d64fbd388cb2294447df5185366d8b5016591949
Merge: 7ec81e7c7d1 c2a0a3ab1a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Wed Jul 11 15:11:44 2018 +0900

    Merge branch 'master' into artifact-format-v2

commit 7ec81e7c7d115f77d712892dfc79db72b9f5bc7a
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:23:54 2018 +0900

    Artifacts presenter (Halfway)

commit a3ccbe4c3a9b7d3095fe1929dee5fd9c57e168e0
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 20:22:52 2018 +0900

    Fix schema.rb

commit b630c670c707548799c6852e4465ef94fb4a0572
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:26:03 2018 +0900

    Allow reports type under artifacts. Allow junit keyword in it.

commit e7e37612487b556320d27f4fe0de32cd4ec20720
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 19:25:10 2018 +0900

    Change column name to artifact_format

commit f3f25d56a7c627f4bb9d91d19de175273a7a6a81
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 18:02:21 2018 +0900

    Rename metadata to archive_metadata, and compress to file_format

commit d7e0709319ab8fe35a2598a3d484eb89b1885934
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Fri Jul 6 17:47:18 2018 +0900

    Validate compression. Clean up schema

commit beb5990e7e3bfbb308245dc97284aaf9700bd982
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 19:06:54 2018 +0900

    Make compression params at the first level

commit 1e2e1c0db5412e1aed3bf47562350c20c69dc1a6
Author: Shinya Maeda <shinya@gitlab.com>
Date:   Thu Jul 5 16:31:03 2018 +0900

    Reorganize components
This commit is contained in:
Shinya Maeda 2018-07-27 14:04:35 +09:00
parent 13ea4b387d
commit 3703cc4bbb
26 changed files with 505 additions and 38 deletions

View File

@ -22,9 +22,10 @@ module Ci
has_many :trace_chunks, class_name: 'Ci::BuildTraceChunk', foreign_key: :build_id
has_many :job_artifacts, class_name: 'Ci::JobArtifact', foreign_key: :job_id, dependent: :destroy, inverse_of: :job # rubocop:disable Cop/ActiveRecordDependent
has_one :job_artifacts_archive, -> { where(file_type: Ci::JobArtifact.file_types[:archive]) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
has_one :job_artifacts_metadata, -> { where(file_type: Ci::JobArtifact.file_types[:metadata]) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
has_one :job_artifacts_trace, -> { where(file_type: Ci::JobArtifact.file_types[:trace]) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
Ci::JobArtifact.file_types.each do |key, value|
has_one :"job_artifacts_#{key}", -> { where(file_type: value) }, class_name: 'Ci::JobArtifact', inverse_of: :job, foreign_key: :job_id
end
has_one :metadata, class_name: 'Ci::BuildMetadata'
has_one :runner_session, class_name: 'Ci::BuildRunnerSession', validate: true, inverse_of: :build
@ -386,6 +387,10 @@ module Ci
trace.exist?
end
def has_test_reports?
job_artifacts.test_reports.any?
end
def has_old_trace?
old_trace.present?
end
@ -453,16 +458,21 @@ module Ci
save
end
def erase_test_reports!
job_artifacts.test_reports.destroy_all
end
def erase(opts = {})
return false unless erasable?
erase_artifacts!
erase_test_reports!
erase_trace!
update_erased!(opts[:erased_by])
end
def erasable?
complete? && (artifacts? || has_trace?)
complete? && (artifacts? || has_test_reports? || has_trace?)
end
def erased?
@ -539,10 +549,6 @@ module Ci
Gitlab::Ci::Build::Image.from_services(self)
end
def artifacts
[options[:artifacts]]
end
def cache
cache = options[:cache]

View File

@ -4,11 +4,17 @@ module Ci
include ObjectStorage::BackgroundMove
extend Gitlab::Ci::Model
TEST_REPORT_FILE_TYPES = %w[junit].freeze
DEFAULT_FILE_NAMES = { junit: 'junit.xml' }.freeze
TYPE_AND_FORMAT_PAIRS = { archive: :zip, metadata: :gzip, trace: :raw, junit: :gzip }.freeze
belongs_to :project
belongs_to :job, class_name: "Ci::Build", foreign_key: :job_id
mount_uploader :file, JobArtifactUploader
validates :file_format, presence: true, unless: :trace?, on: :create
validate :valid_file_format?, unless: :trace?, on: :create
before_save :set_size, if: :file_changed?
after_save :update_project_statistics_after_save, if: :size_changed?
after_destroy :update_project_statistics_after_destroy, unless: :project_destroyed?
@ -17,14 +23,33 @@ module Ci
scope :with_files_stored_locally, -> { where(file_store: [nil, ::JobArtifactUploader::Store::LOCAL]) }
scope :test_reports, -> do
types = self.file_types.select { |file_type| TEST_REPORT_FILE_TYPES.include?(file_type) }.values
where(file_type: types)
end
delegate :exists?, :open, to: :file
enum file_type: {
archive: 1,
metadata: 2,
trace: 3
trace: 3,
junit: 4
}
enum file_format: {
raw: 1,
zip: 2,
gzip: 3
}
def valid_file_format?
unless TYPE_AND_FORMAT_PAIRS[self.file_type&.to_sym] == self.file_format&.to_sym
errors.add(:file_format, 'Invalid file format with specified file type')
end
end
def update_file_store
# The file.object_store is set during `uploader.store!`
# which happens after object is inserted/updated

View File

@ -0,0 +1,43 @@
module Ci
class BuildRunnerPresenter < SimpleDelegator
def artifacts
return unless options[:artifacts]
list = []
list << create_archive(options[:artifacts])
list << create_reports(options[:artifacts][:reports], expire_in: options[:artifacts][:expire_in])
list.flatten.compact
end
private
def create_archive(artifacts)
return unless artifacts[:untracked] || artifacts[:paths]
{
artifact_type: :archive,
artifact_format: :zip,
name: artifacts[:name],
untracked: artifacts[:untracked],
paths: artifacts[:paths],
when: artifacts[:when],
expire_in: artifacts[:expire_in]
}
end
def create_reports(reports, expire_in:)
return unless reports&.any?
reports.map do |k, v|
{
artifact_type: k.to_sym,
artifact_format: :gzip,
name: ::Ci::JobArtifact::DEFAULT_FILE_NAMES[k.to_sym],
paths: v,
when: 'always',
expire_in: expire_in
}
end
end
end
end

View File

@ -0,0 +1,5 @@
---
title: Extend gitlab-ci.yml to request junit.xml test reports
merge_request: 20390
author:
type: added

View File

@ -0,0 +1,7 @@
class AddFileFormatToCiJobArtifacts < ActiveRecord::Migration
DOWNTIME = false
def change
add_column :ci_job_artifacts, :file_format, :integer, limit: 2
end
end

View File

@ -393,6 +393,7 @@ ActiveRecord::Schema.define(version: 20180722103201) do
t.datetime_with_timezone "expire_at"
t.string "file"
t.binary "file_sha256"
t.integer "file_format", limit: 2
end
add_index "ci_job_artifacts", ["expire_at", "job_id"], name: "index_ci_job_artifacts_on_expire_at_and_job_id", using: :btree

View File

@ -1236,7 +1236,13 @@ module API
end
class Artifacts < Grape::Entity
expose :name, :untracked, :paths, :when, :expire_in
expose :name
expose :untracked
expose :paths
expose :when
expose :expire_in
expose :artifact_type
expose :artifact_format
end
class Cache < Grape::Entity

View File

@ -109,7 +109,7 @@ module API
if result.valid?
if result.build
Gitlab::Metrics.add_event(:build_found)
present result.build, with: Entities::JobRequest::Response
present Ci::BuildRunnerPresenter.new(result.build), with: Entities::JobRequest::Response
else
Gitlab::Metrics.add_event(:build_not_found)
header 'X-GitLab-Last-Update', new_update
@ -231,6 +231,10 @@ module API
requires :id, type: Integer, desc: %q(Job's ID)
optional :token, type: String, desc: %q(Job's authentication token)
optional :expire_in, type: String, desc: %q(Specify when artifacts should expire)
optional :artifact_type, type: String, desc: %q(The type of artifact),
default: 'archive', values: Ci::JobArtifact.file_types.keys
optional :artifact_format, type: String, desc: %q(The format of artifact),
default: 'zip', values: Ci::JobArtifact.file_formats.keys
optional 'file.path', type: String, desc: %q(path to locally stored body (generated by Workhorse))
optional 'file.name', type: String, desc: %q(real filename as send in Content-Disposition (generated by Workhorse))
optional 'file.type', type: String, desc: %q(real content type as send in Content-Type (generated by Workhorse))
@ -254,29 +258,29 @@ module API
bad_request!('Missing artifacts file!') unless artifacts
file_to_large! unless artifacts.size < max_artifacts_size
bad_request!("Already uploaded") if job.job_artifacts_archive
expire_in = params['expire_in'] ||
Gitlab::CurrentSettings.current_application_settings.default_artifacts_expire_in
job.build_job_artifacts_archive(
job.job_artifacts.build(
project: job.project,
file: artifacts,
file_type: :archive,
file_type: params['artifact_type'],
file_format: params['artifact_format'],
file_sha256: artifacts.sha256,
expire_in: expire_in)
if metadata
job.build_job_artifacts_metadata(
job.job_artifacts.build(
project: job.project,
file: metadata,
file_type: :metadata,
file_format: :gzip,
file_sha256: metadata.sha256,
expire_in: expire_in)
end
if job.update(artifacts_expire_in: expire_in)
present job, with: Entities::JobRequest::Response
present Ci::BuildRunnerPresenter.new(job), with: Entities::JobRequest::Response
else
render_validation_error!(job)
end

View File

@ -6,13 +6,16 @@ module Gitlab
# Entry that represents a configuration of job artifacts.
#
class Artifacts < Node
include Configurable
include Validatable
include Attributable
ALLOWED_KEYS = %i[name untracked paths when expire_in].freeze
ALLOWED_KEYS = %i[name untracked paths reports when expire_in].freeze
attributes ALLOWED_KEYS
entry :reports, Entry::Reports, description: 'Report-type artifacts.'
validations do
validates :config, type: Hash
validates :config, allowed_keys: ALLOWED_KEYS
@ -21,6 +24,7 @@ module Gitlab
validates :name, type: String
validates :untracked, boolean: true
validates :paths, array_of_strings: true
validates :reports, type: Hash
validates :when,
inclusion: { in: %w[on_success on_failure always],
message: 'should be on_success, on_failure ' \
@ -28,6 +32,13 @@ module Gitlab
validates :expire_in, duration: true
end
end
helpers :reports
def value
@config[:reports] = reports_value if @config.key?(:reports)
@config
end
end
end
end

View File

@ -9,18 +9,7 @@ module Gitlab
include Validatable
validations do
include LegacyValidationHelpers
validate do
unless string_or_array_of_strings?(config)
errors.add(:config,
'should be a string or an array of strings')
end
end
def string_or_array_of_strings?(field)
validate_string(field) || validate_array_of_strings(field)
end
validates :config, array_of_strings_or_string: true
end
def value

View File

@ -0,0 +1,32 @@
module Gitlab
module Ci
class Config
module Entry
##
# Entry that represents a configuration of job artifacts.
#
class Reports < Node
include Validatable
include Attributable
ALLOWED_KEYS = %i[junit].freeze
attributes ALLOWED_KEYS
validations do
validates :config, type: Hash
validates :config, allowed_keys: ALLOWED_KEYS
with_options allow_nil: true do
validates :junit, array_of_strings_or_string: true
end
end
def value
@config.transform_values { |v| Array(v) }
end
end
end
end
end
end

View File

@ -130,6 +130,20 @@ module Gitlab
end
end
class ArrayOfStringsOrStringValidator < RegexpValidator
def validate_each(record, attribute, value)
unless validate_array_of_strings_or_string(value)
record.errors.add(attribute, 'should be an array of strings or a string')
end
end
private
def validate_array_of_strings_or_string(values)
validate_array_of_strings(values) || validate_string(values)
end
end
class TypeValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
type = options[:with]

View File

@ -164,6 +164,8 @@ module Gitlab
def create_build_trace!(job, path)
File.open(path) do |stream|
# TODO: Set `file_format: :raw` after we've cleaned up legacy traces migration
# https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/20307
job.create_job_artifacts_trace!(
project: job.project,
file_type: :trace,

View File

@ -187,6 +187,13 @@ FactoryBot.define do
end
end
trait :test_reports do
after(:create) do |build|
create(:ci_job_artifact, :junit, job: build)
build.reload
end
end
trait :expired do
artifacts_expire_at 1.minute.ago
end

View File

@ -4,6 +4,7 @@ FactoryBot.define do
factory :ci_job_artifact, class: Ci::JobArtifact do
job factory: :ci_build
file_type :archive
file_format :zip
trait :remote_store do
file_store JobArtifactUploader::Store::REMOTE
@ -15,6 +16,7 @@ FactoryBot.define do
trait :archive do
file_type :archive
file_format :zip
after(:build) do |artifact, _|
artifact.file = fixture_file_upload(
@ -24,6 +26,7 @@ FactoryBot.define do
trait :metadata do
file_type :metadata
file_format :gzip
after(:build) do |artifact, _|
artifact.file = fixture_file_upload(
@ -33,6 +36,7 @@ FactoryBot.define do
trait :trace do
file_type :trace
file_format :raw
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
@ -40,6 +44,16 @@ FactoryBot.define do
end
end
trait :junit do
file_type :junit
file_format :gzip
after(:build) do |artifact, evaluator|
artifact.file = fixture_file_upload(
Rails.root.join('spec/fixtures/junit.xml.gz'), 'application/x-gzip')
end
end
trait :correct_checksum do
after(:build) do |artifact, evaluator|
artifact.file_sha256 = Digest::SHA256.file(artifact.file.path).hexdigest

BIN
spec/fixtures/junit.xml.gz vendored Normal file

Binary file not shown.

View File

@ -18,6 +18,14 @@ describe Gitlab::Ci::Config::Entry::Artifacts do
expect(entry).to be_valid
end
end
context "when value includes 'reports' keyword" do
let(:config) { { paths: %w[public/], reports: { junit: 'junit.xml' } } }
it 'returns general artifact and report-type artifacts configuration' do
expect(entry.value).to eq config
end
end
end
context 'when entry value is not correct' do
@ -39,6 +47,15 @@ describe Gitlab::Ci::Config::Entry::Artifacts do
.to include 'artifacts config contains unknown keys: test'
end
end
context "when 'reports' keyword is not hash" do
let(:config) { { paths: %w[public/], reports: 'junit.xml' } }
it 'reports error' do
expect(entry.errors)
.to include 'artifacts reports should be a hash'
end
end
end
end
end

View File

@ -41,8 +41,7 @@ describe Gitlab::Ci::Config::Entry::Commands do
describe '#errors' do
it 'saves errors' do
expect(entry.errors)
.to include 'commands config should be a ' \
'string or an array of strings'
.to include 'commands config should be an array of strings or a string'
end
end
end

View File

@ -0,0 +1,53 @@
require 'spec_helper'
describe Gitlab::Ci::Config::Entry::Reports do
let(:entry) { described_class.new(config) }
describe 'validation' do
context 'when entry config value is correct' do
let(:config) { { junit: %w[junit.xml] } }
describe '#value' do
it 'returns artifacs configuration' do
expect(entry.value).to eq config
end
end
describe '#valid?' do
it 'is valid' do
expect(entry).to be_valid
end
end
context 'when value is not array' do
let(:config) { { junit: 'junit.xml' } }
it 'converts to array' do
expect(entry.value).to eq({ junit: ['junit.xml'] } )
end
end
end
context 'when entry value is not correct' do
describe '#errors' do
context 'when value of attribute is invalid' do
let(:config) { { junit: 10 } }
it 'reports error' do
expect(entry.errors)
.to include 'reports junit should be an array of strings or a string'
end
end
context 'when there is an unknown key present' do
let(:config) { { codeclimate: 'codeclimate.json' } }
it 'reports error' do
expect(entry.errors)
.to include 'reports config contains unknown keys: codeclimate'
end
end
end
end
end
end

View File

@ -514,6 +514,44 @@ describe Ci::Build do
end
end
describe '#has_test_reports?' do
subject { build.has_test_reports? }
context 'when build has a test report' do
let(:build) { create(:ci_build, :test_reports) }
it { is_expected.to be_truthy }
end
context 'when build does not have test reports' do
let(:build) { create(:ci_build, :artifacts) }
it { is_expected.to be_falsy }
end
end
describe '#erase_test_reports!' do
subject { build.erase_test_reports! }
context 'when build has a test report' do
let!(:build) { create(:ci_build, :test_reports) }
it 'removes a test report' do
subject
expect(build.has_test_reports?).to be_falsy
end
end
context 'when build does not have test reports' do
let!(:build) { create(:ci_build, :artifacts) }
it 'does not erase anything' do
expect { subject }.not_to change { Ci::JobArtifact.count }
end
end
end
describe '#has_old_trace?' do
subject { build.has_old_trace? }
@ -776,6 +814,10 @@ describe Ci::Build do
expect(build.artifacts_metadata.exists?).to be_falsy
end
it 'removes test reports' do
expect(build.job_artifacts.test_reports.count).to eq(0)
end
it 'erases build trace in trace file' do
expect(build).not_to have_trace
end
@ -807,7 +849,7 @@ describe Ci::Build do
context 'build is erasable' do
context 'new artifacts' do
let!(:build) { create(:ci_build, :trace_artifact, :success, :artifacts) }
let!(:build) { create(:ci_build, :test_reports, :trace_artifact, :success, :artifacts) }
describe '#erase' do
before do

View File

@ -15,6 +15,22 @@ describe Ci::JobArtifact do
it { is_expected.to delegate_method(:open).to(:file) }
it { is_expected.to delegate_method(:exists?).to(:file) }
describe '.test_reports' do
subject { described_class.test_reports }
context 'when there is a test report' do
let!(:artifact) { create(:ci_job_artifact, :junit) }
it { is_expected.to eq([artifact]) }
end
context 'when there are no test reports' do
let!(:artifact) { create(:ci_job_artifact, :archive) }
it { is_expected.to be_empty }
end
end
describe 'callbacks' do
subject { create(:ci_job_artifact, :archive) }
@ -87,6 +103,40 @@ describe Ci::JobArtifact do
end
end
describe 'validates file format' do
subject { artifact }
context 'when archive type with zip format' do
let(:artifact) { build(:ci_job_artifact, :archive, file_format: :zip) }
it { is_expected.to be_valid }
end
context 'when archive type with gzip format' do
let(:artifact) { build(:ci_job_artifact, :archive, file_format: :gzip) }
it { is_expected.not_to be_valid }
end
context 'when archive type without format specification' do
let(:artifact) { build(:ci_job_artifact, :archive, file_format: nil) }
it { is_expected.not_to be_valid }
end
context 'when junit type with zip format' do
let(:artifact) { build(:ci_job_artifact, :junit, file_format: :zip) }
it { is_expected.not_to be_valid }
end
context 'when junit type with gzip format' do
let(:artifact) { build(:ci_job_artifact, :junit, file_format: :gzip) }
it { is_expected.to be_valid }
end
end
describe '#file' do
subject { artifact.file }

View File

@ -0,0 +1,86 @@
require 'spec_helper'
describe Ci::BuildRunnerPresenter do
let(:presenter) { described_class.new(build) }
let(:archive) { { paths: ['sample.txt'] } }
let(:junit) { { junit: ['junit.xml'] } }
let(:archive_expectation) do
{
artifact_type: :archive,
artifact_format: :zip,
paths: archive[:paths],
untracked: archive[:untracked]
}
end
let(:junit_expectation) do
{
name: 'junit.xml',
artifact_type: :junit,
artifact_format: :gzip,
paths: ['junit.xml'],
when: 'always'
}
end
describe '#artifacts' do
context "when option contains archive-type artifacts" do
let(:build) { create(:ci_build, options: { artifacts: archive } ) }
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(archive_expectation)
end
context "when untracked is specified" do
let(:archive) { { untracked: true } }
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(archive_expectation)
end
end
context "when untracked and paths are missing" do
let(:archive) { { when: 'always' } }
it 'does not present hash' do
expect(presenter.artifacts).to be_empty
end
end
end
context "when option has 'junit' keyword" do
let(:build) { create(:ci_build, options: { artifacts: { reports: junit } } ) }
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(junit_expectation)
end
end
context "when option has both archive and reports specification" do
let(:build) { create(:ci_build, options: { script: 'echo', artifacts: { **archive, reports: junit } } ) }
it 'presents correct hash' do
expect(presenter.artifacts.first).to include(archive_expectation)
expect(presenter.artifacts.second).to include(junit_expectation)
end
context "when archive specifies 'expire_in' keyword" do
let(:archive) { { paths: ['sample.txt'], expire_in: '3 mins 4 sec' } }
it 'inherits expire_in from archive' do
expect(presenter.artifacts.first).to include({ **archive_expectation, expire_in: '3 mins 4 sec' })
expect(presenter.artifacts.second).to include({ **junit_expectation, expire_in: '3 mins 4 sec' })
end
end
end
context "when option has no artifact keywords" do
let(:build) { create(:ci_build, :no_options) }
it 'does not present hash' do
expect(presenter.artifacts).to be_nil
end
end
end
end

View File

@ -655,13 +655,15 @@ describe API::Jobs do
end
context 'job is erasable' do
let(:job) { create(:ci_build, :trace_artifact, :artifacts, :success, project: project, pipeline: pipeline) }
let(:job) { create(:ci_build, :trace_artifact, :artifacts, :test_reports, :success, project: project, pipeline: pipeline) }
it 'erases job content' do
expect(response).to have_gitlab_http_status(201)
expect(job.job_artifacts.count).to eq(0)
expect(job.trace.exist?).to be_falsy
expect(job.artifacts_file.exists?).to be_falsy
expect(job.artifacts_metadata.exists?).to be_falsy
expect(job.has_test_reports?).to be_falsy
end
it 'updates job' do

View File

@ -424,7 +424,9 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
'untracked' => false,
'paths' => %w(out/),
'when' => 'always',
'expire_in' => '7d' }]
'expire_in' => '7d',
"artifact_type" => "archive",
"artifact_format" => "zip" }]
end
let(:expected_cache) do
@ -1420,6 +1422,56 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end
end
end
context 'when artifact_type is archive' do
context 'when artifact_format is zip' do
let(:params) { { artifact_type: :archive, artifact_format: :zip } }
it 'stores junit test report' do
upload_artifacts(file_upload, headers_with_token, params)
expect(response).to have_gitlab_http_status(201)
expect(job.reload.job_artifacts_archive).not_to be_nil
end
end
context 'when artifact_format is gzip' do
let(:params) { { artifact_type: :archive, artifact_format: :gzip } }
it 'returns an error' do
upload_artifacts(file_upload, headers_with_token, params)
expect(response).to have_gitlab_http_status(400)
expect(job.reload.job_artifacts_archive).to be_nil
end
end
end
context 'when artifact_type is junit' do
context 'when artifact_format is gzip' do
let(:file_upload) { fixture_file_upload('spec/fixtures/junit.xml.gz') }
let(:params) { { artifact_type: :junit, artifact_format: :gzip } }
it 'stores junit test report' do
upload_artifacts(file_upload, headers_with_token, params)
expect(response).to have_gitlab_http_status(201)
expect(job.reload.job_artifacts_junit).not_to be_nil
end
end
context 'when artifact_format is raw' do
let(:file_upload) { fixture_file_upload('spec/fixtures/junit.xml.gz') }
let(:params) { { artifact_type: :junit, artifact_format: :raw } }
it 'returns an error' do
upload_artifacts(file_upload, headers_with_token, params)
expect(response).to have_gitlab_http_status(400)
expect(job.reload.job_artifacts_junit).to be_nil
end
end
end
end
context 'when artifacts are being stored outside of tmp path' do

View File

@ -24,7 +24,7 @@ describe Ci::RetryBuildService do
artifacts_file artifacts_metadata artifacts_size created_at
updated_at started_at finished_at queued_at erased_by
erased_at auto_canceled_by job_artifacts job_artifacts_archive
job_artifacts_metadata job_artifacts_trace].freeze
job_artifacts_metadata job_artifacts_trace job_artifacts_junit].freeze
IGNORE_ACCESSORS =
%i[type lock_version target_url base_tags trace_sections
@ -38,7 +38,7 @@ describe Ci::RetryBuildService do
let(:another_pipeline) { create(:ci_empty_pipeline, project: project) }
let(:build) do
create(:ci_build, :failed, :artifacts, :expired, :erased,
create(:ci_build, :failed, :artifacts, :test_reports, :expired, :erased,
:queued, :coverage, :tags, :allowed_to_fail, :on_tag,
:triggered, :trace_artifact, :teardown_environment,
description: 'my-job', stage: 'test', stage_id: stage.id,

View File

@ -79,7 +79,7 @@ describe Projects::UpdatePagesService do
context "for a valid job" do
before do
create(:ci_job_artifact, file: file, job: build)
create(:ci_job_artifact, file_type: :metadata, file: metadata, job: build)
create(:ci_job_artifact, file_type: :metadata, file_format: :gzip, file: metadata, job: build)
build.reload
end