fastlane-plugin-stream_actions 0.4.2 → 0.4.4

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: 5db13e6770f55566dab3812ca6cc13d72a4cfbf55a12c105fd7fd46da6fafa7a
4
- data.tar.gz: 9066d128357a6b2513f3d395246d9c4ec7b9c5bfe7dd52d9cdb54a3a98432e7a
3
+ metadata.gz: c822fdfad8f332a11b18881d8c1a57861942c71e148b6fb4a51720fe28ec5f99
4
+ data.tar.gz: 828397123a0ae1995d7c7d4a5cd7cfcbc5b1ad3276e594f265b312aa024a1194
5
5
  SHA512:
6
- metadata.gz: d916b54cef7c5304f0ec2467fa27e6426f1696212f3b6f857a74b674a04343e4042d0b39736dc30ef1031c487fb78cc3328c0041111405c3f5fd4902adb0c68f
7
- data.tar.gz: 6c0239be3c703aa18bea7fe0b033c065a776c1e6e8ca1d26dd2d6b8e0bbb8648fee9cc4f6394042d3478d110a32702527f28edf43cd638ddc7643f71cd55485d
6
+ metadata.gz: 22683a0374246a7d4c98b7274fe13e7f98aa1649c386fba1f33953d888e7be8e7605838ce122e367a73725a9eb76258bfa6bf7a1f354d28c9fabe6e62b189a02
7
+ data.tar.gz: 8dfedadc11a5e46a23674caecb46bf71835793244475aecbde062d4d4993ff87dadb46693150b656da8ae1d0ba13e598f3e69e609aa64ea1ab9c5ee680aa14e8
@@ -14,15 +14,104 @@ 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 the last commit that
29
+ # did change :sources had all required checks pass; otherwise :sources were never verified.
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 until the last commit that changed :sources is
40
+ # found, then returns whether the check must run based on that commit's required check runs.
41
+ def self.required_due_to_history(params, required_checks)
42
+ repo = (params[:github_repository] || ENV['GITHUB_REPOSITORY']).to_s
43
+ if repo.empty?
44
+ UI.important("No repository provided; cannot verify previous runs, running check")
45
+ return true
46
+ end
47
+
48
+ shas = self.pr_commit_shas(params[:github_pr_num])
49
+ if shas.empty?
50
+ UI.important("Could not list PR commits; running check")
51
+ return true
52
+ end
53
+
54
+ sources_sha = shas.find { |sha| self.touches_sources?(self.commit_files(repo, sha), params[:sources]) }
55
+ if sources_sha.nil?
56
+ UI.message("No commit in this PR changed sources; nothing to test")
57
+ return false
58
+ end
59
+
60
+ short = sources_sha[0, 7]
61
+ if self.required_checks_passed?(repo, sources_sha, required_checks)
62
+ UI.message("Last sources commit #{short} passed required checks; safe to skip")
63
+ false
64
+ else
65
+ UI.important("Last sources commit #{short} did not pass required checks; running check")
66
+ true
67
+ end
68
+ end
69
+
70
+ # PR commits, newest first (gh returns them oldest first).
71
+ def self.pr_commit_shas(pr_num)
72
+ self.gh_path_lines(Actions.sh("gh pr view #{pr_num} --json commits -q '.commits[].oid'")).reverse
73
+ rescue StandardError
74
+ []
75
+ end
76
+
77
+ # Files changed by a single commit (relative to its first parent).
78
+ def self.commit_files(repo, sha)
79
+ self.gh_path_lines(Actions.sh("gh api repos/#{repo}/commits/#{sha} --paginate -q '.files[].filename'"))
80
+ rescue StandardError
81
+ []
82
+ end
83
+
84
+ # True only if every required check has its latest run concluded as 'success' on the commit.
85
+ def self.required_checks_passed?(repo, sha, required_checks)
86
+ out = Actions.sh(
87
+ "gh api \"repos/#{repo}/commits/#{sha}/check-runs?per_page=100\" --paginate " \
88
+ "-H \"Accept: application/vnd.github.v3+json\" " \
89
+ "-q '.check_runs[] | \"\\(.name)\\t\\(.conclusion)\\t\\(.completed_at)\"'"
90
+ )
91
+ latest = self.latest_conclusions(out)
92
+ required_checks.all? { |name| latest[name] == 'success' }
93
+ rescue StandardError
94
+ false
95
+ end
96
+
97
+ # Reduces "name\tconclusion\tcompleted_at" lines to the latest conclusion per check name,
98
+ # so re-runs of the same check supersede earlier attempts.
99
+ def self.latest_conclusions(output)
100
+ latest = {}
101
+ seen_at = {}
102
+ output.to_s.split("\n", -1).each do |line|
103
+ name, conclusion, completed_at = line.split("\t", -1)
104
+ next if name.nil? || name.strip.empty?
105
+
106
+ completed_at = completed_at.to_s
107
+ next if seen_at.key?(name) && completed_at < seen_at[name]
108
+
109
+ seen_at[name] = completed_at
110
+ latest[name] = conclusion.to_s
111
+ end
112
+ latest
113
+ end
114
+
26
115
  # For pull_request: use full PR for `opened` (etc.); for `synchronize` pass
