inquirex-tools 0.8.0 → 0.9.5

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.
@@ -0,0 +1,230 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "colored2"
4
+ require "open3"
5
+ require "rubygems/version"
6
+ require_relative "workspace"
7
+
8
+ module Inquirex
9
+ module Tools
10
+ # Moves every lockstep package to one version, then proves each one still
11
+ # builds — the write half of the pair whose read half is {VersionChecker}.
12
+ #
13
+ # The family shares a serialization format, so a version that identifies
14
+ # one package identifies all of them. Bumping is therefore all-or-nothing:
15
+ # there is no supported way to move a single package.
16
+ #
17
+ # Writing a version and verifying it are one command on purpose. A version
18
+ # written but never checked is the failure this is meant to prevent: the
19
+ # number says the family agrees while one package no longer passes its own
20
+ # suite.
21
+ #
22
+ # @example Move the family to 0.9.2 and check every package
23
+ # Inquirex::Tools::VersionBumper.new.call("0.9.2") # => false if any check fails
24
+ class VersionBumper
25
+ # A version must be exactly MAJOR.MINOR.PATCH — no prereleases, because
26
+ # the npm packages and the gems would spell them differently.
27
+ SEMVER_RE = /\A\d+\.\d+\.\d+\z/
28
+
29
+ # Prefix for the refusal messages. This command's only feedback is what
30
+ # it prints, so the word carries weight.
31
+ ERROR = "ERROR"
32
+
33
+ # What each package is verified with. One recipe for gems and npm
34
+ # packages alike — every repo's justfile defines it, which is the point
35
+ # of having a justfile in each.
36
+ CHECK = %w[just check-all].freeze
37
+
38
+ # Rule across the report, sized to the rows.
39
+ RULE = ("—" * 52).freeze
40
+
41
+ # Bringing a checkout level with origin/main before its suite runs, so a
42
+ # bump is verified against what is actually on main rather than whatever
43
+ # the local clone last saw.
44
+ SYNC_STEPS = [
45
+ %w[fetch --tags origin],
46
+ %w[rebase origin/main]
47
+ ].freeze
48
+
49
+ # Runs one git command, capturing stdout *and* stderr.
50
+ #
51
+ # Capturing is the point. Left attached, a `git` run against a directory
52
+ # that is not a checkout writes "fatal: not a git repository" straight to
53
+ # the terminal — thirty such lines during the specs, which is noise the
54
+ # operator has to learn to ignore. The caller decides what is worth
55
+ # printing.
56
+ #
57
+ # @return [Array(Boolean, String)] success, and the combined output
58
+ DEFAULT_GIT = lambda { |dir, argv|
59
+ output, status = Open3.capture2e("git", "-C", dir, *argv)
60
+ [status.success?, output]
61
+ }
62
+
63
+ # Runs a package's own checks in its own directory.
64
+ DEFAULT_RUNNER = ->(dir, argv) { Dir.chdir(dir) { system(*argv) } }
65
+
66
+ # @param workspace [Workspace] the ecosystem checkout to rewrite
67
+ # @param out [IO] where report output goes
68
+ # @param git [#call] invoked with (dir, argv); returns [ok, output].
69
+ # Injected so specs can assert what would run without touching a repo.
70
+ # @param runner [#call] invoked with (dir, argv) to run a package's
71
+ # checks. Injected for the same reason: a unit test must not shell out
72
+ # to six real suites.
73
+ def initialize(workspace: Workspace.new, out: $stdout, git: DEFAULT_GIT, runner: DEFAULT_RUNNER)
74
+ @workspace = workspace
75
+ @out = out
76
+ @git = git
77
+ @runner = runner
78
+ end
79
+
80
+ # Rewrites every lockstep package to the target version, then runs each
81
+ # package's own `just check-all`.
82
+ #
83
+ # Refuses to move backwards: a version already published cannot be
84
+ # reissued, so the target must be at least the highest current value.
85
+ #
86
+ # @param version [String] target, MAJOR.MINOR.PATCH
87
+ # @param verify [Boolean] run `just check-all` per package afterwards
88
+ # @return [Boolean] true when every package was written and checked
89
+ def call(version, verify: true)
90
+ return false unless valid?(version)
91
+
92
+ out.puts "Setting all lockstep packages to #{version} 🚨:"
93
+ each_package { |name, kind| write(name, kind, version) }
94
+ return true unless verify
95
+
96
+ out.puts
97
+ out.puts "Verifying each package with `#{CHECK.join(" ")}`:"
98
+ results = each_package { |name, _kind| check(name) }
99
+ report(results)
100
+ end
101
+
102
+ private
103
+
104
+ # @return [Workspace] the ecosystem checkout being rewritten
105
+ attr_reader :workspace
106
+
107
+ # @return [IO] where report output goes
108
+ attr_reader :out
109
+
110
+ # @return [#call] runs one git command, returning [ok, output]
111
+ attr_reader :git
112
+
113
+ # @return [#call] runs a package's checks, returning truthy on success
114
+ attr_reader :runner
115
+
116
+ # The one place the package list is walked, so adding a package changes
117
+ # nothing here.
118
+ #
119
+ # @yieldparam name [String] package name
120
+ # @yieldparam kind [Symbol] :gem or :npm
121
+ # @return [Hash{String => Object}] name => whatever the block returned
122
+ def each_package
123
+ Workspace::LOCKSTEP.to_h { |name, kind| [name, yield(name, kind)] }
124
+ end
125
+
126
+ # @return [void]
127
+ def write(name, kind, version)
128
+ workspace.write_version(name, version, kind)
129
+ row(name, kind.to_s.cyan, version.green)
130
+ end
131
+
132
+ # Runs one package's checks in its own directory.
133
+ #
134
+ # A package with no justfile is reported and skipped rather than failed:
135
+ # the fixture used by the specs has none, and a repo that has not grown
136
+ # one yet should not make a legitimate bump look broken.
137
+ #
138
+ # @param name [String] package name
139
+ # @return [Boolean, nil] pass/fail, or nil when skipped
140
+ def check(name)
141
+ dir = File.join(workspace.root, name)
142
+ unless File.exist?(File.join(dir, "justfile"))
143
+ row(name, "skip".yellow, "no justfile".yellow)
144
+ return nil
145
+ end
146
+
147
+ sync(name, dir)
148
+ passed = runner.call(dir, CHECK)
149
+ row(name, passed ? "ok".green : "FAIL".red, dir)
150
+ passed
151
+ end
152
+
153
+ # Brings one package level with origin/main before its suite runs.
154
+ #
155
+ # Two states are reported and left alone rather than acted on:
156
+ #
157
+ # - **not a git checkout** — nothing to sync, and running git here is what
158
+ # printed "fatal: not a git repository" once per command per package.
159
+ # - **uncommitted changes** — the tree is *not* stashed. A version bump
160
+ # that silently runs `git stash -u` can bury work the operator never
161
+ # agreed to move, and the stash stack is shared across worktrees, so it
162
+ # is not even reliably theirs to pop back. Rebasing on top of local
163
+ # edits is equally unwelcome. Skipping is the only non-destructive
164
+ # answer; the checks still run against what is on disk.
165
+ #
166
+ # @param name [String] package name
167
+ # @param dir [String] absolute path to the package
168
+ # @return [void]
169
+ def sync(name, dir)
170
+ state = workspace.git_state(name)
171
+ return row(name, "sync".yellow, "not a git checkout".yellow) if state[:clean].nil?
172
+ return row(name, "sync".yellow, "uncommitted changes — left alone".yellow) unless state[:clean]
173
+
174
+ SYNC_STEPS.each do |argv|
175
+ ok, output = git.call(dir, argv)
176
+ next if ok
177
+
178
+ row(name, "sync".red, "git #{argv.first} failed: #{output.to_s.lines.first&.strip}".red)
179
+ break
180
+ end
181
+ end
182
+
183
+ # The single formatting site for every line of the report.
184
+ #
185
+ # `format`, never `printf`: printf writes straight to $stdout and returns
186
+ # nil, so an injected out would receive one blank line per package while
187
+ # the real output went elsewhere.
188
+ #
189
+ # @return [void]
190
+ def row(name, state, detail)
191
+ out.puts format(" → %<name>-24s %<state>-6s %<detail>s", name: name.yellow, state:, detail:)
192
+ end
193
+
194
+ # @param results [Hash{String => Boolean, nil}] per-package check outcome
195
+ # @return [Boolean] true when nothing failed
196
+ def report(results)
197
+ failed = results.select { |_name, passed| passed == false }.keys
198
+ out.puts RULE
199
+ if failed.empty?
200
+ out.puts "OK: every package checked out".green
201
+ true
202
+ else
203
+ out.puts "#{ERROR.bold.red}: #{failed.join(", ")} failed `#{CHECK.join(" ")}`"
204
+ false
205
+ end
206
+ end
207
+
208
+ # Whether the target is well-formed and moves the family forward.
209
+ # Reports the reason it does not, since this is the CLI's only feedback.
210
+ #
211
+ # @param version [String] proposed target
212
+ # @return [Boolean]
213
+ def valid?(version)
214
+ unless SEMVER_RE.match?(version.to_s)
215
+ out.puts "#{ERROR.bold.red}: #{version.inspect} is not MAJOR.MINOR.PATCH"
216
+ return false
217
+ end
218
+
219
+ highest = workspace.versions.values.compact.max_by { Gem::Version.new(it) }
220
+ if highest && Gem::Version.new(highest) > Gem::Version.new(version)
221
+ out.puts "#{ERROR.bold.red}: #{version} is below the highest existing " \
222
+ "version (#{highest}) — versions only go forward"
223
+ return false
224
+ end
225
+
226
+ true
227
+ end
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "colored2"
4
+ require_relative "workspace"
5
+
6
+ module Inquirex
7
+ module Tools
8
+ # Reports version parity across the lockstep packages.
9
+ #
10
+ # Read-only by construction: nothing here writes a version file. Bumping is
11
+ # {VersionBumper}'s job. The split means a check can be run anywhere — CI, a
12
+ # dirty tree, a colleague's checkout — with no chance of editing something,
13
+ # and the two behaviours no longer share a flag that decides which happens.
14
+ #
15
+ # @example Check for drift
16
+ # Inquirex::Tools::VersionChecker.new.call # => false when versions differ
17
+ class VersionChecker
18
+ # @param workspace [Workspace] the ecosystem checkout to inspect
19
+ # @param out [IO] where report output goes
20
+ def initialize(workspace: Workspace.new, out: $stdout)
21
+ @workspace = workspace
22
+ @out = out
23
+ end
24
+
25
+ # Prints the current state of every lockstep package.
26
+ #
27
+ # @return [Boolean] true when all packages agree on one version
28
+ def call
29
+ versions = workspace.versions
30
+ print_table(versions)
31
+ verdict(versions)
32
+ end
33
+
34
+ # Parity plus git readiness: clean tree, on main, tagged at the version.
35
+ #
36
+ # @return [Boolean] true when every package could be published now
37
+ def preflight
38
+ ok = call
39
+ target = workspace.versions.values.compact.uniq.first
40
+ out.puts
41
+ out.puts "Release readiness:"
42
+
43
+ Workspace::LOCKSTEP.each_key do |name|
44
+ problems = readiness_problems(name, target)
45
+ # `.green`, not `.bright_green`: colored2 defines no such method, so
46
+ # the ready branch raised NoMethodError — and only the ready branch,
47
+ # which is why a preflight that found problems looked fine.
48
+ out.puts format(" %<name>-16s %<state>s", name: name, state: problems.empty? ? "ready".green : problems.join(", ").red)
49
+ ok &&= problems.empty?
50
+ end
51
+
52
+ out.puts
53
+ out.puts ok ? "ALL READY — publish with `gem push` / `npm publish`" : "NOT READY — resolve the above"
54
+ ok
55
+ end
56
+
57
+ private
58
+
59
+ # @return [Workspace] the ecosystem checkout being inspected
60
+ attr_reader :workspace
61
+
62
+ # @return [IO] where report output goes
63
+ attr_reader :out
64
+
65
+ # @param versions [Hash{String => String, nil}]
66
+ # @return [void]
67
+ def print_table(versions)
68
+ versions.each do |name, version|
69
+ # format, not printf: printf writes straight to $stdout and returns
70
+ # nil, so the injected out saw one blank line per package and the
71
+ # real table bypassed it entirely.
72
+ out.puts format(" → %<name>-30s %<kind>5s %<version>6s",
73
+ name: name.to_s.yellow,
74
+ kind: Workspace::LOCKSTEP[name].to_s.cyan,
75
+ version: (version || "MISSING").to_s.green)
76
+ end
77
+ end
78
+
79
+ # @param versions [Hash{String => String, nil}]
80
+ # @return [Boolean] true when every package agrees on one version
81
+ def verdict(versions)
82
+ out.puts "——————————————————————————————————"
83
+ distinct = versions.values.compact.uniq
84
+ if versions.value?(nil)
85
+ out.puts "DRIFT: a version could not be read (MISSING above)".red
86
+ false
87
+ elsif distinct.one?
88
+ out.puts "OK: all #{versions.size} at #{distinct.first}".green
89
+ true
90
+ else
91
+ out.puts "DRIFT: #{distinct.sort.join(", ")} — run `inquirex versions-bump <version>`".yellow
92
+ false
93
+ end
94
+ end
95
+
96
+ # Why a package is not publishable right now.
97
+ #
98
+ # @param name [String] package name
99
+ # @param target [String, nil] the version its tag must match
100
+ # @return [Array<String>] empty when ready
101
+ def readiness_problems(name, target)
102
+ state = workspace.git_state(name)
103
+ return ["no git checkout"] if state[:clean].nil?
104
+
105
+ problems = []
106
+ problems << "DIRTY" unless state[:clean]
107
+ problems << "on #{state[:branch]}" unless state[:branch] == "main"
108
+ problems << "untagged" unless state[:tags].any? { |tag| tag.delete_prefix("v") == target }
109
+ problems
110
+ end
111
+ end
112
+ end
113
+ end
@@ -11,34 +11,34 @@ module Inquirex
11
11
  # walking up from the working directory looking for the sibling checkouts,
