getv-rs 2.3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a0f9f67eef721617d91a03f548a9a24488d8e1f74d071b479d4df874fc57578
4
+ data.tar.gz: c92fc90d57b1b25a4bc6dc1d20400022f7fbfacc52bf300735e1f154b00ba004
5
+ SHA512:
6
+ metadata.gz: 0df35d693cd27977bf421e154d8be695fd22f85d6cf0945186cd0992221d28bb303451e385e5ed5b5e0c740ef7557184d13fd0b617984284cc6526d076b4c7b5
7
+ data.tar.gz: fe427c825af69ed7e0b33e2bce52c7e10ceb7c398fc3739ecca315416cb535f907533580af652a59abf461dbb058485f25b92325121f450b0328dcc55997b101
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Richard Grainger
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # getv
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/getv.svg)](https://rubygems.org/gems/getv)
4
+
5
+ The goal of `getv` is to make it easy and quick to pull software package version numbers from various sources on the web. The application is packaged as a [gem](https://rubygems.org/gems/getv) and provides both a Ruby library and an executable command line tool, `getv`.
6
+
7
+ ## Installation
8
+
9
+ Install `getv` with:
10
+
11
+ ```
12
+ gem install getv
13
+ ```
14
+
15
+ Or add this line to your application's Gemfile:
16
+
17
+ ```ruby
18
+ gem 'getv'
19
+ ```
20
+
21
+ And then execute:
22
+
23
+ ```sh
24
+ bundle install
25
+ ```
26
+
27
+ ## CLI
28
+
29
+ An executable command tool, `getv` is bundled with this gem:
30
+
31
+ ```console
32
+ $ getv
33
+ NAME
34
+ getv - Get package version numbers from the web in various ways
35
+
36
+
37
+ SYNOPSIS
38
+ getv [global options] command [command options] [arguments...]
39
+
40
+
41
+ VERSION
42
+ 2.1.4
43
+
44
+
45
+
46
+ GLOBAL OPTIONS
47
+ --help - Show this message
48
+ -j, --json - Output in json
49
+ -l, --latest - Latest version
50
+ -p, --proxy=arg - Web proxy (default: none)
51
+ --version - Display the program version
52
+
53
+
54
+
55
+ COMMANDS
56
+ docker - Get package versions from a Docker or OCI container image registry
57
+ gem - Get package versions from RubyGems.org
58
+ github_commit - Get package versions from GitHub commits
59
+ github_release - Get package versions from GitHub releases
60
+ github_tag - Get package versions from GitHub tags
61
+ helm - Get package versions from a Helm chart repository
62
+ help - Shows a list of commands or help for one command
63
+ npm - Get package versions from npm at registry.npmjs.org
64
+ pypi - Get package versions from the Python Package Index at pypi.org
65
+ text - Get package versions from text file URL
66
+ xml - Get package versions from XML file URL
67
+ ```
68
+
69
+ ### CLI examples
70
+
71
+ Show the latest available version of the `getv` gem:
72
+
73
+ ```console
74
+ $ getv --latest gem getv
75
+ 2.1.4
76
+ ```
77
+
78
+ Show all `dep` GitHub release versions in JSON:
79
+
80
+ ```console
81
+ $ getv --json github_release golang/dep
82
+ {"name":"golang/dep","versions":["0.2.0","0.2.1","0.3.0","0.3.1","0.3.2","0.4.0","0.4.1","0.5.0","0.5.1","0.5.2","0.5.3","0.5.4"]}
83
+ ```
84
+
85
+ Show all AtomicParsley Github release versions:
86
+
87
+ ```console
88
+ $ getv github_release --invalid_versions wez/atomicparsley
89
+ 20200701.154658.b0d6223
90
+ 20201231.092811.cbecfb1
91
+ 20210114.184825.1dbe1be
92
+ 20210124.204813.840499f
93
+ 20210617.200601.1ac7c08
94
+ 20210715.151551.e7ad03a
95
+ ```
96
+
97
+ Show the latest stable version of Kubernetes using the release text file URL:
98
+
99
+ ```console
100
+ $ getv -l text --url=https://storage.googleapis.com/kubernetes-release/release/stable.txt kubernetes
101
+ 1.23.2
102
+ ```
103
+
104
+ Show selected semantic versions of the `apache/superset` Docker image in JSON:
105
+
106
+ ```console
107
+ $ getv --json docker --reject '-' --semantic_select '~>1.3.0,!=1.3.1' apache/superset
108
+ {"name":"apache/superset","versions":["1.3.0","1.3.2"]}
109
+ ```
110
+
111
+ Show all versions of `libnetfilter_acct` using selected link values (`<a>` HTML elements) on an indexed web page:
112
+
113
+ ```console
114
+ $ getv xml --url=https://netfilter.org/projects/libnetfilter_acct/files --xpath '//a' --select_search='^.*libnetfilter_acct-([\d\.]*)\.tar\.bz2$' libnetfilter_acct
115
+ 1.0.0
116
+ 1.0.1
117
+ 1.0.2
118
+ 1.0.3
119
+ ```
120
+
121
+ Show the latest GitHub commit to the `main` branch of the `getv` project in a useful versioning format:
122
+
123
+ ```console
124
+ # By default the \2 capture group contains the date and \5 contains the short commit hash
125
+ $ getv -l github_commit --select_replace '\2git\5' --branch main liger1978/getv
126
+ 20220123git9ed86f0
127
+ ```
128
+
129
+ ## Ruby library
130
+
131
+ Example:
132
+
133
+ ```ruby
134
+ require 'getv'
135
+
136
+ superset = Getv::Package::Docker.new 'apache/superset', reject: '-'
137
+ puts superset.versions
138
+ puts superset.latest_version
139
+
140
+ # You can also use the flexible "create" factory method
141
+ Getv::Package.create 'apache/superset', type: 'docker', reject: '-'
142
+ Getv::Package.create 'golang/dep', type: 'github release'
143
+ Getv::Package.create 'golang/dep', type: 'github_release'
144
+ Getv::Package.create 'golang/dep', type: 'GitHub::Release'
145
+ Getv::Package.create 'rubygem-getv'
146
+ ```
147
+
148
+ ## Development
149
+
150
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rake spec` to run the tests. Run `bundle exec rubocop` to run the linter. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
151
+
152
+ Note that by default, Bundler will attempt to install gems to the system, e.g. `/usr/bin`, `/usr/share`, which requires elevated access and can interfere with files that are managed by the system's package manager. This behaviour can be overridden by creating the file `.bundle/config` and adding the following line:
153
+ ```
154
+ BUNDLE_PATH: "./.bundle"
155
+ ```
156
+ When you run `bin/setup` or `bundle install`, all gems will be installed inside the .bundle directory of this project.
157
+
158
+ To make this behaviour a default for all gem projects, the above line can be added to the user's bundle config file in their home directory (`~/.bundle/config`)
159
+
160
+ ## Contributing
161
+
162
+ Bug reports and pull requests are welcome on [GitHub](https://github.com/liger1978/getv).
163
+
164
+ ## License
165
+
166
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/exe/getv ADDED
@@ -0,0 +1,324 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'getv'
5
+ require 'gli'
6
+
7
+ module Getv
8
+ # cli class
9
+ class Cli
10
+ def self.output(package, latest: false, json: false)
11
+ key = latest ? 'latest_version' : 'versions'
12
+ result = package.send(key)
13
+
14
+ if json
15
+ require 'json'
16
+ result = { 'name' => package.name, key => result }.to_json
17
+ end
18
+
19
+ puts result
20
+ end
21
+ end
22
+ end
23
+
24
+ # app class
25
+ class App # rubocop:disable Metrics/ClassLength
26
+ extend GLI::App
27
+
28
+ program_desc 'Get package version numbers from the web in various ways'
29
+
30
+ version Getv::VERSION
31
+
32
+ subcommand_option_handling :normal
33
+ arguments :strict
34
+
35
+ switch %i[l latest], desc: 'Latest version', negatable: false
36
+ switch %i[j json], desc: 'Output in json', negatable: false
37
+ flag %i[p proxy], desc: 'Web proxy', default_value: nil
38
+
39
+ desc 'Get package versions from a Docker or OCI container image registry'
40
+ arg_name 'package_name'
41
+ command :docker do |c| # rubocop:disable Metrics/BlockLength
42
+ defaults = (Getv::Package::Docker.new 'name').opts
43
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
44
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
45
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
46
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
47
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
48
+ default_value: defaults[:semantic_select]
49
+ c.flag %i[owner], desc: 'Repository owner',
50
+ default_value: "'<owner>' if package_name is in format '<registry>/<owner>/<repo>' or '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
51
+ c.flag %i[repo], desc: 'Repository name',
52
+ default_value: "'<repo>' if package_name is in format '<registry>/<owner>/<repo>' or <owner>/<repo>, otherwise just package_name" # rubocop:disable Layout/LineLength
53
+ c.flag %i[url], desc: 'URL',
54
+ default_value: "'https://<registry>' if package_name is in format '<registry>/<owner>/<repo>', otherwise #{defaults[:url]}" # rubocop:disable Layout/LineLength
55
+ c.flag %i[user], desc: 'Username', default_value: defaults[:user]
56
+ c.flag %i[password], desc: 'Password', default_value: defaults[:password]
57
+ c.action do |global_options, options, args|
58
+ help_now! unless args.size == 1
59
+
60
+ opts = global_options.merge(options)
61
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
62
+ :url, :user, :password, :proxy
63
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
64
+ opts[:semantic_only] = !options[:invalid_versions]
65
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
66
+ package = Getv::Package::Docker.new args[0], opts
67
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
68
+ end
69
+ end
70
+
71
+ desc 'Get package versions from RubyGems.org'
72
+ arg_name 'package_name'
73
+ command :gem do |c|
74
+ defaults = (Getv::Package::Gem.new 'name').opts
75
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
76
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
77
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
78
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
79
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
80
+ default_value: defaults[:semantic_select]
81
+ c.action do |global_options, options, args|
82
+ help_now! unless args.size == 1
83
+
84
+ opts = global_options.merge(options)
85
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
86
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
87
+ opts[:semantic_only] = !options[:invalid_versions]
88
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
89
+ package = Getv::Package::Gem.new args[0], opts
90
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
91
+ end
92
+ end
93
+
94
+ desc 'Get package versions from text file URL'
95
+ arg_name 'package_name'
96
+ command :text do |c|
97
+ defaults = (Getv::Package::Text.new 'name').opts
98
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
99
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
100
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
101
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
102
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
103
+ default_value: defaults[:semantic_select]
104
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
105
+ c.action do |global_options, options, args|
106
+ help_now! unless args.size == 1
107
+
108
+ opts = global_options.merge(options)
109
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :url, :proxy
110
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
111
+ opts[:semantic_only] = !options[:invalid_versions]
112
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
113
+ package = Getv::Package::Text.new args[0], opts
114
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
115
+ end
116
+ end
117
+
118
+ desc 'Get package versions from GitHub commits'
119
+ arg_name 'package_name'
120
+ command :github_commit do |c|
121
+ defaults = (Getv::Package::GitHub::Commit.new 'name').opts
122
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
123
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
124
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
125
+ c.flag %i[owner], desc: 'Repository owner',
126
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
127
+ c.flag %i[repo], desc: 'Repository name',
128
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
129
+ c.flag %i[branch], desc: 'Repository branch', default_value: defaults[:branch]
130
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
131
+ c.action do |global_options, options, args|
132
+ help_now! unless args.size == 1
133
+
134
+ opts = global_options.merge(options)
135
+ opts = opts.slice :select_search, :select_replace, :reject, :owner, :repo, :branch, :token, :proxy
136
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
137
+ package = Getv::Package::GitHub::Commit.new args[0], opts
138
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
139
+ end
140
+ end
141
+
142
+ desc 'Get package versions from GitHub releases'
143
+ arg_name 'package_name'
144
+ command :github_release do |c|
145
+ defaults = (Getv::Package::GitHub::Release.new 'name').opts
146
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
147
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
148
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
149
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
150
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
151
+ default_value: defaults[:semantic_select]
152
+ c.flag %i[owner], desc: 'Repository owner',
153
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
154
+ c.flag %i[repo], desc: 'Repository name',
155
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
156
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
157
+ c.action do |global_options, options, args|
158
+ help_now! unless args.size == 1
159
+
160
+ opts = global_options.merge(options)
161
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
162
+ :token, :proxy
163
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
164
+ opts[:semantic_only] = !options[:invalid_versions]
165
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
166
+ package = Getv::Package::GitHub::Release.new args[0], opts
167
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
168
+ end
169
+ end
170
+
171
+ desc 'Get package versions from GitHub tags'
172
+ arg_name 'package_name'
173
+ command :github_tag do |c|
174
+ defaults = (Getv::Package::GitHub::Tag.new 'name').opts
175
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
176
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
177
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
178
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
179
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
180
+ default_value: defaults[:semantic_select]
181
+ c.flag %i[owner], desc: 'Repository owner',
182
+ default_value: "'<owner>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
183
+ c.flag %i[repo], desc: 'Repository name',
184
+ default_value: "'<repo>' if package_name is in format '<owner>/<repo>', otherwise just package_name" # rubocop:disable Layout/LineLength
185
+ c.flag %i[token], desc: 'Token', default_value: defaults[:token]
186
+ c.action do |global_options, options, args|
187
+ help_now! unless args.size == 1
188
+
189
+ opts = global_options.merge(options)
190
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :owner, :repo,
191
+ :token, :proxy
192
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
193
+ opts[:semantic_only] = !options[:invalid_versions]
194
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
195
+ package = Getv::Package::GitHub::Tag.new args[0], opts
196
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
197
+ end
198
+ end
199
+
200
+ desc 'Get package versions from a Helm chart repository'
201
+ arg_name 'package_name'
202
+ command :helm do |c|
203
+ defaults = (Getv::Package::Helm.new 'name').opts
204
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
205
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
206
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
207
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
208
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
209
+ default_value: defaults[:semantic_select]
210
+ c.flag %i[chart], desc: 'Chart name', default_value: 'package_name'
211
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
212
+ c.flag %i[user], desc: 'Username', default_value: defaults[:user]
213
+ c.flag %i[password], desc: 'Password', default_value: defaults[:password]
214
+ c.action do |global_options, options, args|
215
+ help_now! unless args.size == 1
216
+
217
+ opts = global_options.merge(options)
218
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :chart, :url,
219
+ :user, :password, :proxy
220
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
221
+ opts[:semantic_only] = !options[:invalid_versions]
222
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
223
+ package = Getv::Package::Helm.new args[0], opts
224
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
225
+ end
226
+ end
227
+
228
+ desc 'Get package versions from XML file URL'
229
+ arg_name 'package_name'
230
+ command :xml do |c|
231
+ defaults = (Getv::Package::Xml.new 'name').opts
232
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
233
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
234
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
235
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
236
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
237
+ default_value: defaults[:semantic_select]
238
+ c.flag %i[url], desc: 'URL', default_value: defaults[:url]
239
+ c.flag %i[xpath], desc: 'XPath', default_value: defaults[:xpath]
240
+ c.switch %i[link_value], desc: 'Use the value (target) of links rather than the content (display text)',
241
+ negatable: false, default_value: false
242
+ c.action do |global_options, options, args|
243
+ help_now! unless args.size == 1
244
+
245
+ opts = global_options.merge(options)
246
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :url, :proxy
247
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
248
+ opts[:link] == 'value' if options[:link_value]
249
+ opts[:semantic_only] = !options[:invalid_versions]
250
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
251
+ package = Getv::Package::Xml.new args[0], opts
252
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
253
+ end
254
+ end
255
+
256
+ desc 'Get package versions from npm at registry.npmjs.org'
257
+ arg_name 'package_name'
258
+ command :npm do |c|
259
+ defaults = (Getv::Package::Npm.new 'name').opts
260
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
261
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
262
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
263
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
264
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
265
+ default_value: defaults[:semantic_select]
266
+ c.action do |global_options, options, args|
267
+ help_now! unless args.size == 1
268
+
269
+ opts = global_options.merge(options)
270
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
271
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
272
+ opts[:semantic_only] = !options[:invalid_versions]
273
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
274
+ package = Getv::Package::Npm.new args[0], opts
275
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
276
+ end
277
+ end
278
+
279
+ desc 'Get package versions from the Python Package Index at pypi.org'
280
+ arg_name 'package_name'
281
+ command :pypi do |c|
282
+ defaults = (Getv::Package::Pypi.new 'name').opts
283
+ c.flag %i[select_search], desc: 'Regex version selection search', default_value: defaults[:select_search]
284
+ c.flag %i[select_replace], desc: 'Regex version selection replace', default_value: defaults[:select_replace]
285
+ c.flag %i[reject], desc: 'Regex version rejection', default_value: defaults[:reject]
286
+ c.switch %i[invalid_versions], desc: 'Include invalid semantic versions', negatable: false, default_value: false
287
+ c.flag %i[semantic_select], desc: 'Semantic version selection (comma delimited)',
288
+ default_value: defaults[:semantic_select]
289
+ c.action do |global_options, options, args|
290
+ help_now! unless args.size == 1
291
+
292
+ opts = global_options.merge(options)
293
+ opts = opts.slice :select_search, :select_replace, :reject, :semantic_only, :semantic_select, :proxy
294
+ opts = opts.delete_if { |k, v| v.nil? || v == c.flags[k].default_value }
295
+ opts[:semantic_only] = !options[:invalid_versions]
296
+ opts[:semantic_select] = opts[:semantic_select].split(',') unless opts.fetch(:semantic_select, nil).nil?
297
+ package = Getv::Package::Pypi.new args[0], opts
298
+ Getv::Cli.output(package, latest: global_options[:latest], json: global_options[:json])
299
+ end
300
+ end
301
+
302
+ pre do |_global, _command, _options, _args|
303
+ # Pre logic here
304
+ # Return true to proceed; false to abort and not call the
305
+ # chosen command
306
+ # Use skips_pre before a command to skip this block
307
+ # on that command only
308
+ true
309
+ end
310
+
311
+ post do |global, command, options, args|
312
+ # Post logic here
313
+ # Use skips_post before a command to skip this
314
+ # block on that command only
315
+ end
316
+
317
+ on_error do |_exception|
318
+ # Error logic here
319
+ # return false to skip default error handling
320
+ true
321
+ end
322
+ end
323
+
324
+ exit App.run(ARGV)
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Docker class
6
+ class Docker < Package
7
+ def initialize(name, opts = {}, no_owner_domains = [])
8
+ @no_owner_domains = no_owner_domains
9
+ opts = defaults.merge(opts)
10
+ opts = { user: nil, password: nil, auto_paginate: true }.merge(opts)
11
+ opts = docker_defaults(name).merge(opts)
12
+ super name, opts
13
+ end
14
+
15
+ private
16
+
17
+ def docker_defaults(name)
18
+ case name.count('/')
19
+ when 0
20
+ { owner: 'library', repo: name, url: 'https://registry.hub.docker.com' }
21
+ when 1
22
+ if @no_owner_domains.include?(name.split('/')[0])
23
+ { owner: '', repo: name.split('/')[1],
24
+ url: "https://#{name.split('/')[0]}" }
25
+ else
26
+ { owner: name.split('/')[0], repo: name.split('/')[1],
27
+ url: 'https://registry.hub.docker.com' }
28
+ end
29
+ else
30
+ { owner: name.split('/')[1], repo: name.split('/')[2..].join('/'),
31
+ url: "https://#{name.split('/')[0]}" }
32
+ end
33
+ end
34
+
35
+ def docker_opts
36
+ d_opts = {}
37
+ d_opts[:http_options] = { proxy: opts[:proxy] } unless opts[:proxy].nil?
38
+ if opts[:user] && opts[:password]
39
+ d_opts[:user] = opts[:user]
40
+ d_opts[:password] = opts[:password]
41
+ end
42
+ d_opts
43
+ end
44
+
45
+ def retrieve_versions # rubocop:disable Metrics/MethodLength,Metrics/AbcSize
46
+ require 'docker_registry2'
47
+ retries ||= 0
48
+ docker = DockerRegistry2.connect(opts[:url], docker_opts)
49
+ full_name = if opts[:owner].empty?
50
+ opts[:repo]
51
+ else
52
+ "#{opts[:owner]}/#{opts[:repo]}"
53
+ end
54
+ docker.tags(full_name, auto_paginate: opts[:auto_paginate])['tags'] || []
55
+ rescue DockerRegistry2::NotFound
56
+ []
57
+ rescue StandardError => e
58
+ if (retries += 1) < 4
59
+ retry
60
+ else
61
+ puts "Error fetching tags for docker image #{opts[:url]}/#{opts[:owner]}/#{opts[:repo]}:"
62
+ puts e.message
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Gem class
6
+ class Gem < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { gem: name[/ruby(gem)?-(.*)/, 2] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://rubygems.org/api/v1/versions/#{opts[:gem]}.json")).map do |v|
19
+ v['number']
20
+ end
21
+ rescue StandardError
22
+ retry if (retries += 1) < 4
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Commit class
7
+ class Commit < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = {
10
+ branch: 'master',
11
+ select_search: '^((\d{8})(\d{6}),(([a-z\d]{7})(.*)))$',
12
+ semantic_only: false
13
+ }.merge(opts)
14
+ opts = defaults.merge(opts)
15
+ opts = github_defaults(name).merge(opts)
16
+ super name, opts
17
+ end
18
+
19
+ private
20
+
21
+ def retrieve_versions # rubocop:disable Metrics/AbcSize
22
+ retries ||= 0
23
+ github.commits("#{opts[:owner]}/#{opts[:repo]}", opts[:branch]).map do |c|
24
+ "#{DateTime.parse(c[:commit][:author][:date].to_s).strftime('%Y%m%d%H%M%S')},#{c[:sha]}"
25
+ end
26
+ rescue StandardError
27
+ retry if (retries += 1) < 4
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Release class
7
+ class Release < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = defaults.merge(opts)
10
+ opts = github_defaults(name).merge(opts)
11
+ super name, opts
12
+ end
13
+
14
+ private
15
+
16
+ def retrieve_versions
17
+ retries ||= 0
18
+ github.releases("#{opts[:owner]}/#{opts[:repo]}").map(&:tag_name)
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ class GitHub
6
+ # Getv::Package::GitHub::Tag class
7
+ class Tag < Package::GitHub
8
+ def initialize(name, opts = {})
9
+ opts = defaults.merge(opts)
10
+ opts = github_defaults(name).merge(opts)
11
+ super name, opts
12
+ end
13
+
14
+ private
15
+
16
+ def retrieve_versions
17
+ retries ||= 0
18
+ github.tags("#{opts[:owner]}/#{opts[:repo]}").map { |t| t[:name] }
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::GitHub class
6
+ class GitHub < Package
7
+ def initialize(name, opts = {})
8
+ super name, opts
9
+ end
10
+
11
+ private
12
+
13
+ def github_defaults(name)
14
+ case name.count('/')
15
+ when 1
16
+ { owner: name.split('/')[0], repo: name.split('/')[1], token: nil }
17
+ else
18
+ { owner: name, repo: name, token: nil }
19
+ end
20
+ end
21
+
22
+ def github # rubocop:disable Metrics/MethodLength
23
+ require 'octokit'
24
+ if opts[:token]
25
+ github = Octokit::Client.new(access_token: opts[:token])
26
+ user = github.user
27
+ user.login
28
+ else
29
+ github = Octokit::Client.new
30
+ end
31
+ github.auto_paginate = true
32
+ github.proxy = opts[:proxy]
33
+ github
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Helm class
6
+ class Helm < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { chart: name, url: nil, user: nil, password: nil }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'yaml'
17
+ retries ||= 0
18
+ YAML.safe_load(get("#{opts[:url]}/index.yaml")).fetch('entries', {}).fetch(opts[:chart], []).map do |e|
19
+ e['version']
20
+ end
21
+ rescue StandardError
22
+ retry if (retries += 1) < 4
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Npm class
6
+ class Npm < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { npm: name[/node(js)?-(.*)/, 2] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://registry.npmjs.org/#{opts[:npm]}"))['versions'].keys
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Pypi class
6
+ class Pypi < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { pypi: name[/python.*-(.*)/, 1] || name }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ require 'json'
17
+ retries ||= 0
18
+ JSON.parse(get("https://pypi.org/pypi/#{opts[:pypi]}/json"))['releases'].keys
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Text class
6
+ class Text < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { url: nil, user: nil, password: nil }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ retries ||= 0
17
+ get(opts[:url]).split("\n")
18
+ rescue StandardError
19
+ retry if (retries += 1) < 4
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ class Package
5
+ # Getv::Package::Xml class
6
+ class Xml < Package
7
+ def initialize(name, opts = {})
8
+ opts = defaults.merge(opts)
9
+ opts = { url: nil, user: nil, password: nil, xpath: '//a/@href' }.merge(opts)
10
+ super name, opts
11
+ end
12
+
13
+ private
14
+
15
+ def retrieve_versions
16
+ retries ||= 0
17
+ require 'nokogiri'
18
+ Nokogiri::XML(get(opts[:url])).xpath(opts[:xpath]).map(&:text)
19
+ rescue StandardError
20
+ retry if (retries += 1) < 4
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,111 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ # Getv::Package class
5
+ class Package
6
+ attr_accessor :name, :opts
7
+
8
+ def self.create(name, opts = {})
9
+ if opts.fetch(:type, nil).nil?
10
+ opts.delete(:type)
11
+ create_using_name(name, opts)
12
+ else
13
+ type = opts[:type]
14
+ opts.delete(:type)
15
+ type_to_class(type).new name, opts
16
+ end
17
+ end
18
+
19
+ private_class_method def self.create_using_name(name, opts)
20
+ case name
21
+ when /ruby(gem)?-.*/
22
+ Getv::Package::Gem.new name, opts
23
+ when /node(js)?-.*/
24
+ Getv::Package::Npm.new name, opts
25
+ when /python.*-.*/
26
+ Getv::Package::Pypi.new name, opts
27
+ else
28
+ Getv::Package::GitHub::Release.new name, opts
29
+ end
30
+ end
31
+
32
+ private_class_method def self.type_to_class(type)
33
+ sections = type.split(/_|::| |-|:/)
34
+ sections.each(&:capitalize!)
35
+ sections.each { |section| section.sub! 'Github', 'GitHub' }
36
+ type = sections.join '::'
37
+ Object.const_get("Getv::Package::#{type}")
38
+ end
39
+
40
+ def initialize(name, opts = {})
41
+ @name = name
42
+ @opts = opts
43
+ end
44
+
45
+ def defaults # rubocop:disable Metrics/MethodLength
46
+ {
47
+ select_search: '^\s*v?(.*)\s*$',
48
+ select_replace: '\1',
49
+ reject: nil,
50
+ semantic_only: true,
51
+ semantic_prefix: nil,
52
+ semantic_select: ['*'],
53
+ proxy: nil,
54
+ versions: nil,
55
+ latest_version: nil
56
+ }
57
+ end
58
+
59
+ def latest_version
60
+ update_versions if opts[:latest_version].nil?
61
+ opts[:latest_version]
62
+ end
63
+
64
+ def versions
65
+ update_versions if opts[:versions].nil?
66
+ opts[:versions]
67
+ end
68
+
69
+ def update_versions # rubocop:disable Metrics/PerceivedComplexity,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/AbcSize
70
+ versions = retrieve_versions || []
71
+ versions.sort! if instance_of?(Getv::Package::GitHub::Commit)
72
+ select_pattern = Regexp.new(opts[:select_search])
73
+ versions.select! { |v| v =~ select_pattern }
74
+ versions.map! { |v| v.sub(select_pattern, opts[:select_replace]) }
75
+ versions.reject! { |v| v =~ Regexp.new(opts[:reject]) } unless opts[:reject].nil?
76
+
77
+ if opts[:semantic_only]
78
+ require 'semantic'
79
+ require 'semantic/core_ext'
80
+
81
+ # remove non semantic version tags
82
+ versions.select! do |v|
83
+ v.sub(/^#{opts[:semantic_prefix]}/, '').is_version? && v.start_with?(opts[:semantic_prefix].to_s)
84
+ end
85
+
86
+ opts[:semantic_select].each do |comparator|
87
+ versions.select! do |v|
88
+ Semantic::Version.new(v.sub(/^#{opts[:semantic_prefix]}/, '')).satisfies?(comparator)
89
+ end
90
+ end
91
+ versions.sort_by! { |v| Semantic::Version.new(v.sub(/^#{opts[:semantic_prefix]}/, '')) }
92
+ else
93
+ versions.sort! unless instance_of?(Getv::Package::GitHub::Commit)
94
+ end
95
+ opts[:versions] = versions.uniq
96
+ opts[:latest_version] = opts[:versions][-1] unless opts[:versions].empty?
97
+ end
98
+
99
+ private
100
+
101
+ def get(url) # rubocop:disable Metrics/AbcSize
102
+ require 'rest-client'
103
+ if opts[:user] && opts[:password]
104
+ RestClient::Request.execute(method: :get, url: url, proxy: opts[:proxy], user: opts[:user],
105
+ password: opts[:password]).body
106
+ else
107
+ RestClient::Request.execute(method: :get, url: url, proxy: opts[:proxy]).body
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Getv
4
+ VERSION = '2.3.0'
5
+ end
data/lib/getv.rb ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'getv/version'
4
+ require 'getv/package'
5
+ require 'getv/package/docker'
6
+ require 'getv/package/gem'
7
+ require 'getv/package/github'
8
+ require 'getv/package/github/commit'
9
+ require 'getv/package/github/release'
10
+ require 'getv/package/github/tag'
11
+ require 'getv/package/helm'
12
+ require 'getv/package/npm'
13
+ require 'getv/package/pypi'
14
+ require 'getv/package/text'
15
+ require 'getv/package/xml'
16
+
17
+ module Getv
18
+ class Error < StandardError; end
19
+ # Your code goes here...
20
+ end
metadata ADDED
@@ -0,0 +1,184 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: getv-rs
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.3.0
5
+ platform: ruby
6
+ authors:
7
+ - ryan-scheinberg
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-09-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gli
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.20.1
20
+ - - "<"
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 2.20.1
30
+ - - "<"
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ name: docker_registry2
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: 1.10.1
40
+ - - "<"
41
+ - !ruby/object:Gem::Version
42
+ version: 2.0.0
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: 1.10.1
50
+ - - "<"
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.0
53
+ - !ruby/object:Gem::Dependency
54
+ name: nokogiri
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: 1.0.0
60
+ - - "<"
61
+ - !ruby/object:Gem::Version
62
+ version: 2.0.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: 1.0.0
70
+ - - "<"
71
+ - !ruby/object:Gem::Version
72
+ version: 2.0.0
73
+ - !ruby/object:Gem::Dependency
74
+ name: octokit
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: 3.0.0
80
+ - - "<"
81
+ - !ruby/object:Gem::Version
82
+ version: 5.0.0
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: 3.0.0
90
+ - - "<"
91
+ - !ruby/object:Gem::Version
92
+ version: 5.0.0
93
+ - !ruby/object:Gem::Dependency
94
+ name: rest-client
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: 2.1.0
100
+ - - "<"
101
+ - !ruby/object:Gem::Version
102
+ version: 3.0.0
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: 2.1.0
110
+ - - "<"
111
+ - !ruby/object:Gem::Version
112
+ version: 3.0.0
113
+ - !ruby/object:Gem::Dependency
114
+ name: semantic
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: 1.0.0
120
+ - - "<"
121
+ - !ruby/object:Gem::Version
122
+ version: 2.0.0
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - ">="
128
+ - !ruby/object:Gem::Version
129
+ version: 1.0.0
130
+ - - "<"
131
+ - !ruby/object:Gem::Version
132
+ version: 2.0.0
133
+ description: Pull package version numbers from the web in various ways.
134
+ email:
135
+ - ryan.scheinberg@gmail.com
136
+ executables:
137
+ - getv
138
+ extensions: []
139
+ extra_rdoc_files: []
140
+ files:
141
+ - LICENSE.txt
142
+ - README.md
143
+ - exe/getv
144
+ - lib/getv.rb
145
+ - lib/getv/package.rb
146
+ - lib/getv/package/docker.rb
147
+ - lib/getv/package/gem.rb
148
+ - lib/getv/package/github.rb
149
+ - lib/getv/package/github/commit.rb
150
+ - lib/getv/package/github/release.rb
151
+ - lib/getv/package/github/tag.rb
152
+ - lib/getv/package/helm.rb
153
+ - lib/getv/package/npm.rb
154
+ - lib/getv/package/pypi.rb
155
+ - lib/getv/package/text.rb
156
+ - lib/getv/package/xml.rb
157
+ - lib/getv/version.rb
158
+ homepage: https://github.com/ryan-scheinberg/getv
159
+ licenses:
160
+ - MIT
161
+ metadata:
162
+ homepage_uri: https://github.com/ryan-scheinberg/getv
163
+ source_code_uri: https://github.com/ryan-scheinberg/getv
164
+ changelog_uri: https://github.com/ryan-scheinberg/getv
165
+ post_install_message:
166
+ rdoc_options: []
167
+ require_paths:
168
+ - lib
169
+ required_ruby_version: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: '0'
174
+ required_rubygems_version: !ruby/object:Gem::Requirement
175
+ requirements:
176
+ - - ">="
177
+ - !ruby/object:Gem::Version
178
+ version: '0'
179
+ requirements: []
180
+ rubygems_version: 3.0.3.1
181
+ signing_key:
182
+ specification_version: 4
183
+ summary: Pull package version numbers from the web in various ways.
184
+ test_files: []