packaging 0.99.24 → 0.99.25

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 42a454c3b78537b5fc58e2c3dee9027327647eb4
4
- data.tar.gz: 20760d44dce80abc0ee5a4fc3346d9df0dfca29c
2
+ SHA256:
3
+ metadata.gz: 882ec9fd259317c5faf675e1316bc009966c065c0016db603e04a3a92ffda3ee
4
+ data.tar.gz: c309fe43c243bf7c149a46707eb4ddcd5a4d6d9e270999a5ffa22757b6b31fff
5
5
  SHA512:
6
- metadata.gz: a49aba088a2371721113f05c7a05e4b2e27e5782c0e4484eb5dd95450c6f80de4290529e9fb4eb524b31db52b08afdbaca103313b102d819a170f5e2302dd941
7
- data.tar.gz: f1f3e6a0d9fa645cf92e3400905e8bf41da8413f04ae99d7fb040834dd6cbcc423a3eafa7295230fbbdd8adf6b49db60a3816fad9eedee6f5df1af759efd3db1
6
+ metadata.gz: 50444de7d9e7ad4f7c1a583bcb7b68f368b3cce463fe1dcea274bcbd312fb934be4e77f4b0bc6790970a481a7600ca168264e59a9fa89905e9e934a39e4624bd
7
+ data.tar.gz: a1bd3e9837ec9540ebebac3b75dbd84716c99e2e0b5522723afed882b2d17a4ebb77d0a9de73942cb7282966719e9e65b01f1d880085d3503f982fde035b45d6
@@ -1,3 +1,6 @@
1
+ require 'uri'
2
+ require 'open-uri'
3
+
1
4
  module Pkg
2
5
 
3
6
  # The Artifactory class
@@ -203,16 +206,19 @@ module Pkg
203
206
  raise "Attempt to upload '#{package}' to #{File.join(@artifactory_uri, data[:full_artifactory_path])} failed"
204
207
  end
205
208
 
206
- # @param directory [String] optional, The directory where the yaml file will
207
- # be downloaded
208
- # @return [String] The path to the downloaded file
209
- def retrieve_yaml_data_file(directory = nil)
210
- directory ||= Dir.mktmpdir
211
- retrieve_package(DEFAULT_REPO_TYPE, "#{@project_version}.yaml", directory)
212
- File.join(directory, "#{@project_version}.yaml")
209
+ # @param pkg [String] The package to download YAML for
210
+ # i.e. 'puppet-agent' or 'puppetdb'
211
+ # @param ref [String] The git ref (sha or tag) we want the YAML for
212
+ #
213
+ # @return [String] The contents of the YAML file
214
+ def retrieve_yaml_data(pkg, ref)
215
+ yaml_url = "#{@artifactory_uri}/#{DEFAULT_REPO_TYPE}/#{DEFAULT_REPO_BASE}/#{pkg}/#{ref}/#{ref}.yaml"
216
+ open(yaml_url) { |f| f.read }
217
+ rescue
218
+ raise "Failed to load YAML data for #{pkg} at #{ref} from #{yaml_url}!"
213
219
  end
214
220
 
215
- # @param platform_data [Hash] The has of the platform data that needs to be
221
+ # @param platform_data [Hash] The hash of the platform data that needs to be
216
222
  # parsed
217
223
  # @param platform_tag [String] The tag that the data we want belongs to
218
224
  # @return [String] The name of the package for the given project,
@@ -230,47 +236,80 @@ module Pkg
230
236
  raise fail_message
231
237
  end
232
238
 
