fastlane-plugin-stream_actions 0.4.7 → 0.4.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
- data/lib/fastlane/plugin/stream_actions/actions/lint_swift_package.rb +122 -0
- data/lib/fastlane/plugin/stream_actions/actions/read_changelog.rb +13 -2
- data/lib/fastlane/plugin/stream_actions/actions/testflight_build.rb +15 -8
- data/lib/fastlane/plugin/stream_actions/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1cd47c9cf9078fdada6a7022e053bfcd562f02d4c1a75cc2ede14a018c8f769
|
|
4
|
+
data.tar.gz: 9b044e1fe97cf5bf7bdcda612592e54eba35ffe9041779562858e07e71aefb46
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56517c6f3dd4534e62c7112b8873b41efb3b1134e9d150773745c9c36438e5ec963c0a9394ef6d6e9da6394bc18afa3705c177e1494a074640263578e1b53870
|
|
7
|
+
data.tar.gz: af2df2c639cc922e2fdadb265243017be271201b2e4c592acd64bf1b96157697c2150abbbaa1c83aec6653525da30a148ced86139ce89dc5702e2f96f109b93f
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
module Fastlane
|
|
2
|
+
module Actions
|
|
3
|
+
class LintSwiftPackageAction < Action
|
|
4
|
+
def self.run(params)
|
|
5
|
+
path = params[:swift_package_path]
|
|
6
|
+
UI.user_error!("Package.swift not found at path: #{path}") unless File.exist?(path)
|
|
7
|
+
|
|
8
|
+
dependencies = package_declarations(File.read(path))
|
|
9
|
+
violations = dependencies.flat_map { |dependency| dependency_violations(dependency) }
|
|
10
|
+
violations += duplicate_violations(dependencies)
|
|
11
|
+
|
|
12
|
+
if violations.any?
|
|
13
|
+
UI.user_error!("Package.swift contains #{violations.size} dependency issue(s):\n#{violations.join("\n")}")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
UI.success("Package.swift dependencies look good 🚀")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.dependency_violations(dependency)
|
|
20
|
+
body = dependency[:body]
|
|
21
|
+
violations = []
|
|
22
|
+
if body =~ /\bbranch:/ || body.include?('.branch(')
|
|
23
|
+
violations << violation(dependency, 'branch-based dependency — pin it with `from:` or `exact:` instead')
|
|
24
|
+
end
|
|
25
|
+
if body =~ /\brevision:/ || body.include?('.revision(')
|
|
26
|
+
violations << violation(dependency, 'revision-pinned dependency — pin it with `from:` or `exact:` instead')
|
|
27
|
+
end
|
|
28
|
+
if body.include?('..<') || body =~ /"\s*\.\.\.\s*"/ || body.include?('.upToNextMinor(')
|
|
29
|
+
violations << violation(dependency, 'version-range dependency — pin it with `from:` or `exact:` instead')
|
|
30
|
+
end
|
|
31
|
+
if body =~ /\bpath:/
|
|
32
|
+
violations << violation(dependency, 'local path dependency — it will not resolve for package consumers')
|
|
33
|
+
end
|
|
34
|
+
if dependency[:url] && dependency[:url] !~ %r{\Ahttps://}
|
|
35
|
+
violations << violation(dependency, 'insecure or non-https url — use `https://`')
|
|
36
|
+
end
|
|
37
|
+
if violations.empty? && body !~ /\b(from|exact):/ && !body.include?('.exact(') && !body.include?('.upToNextMajor(')
|
|
38
|
+
violations << violation(dependency, 'missing version requirement — pin it with `from:` or `exact:`')
|
|
39
|
+
end
|
|
40
|
+
violations
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.duplicate_violations(dependencies)
|
|
44
|
+
dependencies
|
|
45
|
+
.select { |dependency| dependency[:url] }
|
|
46
|
+
.group_by { |dependency| dependency[:url].downcase.sub(/\.git\z/, '') }
|
|
47
|
+
.values
|
|
48
|
+
.select { |group| group.size > 1 }
|
|
49
|
+
.map do |group|
|
|
50
|
+
lines = group.map { |dependency| dependency[:line] }.join(', ')
|
|
51
|
+
"- #{group.first[:url]} (lines #{lines}): duplicate dependency"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.violation(dependency, message)
|
|
56
|
+
location = dependency[:url] ? "#{dependency[:url]} (line #{dependency[:line]})" : "line #{dependency[:line]}"
|
|
57
|
+
"- #{location}: #{message}"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def self.package_declarations(content)
|
|
61
|
+
declarations = []
|
|
62
|
+
offset = 0
|
|
63
|
+
while (start = content.index('.package(', offset))
|
|
64
|
+
body_start = start + 9 # '.package('.length
|
|
65
|
+
index = body_start
|
|
66
|
+
depth = 1
|
|
67
|
+
in_string = false
|
|
68
|
+
while index < content.length && depth > 0
|
|
69
|
+
char = content[index]
|
|
70
|
+
if in_string
|
|
71
|
+
in_string = false if char == '"' && content[index - 1] != '\\'
|
|
72
|
+
else
|
|
73
|
+
case char
|
|
74
|
+
when '"' then in_string = true
|
|
75
|
+
when '(' then depth += 1
|
|
76
|
+
when ')' then depth -= 1
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
index += 1
|
|
80
|
+
end
|
|
81
|
+
body = content[body_start...(index - 1)]
|
|
82
|
+
declarations << {
|
|
83
|
+
body: body,
|
|
84
|
+
url: body[/url:\s*"([^"]+)"/, 1],
|
|
85
|
+
line: content[0..start].count("\n") + 1
|
|
86
|
+
}
|
|
87
|
+
offset = index
|
|
88
|
+
end
|
|
89
|
+
declarations
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
#####################################################
|
|
93
|
+
# @!group Documentation
|
|
94
|
+
#####################################################
|
|
95
|
+
|
|
96
|
+
def self.description
|
|
97
|
+
'Scans Package.swift for common mistakes in dependency declarations'
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def self.details
|
|
101
|
+
'Fails if any dependency is declared via branch, revision, version range, local path, ' \
|
|
102
|
+
'insecure url, or is duplicated. All dependencies should be pinned with `from:` or `exact:`.'
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def self.available_options
|
|
106
|
+
[
|
|
107
|
+
FastlaneCore::ConfigItem.new(
|
|
108
|
+
key: :swift_package_path,
|
|
109
|
+
description: 'The path to your project Package.swift',
|
|
110
|
+
is_string: true,
|
|
111
|
+
default_value: './Package.swift',
|
|
112
|
+
optional: false
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def self.is_supported?(platform)
|
|
118
|
+
true
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -18,8 +18,12 @@ module Fastlane
|
|
|
18
18
|
changes << line
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if changes.strip.empty?
|
|
22
|
+
changes = params[:default_changes]
|
|
23
|
+
UI.important("No changelog found for #{params[:version]}, using default: \n#{changes}")
|
|
24
|
+
else
|
|
25
|
+
UI.success("Changelog for #{params[:version]}: \n#{changes}")
|
|
26
|
+
end
|
|
23
27
|
changes
|
|
24
28
|
end
|
|
25
29
|
|
|
@@ -47,6 +51,13 @@ module Fastlane
|
|
|
47
51
|
is_string: true,
|
|
48
52
|
default_value: './CHANGELOG.md',
|
|
49
53
|
optional: true
|
|
54
|
+
),
|
|
55
|
+
FastlaneCore::ConfigItem.new(
|
|
56
|
+
key: :default_changes,
|
|
57
|
+
description: 'The default changelog entry if no changes provided',
|
|
58
|
+
is_string: true,
|
|
59
|
+
default_value: '- Bug fixes and improvements',
|
|
60
|
+
optional: true
|
|
50
61
|
)
|
|
51
62
|
]
|
|
52
63
|
end
|
|
@@ -43,14 +43,12 @@ module Fastlane
|
|
|
43
43
|
changelog =
|
|
44
44
|
if params[:use_changelog]
|
|
45
45
|
version = params[:is_manual_upload] ? 'Upcoming' : params[:app_version]
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
)
|
|
52
|
-
.gsub(%r{\[(#\d+)\]\(https?://[^)]+\)}, '(\1)')
|
|
53
|
-
.gsub(/[\u{FE0E}\u{FE0F}\u{200D}]/, '')
|
|
46
|
+
sanitize_changelog(
|
|
47
|
+
other_action.read_changelog(
|
|
48
|
+
version: version,
|
|
49
|
+
changelog_path: params[:changelog_path]
|
|
50
|
+
)
|
|
51
|
+
)
|
|
54
52
|
else
|
|
55
53
|
testflight_instructions(params)
|
|
56
54
|
end
|
|
@@ -76,6 +74,15 @@ module Fastlane
|
|
|
76
74
|
end
|
|
77
75
|
end
|
|
78
76
|
|
|
77
|
+
# Strip all pictographs and their companions (skin tones, flags, variation selectors,
|
|
78
|
+
# ZWJ, keycaps, tag chars): pilot's own emoji stripper misses text-presentation symbols
|
|
79
|
+
# like U+26A0 and leaves companions behind, and App Store Connect rejects them in whatsNew
|
|
80
|
+
def self.sanitize_changelog(changelog)
|
|
81
|
+
changelog.gsub(/^### (.+)$/) { $1.upcase }
|
|
82
|
+
.gsub(%r{\[(#\d+)\]\(https?://[^)]+\)}, '(\1)')
|
|
83
|
+
.gsub(/[\p{Extended_Pictographic}\u{1F3FB}-\u{1F3FF}\u{1F1E6}-\u{1F1FF}\u{FE00}-\u{FE0F}\u{200D}\u{20E3}\u{E0020}-\u{E007F}]/, '')
|
|
84
|
+
end
|
|
85
|
+
|
|
79
86
|
def self.testflight_instructions(params)
|
|
80
87
|
return "This is the official #{params[:app_target]} sample app" unless params[:sdk_target]
|
|
81
88
|
|
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.
|
|
4
|
+
version: 0.4.9
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GetStream
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: xctest_list
|
|
@@ -240,6 +240,7 @@ files:
|
|
|
240
240
|
- lib/fastlane/plugin/stream_actions/actions/git_status.rb
|
|
241
241
|
- lib/fastlane/plugin/stream_actions/actions/install_ios_runtime.rb
|
|
242
242
|
- lib/fastlane/plugin/stream_actions/actions/is_check_required.rb
|
|
243
|
+
- lib/fastlane/plugin/stream_actions/actions/lint_swift_package.rb
|
|
243
244
|
- lib/fastlane/plugin/stream_actions/actions/merge_main_to_develop.rb
|
|
244
245
|
- lib/fastlane/plugin/stream_actions/actions/merge_release_to_main.rb
|
|
245
246
|
- lib/fastlane/plugin/stream_actions/actions/next_pr_number.rb
|