fastlane-plugin-testappio 1.0.5 → 2.0.0
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/CHANGELOG.md +66 -0
- data/README.md +111 -67
- data/lib/fastlane/plugin/testappio/actions/upload_to_testappio.rb +41 -40
- data/lib/fastlane/plugin/testappio/helper/testappio_helper.rb +59 -35
- data/lib/fastlane/plugin/testappio/version.rb +1 -1
- metadata +36 -33
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7686bbb53e5fb7ae977b5830d28a57b9638909a2e641115d0a6b316fc7645f74
|
|
4
|
+
data.tar.gz: 7c612f1238a999bec957e82116037a32e5949711ef68db80d9d8d3d8d2b18c9d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a2c5b8b0ab71fd8ac4e7e9ee0df8c30c067f161764522ad615a8d1860ccae527f7c7c512e7493261f8017842fc624001ea911ca393ac1b94000b7180df03b9d
|
|
7
|
+
data.tar.gz: aa74c763e07c79000723caf43bf6fbb4c3b93cbfae4bf7f7f7cee5cf2126b43333c7b55857527fc85fc999f77b4488bb01e86675851686a5b5865d74d00382b1
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [2.0.0] - 2026-05-28
|
|
11
|
+
|
|
12
|
+
### Breaking
|
|
13
|
+
- **Ruby ≥ 3.0 required.** Customers on Ruby 2.6 or 2.7 should pin to `~> 1.0` in their `Pluginfile`.
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- `fastlane action upload_to_testappio` (the help/docs introspection command) no longer crashes with `NameError`. A `nill` typo in `return_value` was breaking this introspection path — actual uploads were unaffected, but Fastlane's plugin docs couldn't render.
|
|
17
|
+
- `validate_file_path` no longer raises `TypeError` when `apk_file` or `ipa_file` is `nil` — affected iOS-only and Android-only lanes that didn't set the other file param.
|
|
18
|
+
- `handle_error` no longer fails the upload when `ta-cli` writes warning or info lines to stderr — only real `Error:` lines fail the lane now.
|
|
19
|
+
- `--api_token` is now masked (`********`) in verbose-mode command logging — previously the token was echoed in plain text via `UI.command` in `fastlane --verbose` runs.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
- `spec.description` and `spec.metadata` (rubygems_mfa_required, source_code_uri, changelog_uri, bug_tracker_uri) in gemspec.
|
|
23
|
+
- Test coverage raised from 36.79% → **100% line / 86.76% branch** (49 unit + 2 opt-in `:integration` specs exercise the real `ta-cli` binary).
|
|
24
|
+
- Concurrent stdout/stderr reading in `call_ta_cli` via threads — prevents potential deadlock when ta-cli emits a large stderr buffer before stdout completes. Threads are cleanly killed in an `ensure` block if the surrounding popen3 block raises.
|
|
25
|
+
- `Open3.popen3` now uses the array form (no shell interpretation), so shell metacharacters in `api_token` / `release_notes` / file paths are passed literally to ta-cli without depending on manual escaping.
|
|
26
|
+
- `handle_error` now includes the actual `/Error/`-matching stderr lines in the raised `FastlaneError` message so users see the real failure reason in their CI logs.
|
|
27
|
+
- Shared spec helpers in `spec/spec_helper.rb` for stubbing `Open3.popen3` and `FastlaneCore::Globals.verbose?`.
|
|
28
|
+
- SimpleCov `minimum_coverage line: 95, branch: 90` gate (CI-only — local single-file runs no longer trip the gate).
|
|
29
|
+
- Opt-in `:integration` spec suite in `spec/integration/` — runs the real `ta-cli` binary against `fastlane/sample/*` with fake credentials to verify the deploy flow end-to-end. Run with `bundle exec rspec --tag integration` or `INTEGRATION=1 bundle exec rspec`.
|
|
30
|
+
- GitHub Actions CI: matrix over Ruby 3.0–3.3 × ubuntu/macos, with separate lint, test, and build jobs.
|
|
31
|
+
- Codecov coverage upload (via simplecov-cobertura) from one matrix cell.
|
|
32
|
+
- Tag-triggered `release.yml` workflow that builds and pushes the gem to RubyGems.
|
|
33
|
+
- Dependabot config for bundler and github-actions ecosystems.
|
|
34
|
+
- README badges: CI status, Codecov coverage, downloads, license, Ruby version, plus a Compatibility section.
|
|
35
|
+
- `self_update: true` example in `fastlane/Fastfile`.
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
- `rubocop` bumped from `1.12.1` to `~> 1.50` (dependent gems aligned).
|
|
39
|
+
- `simplecov`, `pry`, `fastlane`, `rspec_junit_formatter` bumped to current majors.
|
|
40
|
+
- `.rubocop.yml` `TargetRubyVersion` raised to `3.0`; deprecated cop names updated.
|
|
41
|
+
|
|
42
|
+
### Removed
|
|
43
|
+
- `.travis.yml` and `.circleci/config.yml` (both obsolete; replaced by GitHub Actions).
|
|
44
|
+
- `spec.test_files` from gemspec (deprecated by RubyGems).
|
|
45
|
+
- `rubocop-require_tools` dev dependency (covered by rubocop 1.50+).
|
|
46
|
+
|
|
47
|
+
## [1.0.5] - 2023-04-27
|
|
48
|
+
|
|
49
|
+
### Changed
|
|
50
|
+
- Update Fastlane plugin link in README.
|
|
51
|
+
|
|
52
|
+
## [1.0.4] - 2023
|
|
53
|
+
|
|
54
|
+
### Changed
|
|
55
|
+
- Internal param refinement and result printing.
|
|
56
|
+
|
|
57
|
+
## [1.0.3] - 2022
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- Rolled back to v2 tag of ta-cli.
|
|
61
|
+
|
|
62
|
+
[Unreleased]: https://github.com/testappio/fastlane-plugin-testappio/compare/v2.0.0...HEAD
|
|
63
|
+
[2.0.0]: https://github.com/testappio/fastlane-plugin-testappio/compare/v1.0.5...v2.0.0
|
|
64
|
+
[1.0.5]: https://github.com/testappio/fastlane-plugin-testappio/compare/v1.0.4...v1.0.5
|
|
65
|
+
[1.0.4]: https://github.com/testappio/fastlane-plugin-testappio/compare/v1.0.3...v1.0.4
|
|
66
|
+
[1.0.3]: https://github.com/testappio/fastlane-plugin-testappio/releases/tag/v1.0.3
|
data/README.md
CHANGED
|
@@ -1,107 +1,151 @@
|
|
|
1
1
|
# [<img src="https://assets.testapp.io/logo/blue.svg" alt="TestApp.io"/>](https://testapp.io/) Fastlane Plugin
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Upload your Android (`.apk`) and iOS (`.ipa`) builds to [TestApp.io](https://testapp.io) straight from your Fastlane lane. One action, both platforms, release notes from git, optional team notifications.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
[](https://rubygems.org/gems/fastlane-plugin-testappio)
|
|
6
|
+
[](https://rubygems.org/gems/fastlane-plugin-testappio)
|
|
7
|
+
[](https://github.com/testappio/fastlane-plugin-testappio/actions/workflows/ci.yml)
|
|
8
|
+
[](https://codecov.io/gh/testappio/fastlane-plugin-testappio)
|
|
9
|
+
[](https://rubygems.org/gems/fastlane-plugin-testappio)
|
|
10
|
+
[](LICENSE)
|
|
11
|
+
[](https://www.ruby-lang.org/)
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
## Getting started
|
|
13
|
+
---
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
## Install
|
|
12
16
|
|
|
13
17
|
```bash
|
|
14
18
|
fastlane add_plugin testappio
|
|
15
19
|
```
|
|
16
20
|
|
|
17
|
-
|
|
21
|
+
That's it. The plugin will install the underlying [`ta-cli`](https://help.testapp.io/ta-cli/) binary the first time you upload.
|
|
18
22
|
|
|
19
|
-
|
|
23
|
+
## Quick start
|
|
20
24
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
```ruby
|
|
26
|
+
lane :beta do
|
|
27
|
+
gym(export_method: "ad-hoc") # or gradle(task: "assembleRelease")
|
|
28
|
+
|
|
29
|
+
upload_to_testappio(
|
|
30
|
+
api_token: ENV["TESTAPPIO_API_TOKEN"],
|
|
31
|
+
app_id: ENV["TESTAPPIO_APP_ID"],
|
|
32
|
+
notify: true
|
|
33
|
+
)
|
|
34
|
+
end
|
|
35
|
+
```
|
|
32
36
|
|
|
33
|
-
|
|
37
|
+
Get your `api_token` at <https://portal.testapp.io/profile/tokens>.
|
|
38
|
+
Get your `app_id` at <https://portal.testapp.io/apps>.
|
|
34
39
|
|
|
35
|
-
|
|
40
|
+
## Configuration
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
| Key | Description | Env var | Default |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| `api_token` | API token from <https://portal.testapp.io/profile/tokens> | `TESTAPPIO_API_TOKEN` | — |
|
|
45
|
+
| `app_id` | App ID from your <https://portal.testapp.io/apps> page | `TESTAPPIO_APP_ID` | — |
|
|
46
|
+
| `release` | `ios`, `android`, or `both` | `TESTAPPIO_RELEASE` | current platform |
|
|
47
|
+
| `apk_file` | Path to the Android `.apk` | `TESTAPPIO_ANDROID_PATH` | gradle's output |
|
|
48
|
+
| `ipa_file` | Path to the iOS `.ipa` | `TESTAPPIO_IOS_PATH` | gym's output |
|
|
49
|
+
| `release_notes` | Manual release notes | `TESTAPPIO_RELEASE_NOTES` | — |
|
|
50
|
+
| `git_release_notes` | Use the latest git commit message as release notes | `TESTAPPIO_GIT_RELEASE_NOTES` | `true` |
|
|
51
|
+
| `git_commit_id` | Append the latest commit SHA to the release notes | `TESTAPPIO_GIT_COMMIT_ID` | `false` |
|
|
52
|
+
| `notify` | Notify team members about the new release | `TESTAPPIO_NOTIFY` | `false` |
|
|
53
|
+
| `self_update` | Auto-update `ta-cli` when a new version is available | `TESTAPPIO_SELF_UPDATE` | `true` |
|
|
38
54
|
|
|
39
|
-
|
|
55
|
+
## Examples
|
|
40
56
|
|
|
41
|
-
|
|
57
|
+
### iOS only
|
|
42
58
|
|
|
43
59
|
```ruby
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
)
|
|
60
|
+
lane :beta_ios do
|
|
61
|
+
match(type: "adhoc")
|
|
62
|
+
gym(export_method: "ad-hoc")
|
|
63
|
+
|
|
64
|
+
upload_to_testappio(
|
|
65
|
+
api_token: ENV["TESTAPPIO_API_TOKEN"],
|
|
66
|
+
app_id: ENV["TESTAPPIO_APP_ID"],
|
|
67
|
+
release: "ios",
|
|
68
|
+
release_notes: "Bug fixes and improvements",
|
|
69
|
+
notify: true
|
|
70
|
+
)
|
|
71
|
+
end
|
|
72
|
+
```
|
|
58
73
|
|
|
59
|
-
|
|
74
|
+
### Android only
|
|
60
75
|
|
|
61
|
-
|
|
76
|
+
```ruby
|
|
77
|
+
lane :beta_android do
|
|
78
|
+
gradle(task: "clean assembleRelease")
|
|
79
|
+
|
|
80
|
+
upload_to_testappio(
|
|
81
|
+
api_token: ENV["TESTAPPIO_API_TOKEN"],
|
|
82
|
+
app_id: ENV["TESTAPPIO_APP_ID"],
|
|
83
|
+
release: "android",
|
|
84
|
+
git_release_notes: true,
|
|
85
|
+
git_commit_id: true,
|
|
86
|
+
notify: true
|
|
87
|
+
)
|
|
88
|
+
end
|
|
62
89
|
```
|
|
63
90
|
|
|
64
|
-
|
|
91
|
+
### Both platforms in one lane
|
|
65
92
|
|
|
66
93
|
```ruby
|
|
67
|
-
|
|
94
|
+
lane :beta_both do
|
|
95
|
+
gradle(task: "clean assembleRelease")
|
|
96
|
+
gym(export_method: "ad-hoc")
|
|
97
|
+
|
|
98
|
+
upload_to_testappio(
|
|
99
|
+
api_token: ENV["TESTAPPIO_API_TOKEN"],
|
|
100
|
+
app_id: ENV["TESTAPPIO_APP_ID"],
|
|
101
|
+
release: "both",
|
|
102
|
+
notify: true
|
|
103
|
+
)
|
|
104
|
+
end
|
|
105
|
+
```
|
|
68
106
|
|
|
69
|
-
|
|
107
|
+
A runnable example lives in [`fastlane/Fastfile`](fastlane/Fastfile). Try it with `bundle exec fastlane test`.
|
|
70
108
|
|
|
71
|
-
|
|
109
|
+
## Compatibility
|
|
72
110
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
git_release_notes: true,
|
|
78
|
-
git_commit_id: false,
|
|
79
|
-
notify: true
|
|
80
|
-
)
|
|
111
|
+
| Plugin version | Ruby | Status |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| **2.x** | `>= 3.0` | Active — feature work + security fixes |
|
|
114
|
+
| **1.x** | `>= 2.6` | Maintenance only — security fixes through May 2027 |
|
|
81
115
|
|
|
82
|
-
|
|
83
|
-
```
|
|
116
|
+
If your CI image uses Ruby 2.6 or 2.7, pin to `~> 1.0` in your `Pluginfile`:
|
|
84
117
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
118
|
+
```ruby
|
|
119
|
+
gem "fastlane-plugin-testappio", "~> 1.0"
|
|
120
|
+
```
|
|
88
121
|
|
|
89
|
-
|
|
122
|
+
When you upgrade your CI to Ruby 3.0+, drop the pin and you'll get 2.x automatically.
|
|
90
123
|
|
|
91
|
-
|
|
124
|
+
## Troubleshooting
|
|
92
125
|
|
|
93
|
-
|
|
126
|
+
- **`fastlane add_plugin testappio` fails on Bundler 2.0 issues** — make sure your Ruby is 3.0 or higher (`ruby -v`).
|
|
127
|
+
- **Upload fails with a `ta-cli` error** — the error message now includes the underlying `ta-cli` output so you can see exactly what went wrong (auth, network, provisioning, etc.). Run with `fastlane --verbose` for full context.
|
|
128
|
+
- **Token visible in CI logs** — should never happen in 2.x; tokens are masked as `********`. If you see this in 1.x, upgrade.
|
|
129
|
+
- **Other plugin issues** — see the official [Fastlane plugin troubleshooting guide](https://docs.fastlane.tools/plugins/plugins-troubleshooting/).
|
|
94
130
|
|
|
95
|
-
|
|
131
|
+
## Contributing
|
|
96
132
|
|
|
97
|
-
|
|
133
|
+
PRs welcome. Local development:
|
|
98
134
|
|
|
99
|
-
|
|
135
|
+
```bash
|
|
136
|
+
bundle install # install dev dependencies
|
|
137
|
+
bundle exec rspec # run the unit test suite (49 specs)
|
|
138
|
+
bundle exec rubocop # lint
|
|
139
|
+
bundle exec rake # spec + rubocop together
|
|
140
|
+
INTEGRATION=1 bundle exec rspec # also run the 2 :integration specs (needs ta-cli installed)
|
|
141
|
+
```
|
|
100
142
|
|
|
101
|
-
|
|
143
|
+
Every PR adds an entry under `## [Unreleased]` in [`CHANGELOG.md`](CHANGELOG.md). See it for the full list of what changed between versions.
|
|
102
144
|
|
|
103
|
-
|
|
145
|
+
## Feedback & support
|
|
104
146
|
|
|
105
|
-
|
|
147
|
+
- **Help center:** <https://help.testapp.io/>
|
|
148
|
+
- **Community:** <https://help.testapp.io/faq/join-our-community/>
|
|
149
|
+
- **Bug reports / feature requests:** [GitHub issues](https://github.com/testappio/fastlane-plugin-testappio/issues)
|
|
106
150
|
|
|
107
|
-
|
|
151
|
+
Built by [TestApp.io](https://testapp.io) — happy releasing 🚀
|
|
@@ -4,7 +4,6 @@ module Fastlane
|
|
|
4
4
|
SUPPORTED_FILE_EXTENSIONS = ["apk", "ipa"]
|
|
5
5
|
|
|
6
6
|
def self.run(params)
|
|
7
|
-
|
|
8
7
|
# Check if `ta_cli` exists, install it if not
|
|
9
8
|
unless Helper::TestappioHelper.check_ta_cli
|
|
10
9
|
UI.error("Error detecting ta-cli")
|
|
@@ -53,6 +52,8 @@ module Fastlane
|
|
|
53
52
|
end
|
|
54
53
|
|
|
55
54
|
def self.validate_file_path(file_path)
|
|
55
|
+
return if file_path.nil?
|
|
56
|
+
|
|
56
57
|
UI.user_error!("No file found at '#{file_path}'.") unless File.exist?(file_path)
|
|
57
58
|
|
|
58
59
|
file_ext = File.extname(file_path).delete('.')
|
|
@@ -87,60 +88,60 @@ module Fastlane
|
|
|
87
88
|
[
|
|
88
89
|
FastlaneCore::ConfigItem.new(key: :api_token,
|
|
89
90
|
env_name: "TESTAPPIO_API_TOKEN",
|
|
90
|
-
description: "You can get it from https://portal.testapp.io/
|
|
91
|
+
description: "You can get it from https://portal.testapp.io/profile/tokens",
|
|
91
92
|
verify_block: proc do |value|
|
|
92
|
-
UI.user_error!("No API token provided. You can get it from https://portal.testapp.io/
|
|
93
|
+
UI.user_error!("No API token provided. You can get it from https://portal.testapp.io/profile/tokens") unless value && !value.empty?
|
|
93
94
|
end),
|
|
94
95
|
FastlaneCore::ConfigItem.new(key: :app_id,
|
|
95
96
|
env_name: "TESTAPPIO_APP_ID",
|
|
96
|
-
description: "You can get it from your app page in https://portal.testapp.io/apps?
|
|
97
|
+
description: "You can get it from your app page in https://portal.testapp.io/apps?to=app-integrations&tab=releases",
|
|
97
98
|
is_string: false),
|
|
98
99
|
FastlaneCore::ConfigItem.new(key: :release,
|
|
99
100
|
env_name: "TESTAPPIO_RELEASE",
|
|
100
101
|
description: "It can be either both or android or ios",
|
|
101
102
|
is_string: true,
|
|
102
|
-
|
|
103
|
+
default_value: Actions.lane_context[Actions::SharedValues::PLATFORM_NAME]),
|
|
103
104
|
FastlaneCore::ConfigItem.new(key: :apk_file,
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
105
|
+
env_name: "TESTAPPIO_ANDROID_PATH",
|
|
106
|
+
description: "Full path to the Android .apk file",
|
|
107
|
+
optional: true,
|
|
108
|
+
is_string: true,
|
|
109
|
+
default_value: default_file_path),
|
|
109
110
|
FastlaneCore::ConfigItem.new(key: :ipa_file,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
env_name: "TESTAPPIO_IOS_PATH",
|
|
112
|
+
description: "Full path to the iOS .ipa file",
|
|
113
|
+
optional: true,
|
|
114
|
+
is_string: true,
|
|
115
|
+
default_value: default_file_path),
|
|
115
116
|
FastlaneCore::ConfigItem.new(key: :release_notes,
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
env_name: "TESTAPPIO_RELEASE_NOTES",
|
|
118
|
+
description: "Manually add the release notes to be displayed for the testers",
|
|
119
|
+
optional: true,
|
|
120
|
+
is_string: true),
|
|
120
121
|
FastlaneCore::ConfigItem.new(key: :git_release_notes,
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
env_name: "TESTAPPIO_GIT_RELEASE_NOTES",
|
|
123
|
+
description: "Collect release notes from the latest git commit message to be displayed for the testers: true or false",
|
|
124
|
+
optional: true,
|
|
125
|
+
is_string: false,
|
|
126
|
+
default_value: true),
|
|
126
127
|
FastlaneCore::ConfigItem.new(key: :git_commit_id,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
128
|
+
env_name: "TESTAPPIO_GIT_COMMIT_ID",
|
|
129
|
+
description: "Include the last commit ID in the release notes (works with both release notes option): true or false",
|
|
130
|
+
optional: true,
|
|
131
|
+
is_string: false,
|
|
132
|
+
default_value: false),
|
|
132
133
|
FastlaneCore::ConfigItem.new(key: :notify,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
env_name: "TESTAPPIO_NOTIFY",
|
|
135
|
+
description: "Send notificaitons to your team members about this release: true or false",
|
|
136
|
+
optional: true,
|
|
137
|
+
is_string: false,
|
|
138
|
+
default_value: false),
|
|
138
139
|
FastlaneCore::ConfigItem.new(key: :self_update,
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
env_name: "TESTAPPIO_SELF_UPDATE",
|
|
141
|
+
description: "Automatically update ta-cli if a new version is available or required: true or false",
|
|
142
|
+
optional: true,
|
|
143
|
+
is_string: false,
|
|
144
|
+
default_value: true)
|
|
144
145
|
]
|
|
145
146
|
end
|
|
146
147
|
|
|
@@ -149,7 +150,7 @@ module Fastlane
|
|
|
149
150
|
end
|
|
150
151
|
|
|
151
152
|
def self.return_value
|
|
152
|
-
|
|
153
|
+
nil
|
|
153
154
|
end
|
|
154
155
|
|
|
155
156
|
def self.authors
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
require 'fastlane_core/ui/ui'
|
|
2
|
+
require 'open3'
|
|
2
3
|
|
|
3
4
|
module Fastlane
|
|
4
5
|
UI = FastlaneCore::UI unless Fastlane.const_defined?(:UI)
|
|
5
6
|
|
|
6
7
|
module Helper
|
|
7
8
|
class TestappioHelper
|
|
8
|
-
|
|
9
9
|
# Check if `ta_cli` exists, install it if not
|
|
10
10
|
def self.check_ta_cli
|
|
11
11
|
unless system('which ta-cli > /dev/null 2>&1')
|
|
@@ -22,8 +22,6 @@ module Fastlane
|
|
|
22
22
|
|
|
23
23
|
# Check if there is an update available for `ta_cli`, and install it if necessary
|
|
24
24
|
def self.check_update(self_update)
|
|
25
|
-
require 'open3'
|
|
26
|
-
|
|
27
25
|
version_output = `ta-cli version`
|
|
28
26
|
UI.verbose(version_output)
|
|
29
27
|
|
|
@@ -31,14 +29,14 @@ module Fastlane
|
|
|
31
29
|
if self_update
|
|
32
30
|
UI.message("Updating ta-cli due to breaking changes...")
|
|
33
31
|
else
|
|
32
|
+
# UI.user_error! raises FastlaneError; method never returns past this point.
|
|
34
33
|
UI.user_error!("Update necessary due to breaking changes. Please update ta-cli manually or set self_update to true")
|
|
35
|
-
return false
|
|
36
34
|
end
|
|
37
35
|
elsif version_output.include?("New version available")
|
|
38
36
|
if self_update
|
|
39
37
|
UI.message("Updating ta-cli...")
|
|
40
38
|
else
|
|
41
|
-
UI.
|
|
39
|
+
UI.important("New version available, but skipping update as self_update is set to false.")
|
|
42
40
|
return true
|
|
43
41
|
end
|
|
44
42
|
else
|
|
@@ -47,7 +45,7 @@ module Fastlane
|
|
|
47
45
|
end
|
|
48
46
|
|
|
49
47
|
update_command = "curl -Ls https://github.com/testappio/cli/releases/latest/download/install | bash"
|
|
50
|
-
update_output,
|
|
48
|
+
update_output, = Open3.capture3(update_command)
|
|
51
49
|
UI.verbose(update_output)
|
|
52
50
|
|
|
53
51
|
if update_output.include?("ta-cli successfully installed") || update_output.include?("ta-cli has been updated")
|
|
@@ -56,67 +54,93 @@ module Fastlane
|
|
|
56
54
|
|
|
57
55
|
if version_output.include?("Update necessary due to breaking changes") || version_output.include?("New version available")
|
|
58
56
|
UI.user_error!("Error updating ta-cli: the version is still outdated")
|
|
59
|
-
return false
|
|
60
57
|
else
|
|
61
58
|
UI.success("ta-cli has been updated successfully")
|
|
62
59
|
return true
|
|
63
60
|
end
|
|
64
61
|
else
|
|
65
62
|
UI.user_error!("Error updating ta-cli: #{update_output}")
|
|
66
|
-
return false
|
|
67
63
|
end
|
|
68
64
|
end
|
|
69
65
|
|
|
70
|
-
# Handle errors from
|
|
71
|
-
#
|
|
66
|
+
# Handle errors from ta-cli. Raises user_error only when stderr contains an
|
|
67
|
+
# /Error/-matching line. Non-error stderr (warnings, info) is logged via UI.verbose.
|
|
68
|
+
# The raised message includes the actual error lines so the user has context
|
|
69
|
+
# (auth failure, provisioning issue, network error, etc.) without re-running verbose.
|
|
72
70
|
def self.handle_error(errors)
|
|
73
71
|
errors.each do |error|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
next unless error
|
|
73
|
+
|
|
74
|
+
if error.include?('Error')
|
|
75
|
+
UI.error(error.to_s)
|
|
76
|
+
else
|
|
77
|
+
UI.verbose(error.to_s)
|
|
80
78
|
end
|
|
81
79
|
end
|
|
82
80
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
end
|
|
81
|
+
error_lines = errors.compact.select { |e| e.include?('Error') }
|
|
82
|
+
return if error_lines.empty?
|
|
83
|
+
|
|
84
|
+
UI.user_error!("Error while calling ta-cli: #{error_lines.join(' | ')}")
|
|
88
85
|
end
|
|
89
86
|
|
|
90
|
-
# Run the given command
|
|
87
|
+
# Run the given command. Streams stdout to UI.message; routes stderr through
|
|
88
|
+
# handle_error on non-zero exit. Masks --api_token in verbose command echo.
|
|
89
|
+
#
|
|
90
|
+
# Uses Open3.popen3 with the command array form (no shell interpretation), so
|
|
91
|
+
# shell metacharacters in api_token / release_notes / file paths are passed
|
|
92
|
+
# literally to ta-cli without need for manual escaping.
|
|
91
93
|
def self.call_ta_cli(command)
|
|
92
94
|
UI.message("Starting ta-cli...")
|
|
93
|
-
require 'open3'
|
|
94
95
|
if FastlaneCore::Globals.verbose?
|
|
95
96
|
UI.verbose("ta-cli command:\n\n")
|
|
96
|
-
UI.command(command.to_s)
|
|
97
|
+
UI.command(redact_command(command).to_s)
|
|
97
98
|
UI.verbose("\n\n")
|
|
98
99
|
end
|
|
99
|
-
|
|
100
|
+
|
|
100
101
|
out = []
|
|
101
102
|
error = []
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
103
|
+
out_thread = nil
|
|
104
|
+
err_thread = nil
|
|
105
|
+
Open3.popen3(*command) do |stdin, stdout, stderr, wait_thr|
|
|
106
|
+
stdin.close
|
|
107
|
+
|
|
108
|
+
# Read stdout and stderr concurrently to avoid deadlock when ta-cli
|
|
109
|
+
# fills one buffer before we finish draining the other.
|
|
110
|
+
out_thread = Thread.new do
|
|
111
|
+
while (line = stdout.gets)
|
|
112
|
+
out << line
|
|
113
|
+
UI.message(line.strip) unless line.strip.empty?
|
|
114
|
+
end
|
|
110
115
|
end
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
|
|
117
|
+
err_thread = Thread.new do
|
|
118
|
+
while (line = stderr.gets)
|
|
119
|
+
error << line.strip
|
|
120
|
+
end
|
|
113
121
|
end
|
|
122
|
+
|
|
123
|
+
out_thread.join
|
|
124
|
+
err_thread.join
|
|
125
|
+
|
|
114
126
|
exit_status = wait_thr.value
|
|
115
127
|
handle_error(error) unless exit_status.success?
|
|
116
128
|
end
|
|
117
129
|
out.join
|
|
130
|
+
ensure
|
|
131
|
+
# If popen3's block raised before threads joined, make sure no readers
|
|
132
|
+
# are left holding pipe FDs.
|
|
133
|
+
out_thread&.kill if out_thread&.alive?
|
|
134
|
+
err_thread&.kill if err_thread&.alive?
|
|
118
135
|
end
|
|
119
136
|
|
|
137
|
+
# Return a copy of the command array with --api_token=... masked.
|
|
138
|
+
def self.redact_command(command)
|
|
139
|
+
command.map do |arg|
|
|
140
|
+
arg.kind_of?(String) && arg.start_with?("--api_token=") ? "--api_token=********" : arg
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
private_class_method :redact_command
|
|
120
144
|
end
|
|
121
145
|
end
|
|
122
146
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fastlane-plugin-testappio
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- TestApp.io
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-05-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -30,34 +30,28 @@ dependencies:
|
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '2.
|
|
34
|
-
- - ">="
|
|
35
|
-
- !ruby/object:Gem::Version
|
|
36
|
-
version: 2.204.3
|
|
33
|
+
version: '2.217'
|
|
37
34
|
type: :development
|
|
38
35
|
prerelease: false
|
|
39
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
40
37
|
requirements:
|
|
41
38
|
- - "~>"
|
|
42
39
|
- !ruby/object:Gem::Version
|
|
43
|
-
version: '2.
|
|
44
|
-
- - ">="
|
|
45
|
-
- !ruby/object:Gem::Version
|
|
46
|
-
version: 2.204.3
|
|
40
|
+
version: '2.217'
|
|
47
41
|
- !ruby/object:Gem::Dependency
|
|
48
42
|
name: pry
|
|
49
43
|
requirement: !ruby/object:Gem::Requirement
|
|
50
44
|
requirements:
|
|
51
45
|
- - "~>"
|
|
52
46
|
- !ruby/object:Gem::Version
|
|
53
|
-
version: '0.
|
|
47
|
+
version: '0.14'
|
|
54
48
|
type: :development
|
|
55
49
|
prerelease: false
|
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
57
51
|
requirements:
|
|
58
52
|
- - "~>"
|
|
59
53
|
- !ruby/object:Gem::Version
|
|
60
|
-
version: '0.
|
|
54
|
+
version: '0.14'
|
|
61
55
|
- !ruby/object:Gem::Dependency
|
|
62
56
|
name: rake
|
|
63
57
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -92,76 +86,81 @@ dependencies:
|
|
|
92
86
|
requirements:
|
|
93
87
|
- - "~>"
|
|
94
88
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: '0.
|
|
89
|
+
version: '0.6'
|
|
96
90
|
type: :development
|
|
97
91
|
prerelease: false
|
|
98
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
93
|
requirements:
|
|
100
94
|
- - "~>"
|
|
101
95
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '0.
|
|
96
|
+
version: '0.6'
|
|
103
97
|
- !ruby/object:Gem::Dependency
|
|
104
98
|
name: rubocop
|
|
105
99
|
requirement: !ruby/object:Gem::Requirement
|
|
106
100
|
requirements:
|
|
107
|
-
- -
|
|
101
|
+
- - "~>"
|
|
108
102
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: 1.
|
|
103
|
+
version: '1.50'
|
|
110
104
|
type: :development
|
|
111
105
|
prerelease: false
|
|
112
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
107
|
requirements:
|
|
114
|
-
- -
|
|
108
|
+
- - "~>"
|
|
115
109
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: 1.
|
|
110
|
+
version: '1.50'
|
|
117
111
|
- !ruby/object:Gem::Dependency
|
|
118
112
|
name: rubocop-performance
|
|
119
113
|
requirement: !ruby/object:Gem::Requirement
|
|
120
114
|
requirements:
|
|
121
115
|
- - "~>"
|
|
122
116
|
- !ruby/object:Gem::Version
|
|
123
|
-
version: 1.
|
|
117
|
+
version: '1.20'
|
|
124
118
|
type: :development
|
|
125
119
|
prerelease: false
|
|
126
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
127
121
|
requirements:
|
|
128
122
|
- - "~>"
|
|
129
123
|
- !ruby/object:Gem::Version
|
|
130
|
-
version: 1.
|
|
124
|
+
version: '1.20'
|
|
131
125
|
- !ruby/object:Gem::Dependency
|
|
132
|
-
name:
|
|
126
|
+
name: simplecov
|
|
133
127
|
requirement: !ruby/object:Gem::Requirement
|
|
134
128
|
requirements:
|
|
135
129
|
- - "~>"
|
|
136
130
|
- !ruby/object:Gem::Version
|
|
137
|
-
version: 0.
|
|
131
|
+
version: '0.22'
|
|
138
132
|
type: :development
|
|
139
133
|
prerelease: false
|
|
140
134
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
135
|
requirements:
|
|
142
136
|
- - "~>"
|
|
143
137
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: 0.
|
|
138
|
+
version: '0.22'
|
|
145
139
|
- !ruby/object:Gem::Dependency
|
|
146
|
-
name: simplecov
|
|
140
|
+
name: simplecov-cobertura
|
|
147
141
|
requirement: !ruby/object:Gem::Requirement
|
|
148
142
|
requirements:
|
|
149
143
|
- - "~>"
|
|
150
144
|
- !ruby/object:Gem::Version
|
|
151
|
-
version: '
|
|
145
|
+
version: '3.1'
|
|
152
146
|
type: :development
|
|
153
147
|
prerelease: false
|
|
154
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
155
149
|
requirements:
|
|
156
150
|
- - "~>"
|
|
157
151
|
- !ruby/object:Gem::Version
|
|
158
|
-
version: '
|
|
159
|
-
description:
|
|
152
|
+
version: '3.1'
|
|
153
|
+
description: |
|
|
154
|
+
A Fastlane plugin that uploads Android (.apk) and iOS (.ipa) builds to TestApp.io,
|
|
155
|
+
notifying your team for testing and feedback. Wraps the ta-cli binary to provide a
|
|
156
|
+
single upload_to_testappio Fastlane action with platform detection, release notes
|
|
157
|
+
from git, and selective team notifications.
|
|
160
158
|
email: support@testapp.io
|
|
161
159
|
executables: []
|
|
162
160
|
extensions: []
|
|
163
161
|
extra_rdoc_files: []
|
|
164
162
|
files:
|
|
163
|
+
- CHANGELOG.md
|
|
165
164
|
- LICENSE
|
|
166
165
|
- README.md
|
|
167
166
|
- lib/fastlane/plugin/testappio.rb
|
|
@@ -171,8 +170,12 @@ files:
|
|
|
171
170
|
homepage: https://github.com/testappio/fastlane-plugin-testappio
|
|
172
171
|
licenses:
|
|
173
172
|
- MIT
|
|
174
|
-
metadata:
|
|
175
|
-
|
|
173
|
+
metadata:
|
|
174
|
+
rubygems_mfa_required: 'true'
|
|
175
|
+
source_code_uri: https://github.com/testappio/fastlane-plugin-testappio
|
|
176
|
+
changelog_uri: https://github.com/testappio/fastlane-plugin-testappio/blob/main/CHANGELOG.md
|
|
177
|
+
bug_tracker_uri: https://github.com/testappio/fastlane-plugin-testappio/issues
|
|
178
|
+
post_install_message:
|
|
176
179
|
rdoc_options: []
|
|
177
180
|
require_paths:
|
|
178
181
|
- lib
|
|
@@ -180,15 +183,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
180
183
|
requirements:
|
|
181
184
|
- - ">="
|
|
182
185
|
- !ruby/object:Gem::Version
|
|
183
|
-
version: '
|
|
186
|
+
version: '3.0'
|
|
184
187
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
188
|
requirements:
|
|
186
189
|
- - ">="
|
|
187
190
|
- !ruby/object:Gem::Version
|
|
188
191
|
version: '0'
|
|
189
192
|
requirements: []
|
|
190
|
-
rubygems_version: 3.4.
|
|
191
|
-
signing_key:
|
|
193
|
+
rubygems_version: 3.4.19
|
|
194
|
+
signing_key:
|
|
192
195
|
specification_version: 4
|
|
193
196
|
summary: Deploy your Android & iOS to TestApp.io
|
|
194
197
|
test_files: []
|