12
12
  # or taken from INQUIREX_ROOT.
13
13
  class Workspace
14
- # Packages that must always carry the same version. They share one
15
- # serialization format — the gem defines the DSL and emits step JSON,
16
- # inquirex-js renders it, inquirex-webui prints it back to DSL,
17
- # inquirex-llm extends the vocabulary, and inquirex-tools is the tooling
18
- # that ships alongside them. A verb present in one and absent in another
19
- # does not fail loudly; it drops data.
14
+ # Every package in the family, all carrying the same version. They share
15
+ # one serialization format — the gem defines the DSL and emits step JSON,
16
+ # inquirex-widget (npm; formerly @kigster/inquirex-js) renders it,
17
+ # inquirex-webui prints it back to DSL, inquirex-llm extends the
18
+ # vocabulary, inquirex-tty walks a flow in the terminal, and
19
+ # inquirex-tools is the tooling that ships alongside them. A verb present
20
+ # in one and absent in another does not fail loudly; it drops data.
20
21
  #
21
- # `inquirex-tty` is deliberately absent: a developer tool outside the
22
- # wire contract, versioned on its own cadence.
22
+ # Nothing is excluded. One version number across the whole family means
23
+ # "which combination has this bug?" is a lookup rather than an
24
+ # investigation.
23
25
  LOCKSTEP = {
24
- "inquirex" => :gem,
25
- "inquirex-llm" => :gem,
26
- "inquirex-tools" => :gem,
27
- "inquirex-js" => :npm,
28
- "inquirex-webui" => :npm
26
+ "inquirex" => :gem,
27
+ "inquirex-llm" => :gem,
28
+ "inquirex-tools" => :gem,
29
+ "inquirex-tty" => :gem,
30
+ "inquirex-widget" => :npm,
31
+ "inquirex-webui" => :npm
29
32
  }.freeze