233
- # @param platform_tags [Array[String], String] optional, either a string, or
234
- # an array of strings. These are the platform or platforms that we will
235
- # download packages for.
236
- # @param package [String] optional, the name of the package to be
237
- # retrieved. If the user does not know this information, we can derive it
238
- # from the yaml data. This ignores everything but the package name. Any
239
- # customization for where the user wants to fetch the package is via the
240
- # download_path parameter.
241
- # @param download_path [String] Optional, an optional path set to where
242
- # the user wants the retrieved package to end up. If no path is specified
243
- # this defaults to the pkg directory.
244
- def retrieve_package(platform_tags = nil, package = nil, download_path = nil)
245
-
246
- if platform_tags.nil? && !package.nil?
247
- platform_tags = Pkg::Paths.tag_from_artifact_path(package) || DEFAULT_REPO_TYPE
248
- elsif platform_tags.nil? && package.nil?
249
- yaml_file = retrieve_yaml_data_file(download_path)
250
- yaml_data = Pkg::Config.config_from_yaml(yaml_file)
251
- platform_data = yaml_data[:platform_data]
252
- platform_tags = platform_data.keys
253
- end
239
+ # @param platform_data [Hash] The hash of the platform data that needs to be
240
+ # parsed
241
+ # @param platform_tag [String] The tag that the data we want belongs to
242
+ # @return [Array] An array containing all packages for the given project,
243
+ # project_version, and platform_tag
244
+ def all_package_names(platform_data, platform_tag)
245
+ packages = [platform_data[platform_tag][:artifact]]
246
+ packages << platform_data[platform_tag][:additional_artifacts]
247
+ packages.flatten!
248
+ packages.reject! { |package| package.empty? || package.nil? }
249
+ packages.map { |package| File.basename(package) }
250
+ rescue
251
+ fail_message = <<-DOC
252
+ Package name could not be found from loaded yaml data. Either this package
253
+ does not exist, or '#{@platform_tag}' is not present in this dataset.
254
+
255
+ The following are available platform tags for '#{@project}' '#{@project_version}':
256
+ #{platform_data.keys.sort}
257
+ DOC
258
+ raise fail_message
259
+ end
260
+
261
+ # Promotes a build based on build SHA or tag (or SNAPSHOT version, for ezbake)
262
+ # Depending on if it's an RPM or Deb package promote accordingly
263
+ # 'promote' by copying the package(s) to the enterprise directory on artifactory
264
+ #
265
+ # @param pkg [String] the package name ex. puppet-agent
266
+ # @param ref [String] tag or SHA of package(s) to be promoted
267
+ # @param platform_tag [String] the platform tag of the artifact
268
+ # ex. el-7-x86_64, ubuntu-18.04-amd64
269
+ # @param repositories [Array(String)] the repositories to promote
270
+ # the artifact to. Will prepend 'rpm_' or 'debian_' to the repositories
271
+ # depending on package type
272
+ def promote_package(pkg, ref, platform_tag, repositories)
273
+ # load package metadata
274
+ yaml_content = retrieve_yaml_data(pkg, ref)
275
+ yaml_data = YAML::load(yaml_content)
276
+
277
+ # get the artifact name
278
+ artifact_names = all_package_names(yaml_data[:platform_data], platform_tag)
279
+ artifact_names.each do |artifact_name|
280
+ artifact_to_promote = Artifactory::Resource::Artifact.search(name: artifact_name, :artifactory_uri => @artifactory_uri)
281
+
282
+ if artifact_to_promote.empty?
283
+ raise "Error: could not find PKG=#{pkg} at REF=#{git_ref} for #{platform_tag}"
284
+ end
254
285
 
255
- Array(platform_tags).each do |platform_tag|
256
- puts "fetching package for #{platform_tag}"
257
- data = platform_specific_data(platform_tag)
258
- if package.nil?
259
- package_for_tag = package_name(platform_data, platform_tag)
260
- puts "package name is #{package_for_tag}"
286
+ # This makes an assumption that we're using some consistent repo names
287
+ # but need to either prepend 'rpm_' or 'debian_' based on package type
288
+ if File.extname(artifact_name) == '.rpm'
289
+ promotion_paths = Array(repositories).compact.map { |repo| "rpm_#{repo}/#{platform_tag}/#{artifact_name}" }
290
+ elsif File.extname(artifact_name) == '.deb'
291
+ promotion_paths = Array(repositories).compact.map { |repo| "debian_#{repo}/#{platform_tag}/#{artifact_name}" }
261
292
  else
262
- package_for_tag = package
293
+ raise "Error: Unknown promotion repository for #{artifact_name}! Only .rpm and .deb files are supported!"
263
294
  end
264
- download_path_for_tag = download_path || data[:repo_subdirectories].sub(@repo_base, 'pkg')
265
295
 
