kettle-gha-pins 0.3.7 → 0.3.9
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 +27 -1
- data/README.md +1 -1
- data/lib/kettle/gha/pins/action_resolver.rb +2 -1
- data/lib/kettle/gha/pins/cli.rb +42 -4
- data/lib/kettle/gha/pins/github_client.rb +29 -7
- data/lib/kettle/gha/pins/version.rb +1 -1
- data/lib/kettle/gha/pins/version_rubric.rb +33 -6
- data.tar.gz.sig +0 -0
- metadata +4 -4
- 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: 40a359f61e73b1b17ee62829c001c9690844f8ccfb944b776ecb21cbd402b382
|
|
4
|
+
data.tar.gz: c5f15b58492474aefb12423903e34e3b4107f8e01dc92d964a0f0ad9c8320408
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 786283e4de7a16524b78e7c30552a8622465d559df4edeb8cbfd1808dda7c3cd7c5ad730c19f5d3c35cc328c11cb9829f0fc056f531e787997961bb442ee97ca
|
|
7
|
+
data.tar.gz: c8d901235c8b8ebb5e9aae9fa0918a58965abdd1a61f612a76985df9068ddfa5aaac871e7ace466a2732a0a03821cb3352be232641e692283c4083287b8b4beb
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,28 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [0.3.9] - 2026-08-05
|
|
34
|
+
|
|
35
|
+
- TAG: [v0.3.9][0.3.9t]
|
|
36
|
+
- COVERAGE: 98.36% -- 961/977 lines in 8 files
|
|
37
|
+
- BRANCH COVERAGE: 89.95% -- 394/438 branches in 8 files
|
|
38
|
+
- 25.71% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- Emit NDJSON progress events for family orchestration without replaying the full human report.
|
|
43
|
+
|
|
44
|
+
## [0.3.8] - 2026-08-05
|
|
45
|
+
|
|
46
|
+
- TAG: [v0.3.8][0.3.8t]
|
|
47
|
+
- COVERAGE: 98.34% -- 945/961 lines in 8 files
|
|
48
|
+
- BRANCH COVERAGE: 89.81% -- 388/432 branches in 8 files
|
|
49
|
+
- 25.71% documented
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- Refresh cached GitHub Action release data when a newer release tag is detected.
|
|
54
|
+
|
|
33
55
|
## [0.3.7] - 2026-08-05
|
|
34
56
|
|
|
35
57
|
- TAG: [v0.3.7][0.3.7t]
|
|
@@ -260,7 +282,11 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
260
282
|
- kettle-jem-template-20260720-005 - Generated README Support & Community rows
|
|
261
283
|
now include a RubyForum help badge.
|
|
262
284
|
|
|
263
|
-
[Unreleased]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.
|
|
285
|
+
[Unreleased]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.9...HEAD
|
|
286
|
+
[0.3.9]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.8...v0.3.9
|
|
287
|
+
[0.3.9t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.9
|
|
288
|
+
[0.3.8]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.7...v0.3.8
|
|
289
|
+
[0.3.8t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.8
|
|
264
290
|
[0.3.7]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.6...v0.3.7
|
|
265
291
|
[0.3.7t]: https://github.com/kettle-dev/kettle-gha-pins/releases/tag/v0.3.7
|
|
266
292
|
[0.3.6]: https://github.com/kettle-dev/kettle-gha-pins/compare/v0.3.5...v0.3.6
|
data/README.md
CHANGED
|
@@ -563,7 +563,7 @@ Thanks for RTFM. ☺️
|
|
|
563
563
|
[📌gitmoji]: https://gitmoji.dev
|
|
564
564
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
565
565
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
566
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.
|
|
566
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-0.977-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
567
567
|
[🔐security]: https://github.com/kettle-dev/kettle-gha-pins/blob/main/SECURITY.md
|
|
568
568
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
569
569
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
data/lib/kettle/gha/pins/cli.rb
CHANGED
|
@@ -59,6 +59,7 @@ module Kettle
|
|
|
59
59
|
dry_run: true,
|
|
60
60
|
token: ENV["GITHUB_TOKEN"] || ENV["GH_TOKEN"],
|
|
61
61
|
json: false,
|
|
62
|
+
events: false,
|
|
62
63
|
validate: true,
|
|
63
64
|
write: false,
|
|
64
65
|
check: false,
|
|
@@ -104,8 +105,10 @@ module Kettle
|
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
progress_message("Discovering workflow files under #{display_path(@options[:root])}...")
|
|
108
|
+
emit_event("start", root: @options[:root])
|
|
107
109
|
workflow_files = discover_workflow_files(@options[:root], @options[:reject_patterns])
|
|
108
110
|
progress_message("Discovered #{workflow_files.length} workflow file(s).")
|
|
111
|
+
emit_event("workflows", total: workflow_files.length)
|
|
109
112
|
|
|
110
113
|
workflows = load_workflows(workflow_files, state)
|
|
111
114
|
action_count = workflows.sum { |workflow| workflow[:uses_nodes].count { |node| classify_action_ref(node[:value].to_s) } }
|
|
@@ -119,6 +122,7 @@ module Kettle
|
|
|
119
122
|
)
|
|
120
123
|
action_plan_cache = {}
|
|
121
124
|
|
|
125
|
+
completed_actions = 0
|
|
122
126
|
workflows.each do |workflow|
|
|
123
127
|
path = workflow.fetch(:path)
|
|
124
128
|
text = workflow.fetch(:text)
|
|
@@ -134,6 +138,7 @@ module Kettle
|
|
|
134
138
|
action = parsed_ref[:action]
|
|
135
139
|
repo_ref = "#{action[:owner]}/#{action[:repo]}"
|
|
136
140
|
old_ref = action[:ref]
|
|
141
|
+
cached_before = action_plan_cache.key?(repo_ref)
|
|
137
142
|
upgrade_plan = resolve_action_plan(
|
|
138
143
|
cache: action_plan_cache,
|
|
139
144
|
client: client,
|
|
@@ -141,6 +146,16 @@ module Kettle
|
|
|
141
146
|
repo_ref: repo_ref,
|
|
142
147
|
old_ref: old_ref
|
|
143
148
|
)
|
|
149
|
+
completed_actions += 1
|
|
150
|
+
emit_event(
|
|
151
|
+
"action",
|
|
152
|
+
action_ref: repo_ref,
|
|
153
|
+
path: path,
|
|
154
|
+
line: node[:line] + 1,
|
|
155
|
+
completed: completed_actions,
|
|
156
|
+
total: action_count,
|
|
157
|
+
cache: (cached_before || (client.respond_to?(:last_versions_cache_hit) && client.last_versions_cache_hit)) ? "hit" : "miss"
|
|
158
|
+
)
|
|
144
159
|
|
|
145
160
|
updates = nil
|
|
146
161
|
if upgrade_plan[:updates]
|
|
@@ -154,7 +169,8 @@ module Kettle
|
|
|
154
169
|
comment_update_version = VersionRubric.comment_update_version(
|
|
155
170
|
comment_version,
|
|
156
171
|
upgrade_plan[:current_version],
|
|
157
|
-
known_versions: upgrade_plan.fetch(:versions, [])
|
|
172
|
+
known_versions: upgrade_plan.fetch(:versions, []),
|
|
173
|
+
resolved_sha: upgrade_plan[:current_sha]
|
|
158
174
|
)
|
|
159
175
|
if comment_update_version
|
|
160
176
|
updates = {
|
|
@@ -260,6 +276,15 @@ module Kettle
|
|
|
260
276
|
end
|
|
261
277
|
action_progress.stop
|
|
262
278
|
progress_message("Action resolution checks: #{action_progress.cached_count} cached, #{action_progress.live_count} live.") if action_count.positive?
|
|
279
|
+
emit_event(
|
|
280
|
+
"summary",
|
|
281
|
+
files_scanned: state[:files_scanned],
|
|
282
|
+
changed_files: state[:changed_files].length,
|
|
283
|
+
updates: state[:updates],
|
|
284
|
+
failures: state[:failures],
|
|
285
|
+
cached: action_progress.cached_count,
|
|
286
|
+
live: action_progress.live_count
|
|
287
|
+
)
|
|
263
288
|
|
|
264
289
|
print_report(state)
|
|
265
290
|
return 2 unless state[:failures].zero?
|
|
@@ -309,6 +334,9 @@ module Kettle
|
|
|
309
334
|
opt.on("--json", "Emit JSON report") do
|
|
310
335
|
@options[:json] = true
|
|
311
336
|
end
|
|
337
|
+
opt.on("--events", "Emit line-delimited JSON events") do
|
|
338
|
+
@options[:events] = true
|
|
339
|
+
end
|
|
312
340
|
opt.on("--[no-]progress", "Show progress feedback on STDERR (default: on unless --json)") do |bool|
|
|
313
341
|
@options[:progress] = bool
|
|
314
342
|
end
|
|
@@ -383,7 +411,13 @@ module Kettle
|
|
|
383
411
|
def progress_enabled?
|
|
384
412
|
return @options[:progress] unless @options[:progress].nil?
|
|
385
413
|
|
|
386
|
-
!@options[:json]
|
|
414
|
+
!@options[:json] && !@options[:events]
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def emit_event(action, payload = {})
|
|
418
|
+
return unless @options[:events]
|
|
419
|
+
|
|
420
|
+
puts JSON.generate({"event_version" => 1, "type" => "gha_sha_pins_#{action}", "action" => action}.merge(payload))
|
|
387
421
|
end
|
|
388
422
|
|
|
389
423
|
def progress_message(message)
|
|
@@ -857,8 +891,12 @@ module Kettle
|
|
|
857
891
|
lines << "Recommended fix: kettle-gha-pins --write --upgrade #{@options[:upgrade]}"
|
|
858
892
|
end
|
|
859
893
|
|
|
860
|
-
|
|
861
|
-
|
|
894
|
+
output = lines.join("\n")
|
|
895
|
+
if @options[:events]
|
|
896
|
+
@err.puts output
|
|
897
|
+
else
|
|
898
|
+
puts output
|
|
899
|
+
end
|
|
862
900
|
end
|
|
863
901
|
end
|
|
864
902
|
end
|
|
@@ -38,9 +38,11 @@ module Kettle
|
|
|
38
38
|
unless @refresh_cache
|
|
39
39
|
cached = @persistent_cache&.versions_for_repo(repo_ref, fresh: true)
|
|
40
40
|
if cached
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
unless cache_requires_refresh?(repo_ref, cached)
|
|
42
|
+
@last_versions_cache_hit = true
|
|
43
|
+
@release_cache[repo_ref] = cached
|
|
44
|
+
return cached
|
|
45
|
+
end
|
|
44
46
|
end
|
|
45
47
|
stale = @persistent_cache&.versions_for_repo(repo_ref, fresh: false)
|
|
46
48
|
end
|
|
@@ -62,13 +64,13 @@ module Kettle
|
|
|
62
64
|
cached_versions(repo_ref, stale)
|
|
63
65
|
end
|
|
64
66
|
|
|
65
|
-
def commit_sha(repo_ref, ref)
|
|
67
|
+
def commit_sha(repo_ref, ref, refresh: false)
|
|
66
68
|
return nil if repo_ref.to_s.empty? || ref.to_s.empty?
|
|
67
69
|
|
|
68
70
|
cache_key = "commit:#{repo_ref}:#{ref}"
|
|
69
|
-
return @commit_cache[cache_key] if @commit_cache.key?(cache_key)
|
|
71
|
+
return @commit_cache[cache_key] if @commit_cache.key?(cache_key) && !refresh
|
|
70
72
|
|
|
71
|
-
unless @refresh_cache
|
|
73
|
+
unless @refresh_cache || refresh
|
|
72
74
|
cached = @persistent_cache&.ref_sha(repo_ref, ref, fresh: true)
|
|
73
75
|
if cached
|
|
74
76
|
@commit_cache[cache_key] = cached
|
|
@@ -104,6 +106,26 @@ module Kettle
|
|
|
104
106
|
versions
|
|
105
107
|
end
|
|
106
108
|
|
|
109
|
+
# Release tags can be added or retargeted inside the cache TTL. Probe
|
|
110
|
+
# the latest release before trusting a cached inventory, and refresh
|
|
111
|
+
# only when that probe identifies a tag or target the cache lacks.
|
|
112
|
+
def cache_requires_refresh?(repo_ref, cached)
|
|
113
|
+
latest = request_json("/repos/#{repo_ref}/releases/latest")
|
|
114
|
+
return false unless latest.is_a?(Hash)
|
|
115
|
+
|
|
116
|
+
tag = latest["tag_name"].to_s
|
|
117
|
+
return false unless VersionRubric.parse(tag)
|
|
118
|
+
|
|
119
|
+
cached_entry = cached.find { |entry| entry[:tag].to_s == tag }
|
|
120
|
+
return true unless cached_entry
|
|
121
|
+
|
|
122
|
+
latest_sha = commit_sha(repo_ref, tag, refresh: true)
|
|
123
|
+
cached_sha = cached_entry[:sha].to_s
|
|
124
|
+
return !latest_sha.to_s.empty? if cached_sha.empty?
|
|
125
|
+
|
|
126
|
+
!latest_sha.to_s.empty? && latest_sha != cached_sha
|
|
127
|
+
end
|
|
128
|
+
|
|
107
129
|
def build_release_versions(data, tag_shas)
|
|
108
130
|
release_dates = {}
|
|
109
131
|
release_tags = data.each_with_object([]) do |release, memo|
|
|
@@ -143,7 +165,7 @@ module Kettle
|
|
|
143
165
|
when "commit"
|
|
144
166
|
memo[tag] = sha
|
|
145
167
|
when "tag"
|
|
146
|
-
memo[tag] =
|
|
168
|
+
memo[tag] = annotated_tag_commit_sha(repo_ref, sha)
|
|
147
169
|
end
|
|
148
170
|
end
|
|
149
171
|
end
|
|
@@ -6,7 +6,7 @@ module Kettle
|
|
|
6
6
|
# Version namespace for this gem.
|
|
7
7
|
module Version
|
|
8
8
|
# Current gem version.
|
|
9
|
-
VERSION = "0.3.
|
|
9
|
+
VERSION = "0.3.9"
|
|
10
10
|
end
|
|
11
11
|
# Current gem version exposed at the traditional constant location.
|
|
12
12
|
VERSION = Version::VERSION # Traditional Constant Location
|
|
@@ -112,12 +112,17 @@ module Kettle
|
|
|
112
112
|
# the comment even when both values parse to version objects).
|
|
113
113
|
# 2. Normalize equivalent spellings (v2, v2.0, v2.0.0...) to the most
|
|
114
114
|
# specific canonical form available for that SHA in known_versions.
|
|
115
|
-
def comment_update_version(comment_version, resolved_version, known_versions: [])
|
|
115
|
+
def comment_update_version(comment_version, resolved_version, resolved_sha: nil, known_versions: [])
|
|
116
116
|
comment = parse(comment_version)
|
|
117
117
|
resolved = parse(resolved_version)
|
|
118
118
|
return nil unless comment && resolved
|
|
119
119
|
|
|
120
|
-
canonical = canonical_version_for(
|
|
120
|
+
canonical = canonical_version_for(
|
|
121
|
+
resolved_version,
|
|
122
|
+
known_versions,
|
|
123
|
+
resolved_sha: resolved_sha,
|
|
124
|
+
comment_version: comment_version
|
|
125
|
+
)
|
|
121
126
|
return nil if comment_version.to_s == canonical
|
|
122
127
|
|
|
123
128
|
canonical
|
|
@@ -127,18 +132,40 @@ module Kettle
|
|
|
127
132
|
versions.select { |entry| entry.fetch(:version_obj, nil) == version_obj }
|
|
128
133
|
end
|
|
129
134
|
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
#
|
|
133
|
-
|
|
135
|
+
# Canonical spellings are version-specific and SHA-aware.
|
|
136
|
+
#
|
|
137
|
+
# - For SHA-tracked tags, prefer the most explicit spelling that resolves
|
|
138
|
+
# to the same SHA as the currently resolved target.
|
|
139
|
+
# - If the resolved SHA is known but the currently-commented spellings
|
|
140
|
+
# are tied to a different SHA, keep the in-file spelling when the
|
|
141
|
+
# semantic version is unchanged, so we don't rewrite between aliases that
|
|
142
|
+
# no longer represent the same object.
|
|
143
|
+
# - Otherwise fall back to the resolved version form.
|
|
144
|
+
def canonical_version_for(resolved_version, known_versions, resolved_sha: nil, comment_version: nil)
|
|
134
145
|
resolved = parse(resolved_version)
|
|
135
146
|
return resolved_version.to_s unless resolved
|
|
136
147
|
|
|
137
148
|
equivalents = entries_for_semantic_version(known_versions, resolved)
|
|
149
|
+
if !resolved_sha.to_s.empty?
|
|
150
|
+
sha_matched_equivalents = equivalents.select do |entry|
|
|
151
|
+
entry.fetch(:sha).to_s == resolved_sha.to_s
|
|
152
|
+
end
|
|
153
|
+
equivalents = sha_matched_equivalents unless sha_matched_equivalents.empty?
|
|
154
|
+
|
|
155
|
+
if sha_matched_equivalents.empty? &&
|
|
156
|
+
comment_version &&
|
|
157
|
+
parse(comment_version) == resolved
|
|
158
|
+
return strip_leading_v(comment_version)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
138
161
|
preferred = equivalents.max_by { |entry| sort_key(entry) }
|
|
139
162
|
preferred ? preferred[:version] : resolved.to_s
|
|
140
163
|
end
|
|
141
164
|
|
|
165
|
+
def strip_leading_v(text)
|
|
166
|
+
text.to_s.sub(/\A[vV]/, "")
|
|
167
|
+
end
|
|
168
|
+
|
|
142
169
|
def normalize_upgrade_level(level)
|
|
143
170
|
normalized = level.to_s.downcase
|
|
144
171
|
VALID_UPGRADE_LEVELS.include?(normalized) ? normalized : DEFAULT_UPGRADE_LEVEL
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: kettle-gha-pins
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -301,10 +301,10 @@ licenses:
|
|
|
301
301
|
- MIT
|
|
302
302
|
metadata:
|
|
303
303
|
homepage_uri: https://github.com/kettle-dev/kettle-gha-pins
|
|
304
|
-
source_code_uri: https://github.com/kettle-dev/kettle-gha-pins/tree/v0.3.
|
|
305
|
-
changelog_uri: https://github.com/kettle-dev/kettle-gha-pins/blob/v0.3.
|
|
304
|
+
source_code_uri: https://github.com/kettle-dev/kettle-gha-pins/tree/v0.3.9
|
|
305
|
+
changelog_uri: https://github.com/kettle-dev/kettle-gha-pins/blob/v0.3.9/CHANGELOG.md
|
|
306
306
|
bug_tracker_uri: https://github.com/kettle-dev/kettle-gha-pins/issues
|
|
307
|
-
documentation_uri: https://www.rubydoc.info/gems/kettle-gha-pins/0.3.
|
|
307
|
+
documentation_uri: https://www.rubydoc.info/gems/kettle-gha-pins/0.3.9
|
|
308
308
|
funding_uri: https://github.com/sponsors/pboling
|
|
309
309
|
wiki_uri: https://github.com/kettle-dev/kettle-gha-pins/wiki
|
|
310
310
|
news_uri: https://www.railsbling.com/tags/kettle-gha-pins
|
metadata.gz.sig
CHANGED
|
Binary file
|