30
33
 
31
- # Excluded from lockstep, documented so the omission reads as deliberate.
32
- EXCLUDED = %w[inquirex-tty].freeze
33
-
34
34
  # Repositories that carry a generated CHANGELOG.md but are not versioned
35
35
  # in lockstep.
36
- CHANGELOG_ONLY = %w[inquirex-tty qualified-at].freeze
36
+ CHANGELOG_ONLY = %w[qualified-at].freeze
37
37
 
38
38
  GEM_VERSION_RE = /VERSION\s*=\s*"([^"]+)"/
39
39
 
40
40
  # Directories whose presence identifies the ecosystem root.
41
- MARKERS = %w[inquirex inquirex-js].freeze
41
+ MARKERS = %w[inquirex inquirex-widget].freeze
42
42
 
43
43
  # @return [String] absolute path to the ecosystem root
44
44
  attr_reader :root
@@ -92,18 +92,21 @@ module Inquirex
92
92
  #
93
93
  # @param name [String] package name
94
94
  # @param version [String] new version
95
+ # @param kind [Symbol] :gem or :npm — which version line to rewrite.
96
+ # Passed by the caller rather than looked up here so a caller that
97
+ # already knows the kind does not pay for a second lookup.
95
98
  # @return [void]
96
- def write_version(name, version)
99
+ def write_version(name, version, kind)
97
100
  file = version_file(name)
