bosh_cli 1.2831.0 → 1.2839.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cli.rb +7 -3
- data/lib/cli/archive_builder.rb +119 -0
- data/lib/cli/archive_repository.rb +108 -0
- data/lib/cli/archive_repository_provider.rb +12 -0
- data/lib/cli/base_command.rb +1 -1
- data/lib/cli/build_artifact.rb +75 -0
- data/lib/cli/commands/deployment.rb +4 -9
- data/lib/cli/commands/release/create_release.rb +36 -39
- data/lib/cli/glob_match.rb +32 -0
- data/lib/cli/job_property_collection.rb +5 -5
- data/lib/cli/job_property_validator.rb +8 -8
- data/lib/cli/release_builder.rb +43 -44
- data/lib/cli/release_compiler.rb +11 -11
- data/lib/cli/resources/job.rb +190 -0
- data/lib/cli/resources/package.rb +210 -0
- data/lib/cli/version.rb +1 -1
- data/lib/cli/versions/local_version_storage.rb +4 -4
- data/lib/cli/versions/version_file_resolver.rb +1 -3
- metadata +16 -12
- data/lib/cli/job_builder.rb +0 -277
- data/lib/cli/package_builder.rb +0 -316
- data/lib/cli/packaging_helper.rb +0 -217
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f11dc3119b4347b9e61c770c43d31b09ec3e1aa
|
4
|
+
data.tar.gz: 5d829eee1ce9742ea980476c1b7cb769887ab59e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bb7ac41c08a80eee35cec3672d9969c91de24cea903e0ae1c765bfbd1c4c86940e7b4ce3953c3cf5717c610b2988c8e0609ec7621520fc882fc67c449914ab29
|
7
|
+
data.tar.gz: a0ba29122f2ff944793adb8f99473b0e29ffd39ac49db87ad368446bf38e9bdeecaebe3c33d3ccedfaa0c92a70894fbaf70ae019eb615865906108adee3f76ec
|
data/lib/cli.rb
CHANGED
@@ -51,6 +51,7 @@ require 'common/thread_pool'
|
|
51
51
|
require 'cli/config'
|
52
52
|
require 'cli/core_ext'
|
53
53
|
require 'cli/errors'
|
54
|
+
require 'cli/glob_match'
|
54
55
|
require 'cli/yaml_helper'
|
55
56
|
require 'cli/dependency_helper'
|
56
57
|
require 'cli/deployment_manifest'
|
@@ -75,9 +76,12 @@ require 'cli/versions/releases_dir_migrator'
|
|
75
76
|
require 'cli/versions/version_file_resolver'
|
76
77
|
require 'cli/versions/multi_release_support'
|
77
78
|
|
78
|
-
require 'cli/
|
79
|
-
require 'cli/
|
80
|
-
require 'cli/
|
79
|
+
require 'cli/archive_builder'
|
80
|
+
require 'cli/archive_repository_provider'
|
81
|
+
require 'cli/archive_repository'
|
82
|
+
require 'cli/build_artifact'
|
83
|
+
require 'cli/resources/job'
|
84
|
+
require 'cli/resources/package'
|
81
85
|
require 'cli/changeset_helper'
|
82
86
|
require 'cli/deployment_manifest_compiler'
|
83
87
|
require 'cli/task_tracking'
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Bosh::Cli
|
2
|
+
class ArchiveBuilder
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def initialize(archive_repository_provider, options = {})
|
6
|
+
@archive_repository_provider = archive_repository_provider
|
7
|
+
@options = options
|
8
|
+
end
|
9
|
+
|
10
|
+
def build(resource)
|
11
|
+
@archive_repository = @archive_repository_provider.get(resource)
|
12
|
+
resource.run_script(:prepare)
|
13
|
+
|
14
|
+
artifact = nil
|
15
|
+
with_indent(' ') do
|
16
|
+
artifact = locate_artifact(resource)
|
17
|
+
if artifact.nil?
|
18
|
+
artifact = create_artifact(resource)
|
19
|
+
say("Generated version '#{artifact.fingerprint}'".make_green)
|
20
|
+
|
21
|
+
unless dry_run?
|
22
|
+
artifact = @archive_repository.install(artifact)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
if final? && !dry_run?
|
27
|
+
say("Uploading final version '#{artifact.version}'...")
|
28
|
+
artifact, blobstore_id = @archive_repository.upload_to_blobstore(artifact)
|
29
|
+
say("Uploaded, blobstore id '#{blobstore_id}'")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
artifact
|
34
|
+
rescue Bosh::Blobstore::BlobstoreError => e
|
35
|
+
raise BlobstoreError, "Blobstore error: #{e}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def dry_run?
|
39
|
+
!!options[:dry_run]
|
40
|
+
end
|
41
|
+
|
42
|
+
def final?
|
43
|
+
!!options[:final]
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def copy_files(resource)
|
49
|
+
resource.files.each do |src, dest|
|
50
|
+
dest_path = Pathname(staging_dir).join(dest)
|
51
|
+
if File.directory?(src)
|
52
|
+
FileUtils.mkdir_p(dest_path)
|
53
|
+
else
|
54
|
+
FileUtils.mkdir_p(dest_path.parent)
|
55
|
+
FileUtils.cp(src, dest_path, :preserve => true)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def locate_artifact(resource)
|
61
|
+
artifact = @archive_repository.lookup(resource)
|
62
|
+
|
63
|
+
if artifact.nil?
|
64
|
+
say("No artifact found for #{resource.name}".make_red)
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
|
68
|
+
if artifact.dev_artifact? && final? && !dry_run?
|
69
|
+
artifact = @archive_repository.copy_from_dev_to_final(artifact)
|
70
|
+
end
|
71
|
+
|
72
|
+
artifact
|
73
|
+
rescue Bosh::Cli::CorruptedArchive => e
|
74
|
+
say "#{"Warning".make_red}: #{e.message}"
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_artifact(resource)
|
79
|
+
tarball_path = safe_temp_file(resource.name, '.tgz')
|
80
|
+
|
81
|
+
say('Generating...')
|
82
|
+
|
83
|
+
copy_files(resource)
|
84
|
+
resource.run_script(:pre_packaging, staging_dir)
|
85
|
+
|
86
|
+
in_staging_dir do
|
87
|
+
tar_out = `tar -chzf #{tarball_path} . 2>&1`
|
88
|
+
unless $?.exitstatus == 0
|
89
|
+
raise PackagingError, "Cannot create tarball: #{tar_out}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
fingerprint = BuildArtifact.make_fingerprint(resource)
|
94
|
+
|
95
|
+
sha1 = BuildArtifact.checksum(tarball_path)
|
96
|
+
BuildArtifact.new(resource.name, fingerprint, tarball_path, sha1, resource.dependencies, true, !final?)
|
97
|
+
end
|
98
|
+
|
99
|
+
def file_checksum(path)
|
100
|
+
Digest::SHA1.file(path).hexdigest
|
101
|
+
end
|
102
|
+
|
103
|
+
def staging_dir
|
104
|
+
@staging_dir ||= Dir.mktmpdir
|
105
|
+
end
|
106
|
+
|
107
|
+
def in_staging_dir
|
108
|
+
Dir.chdir(staging_dir) { yield }
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def safe_temp_file(prefix, suffix, dir = Dir.tmpdir)
|
114
|
+
Dir::Tmpname.create([prefix, suffix], dir) do |tmpname, _, _|
|
115
|
+
File.open(tmpname, File::RDWR|File::CREAT|File::EXCL).close
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Bosh::Cli
|
2
|
+
class ArchiveRepository
|
3
|
+
def initialize(archive_dir, blobstore, resource)
|
4
|
+
@archive_dir = archive_dir
|
5
|
+
@blobstore = blobstore
|
6
|
+
|
7
|
+
dev_builds_dir = Pathname(@archive_dir).join(".dev_builds", resource.plural_type, resource.name).to_s
|
8
|
+
FileUtils.mkdir_p(dev_builds_dir)
|
9
|
+
@dev_index = Versions::VersionsIndex.new(dev_builds_dir)
|
10
|
+
@dev_storage = Versions::LocalVersionStorage.new(dev_builds_dir)
|
11
|
+
|
12
|
+
final_builds_dir = Pathname(@archive_dir).join(".final_builds", resource.plural_type, resource.name).to_s
|
13
|
+
FileUtils.mkdir_p(final_builds_dir)
|
14
|
+
@final_index = Versions::VersionsIndex.new(final_builds_dir)
|
15
|
+
@final_storage = Versions::LocalVersionStorage.new(final_builds_dir)
|
16
|
+
|
17
|
+
@final_resolver = Versions::VersionFileResolver.new(@final_storage, @blobstore)
|
18
|
+
end
|
19
|
+
|
20
|
+
def lookup(resource)
|
21
|
+
fingerprint = BuildArtifact.make_fingerprint(resource)
|
22
|
+
|
23
|
+
artifact_info = @final_index[fingerprint]
|
24
|
+
if artifact_info && artifact_info['blobstore_id']
|
25
|
+
blobstore_id = artifact_info['blobstore_id']
|
26
|
+
version = artifact_info['version'] || fingerprint
|
27
|
+
sha1 = artifact_info['sha1']
|
28
|
+
|
29
|
+
say('Using final version')
|
30
|
+
tarball_path = @final_resolver.find_file(blobstore_id, sha1, version, "#{resource.singular_type} #{resource.name} (#{version})") # todo: 'package' vs 'job'
|
31
|
+
|
32
|
+
BuildArtifact.new(resource.name, fingerprint, tarball_path, sha1, resource.dependencies, false, false)
|
33
|
+
else
|
34
|
+
artifact_info = @dev_index[fingerprint]
|
35
|
+
if artifact_info
|
36
|
+
version = artifact_info['version'] || fingerprint
|
37
|
+
if @dev_storage.has_file?(version)
|
38
|
+
say('Using dev version')
|
39
|
+
|
40
|
+
tarball_path = @dev_storage.get_file(version)
|
41
|
+
if file_checksum(tarball_path) != artifact_info['sha1']
|
42
|
+
raise CorruptedArchive, "#{resource.singular_type} #{resource.name} (#{version}) archive at #{tarball_path} corrupted"
|
43
|
+
end
|
44
|
+
|
45
|
+
BuildArtifact.new(resource.name, fingerprint, tarball_path, artifact_info['sha1'], resource.dependencies, false, true)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
rescue Bosh::Blobstore::NotFound
|
51
|
+
raise BlobstoreError, "Final version of '#{name}' not found in blobstore"
|
52
|
+
rescue Bosh::Blobstore::BlobstoreError => e
|
53
|
+
raise BlobstoreError, "Blobstore error: #{e}"
|
54
|
+
end
|
55
|
+
|
56
|
+
def upload_to_blobstore(artifact)
|
57
|
+
artifact_info = @final_index[artifact.fingerprint]
|
58
|
+
# todo raise if artifact.dev_artifact?
|
59
|
+
return artifact, artifact_info['blobstore_id'] if artifact_info['blobstore_id']
|
60
|
+
|
61
|
+
blobstore_id = nil
|
62
|
+
File.open(artifact.tarball_path, 'r') do |f|
|
63
|
+
blobstore_id = @blobstore.create(f)
|
64
|
+
end
|
65
|
+
|
66
|
+
@final_index.update_version(artifact.fingerprint, {
|
67
|
+
'version' => artifact.version,
|
68
|
+
'sha1' => artifact.sha1,
|
69
|
+
'blobstore_id' => blobstore_id
|
70
|
+
})
|
71
|
+
artifact = BuildArtifact.new(artifact.name, artifact.fingerprint, artifact.tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, false)
|
72
|
+
return artifact, blobstore_id
|
73
|
+
end
|
74
|
+
|
75
|
+
def install(artifact)
|
76
|
+
fingerprint = artifact.fingerprint
|
77
|
+
origin_file = artifact.tarball_path
|
78
|
+
new_tarball_path = place_file_and_update_index(fingerprint, origin_file,
|
79
|
+
artifact.dev_artifact? ? @dev_index : @final_index,
|
80
|
+
artifact.dev_artifact? ? @dev_storage : @final_storage)
|
81
|
+
|
82
|
+
BuildArtifact.new(artifact.name, artifact.fingerprint, new_tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, artifact.dev_artifact?)
|
83
|
+
end
|
84
|
+
|
85
|
+
def copy_from_dev_to_final(artifact)
|
86
|
+
final_tarball_path = place_file_and_update_index(artifact.fingerprint, artifact.tarball_path, @final_index, @final_storage)
|
87
|
+
BuildArtifact.new(artifact.name, artifact.fingerprint, final_tarball_path, artifact.sha1, artifact.dependencies, artifact.new_version?, false)
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def place_file_and_update_index(fingerprint, origin_file, index, storage)
|
93
|
+
# add version (with its validation) before adding sha1
|
94
|
+
index.add_version(fingerprint, {'version' => fingerprint} )
|
95
|
+
tarball_path = storage.put_file(fingerprint, origin_file)
|
96
|
+
sha1 = file_checksum(tarball_path)
|
97
|
+
index.update_version(fingerprint, {'version' => fingerprint, 'sha1' => sha1})
|
98
|
+
tarball_path
|
99
|
+
end
|
100
|
+
|
101
|
+
def file_checksum(path)
|
102
|
+
Digest::SHA1.file(path).hexdigest
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class CorruptedArchive < StandardError
|
107
|
+
end
|
108
|
+
end
|
data/lib/cli/base_command.rb
CHANGED
@@ -0,0 +1,75 @@
|
|
1
|
+
module Bosh::Cli
|
2
|
+
class BuildArtifact
|
3
|
+
attr_reader :name, :fingerprint, :tarball_path, :sha1, :dependencies
|
4
|
+
|
5
|
+
def initialize(name, fingerprint, tarball_path, sha1, dependencies, is_new_version, is_dev_artifact)
|
6
|
+
@name = name
|
7
|
+
@fingerprint = fingerprint
|
8
|
+
@tarball_path = tarball_path
|
9
|
+
@sha1 = sha1
|
10
|
+
@dependencies = dependencies
|
11
|
+
@is_dev_artifact = is_dev_artifact
|
12
|
+
@notes = []
|
13
|
+
@is_new_version = is_new_version
|
14
|
+
end
|
15
|
+
|
16
|
+
def version
|
17
|
+
fingerprint
|
18
|
+
end
|
19
|
+
|
20
|
+
def dev_artifact?
|
21
|
+
@is_dev_artifact
|
22
|
+
end
|
23
|
+
|
24
|
+
def new_version?
|
25
|
+
@is_new_version
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def self.checksum(tarball_path)
|
31
|
+
if tarball_path && File.exists?(tarball_path)
|
32
|
+
digest_file(tarball_path)
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.digest_file(filename)
|
39
|
+
File.file?(filename) ? Digest::SHA1.file(filename).hexdigest : ''
|
40
|
+
end
|
41
|
+
|
42
|
+
# Git doesn't really track file permissions, it just looks at executable
|
43
|
+
# bit and uses 0755 if it's set or 0644 if not. We have to mimic that
|
44
|
+
# behavior in the fingerprint calculation to avoid the situation where
|
45
|
+
# seemingly clean working copy would trigger new fingerprints for
|
46
|
+
# artifacts with changed permissions. Also we don't want current
|
47
|
+
# fingerprints to change, hence the exact values below.
|
48
|
+
def self.file_mode(path)
|
49
|
+
if File.directory?(path)
|
50
|
+
'40755'
|
51
|
+
elsif File.executable?(path)
|
52
|
+
'100755'
|
53
|
+
else
|
54
|
+
'100644'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# TODO: be sure we are handling the case in which there was an index, with a pre-defined fingerprint
|
59
|
+
def self.make_fingerprint(resource)
|
60
|
+
scheme = 2
|
61
|
+
contents = "v#{scheme}"
|
62
|
+
|
63
|
+
resource.files.each do |filename, name|
|
64
|
+
contents << resource.format_fingerprint(digest_file(filename), filename, name, file_mode(filename))
|
65
|
+
end
|
66
|
+
|
67
|
+
contents << resource.additional_fingerprints.join(",")
|
68
|
+
Digest::SHA1.hexdigest(contents)
|
69
|
+
end
|
70
|
+
|
71
|
+
def resource
|
72
|
+
raise
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -154,18 +154,13 @@ module Bosh::Cli::Command
|
|
154
154
|
end
|
155
155
|
|
156
156
|
say(" - discovering packages")
|
157
|
-
packages = Bosh::Cli::
|
158
|
-
work_dir,
|
159
|
-
:dry_run => true,
|
160
|
-
:final => false
|
161
|
-
)
|
157
|
+
packages = Bosh::Cli::Resources::Package.discover(work_dir)
|
162
158
|
|
163
159
|
say(" - discovering jobs")
|
164
|
-
jobs = Bosh::Cli::
|
160
|
+
jobs = Bosh::Cli::Resources::Job.discover(
|
165
161
|
work_dir,
|
166
|
-
:
|
167
|
-
|
168
|
-
:package_names => packages.map {|package| package.name}
|
162
|
+
# TODO: be sure this is covered in integration
|
163
|
+
packages.map {|package| package['name']}
|
169
164
|
)
|
170
165
|
|
171
166
|
say(" - validating properties")
|
@@ -85,13 +85,13 @@ module Bosh::Cli::Command
|
|
85
85
|
end
|
86
86
|
|
87
87
|
header('Building packages')
|
88
|
-
|
88
|
+
package_artifacts = build_packages(dry_run, final)
|
89
89
|
|
90
90
|
header('Building jobs')
|
91
|
-
|
91
|
+
job_artifacts = build_jobs(package_artifacts.map { |artifact| artifact.name }, dry_run, final)
|
92
92
|
|
93
93
|
header('Building release')
|
94
|
-
release_builder = build_release(dry_run, final,
|
94
|
+
release_builder = build_release(dry_run, final, job_artifacts, manifest_only, package_artifacts, name, version)
|
95
95
|
|
96
96
|
header('Release summary')
|
97
97
|
show_summary(release_builder)
|
@@ -134,22 +134,19 @@ module Bosh::Cli::Command
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def build_packages(dry_run, final)
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
:dry_run => dry_run
|
142
|
-
)
|
143
|
-
|
144
|
-
packages.each do |package|
|
137
|
+
archive_builder = Bosh::Cli::ArchiveBuilder.new(archive_repository_provider,
|
138
|
+
dry_run: dry_run, final: final)
|
139
|
+
packages = Bosh::Cli::Resources::Package.discover(work_dir)
|
140
|
+
artifacts = packages.map do |package|
|
145
141
|
say("Building #{package.name.make_green}...")
|
146
|
-
|
142
|
+
artifact = archive_builder.build(package)
|
147
143
|
nl
|
144
|
+
artifact
|
148
145
|
end
|
149
146
|
|
150
147
|
if packages.size > 0
|
151
|
-
package_index =
|
152
|
-
index[
|
148
|
+
package_index = artifacts.inject({}) do |index, artifact|
|
149
|
+
index[artifact.name] = artifact.dependencies
|
153
150
|
index
|
154
151
|
end
|
155
152
|
sorted_packages = tsort_packages(package_index)
|
@@ -161,11 +158,15 @@ module Bosh::Cli::Command
|
|
161
158
|
nl
|
162
159
|
end
|
163
160
|
|
164
|
-
|
161
|
+
artifacts
|
162
|
+
end
|
163
|
+
|
164
|
+
def archive_repository_provider
|
165
|
+
@archive_repository_provider ||= Bosh::Cli::ArchiveRepositoryProvider.new(work_dir, release.blobstore)
|
165
166
|
end
|
166
167
|
|
167
|
-
def build_release(dry_run, final,
|
168
|
-
release_builder = Bosh::Cli::ReleaseBuilder.new(release,
|
168
|
+
def build_release(dry_run, final, job_artifacts, manifest_only, package_artifacts, name, version)
|
169
|
+
release_builder = Bosh::Cli::ReleaseBuilder.new(release, package_artifacts, job_artifacts, name,
|
169
170
|
final: final,
|
170
171
|
commit_hash: commit_hash,
|
171
172
|
version: version,
|
@@ -183,22 +184,18 @@ module Bosh::Cli::Command
|
|
183
184
|
release_builder
|
184
185
|
end
|
185
186
|
|
186
|
-
def build_jobs(
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
:dry_run => dry_run,
|
192
|
-
:package_names => built_package_names
|
193
|
-
)
|
194
|
-
|
195
|
-
jobs.each do |job|
|
187
|
+
def build_jobs(packages, dry_run, final)
|
188
|
+
archive_builder = Bosh::Cli::ArchiveBuilder.new(archive_repository_provider,
|
189
|
+
:final => final, :dry_run => dry_run)
|
190
|
+
jobs = Bosh::Cli::Resources::Job.discover(work_dir, packages)
|
191
|
+
artifacts = jobs.map do |job|
|
196
192
|
say("Building #{job.name.make_green}...")
|
197
|
-
|
193
|
+
artifact = archive_builder.build(job)
|
198
194
|
nl
|
195
|
+
artifact
|
199
196
|
end
|
200
197
|
|
201
|
-
|
198
|
+
artifacts
|
202
199
|
end
|
203
200
|
|
204
201
|
def save_final_release_name
|
@@ -225,15 +222,15 @@ module Bosh::Cli::Command
|
|
225
222
|
def show_summary(builder)
|
226
223
|
packages_table = table do |t|
|
227
224
|
t.headings = %w(Name Version Notes)
|
228
|
-
builder.packages.each do |
|
229
|
-
t << artifact_summary(
|
225
|
+
builder.packages.each do |package_artifact|
|
226
|
+
t << artifact_summary(package_artifact)
|
230
227
|
end
|
231
228
|
end
|
232
229
|
|
233
230
|
jobs_table = table do |t|
|
234
231
|
t.headings = %w(Name Version Notes)
|
235
|
-
builder.jobs.each do |
|
236
|
-
t << artifact_summary(
|
232
|
+
builder.jobs.each do |job_artifact|
|
233
|
+
t << artifact_summary(job_artifact)
|
237
234
|
end
|
238
235
|
end
|
239
236
|
|
@@ -260,12 +257,12 @@ module Bosh::Cli::Command
|
|
260
257
|
end
|
261
258
|
end
|
262
259
|
|
263
|
-
def artifact_summary(
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
260
|
+
def artifact_summary(artifact)
|
261
|
+
[
|
262
|
+
artifact.name,
|
263
|
+
artifact.version,
|
264
|
+
artifact.new_version? ? 'new version' : '',
|
265
|
+
]
|
269
266
|
end
|
270
267
|
|
271
268
|
def commit_hash
|