266
- check_authorization
267
- artifact = Artifactory::Resource::Artifact.new(
268
- download_uri: File.join(@artifactory_uri, data[:full_artifactory_path], File.basename(package_for_tag))
269
- )
270
- artifact.download(download_path_for_tag)
296
+ begin
297
+ promotion_paths.each do |path|
298
+ puts "promoting #{artifact_name} to #{path}"
299
+ artifact_to_promote[0].copy(path)
300
+ end
301
+ rescue Artifactory::Error::HTTPError => e
302
+ if e.message =~ /destination and source are the same/i
303
+ puts "Skipping promotion of #{artifact_name}; it has already been promoted"
304
+ else
305
+ puts "#{e.level}: #{e.message}"
306
+ raise e
307
+ end
308
+ rescue => e
309
+ puts "Something went wrong promoting #{artifact_name}!"
310
+ raise e
311
+ end
271
312
  end
272
- rescue
273
- raise "Attempt to download '#{File.basename(package)}' from #{File.join(@artifactory_uri, data[:full_artifactory_path])} failed."
274
313
  end
275
314
 
276
315
  private :check_authorization
@@ -81,6 +81,13 @@ module Pkg
81
81
  data = {}
82
82
  artifacts.each do |artifact|
83
83
  tag = Pkg::Paths.tag_from_artifact_path(artifact)
84
+
85
+ # Remove the f-prefix from the fedora platform tag keys so that
86
+ # beaker can rely on consistent keys once we rip out the f for good
87
+ tag = tag.sub(/fedora-f/, 'fedora-')
88
+
89
+ data[tag] ||= {}
90
+
84
91
  platform, version, arch = Pkg::Platforms.parse_platform_tag(tag)
85
92
  package_format = Pkg::Platforms.get_attribute(tag, :package_format)
86
93
 
@@ -89,6 +96,7 @@ module Pkg
89
96
  # information, but we should report the versioned artifact in
90
97
  # platform_data
91
98
  next if platform == 'windows' && File.basename(artifact) == "#{self.project}-#{arch}.#{package_format}"
99
+
92
100
  # Sometimes we have source or debug packages. We don't want to save
93
101
  # these paths in favor of the artifact paths.
94
102
  if platform == 'solaris'
@@ -97,7 +105,14 @@ module Pkg
97
105
  else
98
106
  next if File.extname(artifact) != ".#{package_format}"
99
107
  end
100
- next if /#{self.project}-[a-z]+/.match(File.basename(artifact))
108
+
109
+ # Don't want to include debian debug packages
110
+ next if /-dbgsym/.match(File.basename(artifact))
111
+
112
+ if /#{self.project}-[a-z]+/.match(File.basename(artifact))
113
+ add_additional_artifact(data, tag, artifact.sub('artifacts/', ''))
114
+ next
115
+ end
101
116
 
102
117
  case package_format
103
118
  when 'deb'
@@ -109,12 +124,17 @@ module Pkg
109
124
  else
110
125
  fail "Not sure what to do with packages with a package format of '#{package_format}' - maybe update PLATFORM_INFO?"
111
126
  end
112
- # Remove the f-prefix from the fedora platform tag keys so that
113
- # beaker can rely on consistent keys once we rip out the f for good
114
- tag = tag.sub(/fedora-f/, 'fedora-')
115
- data[tag] = { :artifact => artifact.sub('artifacts/', ''),
116
- :repo_config => repo_config,
117
- }
127
+
128
+ # handle the case where there are multiple artifacts but the artifacts are not
129
+ # named based on project name (e.g. puppet-enterprise-vanagon).
130
+ # In this case, the first one will get set as the artifact, everything else
131
+ # will be in the additional artifacts
132
+ if data[tag][:artifact].nil?
133
+ data[tag][:artifact] = artifact.sub('artifacts/', '')
134
+ data[tag][:repo_config] = repo_config
135
+ else
136
+ add_additional_artifact(data, tag, artifact.sub('artifacts/', ''))
137
+ end
118
138
  end
119
139
  return data
120
140
  else
@@ -123,6 +143,32 @@ module Pkg
123
143
  end
124
144
  end
125
145
 