98
101
  raise Error, "no version file for #{name}" unless file
99
102
 
100
103
  src = File.read(file)
101
- updated =
102
- if LOCKSTEP[name] == :gem
103
- src.sub(GEM_VERSION_RE, %(VERSION = "#{version}"))
104
- else
105
- src.sub(/"version":\s*"[^"]*"/, %("version": "#{version}"))
106
- end
104
+ updated = case kind
105
+ when :gem
106
+ src.sub(GEM_VERSION_RE, %(VERSION = "#{version}"))
107
+ when :npm
108
+ src.sub(/"version":\s*"[^"]*"/, %("version": "#{version}"))
109
+ end
107
110
  File.write(file, updated)
108
111
  end
109
112
 
@@ -114,9 +117,9 @@ module Inquirex
114
117
  return { clean: nil, branch: nil, tags: [] } unless File.exist?(File.join(dir, ".git"))
115
118
 
116
119
  {
117
- clean: `git -C #{dir} status --porcelain 2>/dev/null`.strip.empty?,
120
+ clean: `git -C #{dir} status --porcelain 2>/dev/null`.strip.empty?,
118
121
  branch: `git -C #{dir} rev-parse --abbrev-ref HEAD 2>/dev/null`.strip,
119
- tags: `git -C #{dir} tag --points-at HEAD 2>/dev/null`.split("\n").map(&:strip).reject(&:empty?)
122
+ tags: `git -C #{dir} tag --points-at HEAD 2>/dev/null`.split("\n").map(&:strip).reject(&:empty?)
120
123
  }
