gem_kit-release 0.1.0 → 0.2.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/LICENSE +201 -0
- data/README.md +191 -0
- data/lib/gem_kit/release/changelog.rb +6 -2
- data/lib/gem_kit/release/cli.rb +228 -76
- data/lib/gem_kit/release/{cli → commands}/bump.rb +3 -16
- data/lib/gem_kit/release/{cli → commands}/changelog.rb +3 -15
- data/lib/gem_kit/release/{cli → commands}/command.rb +18 -14
- data/lib/gem_kit/release/{cli → commands}/deprecations.rb +4 -12
- data/lib/gem_kit/release/{cli → commands}/release.rb +4 -11
- data/lib/gem_kit/release/{cli → commands}/tag.rb +26 -12
- data/lib/gem_kit/release/gate.rb +7 -7
- data/lib/gem_kit/release/generators/setup.rb +251 -0
- data/lib/gem_kit/release/project.rb +126 -9
- data/lib/gem_kit/release/templates/DEPRECATIONS.md.erb +19 -20
- data/lib/gem_kit/release/templates/RELEASE.md.erb +20 -20
- data/lib/gem_kit/release/version.rb +1 -1
- data/lib/gem_kit/release.rb +23 -11
- data/lib/rubygems/commands/kit_command.rb +1 -1
- metadata +50 -19
- data/lib/gem_kit/release/cli/setup.rb +0 -136
- data/lib/gem_kit/release/deprecate.rb +0 -285
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "rubygems/deprecate"
|
|
4
|
-
|
|
5
|
-
module GemKit
|
|
6
|
-
module Release
|
|
7
|
-
# A deprecation is a dated promise: it names the replacement *and* the
|
|
8
|
-
# version the old name stops existing in. Built on Gem::Deprecate, which
|
|
9
|
-
# gets the message format and the skip_during escape hatch right, plus one
|
|
10
|
-
# addition — a registry, so the set of outstanding promises is data the
|
|
11
|
-
# release tooling can enforce rather than prose someone has to remember.
|
|
12
|
-
#
|
|
13
|
-
# Deprecate a method:
|
|
14
|
-
#
|
|
15
|
-
# class Session
|
|
16
|
-
# extend GemKit::Release::Deprecate
|
|
17
|
-
#
|
|
18
|
-
# def old_reset = new_reset
|
|
19
|
-
# deprecate :old_reset, "Session#new_reset", "5.0"
|
|
20
|
-
# end
|
|
21
|
-
#
|
|
22
|
-
# Deprecate a whole constant that has moved or been renamed — leave the old
|
|
23
|
-
# name in place as a subclass of the new one, then declare it:
|
|
24
|
-
#
|
|
25
|
-
# class Completion < Brute::Completion::OpenRouter
|
|
26
|
-
# extend GemKit::Release::Deprecate
|
|
27
|
-
# superseded_by "Brute::Completion::OpenRouter", "5.0"
|
|
28
|
-
# end
|
|
29
|
-
#
|
|
30
|
-
# Both warn on use, naming the caller. Gem::Deprecate.skip_during silences
|
|
31
|
-
# them, so a test suite can exercise the old path in quiet.
|
|
32
|
-
module Deprecate
|
|
33
|
-
extend Gem::Deprecate
|
|
34
|
-
|
|
35
|
-
# One outstanding deprecation. `removed_in` is the deadline the release
|
|
36
|
-
# gate reads.
|
|
37
|
-
Entry = Struct.new(:name, :replacement, :removed_in, :declared_at, keyword_init: true) do
|
|
38
|
-
def to_s
|
|
39
|
-
"#{name} -> #{replacement == :none ? "(no replacement)" : replacement}"
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
class << self
|
|
44
|
-
# Every deprecation declared in the loaded library, in declaration order.
|
|
45
|
-
def registry
|
|
46
|
-
@registry ||= []
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
def register(name:, replacement:, removed_in:, declared_at: nil)
|
|
50
|
-
entry = Entry.new(
|
|
51
|
-
name: name.to_s,
|
|
52
|
-
replacement: replacement,
|
|
53
|
-
removed_in: Gem::Version.new(removed_in.to_s),
|
|
54
|
-
declared_at: declared_at || location(1),
|
|
55
|
-
)
|
|
56
|
-
registry << entry
|
|
57
|
-
entry
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# The deprecations that come due at `version` — every deadline that has
|
|
61
|
-
# arrived or passed. Releasing `version` with any of these still in the
|
|
62
|
-
# tree breaks the promise the warning made.
|
|
63
|
-
def pending(version)
|
|
64
|
-
target = Gem::Version.new(version.to_s)
|
|
65
|
-
registry.select { |entry| entry.removed_in <= target }
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# Deprecations still inside their grace period at `version`.
|
|
69
|
-
def upcoming(version)
|
|
70
|
-
target = Gem::Version.new(version.to_s)
|
|
71
|
-
registry.reject { |entry| entry.removed_in <= target }
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# Single funnel for every warning: Gem::Deprecate.skip_during works
|
|
75
|
-
# across all of them, and specs have one place to listen.
|
|
76
|
-
def warn(message)
|
|
77
|
-
Kernel.warn(message) unless Gem::Deprecate.skip
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
# The Gem::Deprecate-shaped message. `origin` must be computed at the
|
|
81
|
-
# call site — one frame deeper and it names this file rather than the
|
|
82
|
-
# code that needs changing.
|
|
83
|
-
def message(target, replacement, removed_in, origin)
|
|
84
|
-
[
|
|
85
|
-
"NOTE: #{target} is deprecated",
|
|
86
|
-
replacement == :none ? " with no replacement" : "; use #{replacement} instead",
|
|
87
|
-
". It will be removed in #{removed_in}",
|
|
88
|
-
"\n#{target} called from #{origin}.",
|
|
89
|
-
].join
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
def location(depth)
|
|
93
|
-
caller_locations(depth + 1, 1)&.first&.then { |l| "#{l.path}:#{l.lineno}" }
|
|
94
|
-
end
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
# Deprecate one method. Mirrors Gem::Deprecate#rubygems_deprecate, but the
|
|
98
|
-
# deadline is explicit — a deprecation added late in a cycle usually wants
|
|
99
|
-
# the major after next, and guessing that is not the tool's business.
|
|
100
|
-
def deprecate(name, replacement, removed_in)
|
|
101
|
-
label = singleton_class? ? "#{attached_object}.#{name}" : "#{self}##{name}"
|
|
102
|
-
Deprecate.register(name: label, replacement: replacement, removed_in: removed_in,
|
|
103
|
-
declared_at: Deprecate.location(1))
|
|
104
|
-
|
|
105
|
-
class_eval do
|
|
106
|
-
old = "_deprecated_#{name}"
|
|
107
|
-
alias_method old, name
|
|
108
|
-
define_method name do |*args, &block|
|
|
109
|
-
target = is_a?(Module) ? "#{self}.#{name}" : "#{self.class}##{name}"
|
|
110
|
-
origin = Gem.location_of_caller.join(":")
|
|
111
|
-
Deprecate.warn(Deprecate.message(target, replacement, removed_in, origin))
|
|
112
|
-
send(old, *args, &block)
|
|
113
|
-
end
|
|
114
|
-
ruby2_keywords name if respond_to?(:ruby2_keywords, true)
|
|
115
|
-
end
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
# Deprecate the constant this is called in — the renamed-or-moved case.
|
|
119
|
-
# Named `superseded_by` rather than `deprecate_constant` because Module
|
|
120
|
-
# already has a method by that name and shadowing it would be rude.
|
|
121
|
-
def superseded_by(replacement, removed_in)
|
|
122
|
-
Deprecate.register(name: name || to_s, replacement: replacement, removed_in: removed_in,
|
|
123
|
-
declared_at: Deprecate.location(1))
|
|
124
|
-
|
|
125
|
-
return unless respond_to?(:new)
|
|
126
|
-
|
|
127
|
-
define_singleton_method(:new) do |*args, **options, &block|
|
|
128
|
-
origin = Gem.location_of_caller.join(":")
|
|
129
|
-
Deprecate.warn(Deprecate.message(name || to_s, replacement, removed_in, origin))
|
|
130
|
-
super(*args, **options, &block)
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
__END__
|
|
138
|
-
|
|
139
|
-
describe "gem_kit/release/deprecate" do
|
|
140
|
-
Deprecate = GemKit::Release::Deprecate unless defined?(Deprecate)
|
|
141
|
-
|
|
142
|
-
captured = []
|
|
143
|
-
# Capture what Deprecate.warn emits and keep the shared registry clean —
|
|
144
|
-
# these specs declare throwaway deprecations.
|
|
145
|
-
isolated = lambda do |&block|
|
|
146
|
-
saved = Deprecate.registry.dup
|
|
147
|
-
original = Deprecate.method(:warn)
|
|
148
|
-
captured.clear
|
|
149
|
-
Deprecate.define_singleton_method(:warn) { |message| captured << message }
|
|
150
|
-
begin
|
|
151
|
-
block.call
|
|
152
|
-
ensure
|
|
153
|
-
Deprecate.define_singleton_method(:warn, original)
|
|
154
|
-
Deprecate.registry.replace(saved)
|
|
155
|
-
end
|
|
156
|
-
end
|
|
157
|
-
|
|
158
|
-
it "warns on a deprecated method, naming replacement, version and caller" do
|
|
159
|
-
isolated.call do
|
|
160
|
-
klass = Class.new do
|
|
161
|
-
extend Deprecate
|
|
162
|
-
def new_name = :result
|
|
163
|
-
def old_name = new_name
|
|
164
|
-
deprecate :old_name, "Thing#new_name", "9.0"
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
klass.new.old_name.should == :result # still works
|
|
168
|
-
captured.size.should == 1
|
|
169
|
-
captured.first.should.match(/is deprecated/)
|
|
170
|
-
captured.first.should.match(/use Thing#new_name instead/)
|
|
171
|
-
captured.first.should.match(/removed in 9\.0/)
|
|
172
|
-
captured.first.should.match(/called from /)
|
|
173
|
-
end
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
it "names the caller, not the deprecation machinery" do
|
|
177
|
-
isolated.call do
|
|
178
|
-
klass = Class.new do
|
|
179
|
-
extend Deprecate
|
|
180
|
-
def old_name = :result
|
|
181
|
-
deprecate :old_name, "Thing#new_name", "9.0"
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# These specs live in this file's __END__, so "the caller" is a line in
|
|
185
|
-
# deprecate.rb either way — pin the exact line to tell them apart.
|
|
186
|
-
klass.new.old_name; call_line = __LINE__
|
|
187
|
-
captured.first.should.match(/called from .*deprecate\.rb:#{call_line}\./)
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
it "labels a class-method deprecation by the class, not its singleton" do
|
|
192
|
-
isolated.call do
|
|
193
|
-
Class.new do
|
|
194
|
-
def self.to_s = "Demo"
|
|
195
|
-
def self.old_thing = :ok
|
|
196
|
-
class << self
|
|
197
|
-
extend Deprecate
|
|
198
|
-
deprecate :old_thing, "Other.new_thing", "9.0"
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
Deprecate.registry.last.name.should == "Demo.old_thing"
|
|
203
|
-
end
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
it "warns on a superseded constant but keeps it working" do
|
|
207
|
-
isolated.call do
|
|
208
|
-
modern = Class.new { def initialize(x); @x = x; end; attr_reader :x }
|
|
209
|
-
legacy = Class.new(modern) do
|
|
210
|
-
extend Deprecate
|
|
211
|
-
def self.name = "Old::Name"
|
|
212
|
-
superseded_by "New::Name", "9.0"
|
|
213
|
-
end
|
|
214
|
-
|
|
215
|
-
legacy.new(42).x.should == 42 # still works
|
|
216
|
-
captured.size.should == 1
|
|
217
|
-
captured.first.should.match(/Old::Name is deprecated; use New::Name instead/)
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
it "supports :none for a deprecation with no replacement" do
|
|
222
|
-
isolated.call do
|
|
223
|
-
klass = Class.new do
|
|
224
|
-
extend Deprecate
|
|
225
|
-
def gone = :ok
|
|
226
|
-
deprecate :gone, :none, "9.0"
|
|
227
|
-
end
|
|
228
|
-
|
|
229
|
-
klass.new.gone
|
|
230
|
-
captured.first.should.match(/with no replacement/)
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
it "registers each declaration with its deadline and source" do
|
|
235
|
-
isolated.call do
|
|
236
|
-
Class.new do
|
|
237
|
-
extend Deprecate
|
|
238
|
-
def gone = nil
|
|
239
|
-
deprecate :gone, "Other#kept", "9.0"
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
entry = Deprecate.registry.last
|
|
243
|
-
entry.replacement.should == "Other#kept"
|
|
244
|
-
entry.removed_in.should == Gem::Version.new("9.0")
|
|
245
|
-
entry.declared_at.should.match(/deprecate\.rb:\d+/)
|
|
246
|
-
end
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
it "splits the registry into pending and upcoming at a version" do
|
|
250
|
-
isolated.call do
|
|
251
|
-
Deprecate.registry.clear
|
|
252
|
-
Deprecate.register(name: "A", replacement: "A2", removed_in: "5.0")
|
|
253
|
-
Deprecate.register(name: "B", replacement: "B2", removed_in: "6.0")
|
|
254
|
-
|
|
255
|
-
Deprecate.pending("5.0.0").map(&:name).should == ["A"]
|
|
256
|
-
Deprecate.upcoming("5.0.0").map(&:name).should == ["B"]
|
|
257
|
-
Deprecate.pending("4.9.0").should.be.empty
|
|
258
|
-
Deprecate.pending("6.1.0").map(&:name).should == ["A", "B"]
|
|
259
|
-
end
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
it "stays quiet inside Gem::Deprecate.skip_during" do
|
|
263
|
-
saved = Deprecate.registry.dup
|
|
264
|
-
begin
|
|
265
|
-
klass = Class.new do
|
|
266
|
-
extend Deprecate
|
|
267
|
-
def quiet = :ok
|
|
268
|
-
deprecate :quiet, "Other#loud", "9.0"
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
warned = []
|
|
272
|
-
original = Kernel.method(:warn)
|
|
273
|
-
Kernel.define_singleton_method(:warn) { |*args| warned << args.join }
|
|
274
|
-
begin
|
|
275
|
-
Gem::Deprecate.skip_during { klass.new.quiet.should == :ok }
|
|
276
|
-
ensure
|
|
277
|
-
Kernel.define_singleton_method(:warn, original)
|
|
278
|
-
end
|
|
279
|
-
|
|
280
|
-
warned.should.be.empty
|
|
281
|
-
ensure
|
|
282
|
-
Deprecate.registry.replace(saved)
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
end
|