27
116
  # github_event_before/after (e.g. github.event.before/after) to scope to this push.
28
117
  def self.changed_file_paths(params)
@@ -83,6 +172,16 @@ module Fastlane
83
172
  description: 'GitHub PR number',
84
173
  optional: true
85
174
  ),
175
+ FastlaneCore::ConfigItem.new(
176
+ key: :required_checks,
177
+ description: 'Names of GitHub check runs that must have concluded as success on the last commit ' \
178
+ 'that changed :sources for the check to be skipped when the current push does not ' \
179
+ 'touch :sources. When empty, the check is skipped as soon as the current push does ' \
180
+ 'not touch :sources',
181
+ is_string: false,
182
+ optional: true,
183
+ default_value: []
184
+ ),
86
185
  FastlaneCore::ConfigItem.new(
87
186
  key: :force_check,
88
187
  description: 'GitHub PR number',
@@ -2,35 +2,40 @@ module Fastlane
2
2
  module Actions
3
3
  class PublishIosSdkAction < Action
4
4
  def self.run(params)
5
+ skip_spm = params[:skip_spm].to_s.casecmp('true').zero?
6
+ skip_pods = params[:skip_pods].to_s.casecmp('true').zero?
5
7
  version_number = params[:version]
6
8
 
7
- ensure_everything_is_set_up(params)
8
- ensure_release_tag_is_new(version_number)
9
+ unless skip_spm
10
+ ensure_everything_is_set_up(params)
11
+ ensure_release_tag_is_new(version_number)
9
12
 
10
- changes =
11
- if params[:use_changelog]
12
- params[:changelog] || other_action.read_changelog(version: version_number, changelog_path: params[:changelog_path])
13
- else
14
- version_number
15
- end
13
+ changes =
14
+ if params[:use_changelog]
15
+ params[:changelog] || other_action.read_changelog(version: version_number, changelog_path: params[:changelog_path])
16
+ else
17
+ version_number
18
+ end
16
19
 
17
- release_details = other_action.set_github_release(
18
- repository_name: params[:github_repo],
19
- api_token: params[:github_token],
20
- name: version_number,
21
- tag_name: version_number,
22
- description: changes,
23
- commitish: other_action.current_branch,
24
- upload_assets: params[:upload_assets],
25
- is_prerelease: version_number.downcase.include?('beta')
26
- )
20
+ other_action.set_github_release(
21
+ repository_name: params[:github_repo],
22
+ api_token: params[:github_token],
23
+ name: version_number,
24
+ tag_name: version_number,
25
+ description: changes,
26
+ commitish: other_action.current_branch,
27
+ upload_assets: params[:upload_assets],
28
+ is_prerelease: version_number.downcase.include?('beta')
29
+ )
30
+ end
27
31
 
28
- unless params[:skip_pods].to_s.casecmp('true').zero?
32
+ unless skip_pods
29
33
  podspecs = params[:podspec_names]&.map { |sdk| "#{sdk}.podspec" } || []
30
34
  podspecs.each { |podspec| other_action.pod_push_safely(podspec: podspec) }
31
35
  end
32
36
 
33
- UI.success("Github release v#{version_number} was created, please visit #{release_details['html_url']} to see it! 🚢")
37
+ destination = skip_spm ? 'CocoaPods' : skip_pods ? 'SPM' : 'Error'
38
+ UI.success("Github release v#{version_number} has been published to #{destination} 🚢")
34
39
  end
35
40
 
36
41
  def self.ensure_everything_is_set_up(params)
@@ -66,6 +71,13 @@ module Fastlane
66
71
  is_string: false,
67
72
  optional: true
68
73
  ),
74
+ FastlaneCore::ConfigItem.new(
75
+ key: :skip_spm,
76
+ description: 'Skip release to GitHub and SPM?',
77
+ is_string: false,
78
+ optional: true,
79
+ default_value: false
80
+ ),
69
81
  FastlaneCore::ConfigItem.new(
70
82
  key: :skip_pods,
71
83
  description: 'Skip release to CocoaPods?',
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module StreamActions
3
- VERSION = '0.4.2'
3
+ VERSION = '0.4.4'
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.2
4
+ version: 0.4.4
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-24 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
@@ -282,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
282
282
  - !ruby/object:Gem::Version
283
283
  version: '0'
284
284
  requirements: []
285
- rubygems_version: 3.5.11
285
+ rubygems_version: 3.4.1
286
286
  signing_key:
287
287
  specification_version: 4
288
288
  summary: stream custom actions