121
124
  end
122
125
 
@@ -2,7 +2,10 @@
2
2
 
3
3
  require_relative "tools/version"
4
4
  require_relative "tools/workspace"
5
- require_relative "tools/versions"
5
+ require_relative "tools/version_checker"
6
+ require_relative "tools/version_bumper"
7
+ require_relative "tools/publisher"
8
+ require_relative "tools/releaser"
6
9
  require_relative "tools/changelogs"
7
10
 
8
11
  module Inquirex
@@ -17,13 +20,17 @@ module Inquirex
17
20
  # required to have zero runtime dependencies, and nothing added here changes
18
21
  # that, because nothing here is loaded by the runtime gems.
19
22
  #
20
- # Executables:
23
+ # It ships one executable, `inquirex`, with these subcommands:
21
24
  #
22
- # - `inquirex-version` — version parity across the lockstep packages
23
- # - `inquirex-changelogs` — regenerate CHANGELOG.md from merged PRs
25
+ # - `versions-check` — version parity across the lockstep packages
26
+ # - `versions-bump` — move every lockstep package to one version
27
+ # - `publish` — publish every package to RubyGems and npm
28
+ # - `create-release` — tag and create a GitHub release for every package
29
+ # - `changelogs` — regenerate CHANGELOG.md from merged PRs
30
+ # - `version` — this gem's own version
24
31
  #
