puppet_metadata 5.3.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +168 -33
- data/bin/metadata2gha +0 -15
- data/bin/puppet-metadata +64 -0
- data/bin/setfiles +2 -1
- data/bin/update_eol_dates +267 -0
- data/data/eol_dates.json +292 -0
- data/lib/puppet_metadata/aio.rb +4 -1
- data/lib/puppet_metadata/base_command.rb +50 -0
- data/lib/puppet_metadata/beaker.rb +5 -44
- data/lib/puppet_metadata/command/os_versions.rb +121 -0
- data/lib/puppet_metadata/command/setfiles.rb +23 -0
- data/lib/puppet_metadata/command.rb +18 -0
- data/lib/puppet_metadata/github_actions.rb +0 -1
- data/lib/puppet_metadata/metadata.rb +73 -0
- data/lib/puppet_metadata/operatingsystem.rb +53 -207
- data/lib/puppet_metadata.rb +9 -0
- metadata +23 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9ac5190193748a7ec1f0d61f9c7ef2bac509bb78e1e854b373362e421cf4a656
|
|
4
|
+
data.tar.gz: dcafc939d26360e09cd7525b72ca2e4268802d2e4103d4c61b14570a4700a402
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e18f077b5298afce2a703c1c1c66d941f447a72740dc29105b57d9cd1cb929ed4c4a537a021950ca4ed2c1cda06eaf40d3f1e8c927f7b05212b1f241e0db331
|
|
7
|
+
data.tar.gz: b16239f27e4a1c74174816fe1b59bd28f1503f4839fc52bfc952f3c6ce1fe3d70bdccacb138f136e1f75a1423ef1537d574c07b2625bc044a8a12094ade701a6
|
data/README.md
CHANGED
|
@@ -10,6 +10,120 @@
|
|
|
10
10
|
|
|
11
11
|
The gem intends to provide an abstraction over Puppet's metadata.json file. Its API allow easy iteration over its illogical data structures.
|
|
12
12
|
|
|
13
|
+
- [puppet\_metadata](#puppet_metadata)
|
|
14
|
+
- [New CLI interface in 6.0.0](#new-cli-interface-in-600)
|
|
15
|
+
- [Manage OS versions in metadata.json](#manage-os-versions-in-metadatajson)
|
|
16
|
+
- [List supported OS versions](#list-supported-os-versions)
|
|
17
|
+
- [Add missing supported OS versions](#add-missing-supported-os-versions)
|
|
18
|
+
- [Remove EOL OS versions](#remove-eol-os-versions)
|
|
19
|
+
- [Generating Github Actions outputs](#generating-github-actions-outputs)
|
|
20
|
+
- [Work with the API](#work-with-the-api)
|
|
21
|
+
- [List all supported operating systems](#list-all-supported-operating-systems)
|
|
22
|
+
- [List supported major puppet versions](#list-supported-major-puppet-versions)
|
|
23
|
+
- [Check if an operating systems is supported](#check-if-an-operating-systems-is-supported)
|
|
24
|
+
- [Get all versions for an Operating System that are not EoL](#get-all-versions-for-an-operating-system-that-are-not-eol)
|
|
25
|
+
- [Get all versions for an Operating System that are not EoL after a certain date](#get-all-versions-for-an-operating-system-that-are-not-eol-after-a-certain-date)
|
|
26
|
+
- [Updating OS EOL dates](#updating-os-eol-dates)
|
|
27
|
+
- [Adding new operating systems](#adding-new-operating-systems)
|
|
28
|
+
- [List supported setfiles](#list-supported-setfiles)
|
|
29
|
+
- [Transfer Notice](#transfer-notice)
|
|
30
|
+
- [License](#license)
|
|
31
|
+
- [Release information](#release-information)
|
|
32
|
+
|
|
33
|
+
## New CLI interface in 6.0.0
|
|
34
|
+
|
|
35
|
+
Version 6.0.0 introduces a new CLI interface, in `bin/puppet-metadata`.
|
|
36
|
+
It provides a new way of handling default CLI options, like the path to the metadata.json.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
$ bundle exec bin/puppet-metadata --help
|
|
40
|
+
Usage: puppet-metadata [options] <action> [options]
|
|
41
|
+
--filename METADATA Metadata filename
|
|
42
|
+
|
|
43
|
+
ACTIONS
|
|
44
|
+
os-versions Manage operating system versions in metadata.json
|
|
45
|
+
setfiles Show the various setfiles supported by the metadata
|
|
46
|
+
|
|
47
|
+
See 'puppet-metadata ACTION --help' for more information on a specific action.
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`--filename ` is optional.
|
|
51
|
+
If ommitted, a metadata.json in the current directory will be parsed.
|
|
52
|
+
|
|
53
|
+
Each action is implemented as a file in `lib/puppet_metadata/command/*rb` and automatically loaded via `lib/puppet_metadata/command.rb`.
|
|
54
|
+
|
|
55
|
+
## Manage OS versions in metadata.json
|
|
56
|
+
|
|
57
|
+
The `os-versions` command provides a unified interface to view, add, and remove operating system versions in the metadata.json.
|
|
58
|
+
|
|
59
|
+
### List supported OS versions
|
|
60
|
+
|
|
61
|
+
By default, `os-versions` shows which OS versions in your metadata.json are still supported and which are EOL:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
$ bundle exec puppet-metadata os-versions
|
|
65
|
+
module-name supports these non-EOL operating system versions:
|
|
66
|
+
AlmaLinux: 8, 9
|
|
67
|
+
CentOS: 9
|
|
68
|
+
Debian: 11, 12
|
|
69
|
+
OracleLinux: 8, 9, 10
|
|
70
|
+
RedHat: 8, 9
|
|
71
|
+
Rocky: 8, 9
|
|
72
|
+
Ubuntu: 22.04, 24.04
|
|
73
|
+
|
|
74
|
+
module-name supports these EOL operating system versions:
|
|
75
|
+
Fedora: 40
|
|
76
|
+
Ubuntu: 20.04
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
You can filter to a specific OS:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
$ bundle exec puppet-metadata os-versions --os Ubuntu
|
|
83
|
+
module-name supports these non-EOL operating system versions:
|
|
84
|
+
Ubuntu: 22.04, 24.04
|
|
85
|
+
|
|
86
|
+
module-name supports these EOL operating system versions:
|
|
87
|
+
Ubuntu: 20.04
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Add missing supported OS versions
|
|
91
|
+
|
|
92
|
+
Use `--add-missing` to automatically add all non-EOL OS versions to metadata.json:
|
|
93
|
+
|
|
94
|
+
```
|
|
95
|
+
$ bundle exec puppet-metadata os-versions --add-missing
|
|
96
|
+
Added support:
|
|
97
|
+
CentOS => 10
|
|
98
|
+
Debian => 13
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
These OSes are exceptions (to align with [beaker-hostgenerator](https://github.com/voxpupuli/beaker-hostgenerator) support):
|
|
102
|
+
|
|
103
|
+
- For SLES, only major versions are added.
|
|
104
|
+
- For Ubuntu, only LTS versions are added.
|
|
105
|
+
|
|
106
|
+
### Remove EOL OS versions
|
|
107
|
+
|
|
108
|
+
Use `--remove-eol` to automatically remove all EOL OS versions from metadata.json:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
$ bundle exec puppet-metadata os-versions --remove-eol
|
|
112
|
+
Removed EOL operating systems:
|
|
113
|
+
CentOS => 7, 8
|
|
114
|
+
Debian => 9, 10
|
|
115
|
+
Ubuntu => 20.04
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
You can preview changes without modifying metadata.json using `--noop`:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
$ bundle exec puppet-metadata os-versions --add-missing --noop
|
|
122
|
+
[NOOP] Would add support:
|
|
123
|
+
CentOS => 10
|
|
124
|
+
Debian => 13
|
|
125
|
+
```
|
|
126
|
+
|
|
13
127
|
## Generating Github Actions outputs
|
|
14
128
|
|
|
15
129
|
To get outputs [usable in Github Actions](https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions), there is the `metadata2gha` command available. This generates based on metadata.json, such as [Beaker](https://github.com/voxpupuli/beaker) setfiles, Puppet major versions and a Puppet unit test matrix.
|
|
@@ -71,39 +185,6 @@ Beaker test matrix formatted for readability
|
|
|
71
185
|
]
|
|
72
186
|
```
|
|
73
187
|
|
|
74
|
-
It is possible to specify the path to metadata.json and customize the setfiles. For example, to ensure the setfiles use FQDNs and apply the [systemd PIDFile workaround under docker](https://github.com/docker/for-linux/issues/835). This either means either using an older image (CentOS 7, Ubuntu 16.04) or skipping (CentOS 8).
|
|
75
|
-
|
|
76
|
-
```console
|
|
77
|
-
$ metadata2gha --use-fqdn --pidfile-workaround true /path/to/metadata.json
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
This results in the following JSON data
|
|
81
|
-
```json
|
|
82
|
-
[
|
|
83
|
-
{
|
|
84
|
-
"name": "Puppet 7 - CentOS 7",
|
|
85
|
-
"env": {
|
|
86
|
-
"BEAKER_PUPPET_COLLECTION": "puppet7",
|
|
87
|
-
"BEAKER_SETFILE": "centos7-64{hostname=centos7-64-puppet7.example.com,image=centos:7.6.1810}"
|
|
88
|
-
}
|
|
89
|
-
},
|
|
90
|
-
{
|
|
91
|
-
"name": "Puppet 7 - Debian 12",
|
|
92
|
-
"env": {
|
|
93
|
-
"BEAKER_PUPPET_COLLECTION": "puppet7",
|
|
94
|
-
"BEAKER_SETFILE": "debian12-64{hostname=debian12-64-puppet7.example.com}"
|
|
95
|
-
}
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
"name": "Puppet 7 - Ubuntu 22.04",
|
|
99
|
-
"env": {
|
|
100
|
-
"BEAKER_PUPPET_COLLECTION": "puppet7",
|
|
101
|
-
"BEAKER_SETFILE": "ubuntu2204-64{hostname=ubuntu2204-64-puppet7.example.com}"
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
]
|
|
105
|
-
```
|
|
106
|
-
|
|
107
188
|
If you need custom hostname or multiple hosts in your integration tests this could be achived by using the --beaker-hosts option
|
|
108
189
|
|
|
109
190
|
Option argument is 'HOSTNAME:ROLES;HOSTNAME:..;..' where
|
|
@@ -212,6 +293,60 @@ The metadata object has several different methods that we can call
|
|
|
212
293
|
[7] pry(main)>
|
|
213
294
|
```
|
|
214
295
|
|
|
296
|
+
### Get all versions for an Operating System that are not EoL
|
|
297
|
+
|
|
298
|
+
```
|
|
299
|
+
[1] pry(main)> require 'puppet_metadata'
|
|
300
|
+
=> true
|
|
301
|
+
[2] pry(main)> PuppetMetadata::OperatingSystem.supported_releases('RedHat')
|
|
302
|
+
=> ["8", "9", "10"]
|
|
303
|
+
[3] pry(main)> PuppetMetadata::OperatingSystem.supported_releases('windows')
|
|
304
|
+
=> []
|
|
305
|
+
[4] pry(main)>
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
**For Operating systems without any known releases, an empty array is returned.**
|
|
309
|
+
|
|
310
|
+
### Get all versions for an Operating System that are not EoL after a certain date
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
[1] pry(main)> require 'puppet_metadata'
|
|
314
|
+
=> true
|
|
315
|
+
[2] pry(main)> PuppetMetadata::OperatingSystem.supported_releases('CentOS', Date.parse('2025-04-15'))
|
|
316
|
+
=> ["9", "10"]
|
|
317
|
+
[3] pry(main)>
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
CentOS 8 and older aren't listed.
|
|
321
|
+
8 is EoL since 2024-05-31.
|
|
322
|
+
|
|
323
|
+
## Updating OS EOL dates
|
|
324
|
+
|
|
325
|
+
The EOL dates for operating systems are stored in `data/eol_dates.json` and are automatically updated weekly via GitHub Actions using data from [endoflife.date](https://endoflife.date/).
|
|
326
|
+
|
|
327
|
+
- For Amazon Linux, this is security support, not standard support.
|
|
328
|
+
- For Debian, this is extended life cycle, not standard support.
|
|
329
|
+
- For CentOS, this is security support, not active support.
|
|
330
|
+
- For OracleLinux, this is basic support, not extended support.
|
|
331
|
+
- For RedHat, this is maintenance support, not extended life cycle.
|
|
332
|
+
- For Rocky, this is security support, not active support.
|
|
333
|
+
- For SLES, this is general support, not long term service pack support.
|
|
334
|
+
|
|
335
|
+
To manually update the EOL dates:
|
|
336
|
+
|
|
337
|
+
```bash
|
|
338
|
+
./bin/update_eol_dates
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Adding new operating systems
|
|
342
|
+
|
|
343
|
+
To add a new operating system to the EOL tracking:
|
|
344
|
+
|
|
345
|
+
1. Add an entry to the `OS_MAPPING` hash in `bin/update_eol_dates`
|
|
346
|
+
2. Map it to the corresponding [endoflife.date product identifier](https://endoflife.date/docs/api/)
|
|
347
|
+
3. Run `./bin/update_eol_dates` to fetch the data
|
|
348
|
+
4. If the OS requires special handling (like Amazon Linux which uses multiple API endpoints), add a custom handler function
|
|
349
|
+
|
|
215
350
|
## List supported setfiles
|
|
216
351
|
|
|
217
352
|
When running beaker on the CLI, you can specify a specific setfile. `puppet_metadata` provides `bin/setfiles` to list all setfiles:
|
data/bin/metadata2gha
CHANGED
|
@@ -3,10 +3,7 @@ require 'optparse'
|
|
|
3
3
|
require 'json'
|
|
4
4
|
require 'puppet_metadata'
|
|
5
5
|
|
|
6
|
-
PidfileWorkaround = Object.new
|
|
7
|
-
|
|
8
6
|
options = {
|
|
9
|
-
beaker_pidfile_workaround: false,
|
|
10
7
|
domain: nil,
|
|
11
8
|
minimum_major_puppet_version: nil,
|
|
12
9
|
beaker_fact: nil,
|
|
@@ -14,20 +11,8 @@ options = {
|
|
|
14
11
|
}
|
|
15
12
|
|
|
16
13
|
OptionParser.new do |opts|
|
|
17
|
-
opts.accept(PidfileWorkaround) do |value|
|
|
18
|
-
case value
|
|
19
|
-
when 'true'
|
|
20
|
-
true
|
|
21
|
-
when 'false'
|
|
22
|
-
false
|
|
23
|
-
else
|
|
24
|
-
value.split(',')
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
14
|
opts.banner = "Usage: #{$0} [options] metadata"
|
|
29
15
|
|
|
30
|
-
opts.on('--pidfile-workaround VALUE', 'Generate the systemd PIDFile workaround to work around a docker bug', PidfileWorkaround) { |opt| options[:beaker_pidfile_workaround] = opt }
|
|
31
16
|
opts.on('-d', '--domain VALUE', 'the domain for the box, only used when --use-fqdn is set to true') { |opt| options[:domain] = opt }
|
|
32
17
|
opts.on('--minimum-major-puppet-version VERSION', "Don't create actions for Puppet versions less than this major version") { |opt| options[:minimum_major_puppet_version] = opt }
|
|
33
18
|
opts.on('--beaker-facter FACT:LABEL:VALUES', 'Expand the matrix based on a fact. Separate values using commas') do |opt|
|
data/bin/puppet-metadata
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# optparse subcommands inspired by https://gist.github.com/rkumar/445735
|
|
5
|
+
|
|
6
|
+
require 'optparse'
|
|
7
|
+
require 'optparse/date'
|
|
8
|
+
|
|
9
|
+
require 'puppet_metadata'
|
|
10
|
+
|
|
11
|
+
def main
|
|
12
|
+
subcommands = PuppetMetadata::BaseCommand.commands
|
|
13
|
+
|
|
14
|
+
options = {}
|
|
15
|
+
|
|
16
|
+
parsers = subcommands.transform_values { |cls| cls.parser(options) }
|
|
17
|
+
|
|
18
|
+
global = OptionParser.new do |opts|
|
|
19
|
+
opts.banner = "Usage: #{opts.program_name} [options] <action> [options]"
|
|
20
|
+
opts.on('--filename METADATA', 'Metadata filename') do |value|
|
|
21
|
+
options[:filename] = value
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
opts.separator ''
|
|
25
|
+
opts.separator 'ACTIONS'
|
|
26
|
+
width = subcommands.keys.max { |command, _parser| command.length }.length
|
|
27
|
+
parsers.each do |command, parser|
|
|
28
|
+
# TODO: positional argument
|
|
29
|
+
parser.banner = "Usage: #{opts.program_name} #{command} [options]"
|
|
30
|
+
opts.separator " #{command.ljust(width + 4)}#{parser.program_name}"
|
|
31
|
+
end
|
|
32
|
+
opts.separator ''
|
|
33
|
+
opts.separator "See '#{opts.program_name} ACTION --help' for more information on a specific action."
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
begin
|
|
37
|
+
global.order!
|
|
38
|
+
rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
|
|
39
|
+
warn e.cause ? "#{e}: #{e.cause}" : e
|
|
40
|
+
warn ''
|
|
41
|
+
global.help_exit
|
|
42
|
+
end
|
|
43
|
+
unless (command = ARGV.shift)
|
|
44
|
+
puts global
|
|
45
|
+
exit 1
|
|
46
|
+
end
|
|
47
|
+
if (parser = parsers[command])
|
|
48
|
+
begin
|
|
49
|
+
arguments = parser.parse!
|
|
50
|
+
rescue OptionParser::InvalidArgument, OptionParser::InvalidOption => e
|
|
51
|
+
warn e.cause ? "#{e}: #{e.cause}" : e
|
|
52
|
+
warn ''
|
|
53
|
+
parser.help_exit
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
command = subcommands[command].new(arguments, options)
|
|
57
|
+
command.run
|
|
58
|
+
else
|
|
59
|
+
puts global
|
|
60
|
+
exit 1
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
main
|
data/bin/setfiles
CHANGED
|
@@ -16,13 +16,14 @@ rescue StandardError => e
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
options = {
|
|
19
|
-
beaker_pidfile_workaround: false,
|
|
20
19
|
domain: 'example.com',
|
|
21
20
|
minimum_major_puppet_version: nil,
|
|
22
21
|
beaker_fact: nil,
|
|
23
22
|
beaker_hosts: nil,
|
|
24
23
|
}
|
|
25
24
|
|
|
25
|
+
warn 'Command deprecated - call puppet-metadata setfiles instead'
|
|
26
|
+
|
|
26
27
|
metadata.github_actions(options).outputs[:puppet_beaker_test_matrix].each do |os|
|
|
27
28
|
puts "BEAKER_SETFILE=\"#{os[:env]['BEAKER_SETFILE']}\""
|
|
28
29
|
end
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# This script updates the EOL dates data file using the endoflife.date API
|
|
5
|
+
# It can be run manually or via GitHub Actions automation
|
|
6
|
+
|
|
7
|
+
require 'json'
|
|
8
|
+
require 'net/http'
|
|
9
|
+
require 'uri'
|
|
10
|
+
require 'date'
|
|
11
|
+
|
|
12
|
+
# Mapping between internal OS names and endoflife.date identifiers; only OSes listed here will be updated
|
|
13
|
+
OS_MAPPING = {
|
|
14
|
+
'AlmaLinux' => 'almalinux',
|
|
15
|
+
'Amazon' => 'amazon-linux',
|
|
16
|
+
'CentOS' => 'centos',
|
|
17
|
+
'Debian' => 'debian',
|
|
18
|
+
'OracleLinux' => 'oracle-linux',
|
|
19
|
+
'Fedora' => 'fedora',
|
|
20
|
+
'FreeBSD' => 'freebsd',
|
|
21
|
+
'RedHat' => 'rhel',
|
|
22
|
+
'Rocky' => 'rocky-linux',
|
|
23
|
+
'Scientific' => nil, # Not in endoflife.date
|
|
24
|
+
'SLES' => 'sles',
|
|
25
|
+
'Ubuntu' => 'ubuntu',
|
|
26
|
+
}.freeze
|
|
27
|
+
|
|
28
|
+
def fetch_eol_data(product)
|
|
29
|
+
uri = URI("https://endoflife.date/api/#{product}.json")
|
|
30
|
+
response = Net::HTTP.get_response(uri)
|
|
31
|
+
|
|
32
|
+
unless response.is_a?(Net::HTTPSuccess)
|
|
33
|
+
warn "Failed to fetch data for #{product}: #{response.code} #{response.message}"
|
|
34
|
+
return nil
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
JSON.parse(response.body)
|
|
38
|
+
rescue StandardError => e
|
|
39
|
+
warn "Error fetching data for #{product}: #{e.message}"
|
|
40
|
+
nil
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parse_eol_date(eol_value)
|
|
44
|
+
# endoflife.date returns different formats:
|
|
45
|
+
# - Date string: "2024-06-30"
|
|
46
|
+
# - Boolean false: not yet EOL
|
|
47
|
+
# - Boolean true: EOL date unknown
|
|
48
|
+
case eol_value
|
|
49
|
+
when String
|
|
50
|
+
# Validate it's a proper date
|
|
51
|
+
Date.parse(eol_value)
|
|
52
|
+
eol_value
|
|
53
|
+
when false, 'false', true, 'true'
|
|
54
|
+
# false: Not yet EOL
|
|
55
|
+
# true: EOL date unknown - keep existing data or skip
|
|
56
|
+
nil
|
|
57
|
+
end
|
|
58
|
+
rescue Date::Error
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def update_os_data(os_name, product_id, current_data)
|
|
63
|
+
return current_data unless product_id
|
|
64
|
+
|
|
65
|
+
puts "Fetching data for #{os_name} (#{product_id})..."
|
|
66
|
+
api_data = fetch_eol_data(product_id)
|
|
67
|
+
return current_data unless api_data
|
|
68
|
+
|
|
69
|
+
updated_data = {}
|
|
70
|
+
|
|
71
|
+
api_data.each do |cycle|
|
|
72
|
+
# The API returns an array of cycles, each with:
|
|
73
|
+
# - cycle: version number
|
|
74
|
+
# - eol: end of life date or boolean
|
|
75
|
+
version = cycle['cycle'].to_s
|
|
76
|
+
eol_value = if os_name == 'Debian' && cycle.key?('extendedSupport')
|
|
77
|
+
cycle['extendedSupport']
|
|
78
|
+
else
|
|
79
|
+
cycle['eol']
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
eol = parse_eol_date(eol_value)
|
|
83
|
+
|
|
84
|
+
if eol
|
|
85
|
+
updated_data[version] = eol
|
|
86
|
+
puts " #{version}: #{eol}"
|
|
87
|
+
elsif eol_value == false || cycle['eol'] == false
|
|
88
|
+
# Track versions that aren't EOL yet
|
|
89
|
+
updated_data[version] = nil
|
|
90
|
+
puts " #{version}: not yet EOL"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
current_data[os_name]&.each do |version, date|
|
|
95
|
+
unless updated_data.key?(version)
|
|
96
|
+
puts " Preserving #{version}: #{date || 'nil'} (not in API)"
|
|
97
|
+
updated_data[version] = date
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
updated_data
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def handle_amazon_linux(current_data)
|
|
105
|
+
puts 'Fetching data for Amazon Linux...'
|
|
106
|
+
|
|
107
|
+
updated_data = {}
|
|
108
|
+
|
|
109
|
+
al_data = fetch_eol_data('amazon-linux')
|
|
110
|
+
al_data&.each do |cycle|
|
|
111
|
+
version = cycle['cycle'].to_s
|
|
112
|
+
eol = parse_eol_date(cycle['eol'])
|
|
113
|
+
|
|
114
|
+
# Map version "2" to "2.0" for compatibility with existing metadata entries
|
|
115
|
+
version = '2.0' if version == '2'
|
|
116
|
+
|
|
117
|
+
if eol
|
|
118
|
+
updated_data[version] = eol
|
|
119
|
+
puts " #{version}: #{eol}"
|
|
120
|
+
elsif cycle['eol'] == false
|
|
121
|
+
updated_data[version] = nil
|
|
122
|
+
puts " #{version}: not yet EOL"
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
current_data['Amazon']&.each do |version, date|
|
|
127
|
+
unless updated_data.key?(version)
|
|
128
|
+
puts " Preserving #{version}: #{date || 'nil'} (not in API)"
|
|
129
|
+
updated_data[version] = date
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
updated_data
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def handle_centos(current_data)
|
|
137
|
+
puts 'Fetching data for CentOS...'
|
|
138
|
+
|
|
139
|
+
updated_data = {}
|
|
140
|
+
|
|
141
|
+
centos_data = fetch_eol_data('centos')
|
|
142
|
+
centos_data&.each do |cycle|
|
|
143
|
+
version = cycle['cycle'].to_s
|
|
144
|
+
eol = parse_eol_date(cycle['eol'])
|
|
145
|
+
|
|
146
|
+
if eol
|
|
147
|
+
updated_data[version] = eol
|
|
148
|
+
puts " #{version}: #{eol}"
|
|
149
|
+
elsif cycle['eol'] == false
|
|
150
|
+
updated_data[version] = nil
|
|
151
|
+
puts " #{version}: not yet EOL"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
# Fetch CentOS Stream versions after CentOS. Stream takes precedence for overlapping versions.
|
|
156
|
+
stream_data = fetch_eol_data('centos-stream')
|
|
157
|
+
stream_data&.each do |cycle|
|
|
158
|
+
version = cycle['cycle'].to_s
|
|
159
|
+
eol = parse_eol_date(cycle['eol'])
|
|
160
|
+
|
|
161
|
+
if eol
|
|
162
|
+
updated_data[version] = eol
|
|
163
|
+
puts " #{version}: #{eol}"
|
|
164
|
+
elsif cycle['eol'] == false
|
|
165
|
+
updated_data[version] = nil
|
|
166
|
+
puts " #{version}: not yet EOL"
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
current_data['CentOS']&.each do |version, date|
|
|
171
|
+
unless updated_data.key?(version)
|
|
172
|
+
puts " Preserving #{version}: #{date || 'nil'} (not in API)"
|
|
173
|
+
updated_data[version] = date
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
updated_data
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def handle_ubuntu(current_data)
|
|
181
|
+
puts 'Fetching data for Ubuntu...'
|
|
182
|
+
|
|
183
|
+
updated_data = {}
|
|
184
|
+
|
|
185
|
+
ubuntu_data = fetch_eol_data('ubuntu')
|
|
186
|
+
ubuntu_data&.each do |cycle|
|
|
187
|
+
version = cycle['cycle'].to_s
|
|
188
|
+
eol = parse_eol_date(cycle['eol'])
|
|
189
|
+
|
|
190
|
+
if eol
|
|
191
|
+
updated_data[version] = eol
|
|
192
|
+
puts " #{version}: #{eol}"
|
|
193
|
+
elsif cycle['eol'] == false
|
|
194
|
+
updated_data[version] = nil
|
|
195
|
+
puts " #{version}: not yet EOL"
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
current_data['Ubuntu']&.each do |version, date|
|
|
200
|
+
next if updated_data.key?(version)
|
|
201
|
+
|
|
202
|
+
puts " Preserving #{version}: #{date || 'nil'} (not in API)"
|
|
203
|
+
updated_data[version] = date
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
updated_data
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def main
|
|
210
|
+
data_file = File.expand_path('../data/eol_dates.json', __dir__)
|
|
211
|
+
|
|
212
|
+
# Load current data
|
|
213
|
+
current_data = JSON.parse(File.read(data_file))
|
|
214
|
+
|
|
215
|
+
# Update each OS
|
|
216
|
+
updated_data = {}
|
|
217
|
+
|
|
218
|
+
OS_MAPPING.each do |os_name, product_id|
|
|
219
|
+
if os_name == 'Amazon'
|
|
220
|
+
updated_data[os_name] = handle_amazon_linux(current_data)
|
|
221
|
+
elsif os_name == 'CentOS'
|
|
222
|
+
updated_data[os_name] = handle_centos(current_data)
|
|
223
|
+
elsif os_name == 'Ubuntu'
|
|
224
|
+
updated_data[os_name] = handle_ubuntu(current_data)
|
|
225
|
+
elsif product_id
|
|
226
|
+
updated_data[os_name] = update_os_data(os_name, product_id, current_data)
|
|
227
|
+
else
|
|
228
|
+
puts "Preserving #{os_name} (not in endoflife.date API)"
|
|
229
|
+
updated_data[os_name] = current_data[os_name]
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
# Sort each OS's versions by EOL date (latest EOL first, then nulls)
|
|
234
|
+
sorted_data = {}
|
|
235
|
+
updated_data.each do |os_name, versions|
|
|
236
|
+
sorted_versions = versions.sort do |a, b|
|
|
237
|
+
version_a, eol_a = a
|
|
238
|
+
version_b, eol_b = b
|
|
239
|
+
|
|
240
|
+
# Handle nil values (not yet EOL) - they go first
|
|
241
|
+
return -1 if eol_a.nil? && !eol_b.nil?
|
|
242
|
+
return 1 if !eol_a.nil? && eol_b.nil?
|
|
243
|
+
|
|
244
|
+
if eol_a == eol_b
|
|
245
|
+
# Same EOL date (or both nil) - sort by version number descending
|
|
246
|
+
Gem::Version.new(version_b) <=> Gem::Version.new(version_a)
|
|
247
|
+
else
|
|
248
|
+
# Different EOL dates - sort by date descending (later date first)
|
|
249
|
+
(eol_b || '0000-00-00') <=> (eol_a || '0000-00-00')
|
|
250
|
+
end
|
|
251
|
+
end.to_h
|
|
252
|
+
sorted_data[os_name] = sorted_versions
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
File.write(data_file, "#{JSON.pretty_generate(sorted_data)}\n")
|
|
256
|
+
puts "\nUpdated #{data_file}"
|
|
257
|
+
|
|
258
|
+
if current_data == updated_data
|
|
259
|
+
puts 'No changes detected.'
|
|
260
|
+
exit 0
|
|
261
|
+
else
|
|
262
|
+
puts 'Changes detected!'
|
|
263
|
+
exit 1 # Exit with 1 to signal changes (useful for CI)
|
|
264
|
+
end
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
main if __FILE__ == $0
|