146
+ # Add artifact to the `additional_artifacts` array in platform data.
147
+ # This will not add noarch package paths for the same noarch package
148
+ # multiple times.
149
+ #
150
+ # @param platform_data The platform data hash to update
151
+ # @param tag the platform tag
152
+ # @param artifact the path of the additional artifact path to add
153
+ def add_additional_artifact(platform_data, tag, artifact)
154
+ # Don't add noarch packages to additional_artifacts if the same package
155
+ # is already the artifact
156
+ if File.basename(platform_data[tag][:artifact]) == File.basename(artifact)
157
+ return
158
+ end
159
+
160
+ platform_data[tag][:additional_artifacts] ||= []
161
+
162
+ if platform_data[tag][:additional_artifacts].select { |a| File.basename(a) == File.basename(artifact) }.empty?
163
+ platform_data[tag][:additional_artifacts] << artifact
164
+ end
165
+
166
+ # try to avoid empty entries in the yaml for more concise output
167
+ if platform_data[tag][:additional_artifacts].empty?
168
+ platform_data[tag][:additional_artifacts] = nil
169
+ end
170
+ end
171
+
126
172
  ##
127
173
  # Return a hash of all build parameters and their values, nil if unassigned.
128
174
  #
@@ -1 +1 @@
1
- spec/fixtures/config/ext/../params.yaml
1
+ ../params.yaml
@@ -1 +1 @@
1
- spec/fixtures/config/ext/../params.yaml
1
+ ../params.yaml
@@ -14,26 +14,32 @@ describe 'artifactory.rb' do
14
14
  'el-6-x86_64' => {
15
15
  :artifact => "./el/6/PC1/x86_64/puppet-agent-5.3.1.34.gf65f9ef-1.el6.x86_64.rpm",
16
16
  :repo_config => "../repo_configs/rpm/pl-puppet-agent-f65f9efbb727c3d2d72d6799c0fc345a726f27b5-el-6-x86_64.repo",
17
+ :additional_artifacts => ["./el/6/PC1/x86_64/puppet-agent-extras-5.3.1.34.gf65f9ef-1.el6.x86_64.rpm"],
17
18
  },
18
19
  'ubuntu-16.04-amd64' => {
19
20
  :artifact => "./deb/xenial/PC1/puppet-agent_5.3.1.34.gf65f9ef-1xenial_amd64.deb",
20
21
  :repo_config => "../repo_configs/deb/pl-puppet-agent-f65f9efbb727c3d2d72d6799c0fc345a726f27b5-xenial.list",
22
+ :additional_artifacts => ["./deb/xenial/PC1/puppet-agent-extras_5.3.1.34.gf65f9ef-1xenial_amd64.deb"],
21
23
  },
22
24
  'windows-2012-x86' => {
23
25
  :artifact => "./windows/puppet-agent-5.3.1.34-x86.msi",
24
26
  :repo_config => '',
27
+ :additional_artifacts => ["./windows/puppet-agent-extras-5.3.1.34-x86.msi"],
25
28
  },
26
29
  'eos-4-i386' => {
27
30
  :artifact => "./eos/4/PC1/i386/puppet-agent-5.3.1.34.gf65f9ef-1.eos4.i386.swix",
28
31
  :repo_config => '',
32
+ :additional_artifacts => ["./eos/4/PC1/i386/puppet-agent-extras-5.3.1.34.gf65f9ef-1.eos4.i386.swix"],
29
33
  },
30
34
  'osx-10.12-x86_64' => {
31
35
  :artifact => "./apple/10.12/PC1/x86_64/puppet-agent-5.3.1.34.gf65f9ef-1.osx10.12.dmg",
32
36
  :repo_config => '',
37
+ :additional_artifacts => ["./apple/10.12/PC1/x86_64/puppet-agent-extras-5.3.1.34.gf65f9ef-1.osx10.12.dmg"],
33
38
  },
34
39
  'solaris-10-sparc' => {
35
40
  :artifact => "./solaris/10/PC1/puppet-agent-5.3.1.34.gf65f9ef-1.sparc.pkg.gz",
36
41
  :repo_config => '',
42
+ :additional_artifacts => ["./solaris/10/PC1/puppet-agent-extras-5.3.1.34.gf65f9ef-1.sparc.pkg.gz"],
37
43
  },
