inquirex-tools 0.9.5 → 0.10.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/.envrc +2 -0
- data/docs/plans/001-/342/232/252/357/270/217-many-repo-setup/spec.md +29 -0
- data/lib/inquirex/tools/changelogs.rb +7 -2
- data/lib/inquirex/tools/pin_updater.rb +89 -0
- data/lib/inquirex/tools/publisher.rb +15 -3
- data/lib/inquirex/tools/releaser.rb +4 -2
- data/lib/inquirex/tools/version.rb +1 -1
- data/lib/inquirex/tools/version_bumper.rb +6 -2
- data/lib/inquirex/tools.rb +30 -0
- metadata +5 -4
- data/.DS_Store +0 -0
- /data/docs/{monorepo-migration.md → plans/002-/342/232/252/357/270/217-monorepo-migration/spec.md"} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c0382f5f2ef1fed61354873914a92e24e3b25dbead0959aac9de8f48702bdfdf
|
|
4
|
+
data.tar.gz: 25c18df8bb5cb9a7bcad98668431ff7587df5444b7797917f8c3201308168170
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0dc205efda474da503f17a2ac1259b12193996621bba9041ff696e67563bde5b050dd0ca52bb5149b261b694fdb941b29755dd05a9fb71a81c335c65ce903e8d
|
|
7
|
+
data.tar.gz: ddd1e89483f67689fc64b4d4618d19b0a667dfd91da9778b26ee56d7ff36c54c657540bf15441c7fb53273d15b4403d5d4705f1f61292e8772142fab65d6535c
|
data/.envrc
CHANGED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Many Repos Setup
|
|
2
|
+
|
|
3
|
+
## Problem
|
|
4
|
+
|
|
5
|
+
Inquirex Organization houses several interlinked public repositories under https://github.com/inquirex that are often worked on in tandem, and checked out into the same folder.
|
|
6
|
+
|
|
7
|
+
For instance, seeting up the entire tree requires the following:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
cd ~/
|
|
11
|
+
mkdir -p ~/github/inquirex
|
|
12
|
+
cd ~/github/inquirex
|
|
13
|
+
declare -a repos=(
|
|
14
|
+
inquirex
|
|
15
|
+
inquirex-llm
|
|
16
|
+
inquirex-tty
|
|
17
|
+
inquirex-webui
|
|
18
|
+
inquirex-widget
|
|
19
|
+
inquirex-tools
|
|
20
|
+
inquirex-claude
|
|
21
|
+
)
|
|
22
|
+
for repo in ${repos[@]}; do
|
|
23
|
+
git clone git@github.com:inquirex/${repo}
|
|
24
|
+
done
|
|
25
|
+
|
|
26
|
+
cd inquirex-tools && bin/setup
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
|
|
@@ -22,9 +22,14 @@ module Inquirex
|
|
|
22
22
|
# so nothing here handles a credential in plain text.
|
|
23
23
|
DEFAULT_TOKEN_READER = -> { `gh auth token 2>/dev/null`.strip }
|
|
24
24
|
|
|
25
|
-
# Runs the generator in one repository, discarding its very chatty
|
|
25
|
+
# Runs the generator in one repository, discarding its very chatty
|
|
26
|
+
# output, with this gem's bundle scrubbed — see
|
|
27
|
+
# {Inquirex::Tools.unbundled}. The generator is a gem of its own and must
|
|
28
|
+
# resolve against the installation that provides it, not against ours.
|
|
26
29
|
DEFAULT_RUNNER = lambda { |dir, env|
|
|
27
|
-
|
|
30
|
+
Inquirex::Tools.unbundled do
|
|
31
|
+
system(env, "github_changelog_generator", chdir: dir, out: File::NULL, err: File::NULL)
|
|
32
|
+
end
|
|
28
33
|
}
|
|
29
34
|
|
|
30
35
|
# @param workspace [Workspace]
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "workspace"
|
|
4
|
+
|
|
5
|
+
module Inquirex
|
|
6
|
+
module Tools
|
|
7
|
+
# Raises the "newest published gem" pin that a package's CI installs from
|
|
8
|
+
# rubygems.org.
|
|
9
|
+
#
|
|
10
|
+
# `inquirex-webui` reparses its printer's output with the real gem, which
|
|
11
|
+
# CI installs from the registry rather than from a checkout. That pin
|
|
12
|
+
# therefore cannot name the version in the source tree — it does not exist
|
|
13
|
+
# yet — so it trails by one release and has to be raised by hand afterwards.
|
|
14
|
+
#
|
|
15
|
+
# Nobody remembers. The pin sat at 0.9.4 while the printer started emitting
|
|
16
|
+
# `min`, `max` and `step_size`, added to the gem in 0.9.5, and the
|
|
17
|
+
# round-trip failed with "`min` is not allowed inside a step block":
|
|
18
|
+
# SafeSource is default-deny, so a step setter it has never heard of is
|
|
19
|
+
# rejected outright. The failure names the printer, not the pin.
|
|
20
|
+
#
|
|
21
|
+
# Running immediately after a successful publish is what makes this safe.
|
|
22
|
+
# At that moment the version is on the registry by construction, so the
|
|
23
|
+
# pin's one rule — never run ahead of rubygems.org — cannot be violated.
|
|
24
|
+
#
|
|
25
|
+
# @example Raise the pin to the version just published
|
|
26
|
+
# Inquirex::Tools::PinUpdater.new.call("0.9.6") # => ["inquirex-webui/.github/workflows/ci.yml"]
|
|
27
|
+
class PinUpdater
|
|
28
|
+
# A pinned family version in a workflow's `env:` block. Anchored to the
|
|
29
|
+
# whole line so a value mentioned in a comment is left alone.
|
|
30
|
+
PIN = /^(?<lead>\s*INQUIREX_GEM_VERSION:\s*)(?<quote>["']?)\d+\.\d+\.\d+\k<quote>\s*$/
|
|
31
|
+
|
|
32
|
+
# @param workspace [Workspace] the ecosystem checkout to rewrite
|
|
33
|
+
# @param out [IO] where report output goes
|
|
34
|
+
def initialize(workspace: Workspace.new, out: $stdout)
|
|
35
|
+
@workspace = workspace
|
|
36
|
+
@out = out
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Rewrites every pin to `version`.
|
|
40
|
+
#
|
|
41
|
+
# @param version [String] the version that was just published
|
|
42
|
+
# @param dry_run [Boolean] report what would change and write nothing
|
|
43
|
+
# @return [Array<String>] workspace-relative paths that changed
|
|
44
|
+
def call(version, dry_run: false)
|
|
45
|
+
changed = workflows.select { |path| rewrite(path, version, dry_run:) }
|
|
46
|
+
report(changed, version, dry_run:)
|
|
47
|
+
changed.map { |path| path.delete_prefix("#{workspace.root}/") }
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private
|
|
51
|
+
|
|
52
|
+
# @return [Workspace] the ecosystem checkout being rewritten
|
|
53
|
+
attr_reader :workspace
|
|
54
|
+
|
|
55
|
+
# @return [IO] where report output goes
|
|
56
|
+
attr_reader :out
|
|
57
|
+
|
|
58
|
+
# @return [Array<String>] every workflow file in every lockstep package
|
|
59
|
+
def workflows
|
|
60
|
+
Workspace::LOCKSTEP.keys.flat_map do |name|
|
|
61
|
+
Dir.glob(File.join(workspace.root, name, ".github", "workflows", "*.y{a,}ml"))
|
|
62
|
+
end.sort
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @return [Boolean] whether the file needed rewriting
|
|
66
|
+
def rewrite(path, version, dry_run:)
|
|
67
|
+
source = File.read(path)
|
|
68
|
+
updated = source.gsub(PIN) { "#{::Regexp.last_match(:lead)}\"#{version}\"" }
|
|
69
|
+
return false if updated == source
|
|
70
|
+
|
|
71
|
+
File.write(path, updated) unless dry_run
|
|
72
|
+
true
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @return [void]
|
|
76
|
+
def report(changed, version, dry_run:)
|
|
77
|
+
return if changed.empty?
|
|
78
|
+
|
|
79
|
+
verb = dry_run ? "Would raise" : "Raised"
|
|
80
|
+
out.puts
|
|
81
|
+
out.puts "#{verb} the published-gem pin to #{version}:"
|
|
82
|
+
changed.each { |path| out.puts " #{path.delete_prefix("#{workspace.root}/")}" }
|
|
83
|
+
# The publisher does not commit — it has no business deciding what a
|
|
84
|
+
# release commit looks like — so say plainly that this is not done yet.
|
|
85
|
+
out.puts "Commit that; CI installs the pinned version from the registry.".dark unless dry_run
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
@@ -40,9 +40,11 @@ module Inquirex
|
|
|
40
40
|
ROTATE_INTERVAL = 2
|
|
41
41
|
|
|
42
42
|
# Shells out with the child's stdout and stderr left attached, so a
|
|
43
|
-
# failing package's own output is what the operator sees
|
|
43
|
+
# failing package's own output is what the operator sees, and with this
|
|
44
|
+
# gem's bundle scrubbed so the recipe resolves its own — see
|
|
45
|
+
# {Inquirex::Tools.unbundled}.
|
|
44
46
|
DEFAULT_RUNNER = lambda { |dir, argv|
|
|
45
|
-
Dir.chdir(dir) { system("just", *argv) }
|
|
47
|
+
Inquirex::Tools.unbundled { Dir.chdir(dir) { system("just", *argv) } }
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
# Reads the current RubyGems TOTP. `op` resolves the account from
|
|
@@ -92,16 +94,20 @@ module Inquirex
|
|
|
92
94
|
# without publishing anything.
|
|
93
95
|
# @param otp_reader [#call] returns the current 2FA code, or nil
|
|
94
96
|
# @param published_checker [#call] (name, kind, version) => true/false/nil
|
|
97
|
+
# @param pin_updater [#call] (version, dry_run:) raises the published-gem
|
|
98
|
+
# pin once the version is certainly on the registry
|
|
95
99
|
def initialize(workspace: Workspace.new,
|
|
96
100
|
out: $stdout,
|
|
97
101
|
runner: DEFAULT_RUNNER,
|
|
98
102
|
otp_reader: DEFAULT_OTP_READER,
|
|
99
|
-
published_checker: DEFAULT_PUBLISHED_CHECKER
|
|
103
|
+
published_checker: DEFAULT_PUBLISHED_CHECKER,
|
|
104
|
+
pin_updater: nil)
|
|
100
105
|
@workspace = workspace
|
|
101
106
|
@out = out
|
|
102
107
|
@runner = runner
|
|
103
108
|
@otp_reader = otp_reader
|
|
104
109
|
@published_checker = published_checker
|
|
110
|
+
@pin_updater = pin_updater || PinUpdater.new(workspace:, out:)
|
|
105
111
|
end
|
|
106
112
|
|
|
107
113
|
# Publishes every lockstep package, or prints what it would publish.
|
|
@@ -155,6 +161,9 @@ module Inquirex
|
|
|
155
161
|
|
|
156
162
|
out.puts
|
|
157
163
|
out.puts summary(dry_run:, published:, skipped:)
|
|
164
|
+
# Only now is the version certainly on the registry, which is the one
|
|
165
|
+
# rule the pin has to obey.
|
|
166
|
+
pin_updater.call(workspace.version_of("inquirex"), dry_run:)
|
|
158
167
|
true
|
|
159
168
|
end
|
|
160
169
|
|
|
@@ -175,6 +184,9 @@ module Inquirex
|
|
|
175
184
|
# @return [#call] asks a registry whether a version is already public
|
|
176
185
|
attr_reader :published_checker
|
|
177
186
|
|
|
187
|
+
# @return [#call] raises the published-gem pin after a release
|
|
188
|
+
attr_reader :pin_updater
|
|
189
|
+
|
|
178
190
|
# @return [Boolean] whether the package published cleanly
|
|
179
191
|
def run(name, dir, argv)
|
|
180
192
|
return true if runner.call(dir, argv)
|
|
@@ -34,9 +34,11 @@ module Inquirex
|
|
|
34
34
|
RELEASE_BRANCH = "main"
|
|
35
35
|
|
|
36
36
|
# Shells out with the child's stdout and stderr left attached, so a
|
|
37
|
-
# failing package's own `gh` output is what the operator sees
|
|
37
|
+
# failing package's own `gh` output is what the operator sees, and with
|
|
38
|
+
# this gem's bundle scrubbed so the recipe resolves its own — see
|
|
39
|
+
# {Inquirex::Tools.unbundled}.
|
|
38
40
|
DEFAULT_RUNNER = lambda { |dir, argv|
|
|
39
|
-
Dir.chdir(dir) { system("just", *argv) }
|
|
41
|
+
Inquirex::Tools.unbundled { Dir.chdir(dir) { system("just", *argv) } }
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
# @param workspace [Workspace] the ecosystem checkout to release from
|
|
@@ -60,8 +60,12 @@ module Inquirex
|
|
|
60
60
|
[status.success?, output]
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
# Runs a package's own checks in its own directory
|
|
64
|
-
|
|
63
|
+
# Runs a package's own checks in its own directory, with this gem's
|
|
64
|
+
# bundle scrubbed so those checks resolve the package's own Gemfile
|
|
65
|
+
# rather than inheriting ours — see {Inquirex::Tools.unbundled}.
|
|
66
|
+
DEFAULT_RUNNER = lambda { |dir, argv|
|
|
67
|
+
Inquirex::Tools.unbundled { Dir.chdir(dir) { system(*argv) } }
|
|
68
|
+
}
|
|
65
69
|
|
|
66
70
|
# @param workspace [Workspace] the ecosystem checkout to rewrite
|
|
67
71
|
# @param out [IO] where report output goes
|
data/lib/inquirex/tools.rb
CHANGED
|
@@ -4,6 +4,7 @@ require_relative "tools/version"
|
|
|
4
4
|
require_relative "tools/workspace"
|
|
5
5
|
require_relative "tools/version_checker"
|
|
6
6
|
require_relative "tools/version_bumper"
|
|
7
|
+
require_relative "tools/pin_updater"
|
|
7
8
|
require_relative "tools/publisher"
|
|
8
9
|
require_relative "tools/releaser"
|
|
9
10
|
require_relative "tools/changelogs"
|
|
@@ -33,5 +34,34 @@ module Inquirex
|
|
|
33
34
|
# Inquirex::Tools::VersionChecker.new.preflight # => true when every package is ready
|
|
34
35
|
module Tools
|
|
35
36
|
class Error < StandardError; end
|
|
37
|
+
|
|
38
|
+
# Runs a block with Bundler's environment removed.
|
|
39
|
+
#
|
|
40
|
+
# Every orchestrator here shells into a *different* package and runs
|
|
41
|
+
# `bundle exec` there. `bundle exec inquirex versions-bump` exports
|
|
42
|
+
# BUNDLE_GEMFILE, RUBYOPT and friends, and a child process inherits them —
|
|
43
|
+
# so without this, each sibling resolves against **this gem's** Gemfile
|
|
44
|
+
# instead of its own.
|
|
45
|
+
#
|
|
46
|
+
# That failure is loud but misleading. `versions-bump` reported five of six
|
|
47
|
+
# packages failing `just check-all`: `inquirex` and `inquirex-llm` raised
|
|
48
|
+
# `NoMethodError: undefined method 'skip' for module SimpleCov`, because
|
|
49
|
+
# this gem pins simplecov ~> 0.22 while theirs resolve 1.0.3 where
|
|
50
|
+
# `SimpleCov.skip` exists; `inquirex-tty` raised `LoadError: cannot load
|
|
51
|
+
# such file -- inquirex`, because this gem deliberately does not depend on
|
|
52
|
+
# the gems it manages. Every one of those reads as a defect in the package
|
|
53
|
+
# being checked. None of them was.
|
|
54
|
+
#
|
|
55
|
+
# Bundler is not declared as a dependency — it is present whenever this
|
|
56
|
+
# runs under `bundle exec`, and when it is absent there is no environment
|
|
57
|
+
# to scrub, so the block simply runs.
|
|
58
|
+
#
|
|
59
|
+
# @yield with a clean environment
|
|
60
|
+
# @return [Object] whatever the block returns
|
|
61
|
+
def self.unbundled(&)
|
|
62
|
+
return yield unless defined?(::Bundler) && ::Bundler.respond_to?(:with_unbundled_env)
|
|
63
|
+
|
|
64
|
+
::Bundler.with_unbundled_env(&)
|
|
65
|
+
end
|
|
36
66
|
end
|
|
37
67
|
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.
|
|
4
|
+
version: 0.10.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Konstantin Gredeskoul
|
|
@@ -50,7 +50,6 @@ executables:
|
|
|
50
50
|
extensions: []
|
|
51
51
|
extra_rdoc_files: []
|
|
52
52
|
files:
|
|
53
|
-
- ".DS_Store"
|
|
54
53
|
- ".env.encrypted"
|
|
55
54
|
- ".env.example"
|
|
56
55
|
- ".envrc"
|
|
@@ -64,7 +63,8 @@ files:
|
|
|
64
63
|
- README.md
|
|
65
64
|
- Rakefile
|
|
66
65
|
- docs/badges/coverage_badge.svg
|
|
67
|
-
- docs/
|
|
66
|
+
- docs/plans/001-⚪️-many-repo-setup/spec.md
|
|
67
|
+
- docs/plans/002-⚪️-monorepo-migration/spec.md
|
|
68
68
|
- exe/inquirex
|
|
69
69
|
- exe/inquirexor
|
|
70
70
|
- justfile
|
|
@@ -77,6 +77,7 @@ files:
|
|
|
77
77
|
- lib/inquirex/tools/commands/version.rb
|
|
78
78
|
- lib/inquirex/tools/commands/versions_bump.rb
|
|
79
79
|
- lib/inquirex/tools/commands/versions_check.rb
|
|
80
|
+
- lib/inquirex/tools/pin_updater.rb
|
|
80
81
|
- lib/inquirex/tools/publisher.rb
|
|
81
82
|
- lib/inquirex/tools/releaser.rb
|
|
82
83
|
- lib/inquirex/tools/version.rb
|
|
@@ -106,7 +107,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
106
107
|
- !ruby/object:Gem::Version
|
|
107
108
|
version: '0'
|
|
108
109
|
requirements: []
|
|
109
|
-
rubygems_version: 4.0.
|
|
110
|
+
rubygems_version: 4.0.18
|
|
110
111
|
specification_version: 4
|
|
111
112
|
summary: Release tooling for the Inquirex package family
|
|
112
113
|
test_files: []
|
data/.DS_Store
DELETED
|
Binary file
|
/data/docs/{monorepo-migration.md → plans/002-/342/232/252/357/270/217-monorepo-migration/spec.md"}
RENAMED
|
File without changes
|