25
32
  # @example Check whether the family is releasable
26
- # Inquirex::Tools::Versions.new.preflight # => true when every package is ready
33
+ # Inquirex::Tools::VersionChecker.new.preflight # => true when every package is ready
27
34
  module Tools
28
35
  class Error < StandardError; end
29
36
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inquirex-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Konstantin Gredeskoul
@@ -23,6 +23,20 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: '1.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: colored2
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '0'
26
40
  description: |
27
41
  Ships the `inquirex` command: lockstep version management across the
28
42
  Inquirex gems and npm packages, changelog regeneration, and release
@@ -32,24 +46,42 @@ email:
32
46
  - kigster@gmail.com
33
47
  executables:
34
48
  - inquirex
49
+ - inquirexor
35
50
  extensions: []
36
51
  extra_rdoc_files: []
37
52
  files:
38
53
  - ".DS_Store"
54
+ - ".env.encrypted"
55
+ - ".env.example"
56
+ - ".envrc"
39
57
  - ".github_changelog_generator"
58
+ - ".relaxed_rubocop.yml"
59
+ - ".sops.yaml"
60
+ - ".sopsy.sha"
61
+ - ".sopsy.yml"
40
62
  - CHANGELOG.md
41
63
  - LICENSE.txt
42
64
  - README.md
43
65
  - Rakefile
66
+ - docs/badges/coverage_badge.svg
67
+ - docs/monorepo-migration.md
44
68
  - exe/inquirex
69
+ - exe/inquirexor
70
+ - justfile
45
71
  - lib/inquirex/tools.rb
46
72
  - lib/inquirex/tools/changelogs.rb
47
73
  - lib/inquirex/tools/commands.rb
48
74
  - lib/inquirex/tools/commands/changelogs.rb
75
+ - lib/inquirex/tools/commands/create_release.rb
76
+ - lib/inquirex/tools/commands/publish.rb
49
77
  - lib/inquirex/tools/commands/version.rb
50
- - lib/inquirex/tools/commands/versions.rb
78
+ - lib/inquirex/tools/commands/versions_bump.rb
79
+ - lib/inquirex/tools/commands/versions_check.rb
80
+ - lib/inquirex/tools/publisher.rb
81
+ - lib/inquirex/tools/releaser.rb
51
82
  - lib/inquirex/tools/version.rb
52
- - lib/inquirex/tools/versions.rb
83
+ - lib/inquirex/tools/version_bumper.rb
84
+ - lib/inquirex/tools/version_checker.rb
53
85
  - lib/inquirex/tools/workspace.rb
54
86
  - sig/inquirex/tools.rbs
55
87
  homepage: https://github.com/kigster/inquirex-tools
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Inquirex
4
- module Tools
5
- module Commands
6
- # Reports and enforces version parity across the lockstep packages.
7
- #
8
- # Plural on purpose: `inquirex version` prints this tool's own version,
9
- # `inquirex versions` manages the family's.
10
- class Versions < Dry::CLI::Command
11
- desc "Check, set, or preflight the family's lockstep version"
12
-
13
- option :set, type: :string, desc: "Move every lockstep package to this version"
14
- option :preflight, type: :boolean, default: false,
15
- desc: "Also check clean trees, main branch, and tags"
16
-
17
- example [
18
- " # report parity, exit 1 on drift",
19
- "--set 0.8.0 # move all five packages",
20
- "--preflight # release readiness"
21
- ]
22
-
23
- # @param set [String, nil] target version
24
- # @param preflight [Boolean]
25
- # @return [void]
26
- def call(set: nil, preflight: false, **)
27
- versions = Inquirex::Tools::Versions.new
28
- ok =
29
- if set then versions.set(set)
30
- elsif preflight then versions.preflight
31
- else versions.check
32
- end
33
- exit(1) unless ok
34
- rescue Inquirex::Tools::Error => e
35
- warn "ERROR: #{e.message}"
36
- exit 1
37
- end
38
- end
39
- end
40
- end
41
- end