38
44
  }
39
45
  }
@@ -44,6 +50,7 @@ describe 'artifactory.rb' do
44
50
  :repo_subdirectories => "#{default_repo_name}/#{project}/#{project_version}/el-6-x86_64",
45
51
  :package_format => 'rpm',
46
52
  :package_name => 'path/to/a/el/6/package/puppet-agent-5.3.1.34.gf65f9ef-1.el6.x86_64.rpm',
53
+ :all_package_names => ['puppet-agent-5.3.1.34.gf65f9ef-1.el6.x86_64.rpm', 'puppet-agent-extras-5.3.1.34.gf65f9ef-1.el6.x86_64.rpm']
47
54
  },
48
55
  'ubuntu-16.04-amd64' => {
49
56
  :toplevel_repo => 'debian__local',
@@ -51,26 +58,31 @@ describe 'artifactory.rb' do
51
58
  :codename => 'xenial',
52
59
  :arch => 'amd64',
53
60
  :package_name => 'path/to/a/xenial/package/puppet-agent_5.3.1.34.gf65f9ef-1xenial_amd64.deb',
61
+ :all_package_names => ['puppet-agent_5.3.1.34.gf65f9ef-1xenial_amd64.deb', 'puppet-agent-extras_5.3.1.34.gf65f9ef-1xenial_amd64.deb']
54
62
  },
55
63
  'windows-2012-x86' => {
56
64
  :toplevel_repo => 'generic',
57
65
  :repo_subdirectories => "#{default_repo_name}/#{project}/#{project_version}/windows-x86",
58
66
  :package_name => 'path/to/a/windows/package/puppet-agent-5.3.1.34-x86.msi',
67
+ :all_package_names => ['puppet-agent-5.3.1.34-x86.msi','puppet-agent-extras-5.3.1.34-x86.msi']
59
68
  },
60
69
  'eos-4-i386' => {
61
70
  :toplevel_repo => 'generic',
62
71
  :repo_subdirectories => "#{default_repo_name}/#{project}/#{project_version}/eos-4-i386",
63
72
  :package_name => 'path/to/an/eos/4/package/puppet-agent-5.3.1.34.gf65f9ef-1.eos4.i386.swix',
73
+ :all_package_names => ['puppet-agent-5.3.1.34.gf65f9ef-1.eos4.i386.swix', 'puppet-agent-extras-5.3.1.34.gf65f9ef-1.eos4.i386.swix']
64
74
  },
65
75
  'osx-10.12-x86_64' => {
66
76
  :toplevel_repo => 'generic',
67
77
  :repo_subdirectories => "#{default_repo_name}/#{project}/#{project_version}/osx-10.12-x86_64",
68
78
  :package_name => 'path/to/an/osx/10.12/package/puppet-agent-5.3.1.34.gf65f9ef-1.osx10.12.dmg',
79
+ :all_package_names => ['puppet-agent-5.3.1.34.gf65f9ef-1.osx10.12.dmg', 'puppet-agent-extras-5.3.1.34.gf65f9ef-1.osx10.12.dmg']
69
80
  },
70
81
  'solaris-10-sparc' => {
71
82
  :toplevel_repo => 'generic',
72
83
  :repo_subdirectories => "#{default_repo_name}/#{project}/#{project_version}/solaris-10-sparc",
73
84
  :package_name => 'path/to/a/solaris/10/package/puppet-agent-5.3.1.34.gf65f9ef-1.sparc.pkg.gz',
85
+ :all_package_names => ['puppet-agent-5.3.1.34.gf65f9ef-1.sparc.pkg.gz','puppet-agent-extras-5.3.1.34.gf65f9ef-1.sparc.pkg.gz']
74
86
  },
75
87
  }
76
88
 
@@ -124,6 +136,23 @@ describe 'artifactory.rb' do
124
136
  end
125
137
  end
126
138
 
