fastlane-plugin-stream_actions 0.4.3 → 0.4.5

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca06e9e0820bf90f20192d8bf762e3743b5ef18613cab71ca4126e7c3c6beeb6
4
- data.tar.gz: 6184465095169e256dc90c3ac979fbed6783a597c4db02eaba861ec19a3a8cd9
3
+ metadata.gz: 588bc089b57e2d637ed87e062d4f70b47b9ed434a902331ade91e775b97c251d
4
+ data.tar.gz: '09dd367927a51c2976dc9e2bc2a52827b78ff26b9c6e37bacb6bbd66d1ffc23b'
5
5
  SHA512:
6
- metadata.gz: 3735e7cad6c2ef6a602685cfba12dc7f16b226ed81fa8ebe8edbc10de377ecb04670ca1cf798787b26729750223f99efd82827cc44205e518c6134183fa34a34
7
- data.tar.gz: b7d87ad3aa7d5c0d8a5f0dde85d41fae46ebce067b40e5bb99c6eddae9bc09b9ab8a5e4f648947fbed88788246338acdbe09cf3d623a52d49a165a7f712b9b57
6
+ metadata.gz: d125f60bb7937c1825928b57c77b02eb49fae737636792b252fb257e882817be3b978003ef2d9aea4b4a0a8c7b57c2062b0b1f94a76bb75c103c0cc0b6a3f60a
7
+ data.tar.gz: 07e0d6184d4e3b363fbb0f4cabbff98dd681e96a96b89f7184f2b5bf5cd9d4a746a0eba382181c1866aa4443f55e3bf3c4cafa01aef3d0df3c3bf90e4251444a
@@ -14,15 +14,106 @@ module Fastlane
14
14
  return true
15
15
  end
16
16
 
17
- changed_files.select! do |path|
18
- params[:sources].any? { |required| path.start_with?(required) }
17
+ if self.touches_sources?(changed_files, params[:sources])
18
+ UI.important("Check is required: true")
19
+ return true
20
+ end
21
+
22
+ required_checks = params[:required_checks].to_a
23
+ if required_checks.empty?
24
+ UI.important("Check is required: false")
25
+ return false
19
26
  end
20
27
 
21
- is_check_required = changed_files.size.positive?
28
+ # The current push does not touch :sources. It is only safe to skip if :sources were already
29
+ # verified, i.e. all required checks passed on some commit that has the current :sources tree.
30
+ is_check_required = self.required_due_to_history(params, required_checks)
22
31
  UI.important("Check is required: #{is_check_required}")
23
32
  is_check_required
24
33
  end
25
34
 
35
+ def self.touches_sources?(files, sources)
36
+ files.any? { |path| sources.any? { |required| path.start_with?(required) } }
37
+ end
38
+
39
+ # Walks the PR commits from newest to oldest. Every commit newer than the last :sources change
40
+ # has the current :sources tree, so a passing run on any of them means :sources were verified.
41
+ # The walk stops at the commit that changed :sources, since older commits have different sources.
42
+ def self.required_due_to_history(params, required_checks)
43
+ repo = (params[:github_repository] || ENV['GITHUB_REPOSITORY']).to_s
44
+ if repo.empty?
45
+ UI.important("No repository provided; cannot verify previous runs, running check")
46
+ return true
47
+ end
48
+
49
+ shas = self.pr_commit_shas(params[:github_pr_num])
50
+ if shas.empty?
51
+ UI.important("Could not list PR commits; running check")
52
+ return true
53
+ end
54
+
55
+ shas.each do |sha|
56
+ short = sha[0, 7]
57
+ if self.required_checks_passed?(repo, sha, required_checks)
58
+ UI.message("Commit #{short} passed required checks for the current sources; safe to skip")
59
+ return false
60
+ end
61
+
62
+ next unless self.touches_sources?(self.commit_files(repo, sha), params[:sources])
63
+
64
+ UI.important("Last sources commit #{short} was not verified by a passing run; running check")
65
+ return true
66
+ end
67
+
68
+ UI.message("No commit in this PR changed sources; nothing to test")
69
+ false
70
+ end
71
+
72
+ # PR commits, newest first (gh returns them oldest first).
73
+ def self.pr_commit_shas(pr_num)
74
+ self.gh_path_lines(Actions.sh("gh pr view #{pr_num} --json commits -q '.commits[].oid'")).reverse
75
+ rescue StandardError
76
+ []
77
+ end
78
+
79
+ # Files changed by a single commit (relative to its first parent).
80
+ def self.commit_files(repo, sha)
81
+ self.gh_path_lines(Actions.sh("gh api repos/#{repo}/commits/#{sha} --paginate -q '.files[].filename'"))
82
+ rescue StandardError
83
+ []
84
+ end
85
+
86
+ # True only if every required check has its latest run concluded as 'success' on the commit.
87
+ def self.required_checks_passed?(repo, sha, required_checks)
88
+ out = Actions.sh(
89
+ "gh api \"repos/#{repo}/commits/#{sha}/check-runs?per_page=100\" --paginate " \
90
+ "-H \"Accept: application/vnd.github.v3+json\" " \
91
+ "-q '.check_runs[] | \"\\(.name)\\t\\(.conclusion)\\t\\(.completed_at)\"'"
92
+ )
93
+ latest = self.latest_conclusions(out)
94
+ required_checks.all? { |name| latest[name] == 'success' }
95
+ rescue StandardError
96
+ false
97
+ end
98
+
99
+ # Reduces "name\tconclusion\tcompleted_at" lines to the latest conclusion per check name,
100
+ # so re-runs of the same check supersede earlier attempts.
101
+ def self.latest_conclusions(output)
102
+ latest = {}
103
+ seen_at = {}
104
+ output.to_s.split("\n", -1).each do |line|
105
+ name, conclusion, completed_at = line.split("\t", -1)
106
+ next if name.nil? || name.strip.empty?
107
+
108
+ completed_at = completed_at.to_s
109
+ next if seen_at.key?(name) && completed_at < seen_at[name]
110
+
111
+ seen_at[name] = completed_at
112
+ latest[name] = conclusion.to_s
113
+ end
114
+ latest
115
+ end
116
+
26
117
  # For pull_request: use full PR for `opened` (etc.); for `synchronize` pass
27
118
  # github_event_before/after (e.g. github.event.before/after) to scope to this push.
28
119
  def self.changed_file_paths(params)
@@ -83,6 +174,16 @@ module Fastlane
83
174
  description: 'GitHub PR number',
84
175
  optional: true
85
176
  ),
177
+ FastlaneCore::ConfigItem.new(
178
+ key: :required_checks,
179
+ description: 'Names of GitHub check runs that must have concluded as success on the last commit ' \
180
+ 'that changed :sources for the check to be skipped when the current push does not ' \
181
+ 'touch :sources. When empty, the check is skipped as soon as the current push does ' \
182
+ 'not touch :sources',
183
+ is_string: false,
184
+ optional: true,
185
+ default_value: []
186
+ ),
86
187
  FastlaneCore::ConfigItem.new(
87
188
  key: :force_check,
88
189
  description: 'GitHub PR number',
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module StreamActions
3
- VERSION = '0.4.3'
3
+ VERSION = '0.4.5'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-stream_actions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.3
4
+ version: 0.4.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - GetStream
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-04-29 00:00:00.000000000 Z
11
+ date: 2026-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xctest_list