kube_schema 1.12.0 → 2.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/.envrc +1 -0
- data/.github/FUNDING.yml +3 -0
- data/.rubocop.yml +226 -5984
- data/CHANGELOG.md +110 -3
- data/DEPRECATIONS.md +172 -0
- data/Gemfile +13 -3
- data/Gemfile.lock +41 -31
- data/RELEASE.md +161 -0
- data/Rakefile +1 -1
- data/bin/rubocop +3 -0
- data/bin/test +2 -9
- data/cops/begin_block_assignment.rb +34 -0
- data/cops/comment_structure.rb +307 -0
- data/cops/constant_matches_path.rb +142 -0
- data/cops/multiline_method_arguments.rb +89 -0
- data/cops/no_conditional_assignment.rb +186 -0
- data/cops/no_console_logging.rb +62 -0
- data/cops/no_modifier_if.rb +74 -0
- data/cops/no_return.rb +152 -0
- data/cops/support/prism_source.rb +234 -0
- data/cops/use_tap.rb +100 -0
- data/flake.lock +3 -3
- data/flake.nix +22 -15
- data/gemset.nix +142 -73
- data/kube_schema.gemspec +4 -2
- data/lib/kube/errors.rb +652 -645
- data/lib/kube/monkey_patches.rb +5 -6
- data/lib/kube/schema/instance.rb +344 -363
- data/lib/kube/schema/lazy.rb +370 -0
- data/lib/kube/schema/manifest.rb +286 -325
- data/lib/kube/schema/resource.rb +348 -393
- data/lib/kube/schema/sub_spec.rb +261 -293
- data/lib/kube/schema.rb +173 -172
- data/lib/{kube/schema → kube_schema}/version.rb +1 -1
- data/lib/kube_schema.rb +6 -0
- data/readme.md +5 -0
- metadata +49 -9
- data/bin/increment-version +0 -45
- data/bin/release-gem +0 -32
- data/bin/tag-version +0 -19
- data/lib/kube/schema/version.rb.erb +0 -7
data/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,114 @@ All notable changes to this project are documented here.
|
|
|
4
4
|
|
|
5
5
|
This file starts at 1.10.0; for earlier releases see the git history.
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [2.0.0] - 2026-10-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- `require "kube_schema"` now works alongside `require "kube/schema"`.
|
|
14
|
+
`lib/kube_schema.rb` is a new entry point that loads the library;
|
|
15
|
+
`Kube::Schema::VERSION` is unchanged.
|
|
16
|
+
|
|
17
|
+
- `Kube::Schema::Lazy` — `Scanner` (byte-offset index over the schema files),
|
|
18
|
+
`Index`/`Entry`, `Spill` (temp-file backing for registered schemas), and
|
|
19
|
+
`Source`, which stands in for a compiled schema: it answers `#value`,
|
|
20
|
+
`#valid?`, `#validate` and `#ref`, loading the definition for property names
|
|
21
|
+
and compiling behind a `WeakRef` so repeated validations reuse a live schema
|
|
22
|
+
while the GC can still reclaim it.
|
|
23
|
+
|
|
24
|
+
- `Kube::MissingSchemaError`, raised when a definition cannot be read at
|
|
25
|
+
validation time. A vanished spilled temp file says so explicitly, since that
|
|
26
|
+
means the `Tempfile` was collected or the tmpdir swept, rather than the
|
|
27
|
+
install being broken.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Schemas are compiled per definition, on demand, and collected afterwards.**
|
|
32
|
+
`Instance#schemer` used to parse `v<version>.json`, merge every
|
|
33
|
+
`*-definitions.json` into it, and hand the whole document to
|
|
34
|
+
`JSONSchemer.schema` — one compiled tree held at the class level for the
|
|
35
|
+
life of the process. That tree was **97,381 `JSONSchemer::Schema` nodes and
|
|
36
|
+
~406 MB resident** (one `JSONSchemer::Configuration` per node, plus ~230k
|
|
37
|
+
vocabulary keyword objects and 1.2M hashes), built in full whether you
|
|
38
|
+
validated one resource or none.
|
|
39
|
+
|
|
40
|
+
Validating a Deployment through the public API now looks like this:
|
|
41
|
+
|
|
42
|
+
baseline rss= 26.8 MB schemas= 0
|
|
43
|
+
Instance.new("1.33") rss= 26.8 MB schemas= 0
|
|
44
|
+
instance["Deployment"] rss= 68.5 MB schemas= 0
|
|
45
|
+
Deployment.new(...) rss= 68.5 MB schemas= 0
|
|
46
|
+
after valid? rss= 68.5 MB schemas= 147
|
|
47
|
+
after GC.start rss= 42.4 MB schemas= 16
|
|
48
|
+
|
|
49
|
+
Nothing is compiled until something is validated, a Deployment needs 147
|
|
50
|
+
schema nodes rather than 97,381, and they are collectable the moment the
|
|
51
|
+
validation is done — about **90% less memory** than before.
|
|
52
|
+
|
|
53
|
+
This works because `json_schemer` resolves `$ref` lazily:
|
|
54
|
+
`Draft202012::Vocab::Core::Ref#ref_schema` is memoized inside `#validate`,
|
|
55
|
+
and an unresolved URI goes through `ref_resolver`. So a single definition is
|
|
56
|
+
compiled as its own root, its `#/definitions/...` pointers are rewritten to
|
|
57
|
+
`kube:///<key>`, and a resolver loads referenced definitions on demand —
|
|
58
|
+
which means the cost scales with the instance being validated, not with the
|
|
59
|
+
size of the schema document.
|
|
60
|
+
|
|
61
|
+
- **`Kube::Schema.register` no longer compiles the registered schema.** It
|
|
62
|
+
writes the definition to a temp file and stores an index entry, so a
|
|
63
|
+
registered CRD takes the same lazy path as a built-in type. Registering the
|
|
64
|
+
largest bundled CRD (1.1 MB of `io.argoproj.v1alpha1.Workflow`) now compiles
|
|
65
|
+
nothing at registration time; its 9,656 nodes appear on first `#valid?` and
|
|
66
|
+
collect afterwards. `reset_custom_schemas!` removes the temp files.
|
|
67
|
+
|
|
68
|
+
- `Instance.schemers` is now `Instance.catalogs`, holding a
|
|
69
|
+
`Kube::Schema::Lazy::Index` (definition key to file offset, group/version/kind,
|
|
70
|
+
and property names) instead of a compiled schema. The index is built by
|
|
71
|
+
scanning the JSON for definition boundaries, so the schema documents are
|
|
72
|
+
never parsed whole and nothing but offsets and small metadata is retained.
|
|
73
|
+
Callers that reached into `Instance.schemers` must update to `Instance.catalogs`
|
|
74
|
+
and expect a `Lazy::Index`, not a `JSONSchemer::Schema`.
|
|
75
|
+
|
|
76
|
+
- **The version constant file moved to `lib/kube_schema/version.rb`** from
|
|
77
|
+
`lib/kube/schema/version.rb`. `gem kit bump` derives the path from the gem's
|
|
78
|
+
name and rewrites the literal in place, so the `version.rb.erb` template is
|
|
79
|
+
gone. External code that `require`d `kube/schema/version` directly must now
|
|
80
|
+
`require "kube_schema/version"`; the `Kube::Schema::VERSION` constant itself
|
|
81
|
+
is unchanged.
|
|
82
|
+
|
|
83
|
+
- **Releases run on `gem kit`, not on `bin/*`.** `bin/increment-version`,
|
|
84
|
+
`bin/release-gem` and `bin/tag-version` are gone, replaced by the
|
|
85
|
+
[gem_kit-release](https://github.com/n-at-han-k/gem_kit) RubyGems plugin:
|
|
86
|
+
`gem kit bump`, `gem kit changelog`, `gem kit release` and `gem kit tag`.
|
|
87
|
+
The three scripts between them bumped the version, compared it against
|
|
88
|
+
RubyGems, built, pushed and tagged. What they never did was check that the
|
|
89
|
+
release was documented or that promises made about it had been kept, and
|
|
90
|
+
`gem kit` refuses to build without both — see [RELEASE.md](RELEASE.md) and
|
|
91
|
+
[DEPRECATIONS.md](DEPRECATIONS.md), which are now in the repository.
|
|
92
|
+
|
|
93
|
+
`gem_kit` is a new runtime dependency, so a deprecation can be *declared*
|
|
94
|
+
(`GemKit::Deprecate`) where the deprecated name lives; it has no
|
|
95
|
+
dependencies of its own beyond RubyGems'. `gem_kit-release`, which does the
|
|
96
|
+
enforcing, is in the `release` bundle group and is nobody's dependency.
|
|
97
|
+
|
|
98
|
+
- **Tests run on [scampi](https://github.com/general-intelligence-systems/scampi)
|
|
99
|
+
instead of RSpec.** The co-located specs moved out of
|
|
100
|
+
`if __FILE__ == $0` blocks and into each file's `__END__` section, so they no
|
|
101
|
+
longer load in production — Ruby stops parsing at `__END__`. `bin/test` is now
|
|
102
|
+
`bundle exec scampi`, which discovers every `.rb` carrying an `__END__` spec
|
|
103
|
+
section and emits TAP version 14. The assertions are scampi's `should` chain
|
|
104
|
+
rather than `expect`, and the devshell gained `ripgrep`, which scampi shells
|
|
105
|
+
out to for discovery.
|
|
106
|
+
|
|
107
|
+
### Removed
|
|
108
|
+
|
|
109
|
+
- `bin/increment-version`, `bin/release-gem` and `bin/tag-version`. Use
|
|
110
|
+
`gem kit bump`, `gem kit release` and `gem kit tag` instead.
|
|
111
|
+
- `lib/kube/schema/version.rb.erb`. `gem kit bump` edits the version literal
|
|
112
|
+
in `lib/kube_schema/version.rb` directly.
|
|
113
|
+
|
|
114
|
+
## [1.12.0] - 2026-09-28
|
|
8
115
|
|
|
9
116
|
### Added
|
|
10
117
|
|
|
@@ -22,7 +129,7 @@ This file starts at 1.10.0; for earlier releases see the git history.
|
|
|
22
129
|
the class to a constant, or use a pin expression —
|
|
23
130
|
`^(Kube::Schema["Deployment"])`.
|
|
24
131
|
|
|
25
|
-
## [1.11.0]
|
|
132
|
+
## [1.11.0] - 2026-09-17
|
|
26
133
|
|
|
27
134
|
### Added
|
|
28
135
|
|
|
@@ -33,7 +140,7 @@ This file starts at 1.10.0; for earlier releases see the git history.
|
|
|
33
140
|
from core resource/subresource strings — e.g. building RBAC rules — without
|
|
34
141
|
hardcoding a group list.
|
|
35
142
|
|
|
36
|
-
## [1.10.0]
|
|
143
|
+
## [1.10.0] - 2026-08-03
|
|
37
144
|
|
|
38
145
|
### Added
|
|
39
146
|
|
data/DEPRECATIONS.md
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Deprecations
|
|
2
|
+
|
|
3
|
+
A deprecation in kube_schema is a **dated promise**: it names the replacement
|
|
4
|
+
*and* the version the old name stops existing in. That promise is
|
|
5
|
+
machine-readable — every declaration registers itself, and the release tooling
|
|
6
|
+
refuses to ship a version that breaks one.
|
|
7
|
+
|
|
8
|
+
The mechanism is [`GemKit::Deprecate`](https://rubygems.org/gems/gem_kit),
|
|
9
|
+
built on [`Gem::Deprecate`](https://docs.ruby-lang.org/en/master/Gem/Deprecate.html).
|
|
10
|
+
|
|
11
|
+
## The rules
|
|
12
|
+
|
|
13
|
+
1. **Never delete a public name outright.** Leave it working, deprecated, until
|
|
14
|
+
its deadline.
|
|
15
|
+
2. **Every deprecation names a removal version.** The current version is 2.0.0, so the usual deadline is 3.0.
|
|
16
|
+
3. **Removals happen in major versions only.** A minor or patch release never
|
|
17
|
+
takes a name away.
|
|
18
|
+
4. **The deadline is enforced, not remembered.** `gem kit bump` and `gem kit release`
|
|
19
|
+
both refuse to move to a version that has a deprecation coming due.
|
|
20
|
+
5. **Deprecating something is a changelog entry** — under `### Deprecated`,
|
|
21
|
+
naming the replacement and the removal version.
|
|
22
|
+
|
|
23
|
+
## Deprecating a method
|
|
24
|
+
|
|
25
|
+
```ruby
|
|
26
|
+
class Session
|
|
27
|
+
extend GemKit::Deprecate
|
|
28
|
+
|
|
29
|
+
def new_reset
|
|
30
|
+
# ...
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def old_reset = new_reset
|
|
34
|
+
|
|
35
|
+
deprecate :old_reset, "Session#new_reset", "3.0"
|
|
36
|
+
end
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The old method keeps working and warns on every call, naming the caller:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
NOTE: Session#old_reset is deprecated; use Session#new_reset instead.
|
|
43
|
+
It will be removed in 3.0
|
|
44
|
+
Session#old_reset called from app.rb:12.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Use `:none` as the replacement when there genuinely isn't one:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
deprecate :old_reset, :none, "3.0"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For a class method, follow the `Gem::Deprecate` idiom — the registry records it
|
|
54
|
+
against the class, not its singleton:
|
|
55
|
+
|
|
56
|
+
```ruby
|
|
57
|
+
class << self
|
|
58
|
+
extend GemKit::Deprecate
|
|
59
|
+
deprecate :some_class_method, "Other.method", "3.0"
|
|
60
|
+
end
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Deprecating a renamed or moved constant
|
|
64
|
+
|
|
65
|
+
Keep the old constant as a subclass of the new one and declare the rename in
|
|
66
|
+
its body:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
module Old
|
|
70
|
+
class Thing < New::Thing
|
|
71
|
+
extend GemKit::Deprecate
|
|
72
|
+
superseded_by "New::Thing", "3.0"
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Old code keeps running unchanged; instantiating the old name warns and points at
|
|
78
|
+
the new one. The whole shim is those four lines — the implementation lives in
|
|
79
|
+
one place.
|
|
80
|
+
|
|
81
|
+
It is `superseded_by` rather than `deprecate_constant` because `Module` already
|
|
82
|
+
has a method by that name, and shadowing it would break callers who use it.
|
|
83
|
+
|
|
84
|
+
## Finding what is outstanding
|
|
85
|
+
|
|
86
|
+
```sh
|
|
87
|
+
gem kit deprecations
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
1 outstanding deprecation(s) (current version 2.0.0):
|
|
92
|
+
3.0 Session#old_reset -> Session#new_reset
|
|
93
|
+
lib/session.rb:19
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Pass a version to ask "what comes due here?" — it exits non-zero if anything
|
|
97
|
+
does, which is what makes it usable as a gate in CI:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
gem kit deprecations 3.0.0
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Programmatically, the same data:
|
|
104
|
+
|
|
105
|
+
```ruby
|
|
106
|
+
GemKit::Deprecate.registry # every declaration
|
|
107
|
+
GemKit::Deprecate.pending("3.0.0") # deadlines that have arrived
|
|
108
|
+
GemKit::Deprecate.upcoming("3.0.0") # still in their grace period
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Each entry carries `name`, `replacement`, `removed_in` and `declared_at`.
|
|
112
|
+
|
|
113
|
+
## Paying the debt
|
|
114
|
+
|
|
115
|
+
When a major version comes around, the bump is blocked until the deprecated
|
|
116
|
+
code is actually gone:
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
$ gem kit bump major
|
|
120
|
+
ERROR: Refusing to bump 2.0.0 -> 3.0.0:
|
|
121
|
+
|
|
122
|
+
3.0 Session#old_reset -> Session#new_reset
|
|
123
|
+
lib/session.rb:19
|
|
124
|
+
|
|
125
|
+
Remove them, then bump. Override with --force.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
So the order of work is:
|
|
129
|
+
|
|
130
|
+
1. `gem kit deprecations 3.0.0` — read the list.
|
|
131
|
+
2. Delete each deprecated name and its specs. For a constant shim, that means
|
|
132
|
+
deleting the whole file.
|
|
133
|
+
3. Update anything in `examples/` and the docs still using the old name.
|
|
134
|
+
4. Record the removals in `CHANGELOG.md` under `### Removed`.
|
|
135
|
+
5. `gem kit bump major` — now it goes through.
|
|
136
|
+
|
|
137
|
+
`--force` exists for the case where you have decided to extend a grace period,
|
|
138
|
+
and it prints what it is overriding. It is not the normal path: extending a
|
|
139
|
+
deadline properly means editing the declaration's version, which keeps the
|
|
140
|
+
registry honest.
|
|
141
|
+
|
|
142
|
+
## Testing deprecated code
|
|
143
|
+
|
|
144
|
+
`Gem::Deprecate.skip_during` silences these warnings too, so a spec can
|
|
145
|
+
exercise the old path without noise:
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
Gem::Deprecate.skip_during do
|
|
149
|
+
legacy.old_reset
|
|
150
|
+
end
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To assert *that* something warns, stub the single funnel every warning goes
|
|
154
|
+
through:
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
captured = []
|
|
158
|
+
original = GemKit::Deprecate.method(:warn)
|
|
159
|
+
GemKit::Deprecate.define_singleton_method(:warn) { |message| captured << message }
|
|
160
|
+
begin
|
|
161
|
+
legacy.old_reset
|
|
162
|
+
ensure
|
|
163
|
+
GemKit::Deprecate.define_singleton_method(:warn, original)
|
|
164
|
+
end
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## See also
|
|
168
|
+
|
|
169
|
+
- [RELEASE.md](RELEASE.md) — where the deprecation gates sit in the release
|
|
170
|
+
process.
|
|
171
|
+
- The changelog — its `### Deprecated` and `### Removed` sections are the
|
|
172
|
+
user-facing half of all this.
|
data/Gemfile
CHANGED
|
@@ -2,11 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
source "https://rubygems.org"
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
gem "gem_kit", "~> 0.2"
|
|
6
|
+
gem "json_schemer", "~> 2.5.0"
|
|
7
|
+
gem "rubyshell", "~> 1.5.0"
|
|
8
|
+
|
|
9
|
+
gem "lefthook", "~> 2.1"
|
|
10
|
+
gem "rake", "~> 13.0"
|
|
11
|
+
gem "scampi", "~> 1.0"
|
|
12
|
+
gem "rubocop"
|
|
13
|
+
gem "decode", "~> 0.27"
|
|
14
|
+
|
|
15
|
+
group :release do
|
|
16
|
+
gem "gem_kit-release", "~> 0.3"
|
|
17
|
+
end
|
|
6
18
|
|
|
7
19
|
group :maintenance, optional: true do
|
|
8
20
|
gem "utopia-project"
|
|
9
|
-
gem "bake-gem"
|
|
10
21
|
gem "bake-modernize"
|
|
11
|
-
gem "bake-releases"
|
|
12
22
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,13 +1,7 @@
|
|
|
1
|
-
PATH
|
|
2
|
-
remote: .
|
|
3
|
-
specs:
|
|
4
|
-
kube_schema (1.12.0)
|
|
5
|
-
json_schemer (~> 2.5.0)
|
|
6
|
-
rubyshell (~> 1.5.0)
|
|
7
|
-
|
|
8
1
|
GEM
|
|
9
2
|
remote: https://rubygems.org/
|
|
10
3
|
specs:
|
|
4
|
+
ast (2.4.3)
|
|
11
5
|
async (2.39.0)
|
|
12
6
|
console (~> 1.29)
|
|
13
7
|
fiber-annotation
|
|
@@ -46,8 +40,6 @@ GEM
|
|
|
46
40
|
bake (0.24.1)
|
|
47
41
|
bigdecimal
|
|
48
42
|
samovar (~> 2.1)
|
|
49
|
-
bake-gem (0.13.1)
|
|
50
|
-
console (~> 1.25)
|
|
51
43
|
bake-modernize (0.54.1)
|
|
52
44
|
async-http
|
|
53
45
|
async-ollama (~> 0.10)
|
|
@@ -55,9 +47,6 @@ GEM
|
|
|
55
47
|
build-files (~> 1.6)
|
|
56
48
|
markly (~> 0.13)
|
|
57
49
|
rugged
|
|
58
|
-
bake-releases (0.5.4)
|
|
59
|
-
bake (~> 0.21)
|
|
60
|
-
markly (~> 0.8)
|
|
61
50
|
bigdecimal (4.1.2)
|
|
62
51
|
build-files (1.10.2)
|
|
63
52
|
concurrent-ruby (1.3.6)
|
|
@@ -69,7 +58,6 @@ GEM
|
|
|
69
58
|
decode (0.27.0)
|
|
70
59
|
prism
|
|
71
60
|
rbs
|
|
72
|
-
diff-lcs (1.6.2)
|
|
73
61
|
erb (6.0.4)
|
|
74
62
|
falcon (0.55.3)
|
|
75
63
|
async
|
|
@@ -88,6 +76,10 @@ GEM
|
|
|
88
76
|
fiber-local (1.1.0)
|
|
89
77
|
fiber-storage
|
|
90
78
|
fiber-storage (1.0.1)
|
|
79
|
+
gem_kit (0.2.0)
|
|
80
|
+
gem_kit-release (0.3.2)
|
|
81
|
+
gem_kit (>= 0.1, < 1.0)
|
|
82
|
+
thor (~> 1.3)
|
|
91
83
|
hana (1.3.7)
|
|
92
84
|
http-accept (2.2.1)
|
|
93
85
|
io-console (0.8.2)
|
|
@@ -105,7 +97,9 @@ GEM
|
|
|
105
97
|
hana (~> 1.3)
|
|
106
98
|
regexp_parser (~> 2.0)
|
|
107
99
|
simpleidn (~> 0.2)
|
|
100
|
+
language_server-protocol (3.17.0.6)
|
|
108
101
|
lefthook (2.1.10)
|
|
102
|
+
lint_roller (1.1.0)
|
|
109
103
|
localhost (1.7.0)
|
|
110
104
|
logger (1.7.0)
|
|
111
105
|
mail (2.9.0)
|
|
@@ -133,6 +127,10 @@ GEM
|
|
|
133
127
|
net-smtp (0.5.1)
|
|
134
128
|
net-protocol
|
|
135
129
|
openssl (4.0.1)
|
|
130
|
+
parallel (2.3.0)
|
|
131
|
+
parser (3.3.12.0)
|
|
132
|
+
ast (~> 2.4.1)
|
|
133
|
+
racc
|
|
136
134
|
pp (0.6.3)
|
|
137
135
|
prettyprint
|
|
138
136
|
prettyprint (0.2.0)
|
|
@@ -152,11 +150,13 @@ GEM
|
|
|
152
150
|
psych (5.3.1)
|
|
153
151
|
date
|
|
154
152
|
stringio
|
|
153
|
+
racc (1.8.1)
|
|
155
154
|
rack (3.2.6)
|
|
156
155
|
rackula (1.4.1)
|
|
157
156
|
falcon (~> 0.46)
|
|
158
157
|
samovar (~> 2.1)
|
|
159
158
|
variant
|
|
159
|
+
rainbow (3.1.1)
|
|
160
160
|
rake (13.4.2)
|
|
161
161
|
rbs (4.0.2)
|
|
162
162
|
logger
|
|
@@ -169,31 +169,38 @@ GEM
|
|
|
169
169
|
regexp_parser (2.12.0)
|
|
170
170
|
reline (0.6.3)
|
|
171
171
|
io-console (~> 0.5)
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
172
|
+
rubocop (1.92.0)
|
|
173
|
+
json (>= 2.3)
|
|
174
|
+
language_server-protocol (~> 3.17.0.2)
|
|
175
|
+
lint_roller (~> 1.1.0)
|
|
176
|
+
parallel (>= 1.10)
|
|
177
|
+
parser (>= 3.3.0.2)
|
|
178
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
179
|
+
regexp_parser (>= 2.11.3, < 3.0)
|
|
180
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
181
|
+
ruby-progressbar (~> 1.7)
|
|
182
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
183
|
+
rubocop-ast (1.50.0)
|
|
184
|
+
parser (>= 3.3.7.2)
|
|
185
|
+
prism (~> 1.7)
|
|
186
|
+
ruby-progressbar (1.13.0)
|
|
185
187
|
rubyshell (1.5.0)
|
|
186
188
|
rugged (1.9.0)
|
|
187
189
|
samovar (2.4.1)
|
|
188
190
|
console (~> 1.0)
|
|
189
191
|
mapping (~> 1.0)
|
|
192
|
+
scampi (1.0.0)
|
|
190
193
|
simpleidn (0.2.3)
|
|
191
194
|
string-format (0.2.0)
|
|
192
195
|
stringio (3.2.0)
|
|
196
|
+
thor (1.5.0)
|
|
193
197
|
thread-local (1.1.0)
|
|
194
198
|
timeout (0.6.1)
|
|
195
199
|
traces (0.18.2)
|
|
196
200
|
tsort (0.2.0)
|
|
201
|
+
unicode-display_width (3.3.0)
|
|
202
|
+
unicode-emoji (~> 4.3)
|
|
203
|
+
unicode-emoji (4.3.0)
|
|
197
204
|
utopia (2.32.1)
|
|
198
205
|
bake (~> 0.20)
|
|
199
206
|
concurrent-ruby (~> 1.2)
|
|
@@ -226,14 +233,17 @@ PLATFORMS
|
|
|
226
233
|
x86_64-linux
|
|
227
234
|
|
|
228
235
|
DEPENDENCIES
|
|
229
|
-
bake-gem
|
|
230
236
|
bake-modernize
|
|
231
|
-
|
|
232
|
-
|
|
237
|
+
decode (~> 0.27)
|
|
238
|
+
gem_kit (~> 0.2)
|
|
239
|
+
gem_kit-release (~> 0.3)
|
|
240
|
+
json_schemer (~> 2.5.0)
|
|
233
241
|
lefthook (~> 2.1)
|
|
234
242
|
rake (~> 13.0)
|
|
235
|
-
|
|
243
|
+
rubocop
|
|
244
|
+
rubyshell (~> 1.5.0)
|
|
245
|
+
scampi (~> 1.0)
|
|
236
246
|
utopia-project
|
|
237
247
|
|
|
238
248
|
BUNDLED WITH
|
|
239
|
-
2.
|
|
249
|
+
2.7.2
|
data/RELEASE.md
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Releasing kube_schema
|
|
2
|
+
|
|
3
|
+
The whole process, in order:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
bin/test # 1. green suite
|
|
7
|
+
gem kit bump minor # 2. bump (prints what to run next)
|
|
8
|
+
gem kit changelog --write # 3. write the entry
|
|
9
|
+
gem kit changelog <VERSION> # 4. check it
|
|
10
|
+
git commit -am "Release ..." # 5. commit the bump + changelog
|
|
11
|
+
gem kit release # 6. gate, build, push, tag
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Steps 2 and 6 are gates: they refuse to proceed when something is missing.
|
|
15
|
+
Everything below is what they check and why.
|
|
16
|
+
|
|
17
|
+
## Versioning
|
|
18
|
+
|
|
19
|
+
kube_schema is [semver](https://semver.org/). The version lives in one place —
|
|
20
|
+
`lib/kube_schema/version.rb` — and is only ever changed by `gem kit bump`.
|
|
21
|
+
|
|
22
|
+
| Segment | When | What it may contain |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| **major** | A public name disappears or changes meaning | Removals of deprecated names, breaking signature changes |
|
|
25
|
+
| **minor** | New public surface, backwards compatible | New classes and methods; new deprecations |
|
|
26
|
+
| **patch** | Nothing new, nothing gone | Bug fixes, docs, internals |
|
|
27
|
+
|
|
28
|
+
Two rules follow from this, and both are enforced in code:
|
|
29
|
+
|
|
30
|
+
- **Removals only ever land in a major version.** A name promised to disappear
|
|
31
|
+
in 3.0 disappears in 3.0.0, not in a patch.
|
|
32
|
+
- **Deprecating is a minor.** Adding a deprecation puts no obligation on the
|
|
33
|
+
user *yet*, so it does not need a major — but it starts the clock. See
|
|
34
|
+
[DEPRECATIONS.md](DEPRECATIONS.md).
|
|
35
|
+
|
|
36
|
+
## 1. Green suite
|
|
37
|
+
|
|
38
|
+
```sh
|
|
39
|
+
bin/test
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
A red suite is not a release candidate; nothing downstream checks this for you.
|
|
43
|
+
|
|
44
|
+
## 2. Bump
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
gem kit bump <major|minor|patch>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Rewrites `lib/kube_schema/version.rb` — by rendering its `.erb` template if there is
|
|
51
|
+
one, otherwise by substituting the version literal in place — and prints the
|
|
52
|
+
transition:
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
2.0.0 -> ...
|
|
56
|
+
|
|
57
|
+
now run: gem kit changelog --write
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**It refuses to bump onto a deprecation deadline.** If any registered
|
|
61
|
+
deprecation is due at the new version, it lists them with their source lines
|
|
62
|
+
and fails. Remove the deprecated code first — that is the point of the promise.
|
|
63
|
+
`--force` overrides and says what it overrode. Deprecations *not* yet due are
|
|
64
|
+
reported for information, not blocked on.
|
|
65
|
+
|
|
66
|
+
## 3. Changelog
|
|
67
|
+
|
|
68
|
+
```sh
|
|
69
|
+
gem kit changelog --write
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Hands the entry to the AI CLI named by `config.changelog_writer` (default:
|
|
73
|
+
`claude`), with a prompt describing the format and this project's conventions.
|
|
74
|
+
It reads the commits since the last tag and edits `CHANGELOG.md` only.
|
|
75
|
+
|
|
76
|
+
Review what it writes. It is a first draft with the commits in front of it, not
|
|
77
|
+
an oracle — it cannot know which of two changes mattered to users.
|
|
78
|
+
|
|
79
|
+
The format is [Keep a Changelog](https://keepachangelog.com/en/1.1.0/):
|
|
80
|
+
|
|
81
|
+
```md
|
|
82
|
+
## [Unreleased]
|
|
83
|
+
|
|
84
|
+
## [2.0.0] - 2026-10-17
|
|
85
|
+
|
|
86
|
+
### Added
|
|
87
|
+
|
|
88
|
+
- Something users can now do.
|
|
89
|
+
|
|
90
|
+
### Deprecated
|
|
91
|
+
|
|
92
|
+
- `Old::Name` — use `New::Name` instead. Removed in 3.0.
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Entries go under `Added`, `Changed`, `Deprecated`, `Removed`, `Fixed` or
|
|
96
|
+
`Security` — those six and no others. `[Unreleased]` stays at the top, emptied
|
|
97
|
+
of anything that shipped.
|
|
98
|
+
|
|
99
|
+
## 4. Lint the changelog
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
gem kit changelog # format only
|
|
103
|
+
gem kit changelog 2.0.0 # format, plus "is this version ready?"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Checks the title, that every heading is `## [Unreleased]` or
|
|
107
|
+
`## [1.2.3] - YYYY-MM-DD`, that versions are valid, dated, unique and ordered
|
|
108
|
+
newest-first, that `###` sections are one of the six types and none are empty —
|
|
109
|
+
and, given a version, that it has a non-empty section at the top of the released
|
|
110
|
+
list. Every problem is reported as `CHANGELOG.md:<line> <what>`.
|
|
111
|
+
|
|
112
|
+
## 5. Commit
|
|
113
|
+
|
|
114
|
+
The version bump, the lockfile and the changelog belong in one commit, before
|
|
115
|
+
anything is pushed to RubyGems. A published gem whose changelog is still
|
|
116
|
+
unwritten in git is the failure this process exists to prevent.
|
|
117
|
+
|
|
118
|
+
## 6. Release
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
gem kit release # or --dry-run, which is the CI check
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Three gates, all before `gem build` runs:
|
|
125
|
+
|
|
126
|
+
1. **Changelog** — this version needs its own non-empty, correctly formatted
|
|
127
|
+
section, sitting at the top of the released list.
|
|
128
|
+
2. **Deprecations** — nothing promised to disappear in this version may still
|
|
129
|
+
be in the tree.
|
|
130
|
+
3. **The working tree** — everything committed. A gem built from uncommitted
|
|
131
|
+
files is a gem whose source exists nowhere, and step 2 and step 3 above
|
|
132
|
+
leave exactly two such files behind. `--allow-dirty` overrides it.
|
|
133
|
+
|
|
134
|
+
Then `gem build`, `gem push`, and the tag — `v2.0.0`,
|
|
135
|
+
created and pushed *after* the gem, so a tag never names a version that failed
|
|
136
|
+
to publish. `--no-tag` skips it.
|
|
137
|
+
|
|
138
|
+
Requires RubyGems push credentials.
|
|
139
|
+
|
|
140
|
+
The tag matters beyond bookkeeping: it is what the next
|
|
141
|
+
`gem kit changelog --write` uses to find the commit range, so a
|
|
142
|
+
missing one makes the following release's changelog harder to write.
|
|
143
|
+
|
|
144
|
+
`gem kit tag` still exists for tagging on its own.
|
|
145
|
+
|
|
146
|
+
## When something goes wrong
|
|
147
|
+
|
|
148
|
+
**Published a broken gem.** Don't delete it — `gem yank kube_schema -v X.Y.Z` if
|
|
149
|
+
it is genuinely dangerous, otherwise ship a patch. Yanking a version other
|
|
150
|
+
people have already locked to breaks their builds.
|
|
151
|
+
|
|
152
|
+
**Bumped but the release failed.** The bump is just a file. Fix the cause and
|
|
153
|
+
re-run `gem kit release`; there is no need to un-bump.
|
|
154
|
+
|
|
155
|
+
**Changelog written for the wrong version.** Edit the heading and re-run
|
|
156
|
+
`gem kit changelog <version>`. Nothing downstream caches it.
|
|
157
|
+
|
|
158
|
+
## See also
|
|
159
|
+
|
|
160
|
+
- [DEPRECATIONS.md](DEPRECATIONS.md) — the deprecation policy the gates enforce.
|
|
161
|
+
- [CHANGELOG.md](CHANGELOG.md).
|
data/Rakefile
CHANGED
data/bin/rubocop
ADDED
data/bin/test
CHANGED
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
2
|
-
# frozen_string_literal: true
|
|
1
|
+
#!/usr/bin/env sh
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
files = ARGV.empty? ? Dir.glob("lib/**/*.rb").sort : ARGV
|
|
7
|
-
|
|
8
|
-
files.each do |f|
|
|
9
|
-
system("bundle", "exec", "ruby", f, exception: true)
|
|
10
|
-
end
|
|
3
|
+
exec bundle exec scampi "$@"
|