139
+ describe '#all_package_names' do
140
+ it 'parses the retrieved yaml file and returns the correct package name' do
141
+ all_package_names = artifact.all_package_names(platform_data, platform_tag)
142
+ all_package_names_data = [platform_tag_data[:additional_artifacts], platform_tag_data[:all_package_names]].flatten.compact
143
+ all_package_names.map! { |p| File.basename(p) }
144
+ all_package_names_data.map! { |p| File.basename(p) }
145
+ expect(all_package_names.size).to eq(all_package_names_data.size)
146
+ expect(all_package_names.sort).to eq(all_package_names_data.sort)
147
+ end
148
+
149
+ it 'fails if it cannot find a valid platform name' do
150
+ new_platform_data = platform_data
151
+ new_platform_data.delete_if { |k| k.match(platform_tag) }
152
+ expect{artifact.package_name(new_platform_data, platform_tag)}.to raise_error
153
+ end
154
+ end
155
+
127
156
  describe '#deb_list_contents' do
128
157
  it "returns the correct contents for the debian list file for #{platform_tag}" do
129
158
  if platform_tag_data[:codename]
@@ -239,6 +239,11 @@ describe "Pkg::Config" do
239
239
  "./artifacts/deb/stretch/PC1/puppet-agent_5.3.2.658.gc79ef9a-1stretch_amd64.deb\n" \
240
240
  "./artifacts/deb/stretch/PC1/puppet-agent-dbgsym_5.3.2.658.gc79ef9a-1stretch_amd64.deb"
241
241
 
242
+ artifacts_not_matching_project = \
243
+ "./artifacts/deb/xenial/pe-postgresql-contrib_2019.1.9.6.12-1xenial_amd64.deb\n" \
244
+ "./artifacts/deb/xenial/pe-postgresql-devel_2019.1.9.6.12-1xenial_amd64.deb\n" \
245
+ "./artifacts/deb/xenial/pe-postgresql-server_2019.1.9.6.12-1xenial_amd64.deb\n" \
246
+ "./artifacts/deb/xenial/pe-postgresql_2019.1.9.6.12-1xenial_amd64.deb"
242
247
  project = 'puppet-agent'
243
248
  ref = '5.3.2'
244
249
 
@@ -295,6 +300,16 @@ describe "Pkg::Config" do
295
300
  expect(data['debian-9-amd64']).to include(:artifact => './deb/stretch/PC1/puppet-agent_5.3.2.658.gc79ef9a-1stretch_amd64.deb')
296
301
  end
297
302
 
303
+ it "should collect packages that don't match the project name" do
304
+ allow(Pkg::Util::Net).to receive(:remote_ssh_cmd).and_return(artifacts_not_matching_project, nil)
305
+ data = Pkg::Config.platform_data
306
+ expect(data['ubuntu-16.04-amd64']).to include(:artifact => './deb/xenial/pe-postgresql-contrib_2019.1.9.6.12-1xenial_amd64.deb')
307
+ expect(data['ubuntu-16.04-amd64'][:additional_artifacts].size).to eq(3)
308
+ expect(data['ubuntu-16.04-amd64'][:additional_artifacts]).to include('./deb/xenial/pe-postgresql-devel_2019.1.9.6.12-1xenial_amd64.deb')
309
+ expect(data['ubuntu-16.04-amd64'][:additional_artifacts]).to include('./deb/xenial/pe-postgresql-server_2019.1.9.6.12-1xenial_amd64.deb')
310
+ expect(data['ubuntu-16.04-amd64'][:additional_artifacts]).to include('./deb/xenial/pe-postgresql_2019.1.9.6.12-1xenial_amd64.deb')
311
+ end
312
+
298
313
  it "should use 'ppc' instead of 'power' in aix paths" do
299
314
  allow(Pkg::Util::Net).to receive(:remote_ssh_cmd).and_return(aix_artifacts, nil)
300
315
  data = Pkg::Config.platform_data
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: packaging
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.99.24
4
+ version: 0.99.25
5
5
  platform: ruby
6
6
  authors:
7
7
  - Puppet Labs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-12 00:00:00.000000000 Z
11
+ date: 2019-04-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -223,8 +223,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
223
  - !ruby/object:Gem::Version
224
224
  version: '0'
225
225
  requirements: []
226
- rubyforge_project:
227
- rubygems_version: 2.6.9
226
+ rubygems_version: 3.0.3
228
227
  signing_key:
229
228
  specification_version: 4
230
229
  summary: Puppet Labs' packaging automation