kettle-dev 3.1.6 → 3.1.8
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
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +53 -1
- data/README.md +1 -1
- data/lib/kettle/dev/lockfile_reset.rb +33 -1
- data/lib/kettle/dev/release_cli.rb +104 -10
- data/lib/kettle/dev/ruby_gems_versions.rb +71 -12
- data/lib/kettle/dev/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +10 -10
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 78a3ee1fd963f1a7cb5b8a4c0f0a7ad45b13245a6ad3359505f230298b29a6f6
|
|
4
|
+
data.tar.gz: 647c9da39ce601b3279cfe863cde3986006040cc26ae81ffe51f91164acb9b46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2f18613e1d4d7459c3537c710caa4b705eb940c55342d65d96657ebf992961464a1f79e2511505026af8d0726d1738fd6e9ebcd6cd9d306d77f9a90ae0f55228
|
|
7
|
+
data.tar.gz: 95d49245a2e0335c60a12ce97b20a46db0e921ec35c943641fc973c71391875d12f4d82164a222012e777b18a82c84fdfc2ad5a52aa825a67501ba7312efdba7
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,54 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.1.8] - 2026-10-07
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.1.8][3.1.8t]
|
|
36
|
+
- COVERAGE: 91.65% -- 6276/6848 lines in 49 files
|
|
37
|
+
- BRANCH COVERAGE: 75.90% -- 2390/3149 branches in 49 files
|
|
38
|
+
- 51.77% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- `Kettle::Dev::RubyGemsVersions.fetch` accepts a `source:` keyword so callers can query a RubyGems-compatible private registry such as gem.coop instead of only rubygems.org. The version cache is now namespaced by source host, so a private registry lagging rubygems.org cannot serve stale answers for the other. The default source keeps the historical bare gem-name cache key, so existing caches remain valid.
|
|
43
|
+
|
|
44
|
+
- `Kettle::Dev::RubyGemsVersions.published_version_numbers(gem_name, source:)` returns the version numbers a registry serves for a gem, or nil when the registry could not be consulted. Callers must treat nil as "unknown" rather than "unpublished" so an offline run is not blocked; an empty list, by contrast, means the registry was reached and serves no versions.
|
|
45
|
+
|
|
46
|
+
- [kc] lockfile-registry-specs: `Kettle::Dev::LockfileReset.registry_gem_specs_from_source` returns GEM-section specs as `{remote:, name:, version:}` so a caller can attribute each pinned version to the registry it was resolved from, which is what makes it possible to detect a locally built and installed gem leaking into a lockfile: bundler resolves against the local gem dir, so an ordinary `bundle install` can pin a version no registry serves, and the resulting entry is a normal GEM-section line carrying a valid checksum taken from the installed spec, so nothing in the lockfile text distinguishes it and "is this version published?" can only be answered against the remote that section recorded. `gem_specs_from_source` is now a thin wrapper over it and keeps returning `[[name, version]]` unchanged.
|
|
47
|
+
|
|
48
|
+
- `Kettle::Dev::RubyGemsVersions.published_version_numbers` accepts a `version:` keyword and forwards it to `fetch` as a cache-bust hint, so the on-disk release marker that `kettle-release` writes after publishing busts the cache for exactly that gem and version instead of for every gem released within the marker TTL. Without it a caller cannot distinguish "published moments ago in this very run" from "released sometime in the last month". Also adds `RubyGemsVersions.recently_released?(gem_name, version)`, which reports whether the marker records that exact gem and version as published within the TTL, treating a missing or corrupt marker as false rather than raising.
|
|
49
|
+
|
|
50
|
+
## [3.1.7] - 2026-10-04
|
|
51
|
+
|
|
52
|
+
- TAG: [v3.1.7][3.1.7t]
|
|
53
|
+
- COVERAGE: 91.75% -- 6261/6824 lines in 49 files
|
|
54
|
+
- BRANCH COVERAGE: 76.08% -- 2388/3139 branches in 49 files
|
|
55
|
+
- 51.34% documented
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
|
|
59
|
+
- kettle-release warns when the current branch is not among the release branches its family declares, naming the declaring config and the declared branches, instead of silently treating it as a feature branch destined for trunk.
|
|
60
|
+
|
|
61
|
+
### Fixed
|
|
62
|
+
|
|
63
|
+
- Branch-stack release detection now also reads `release.member_target_branches.<gem>` from the family root config, so a member whose templated local `.kettle-family.yml` is absent (a fresh branch, or a linked worktree) no longer degrades silently into a trunk pull request and a merge into trunk.
|
|
64
|
+
|
|
65
|
+
- Branch-stack release detection no longer uses block-level `rescue` or `Array#filter_map`, which are Ruby 2.6+ and 2.7+ constructs; the gem supports Ruby 2.4. YAML loading is isolated in `safe_load_kettle_family_config` with a method-level rescue, restoring the explicit `begin`/`end` contract the surrounding code relies on.
|
|
66
|
+
|
|
67
|
+
- Preserve the selected Gemfile and lockfile when Bundler restarts during release lockfile reset.
|
|
68
|
+
|
|
69
|
+
### Changed
|
|
70
|
+
|
|
71
|
+
- [kc] kettle-jem/prepare: updated 13 project files:
|
|
72
|
+
- dependencies (13)
|
|
73
|
+
|
|
74
|
+
- [kc] kettle-jem/template: updated 7 project files:
|
|
75
|
+
- code and tests (2)
|
|
76
|
+
- dependencies (1)
|
|
77
|
+
- documentation (1)
|
|
78
|
+
- other (2)
|
|
79
|
+
- workflows (1)
|
|
80
|
+
|
|
33
81
|
## [3.1.6] - 2026-10-02
|
|
34
82
|
|
|
35
83
|
- TAG: [v3.1.6][3.1.6t]
|
|
@@ -3953,7 +4001,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
3953
4001
|
- Selecting will run the selected workflow via `act`
|
|
3954
4002
|
- This may move to its own gem in the future.
|
|
3955
4003
|
|
|
3956
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.
|
|
4004
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.8...HEAD
|
|
4005
|
+
[3.1.8]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.7...v3.1.8
|
|
4006
|
+
[3.1.8t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.1.8
|
|
4007
|
+
[3.1.7]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.6...v3.1.7
|
|
4008
|
+
[3.1.7t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.1.7
|
|
3957
4009
|
[3.1.6]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.5...v3.1.6
|
|
3958
4010
|
[3.1.6t]: https://github.com/kettle-dev/kettle-dev/releases/tag/v3.1.6
|
|
3959
4011
|
[3.1.5]: https://github.com/kettle-dev/kettle-dev/compare/v3.1.4...v3.1.5
|
data/README.md
CHANGED
|
@@ -1067,7 +1067,7 @@ Thanks for RTFM. ☺️
|
|
|
1067
1067
|
[📌gitmoji]: https://gitmoji.dev
|
|
1068
1068
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
1069
1069
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
1070
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.
|
|
1070
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-6.848-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
1071
1071
|
[🔐security]: https://github.com/kettle-dev/kettle-dev/blob/main/SECURITY.md
|
|
1072
1072
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
1073
1073
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -75,19 +75,42 @@ module Kettle
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def gem_specs_from_source(lockfile_source)
|
|
78
|
+
registry_gem_specs_from_source(lockfile_source).map { |spec| [spec.fetch(:name), spec.fetch(:version)] }.uniq
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Like gem_specs_from_source, but attributes each spec to the registry
|
|
82
|
+
# remote of the GEM section it appeared in.
|
|
83
|
+
#
|
|
84
|
+
# Remote attribution matters for detecting locally installed but
|
|
85
|
+
# unpublished versions: a lockfile can carry several GEM sections with
|
|
86
|
+
# different remotes, and "is this version published?" can only be
|
|
87
|
+
# answered against the source that was actually used. Bundler resolves
|
|
88
|
+
# a locally installed spec during an ordinary `bundle install`, so the
|
|
89
|
+
# pinned entry looks exactly like a published one — same GEM section,
|
|
90
|
+
# valid checksum — and only a registry query for that remote reveals
|
|
91
|
+
# the version does not exist there.
|
|
92
|
+
#
|
|
93
|
+
# @return [Array<Hash>] entries of {remote:, name:, version:}
|
|
94
|
+
def registry_gem_specs_from_source(lockfile_source)
|
|
78
95
|
in_gem = false
|
|
79
96
|
in_specs = false
|
|
97
|
+
remote = nil
|
|
80
98
|
specs = []
|
|
81
99
|
lockfile_source.each_line do |line|
|
|
82
100
|
stripped = line.chomp
|
|
83
101
|
if stripped == "GEM"
|
|
84
102
|
in_gem = true
|
|
85
103
|
in_specs = false
|
|
104
|
+
remote = nil
|
|
86
105
|
next
|
|
87
106
|
end
|
|
88
107
|
next unless in_gem
|
|
89
108
|
break if !stripped.empty? && stripped == stripped.upcase && !stripped.start_with?(" ")
|
|
90
109
|
|
|
110
|
+
if stripped.start_with?(" remote:")
|
|
111
|
+
remote = stripped.delete_prefix(" remote:").strip
|
|
112
|
+
next
|
|
113
|
+
end
|
|
91
114
|
if stripped == " specs:"
|
|
92
115
|
in_specs = true
|
|
93
116
|
next
|
|
@@ -96,7 +119,9 @@ module Kettle
|
|
|
96
119
|
next unless line.start_with?(" ") && !line.start_with?(" ")
|
|
97
120
|
|
|
98
121
|
parsed = parse_lockfile_spec_line(stripped)
|
|
99
|
-
|
|
122
|
+
next unless parsed
|
|
123
|
+
|
|
124
|
+
specs << {remote: remote, name: parsed.fetch(:name), version: parsed.fetch(:version)}
|
|
100
125
|
end
|
|
101
126
|
specs.uniq
|
|
102
127
|
end
|
|
@@ -201,6 +226,13 @@ module Kettle
|
|
|
201
226
|
"BUNDLE_GEMFILE" => gemfile,
|
|
202
227
|
"BUNDLE_LOCKFILE" => path
|
|
203
228
|
)
|
|
229
|
+
if update_bundler
|
|
230
|
+
# Bundler's `update --bundler` restarts itself using its original
|
|
231
|
+
# environment. Preserve this reset's selected bundle across that
|
|
232
|
+
# restart instead of falling back to the member's default Gemfile.
|
|
233
|
+
env["BUNDLER_ORIG_BUNDLE_GEMFILE"] = gemfile
|
|
234
|
+
env["BUNDLER_ORIG_BUNDLE_LOCKFILE"] = path
|
|
235
|
+
end
|
|
204
236
|
env["KETTLE_DEV_SKIP_CHANGELOG_DEPENDENCY"] = "true" if skip_changelog_dependency
|
|
205
237
|
if isolated_gem_home
|
|
206
238
|
env["GEM_HOME"] = isolated_gem_home
|
|
@@ -2928,23 +2928,117 @@ module Kettle
|
|
|
2928
2928
|
return false if branch.to_s.empty?
|
|
2929
2929
|
return false if trunk && branch == trunk
|
|
2930
2930
|
|
|
2931
|
-
local_kettle_family_release_target_branches
|
|
2931
|
+
targets = local_kettle_family_release_target_branches
|
|
2932
|
+
return true if targets.include?(branch)
|
|
2933
|
+
|
|
2934
|
+
warn_undeclared_branch_stack_release(branch, targets)
|
|
2935
|
+
false
|
|
2932
2936
|
end
|
|
2933
2937
|
|
|
2938
|
+
# A member whose family declares a branch stack, releasing a branch that
|
|
2939
|
+
# is not in that list, gets merged into trunk and validated by a trunk
|
|
2940
|
+
# PR. That is almost always a wrong-branch release, not a feature
|
|
2941
|
+
# branch, so say so loudly instead of silently degrading.
|
|
2942
|
+
def warn_undeclared_branch_stack_release(branch, targets)
|
|
2943
|
+
declaring_root = family_declared_branch_stack_roots.first
|
|
2944
|
+
return unless declaring_root
|
|
2945
|
+
return if Array(@warned_undeclared_stack_branches).include?(branch)
|
|
2946
|
+
|
|
2947
|
+
@warned_undeclared_stack_branches = Array(@warned_undeclared_stack_branches) + [branch]
|
|
2948
|
+
warn(
|
|
2949
|
+
"[kettle-release] #{branch} is not a declared release branch for #{family_stack_gem_name.inspect} " \
|
|
2950
|
+
"in #{Kettle::Dev.display_path(declaring_root)}; it will be treated as a feature branch and merged into trunk. " \
|
|
2951
|
+
"Declared release branches: #{targets.join(", ")}"
|
|
2952
|
+
)
|
|
2953
|
+
end
|
|
2954
|
+
|
|
2955
|
+
# The member-local `.kettle-family.yml` is a templated copy that can be
|
|
2956
|
+
# absent on a fresh branch or in a worktree. The family root is the
|
|
2957
|
+
# authoritative declaration (`release.member_target_branches.<gem>`), so
|
|
2958
|
+
# consult it too and union the two. Silently returning [] when a family
|
|
2959
|
+
# config *does* declare a stack for this gem is what produced
|
|
2960
|
+
# PR-against-trunk releases and trunk merges for branch-stack members.
|
|
2934
2961
|
def local_kettle_family_release_target_branches
|
|
2962
|
+
branches = []
|
|
2935
2963
|
local_kettle_family_config_paths.each do |path|
|
|
2936
2964
|
next unless File.file?(path)
|
|
2937
2965
|
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2966
|
+
data = safe_load_kettle_family_config(path)
|
|
2967
|
+
next unless data
|
|
2968
|
+
|
|
2969
|
+
branches.concat(
|
|
2970
|
+
Array(dig_string_keys(data, "release", "target_branches")),
|
|
2971
|
+
Array(dig_string_keys(data, "branches", "release_targets"))
|
|
2972
|
+
)
|
|
2973
|
+
end
|
|
2974
|
+
branches.concat(family_root_release_target_branches)
|
|
2975
|
+
branches.map(&:to_s).reject(&:empty?).uniq
|
|
2976
|
+
end
|
|
2977
|
+
|
|
2978
|
+
def family_root_release_target_branches
|
|
2979
|
+
family_declared_branch_stack_roots.flat_map do |path|
|
|
2980
|
+
data = safe_load_kettle_family_config(path) || {}
|
|
2981
|
+
Array(dig_string_keys(data, "release", "member_target_branches", family_stack_gem_name))
|
|
2982
|
+
end
|
|
2983
|
+
end
|
|
2984
|
+
|
|
2985
|
+
# Family-root configs that declare a non-empty branch stack for this gem.
|
|
2986
|
+
def family_declared_branch_stack_roots
|
|
2987
|
+
gem_name = family_stack_gem_name
|
|
2988
|
+
return [] unless gem_name
|
|
2989
|
+
|
|
2990
|
+
family_root_config_paths.select do |path|
|
|
2991
|
+
data = safe_load_kettle_family_config(path)
|
|
2992
|
+
next false unless data
|
|
2993
|
+
|
|
2994
|
+
declared_stack_branches(data, gem_name).any?
|
|
2995
|
+
end
|
|
2996
|
+
end
|
|
2997
|
+
|
|
2998
|
+
# Only treat a parent directory as the family root when its config
|
|
2999
|
+
# actually lists this checkout as a member root.
|
|
3000
|
+
def family_root_config_paths
|
|
3001
|
+
[File.expand_path("..", @root)].map do |candidate|
|
|
3002
|
+
path = File.join(candidate, ".kettle-family.yml")
|
|
3003
|
+
next nil unless File.file?(path)
|
|
3004
|
+
|
|
3005
|
+
data = safe_load_kettle_family_config(path)
|
|
3006
|
+
next nil unless data
|
|
3007
|
+
|
|
3008
|
+
roots = Array(dig_string_keys(data, "members", "roots")).map(&:to_s)
|
|
3009
|
+
path if roots.include?(File.basename(@root))
|
|
3010
|
+
end.compact
|
|
3011
|
+
end
|
|
3012
|
+
|
|
3013
|
+
def declared_stack_branches(data, gem_name)
|
|
3014
|
+
Array(dig_string_keys(data, "release", "member_target_branches", gem_name)).map(&:to_s).reject(&:empty?)
|
|
3015
|
+
end
|
|
3016
|
+
|
|
3017
|
+
# YAML loading is isolated in a method body so a malformed config is
|
|
3018
|
+
# reported once instead of raising inside a block. Block-level `rescue`
|
|
3019
|
+
# is a Ruby 2.6+ construct and this gem supports Ruby 2.4.
|
|
3020
|
+
def safe_load_kettle_family_config(path)
|
|
3021
|
+
Kettle::Dev.safe_load_yaml_file(path) || {}
|
|
3022
|
+
rescue Psych::Exception => e
|
|
3023
|
+
warn("Ignoring invalid kettle-family config #{Kettle::Dev.display_path(path)}: #{e.message}")
|
|
3024
|
+
nil
|
|
3025
|
+
end
|
|
3026
|
+
|
|
3027
|
+
def family_stack_gem_name
|
|
3028
|
+
@family_stack_gem_name ||= begin
|
|
3029
|
+
name = ENV.fetch("K_CHANGELOG_GEM_NAME", "").to_s.strip
|
|
3030
|
+
name = detect_family_stack_gem_name_from_gemspec if name.empty?
|
|
3031
|
+
name.empty? ? nil : name
|
|
2946
3032
|
end
|
|
2947
|
-
|
|
3033
|
+
end
|
|
3034
|
+
|
|
3035
|
+
def detect_family_stack_gem_name_from_gemspec
|
|
3036
|
+
gemspecs = Dir[File.join(@root, "*.gemspec")]
|
|
3037
|
+
path = gemspecs.min
|
|
3038
|
+
return "" unless path
|
|
3039
|
+
|
|
3040
|
+
match = File.read(path).match(/spec\.name\s*=\s*(["'])([^"']+)\1/)
|
|
3041
|
+
match ? match[2].to_s : ""
|
|
2948
3042
|
end
|
|
2949
3043
|
|
|
2950
3044
|
def local_kettle_family_config_paths
|
|
@@ -16,19 +16,27 @@ module Kettle
|
|
|
16
16
|
VERSION_CACHE_TTL_SECONDS = 30 * 24 * 60 * 60
|
|
17
17
|
HTTP_OPEN_TIMEOUT_SECONDS = 5
|
|
18
18
|
HTTP_READ_TIMEOUT_SECONDS = 10
|
|
19
|
+
DEFAULT_SOURCE = "https://rubygems.org"
|
|
19
20
|
ENV_REFRESH = "KETTLE_RUBYGEMS_REFRESH"
|
|
20
21
|
ENV_MARKER_PATH = "KETTLE_RUBYGEMS_CACHE_BUST_PATH"
|
|
21
22
|
ENV_VERSION_CACHE_PATH = "KETTLE_RUBYGEMS_VERSION_CACHE_PATH"
|
|
22
23
|
ENV_LEGACY_VERSION_CACHE_PATH = "KETTLE_JEM_DEPS_FLOOR_CACHE"
|
|
23
24
|
|
|
24
25
|
class << self
|
|
25
|
-
|
|
26
|
+
# Query a RubyGems-compatible versions API.
|
|
27
|
+
#
|
|
28
|
+
# +source+ selects which registry to ask, because a private registry
|
|
29
|
+
# such as gem.coop can lag rubygems.org: a version present on one may
|
|
30
|
+
# be absent from the other. Cache entries are keyed by source for the
|
|
31
|
+
# same reason, so the two registries cannot poison each other.
|
|
32
|
+
def fetch(gem_name, version_hint: nil, refresh: false, source: DEFAULT_SOURCE)
|
|
26
33
|
name = gem_name.to_s
|
|
27
|
-
|
|
34
|
+
key = cache_key(name, source)
|
|
35
|
+
cached = cached_versions(key)
|
|
28
36
|
cache_bust = refresh || env_refresh? || fresh_release_marker?(name, version_hint) || cached_behind_version?(cached, version_hint)
|
|
29
37
|
return cached if cached && !cache_bust
|
|
30
38
|
|
|
31
|
-
uri = versions_uri(gem_name, cache_bust: cache_bust)
|
|
39
|
+
uri = versions_uri(gem_name, source: source, cache_bust: cache_bust)
|
|
32
40
|
request = Net::HTTP::Get.new(uri)
|
|
33
41
|
if cache_bust
|
|
34
42
|
request["Cache-Control"] = "no-cache"
|
|
@@ -44,13 +52,13 @@ module Kettle
|
|
|
44
52
|
http.request(request)
|
|
45
53
|
end
|
|
46
54
|
if response.code.to_i == 404
|
|
47
|
-
write_versions(
|
|
55
|
+
write_versions(key, [])
|
|
48
56
|
return []
|
|
49
57
|
end
|
|
50
58
|
return cached unless response.is_a?(Net::HTTPSuccess)
|
|
51
59
|
|
|
52
60
|
data = JSON.parse(response.body)
|
|
53
|
-
write_versions(
|
|
61
|
+
write_versions(key, data) if data.is_a?(Array)
|
|
54
62
|
data
|
|
55
63
|
rescue => error
|
|
56
64
|
return cached if cached
|
|
@@ -58,6 +66,40 @@ module Kettle
|
|
|
58
66
|
raise error
|
|
59
67
|
end
|
|
60
68
|
|
|
69
|
+
# Published version numbers for a gem on one registry, or nil when the
|
|
70
|
+
# registry could not be consulted (caller must treat that as "unknown",
|
|
71
|
+
# never as "unpublished", so offline runs are not blocked).
|
|
72
|
+
#
|
|
73
|
+
# +source+ is matched against the remote a lockfile actually recorded,
|
|
74
|
+
# since a private registry such as gem.coop can lag rubygems.org.
|
|
75
|
+
#
|
|
76
|
+
# +version+ is the version the caller is asking about, forwarded as
|
|
77
|
+
# fetch's version_hint. That makes cache-busting precise: the on-disk
|
|
78
|
+
# release marker written by kettle-release busts the cache only for the
|
|
79
|
+
# exact gem+version just published, instead of for every gem released
|
|
80
|
+
# within the marker TTL. Without it a caller cannot tell "this version
|
|
81
|
+
# was published moments ago in this very run" from "this gem was
|
|
82
|
+
# released at some point in the last month".
|
|
83
|
+
def published_version_numbers(gem_name, source: DEFAULT_SOURCE, version: nil)
|
|
84
|
+
versions = fetch(gem_name, version_hint: version, source: normalize_source(source))
|
|
85
|
+
return nil if versions.nil?
|
|
86
|
+
|
|
87
|
+
versions.filter_map { |entry| entry["number"] if entry.is_a?(Hash) }
|
|
88
|
+
rescue
|
|
89
|
+
nil
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# Whether kettle-release's on-disk marker says this exact gem+version
|
|
93
|
+
# was published recently enough that cached registry data must not be
|
|
94
|
+
# trusted for it.
|
|
95
|
+
#
|
|
96
|
+
# The marker file is the authority on what this machine just published,
|
|
97
|
+
# so any process-local cache layered on top of the registry must consult
|
|
98
|
+
# it rather than serve a pre-publish answer.
|
|
99
|
+
def recently_released?(gem_name, version = nil)
|
|
100
|
+
fresh_release_marker?(gem_name.to_s, version&.to_s)
|
|
101
|
+
end
|
|
102
|
+
|
|
61
103
|
def mark_released(gem_name, version)
|
|
62
104
|
return if gem_name.to_s.empty? || version.to_s.empty?
|
|
63
105
|
|
|
@@ -99,8 +141,25 @@ module Kettle
|
|
|
99
141
|
|
|
100
142
|
private
|
|
101
143
|
|
|
102
|
-
|
|
103
|
-
|
|
144
|
+
# Cache entries are namespaced by source host so a version list fetched
|
|
145
|
+
# from a private registry cannot be served for rubygems.org, or vice
|
|
146
|
+
# versa. The default source keeps the historical bare gem name as its
|
|
147
|
+
# key so existing caches remain valid.
|
|
148
|
+
def cache_key(gem_name, source)
|
|
149
|
+
normalized = normalize_source(source)
|
|
150
|
+
return gem_name.to_s if normalized == DEFAULT_SOURCE
|
|
151
|
+
|
|
152
|
+
"#{URI(normalized).host}:#{gem_name}"
|
|
153
|
+
rescue URI::InvalidURIError
|
|
154
|
+
"#{normalized}:#{gem_name}"
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def normalize_source(source)
|
|
158
|
+
source.to_s.sub(%r{/+\z}, "")
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def versions_uri(gem_name, source:, cache_bust:)
|
|
162
|
+
uri = URI("#{normalize_source(source)}/api/v1/versions/#{gem_name}.json")
|
|
104
163
|
uri.query = "_kettle_cache_bust=#{Time.now.to_i}" if cache_bust
|
|
105
164
|
uri
|
|
106
165
|
end
|
|
@@ -145,31 +204,31 @@ module Kettle
|
|
|
145
204
|
ENV.fetch(ENV_REFRESH, "").match?(Kettle::Dev::ENV_TRUE_RE)
|
|
146
205
|
end
|
|
147
206
|
|
|
148
|
-
def cached_versions(
|
|
207
|
+
def cached_versions(cache_key)
|
|
149
208
|
path = version_cache_path
|
|
150
209
|
return nil if path.empty?
|
|
151
210
|
|
|
152
|
-
entry = read_version_cache(path).fetch("versions", {})[
|
|
211
|
+
entry = read_version_cache(path).fetch("versions", {})[cache_key]
|
|
153
212
|
return nil unless entry.is_a?(Hash)
|
|
154
213
|
return nil unless fresh_version_cache_entry?(entry)
|
|
155
214
|
|
|
156
215
|
Array(entry["entries"])
|
|
157
216
|
end
|
|
158
217
|
|
|
159
|
-
def write_versions(
|
|
218
|
+
def write_versions(cache_key, entries)
|
|
160
219
|
path = version_cache_path
|
|
161
220
|
return if path.empty?
|
|
162
221
|
|
|
163
222
|
data = read_version_cache(path)
|
|
164
223
|
data["versions"] ||= {}
|
|
165
|
-
data["versions"][
|
|
224
|
+
data["versions"][cache_key] = {
|
|
166
225
|
"cached_at" => Time.now.utc.iso8601,
|
|
167
226
|
"entries" => entries
|
|
168
227
|
}
|
|
169
228
|
FileUtils.mkdir_p(File.dirname(path))
|
|
170
229
|
File.write(path, JSON.pretty_generate(data) << "\n")
|
|
171
230
|
rescue => error
|
|
172
|
-
warn("[kettle-dev] could not update RubyGems
|
|
231
|
+
warn("[kettle-dev] could not update RubyGems version cache: #{error.class}: #{error.message}") if Kettle::Dev::DEBUGGING
|
|
173
232
|
end
|
|
174
233
|
|
|
175
234
|
def read_version_cache(path)
|
data/lib/kettle/dev/version.rb
CHANGED
|
@@ -5,7 +5,7 @@ module Kettle
|
|
|
5
5
|
# Version namespace for this gem.
|
|
6
6
|
module Version
|
|
7
7
|
# Current gem version.
|
|
8
|
-
VERSION = "3.1.
|
|
8
|
+
VERSION = "3.1.8"
|
|
9
9
|
end
|
|
10
10
|
# Current gem version exposed at the traditional constant location.
|
|
11
11
|
VERSION = Version::VERSION # Traditional Constant Location
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-dev
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.1.
|
|
4
|
+
version: 3.1.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -256,7 +256,7 @@ dependencies:
|
|
|
256
256
|
version: '3.2'
|
|
257
257
|
- - ">="
|
|
258
258
|
- !ruby/object:Gem::Version
|
|
259
|
-
version: 3.2.
|
|
259
|
+
version: 3.2.5
|
|
260
260
|
type: :development
|
|
261
261
|
prerelease: false
|
|
262
262
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -266,7 +266,7 @@ dependencies:
|
|
|
266
266
|
version: '3.2'
|
|
267
267
|
- - ">="
|
|
268
268
|
- !ruby/object:Gem::Version
|
|
269
|
-
version: 3.2.
|
|
269
|
+
version: 3.2.5
|
|
270
270
|
- !ruby/object:Gem::Dependency
|
|
271
271
|
name: turbo_tests2
|
|
272
272
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -276,7 +276,7 @@ dependencies:
|
|
|
276
276
|
version: '3.2'
|
|
277
277
|
- - ">="
|
|
278
278
|
- !ruby/object:Gem::Version
|
|
279
|
-
version: 3.2.
|
|
279
|
+
version: 3.2.13
|
|
280
280
|
type: :development
|
|
281
281
|
prerelease: false
|
|
282
282
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -286,7 +286,7 @@ dependencies:
|
|
|
286
286
|
version: '3.2'
|
|
287
287
|
- - ">="
|
|
288
288
|
- !ruby/object:Gem::Version
|
|
289
|
-
version: 3.2.
|
|
289
|
+
version: 3.2.13
|
|
290
290
|
- !ruby/object:Gem::Dependency
|
|
291
291
|
name: stone_checksums
|
|
292
292
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -316,7 +316,7 @@ dependencies:
|
|
|
316
316
|
version: '2.0'
|
|
317
317
|
- - ">="
|
|
318
318
|
- !ruby/object:Gem::Version
|
|
319
|
-
version: 2.0.
|
|
319
|
+
version: 2.0.15
|
|
320
320
|
type: :development
|
|
321
321
|
prerelease: false
|
|
322
322
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -326,7 +326,7 @@ dependencies:
|
|
|
326
326
|
version: '2.0'
|
|
327
327
|
- - ">="
|
|
328
328
|
- !ruby/object:Gem::Version
|
|
329
|
-
version: 2.0.
|
|
329
|
+
version: 2.0.15
|
|
330
330
|
description: "\U0001F372 Kettle::Dev is a meta tool from kettle-dev to streamline
|
|
331
331
|
development and testing. Acts as a shim dependency, pulling in many other dependencies,
|
|
332
332
|
to give you OOTB productivity with a RubyGem, or Ruby app project. Configures a
|
|
@@ -422,10 +422,10 @@ licenses:
|
|
|
422
422
|
- AGPL-3.0-only
|
|
423
423
|
metadata:
|
|
424
424
|
homepage_uri: https://kettle-dev.galtzo.com
|
|
425
|
-
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.1.
|
|
426
|
-
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.1.
|
|
425
|
+
source_code_uri: https://github.com/kettle-dev/kettle-dev/tree/v3.1.8
|
|
426
|
+
changelog_uri: https://github.com/kettle-dev/kettle-dev/blob/v3.1.8/CHANGELOG.md
|
|
427
427
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-dev/issues
|
|
428
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.1.
|
|
428
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-dev/3.1.8
|
|
429
429
|
funding_uri: https://github.com/sponsors/pboling
|
|
430
430
|
wiki_uri: https://github.com/kettle-dev/kettle-dev/wiki
|
|
431
431
|
news_uri: https://www.railsbling.com/tags/kettle-dev
|
metadata.gz.sig
CHANGED
|
Binary file
|