Skip to content

Migrate to composite action + Maestro CLI#66

Open
proksh wants to merge 51 commits intomainfrom
use-cli-instead-of-curl
Open

Migrate to composite action + Maestro CLI#66
proksh wants to merge 51 commits intomainfrom
use-cli-instead-of-curl

Conversation

@proksh
Copy link
Copy Markdown
Contributor

@proksh proksh commented Apr 30, 2026

Summary

Replaces the bundled TypeScript HTTP client with a composite GitHub Action that uses Maestro CLI, aligning the architecture with the Bitrise step and Bitbucket pipe. Removes the bespoke ApiClient/StatusPoller/archive code in favor of a small TypeScript prelude that derives env vars, a bash script that invokes maestro cloud, and a post-processor that reconstructs per-flow results from the junit report. Code-only change — tag cut, v2 pointer move, and README updates are deferred to a follow-up.

Test plan

  • npm test — Jest, 50 PASS (41 prelude + 9 postprocess)
  • npm run test:bats — bats, 23 PASS
  • npm run build — produces dist/prelude.js + dist/postprocess.js; freshness check is clean
  • validate-local.yml Android test passes on ubuntu-latest (run 25175152565)
  • Console URLs in validate-local.yml logs are clickable (project ID inlined)
  • MAESTRO_CLOUD_APP_BINARY_ID, MAESTRO_CLOUD_CONSOLE_URL, and MAESTRO_CLOUD_FLOW_RESULTS populated end-to-end and readable downstream

proksh and others added 30 commits April 28, 2026 16:38
Both inputs are superseded by the string-based device-os parameter
(e.g. device-os: android-33, device-os: iOS-18-2).

- android-api-level: kept as a documented input but marked deprecated
  via deprecationMessage in action.yml; emits a core.warning at
  runtime and is still forwarded to the API.
- ios-version: removed from the typed Params and from the upload
  payload. A core.warning is still emitted if it is supplied so that
  any caller still passing it gets a clear message instead of a
  silent no-op (it has been undocumented since v2.0.0 but the input
  was still being read and forwarded).
- README and device-os/device-model rows updated with the supported
  values for both iOS and Android.

dist/ is intentionally not rebuilt in this commit.
Covers:
- no warnings on the happy path
- android-api-level emits a warning and is still forwarded
- ios-version emits a warning and is NOT forwarded
- device-os / device-model accept iOS and Android values
- device-os: web bypasses the app-file requirement
…d dist

- Restore ios-version forwarding so the deprecation behaviour matches
  android-api-level: emit a core.warning, but still pass the value
  through to the API. This avoids any behaviour change for users still
  passing the input.
- Extract buildUploadRequest into its own module so the wire-format
  mapping can be unit-tested without pulling in node-fetch.
- Add __tests__/uploadRequest.test.ts covering payload shape:
  androidApiLevel/iOSVersion forwarded when set and omitted when not,
  agent='github', appBinaryId coercion, tag forwarding, and a
  serialization sanity check on the legacy wire keys.
- Add __tests__/inputValidation.test.ts covering app-file /
  app-binary-id / device-os: web mutual exclusion (mobile happy paths,
  both-set / neither-set rejections, web rejections when app inputs are
  supplied).
- Update __tests__/deprecation.test.ts to assert ios-version is
  forwarded (was previously asserting it was dropped).
- Update README note to reflect that both inputs warn-and-forward.
- Rebuild dist/index.js so the published action picks up the changes.
Revert this commit before merging — main must stay on @v2.
Folded __tests__/deprecation.test.ts and __tests__/inputValidation.test.ts
into __tests__/getParameters.test.ts and made them table-driven over the
shared dimensions (deprecated input name, device-os platform, validation
rule). Same coverage, fewer copies of the test scaffolding.

Also collapsed __tests__/uploadRequest.test.ts: one assertion against the
fully-populated UploadRequest covers the field-by-field forwarding,
empty-string-to-undefined coercion is table-driven across the four
nullable string fields, and the omit-when-unset case for the deprecated
fields stays as one test.

37 tests now pass (was 43); coverage of behaviour is unchanged.
The CLI prints the upload URL the moment the upload returns so users
can click through and watch the run live. The action set the URL as a
step output but didn't emit it to the log until polling completed,
which made every "Waiting for analyses to complete..." line feel
unactionable.

Print the URL (and app binary id) right after the upload, then start
the poller. Mirrors maestro-cli/CloudInteractor.kt:415-425.
Captures the agreed design for migrating this Action from a bundled
TypeScript HTTP client to a composite action that invokes the Maestro CLI
directly, aligning with the Bitrise step and Bitbucket pipe.

Code change ships in a follow-up; version bump and README rewrite ship in
a separate PR after that.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
23 TDD-shaped tasks across three phases (TS prelude, bash run-cloud
script, action.yml + CI + deletions + CHANGELOG).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…pace test

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
proksh and others added 11 commits April 30, 2026 16:31
The HTTP client, status poller, archive utilities, and app-file inspector
are replaced by the Maestro CLI invocation.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Also includes a plan doc correction noting that composite-action env var
names must preserve hyphens (INPUT_APP-FILE) so @actions/core.getInput
can read them — getInput only normalizes spaces to underscores.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Remove stale dist/37.index.js chunk left over from the deleted index.ts
  build output (Task 21 missed it).
- Prefix build with `rm -rf dist` so future deletions don't accumulate
  orphaned chunks in dist/.
- Add `npm run test:bats` for local convenience (uses npm global root
  for BATS_LIB_PATH).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pre-merge review feedback:
- Guard mktemp so a temp-file failure surfaces a clear error instead of
  silently writing to an empty path.
- Move temp-file cleanup to a trap on EXIT so it runs on every exit path,
  not only after a successful CLI run.
- Add comments pointing to the maestro-cli source lines that produce the
  parsed strings, so future maintainers know what to grep when the CLI
  release notes change log formatting.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Project IDs in Maestro Cloud are identifiers, not credentials — only the
api-key needs to live in secrets. Storing project-id in secrets caused
GitHub to redact it from logs, breaking the console URLs the CLI prints
(e.g. https://app.maestro.dev/project/***/...).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CHANGELOG isn't tracked in this repo's conventions; the migration
notes live in the PR body. The superpowers spec/plan were process
artifacts for the implementation flow, not source-of-truth docs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add runs-on matrix [ubuntu-latest, macos-latest].
- Inline project-id so console URLs are clickable in workflow logs.
- Rename the install step for clarity (it's there for download-samples,
  not for the action — the action installs the CLI itself).

The action reference stays pinned at @v2; once the rolling tag moves
to this branch's lineage, this workflow will start exercising the new
composite action on both platforms.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The macOS-vs-ubuntu split didn't surface platform-specific issues in
the verification run, and the iOS test path is independent of the
runner OS (uploads go to Maestro Cloud regardless). Reverting to a
single ubuntu-latest job keeps the smoke workflows fast and cheap.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The Maestro CLI doesn't expose a JSON output format, but the JUnit
reporter (JUnitTestSuiteReporter.kt) preserves the full FlowStatus
enum on each <testcase status="..."> attribute — including
WARNING/CANCELED/STOPPED. So we can pass --format junit --output
internally and parse the XML to reconstruct the v1 output contract.

- New `postprocess.ts` parses junit XML into [{name, status, errors}]
  using a minimal regex-based parser (no XML lib dep) and writes
  MAESTRO_CLOUD_FLOW_RESULTS via @actions/core.setOutput.
- run-cloud.sh now passes --format junit --output <tmp> to the CLI
  unconditionally, then invokes the post-processor regardless of CLI
  exit code (a junit XML is written even when flows fail).
- Empty array is emitted when no junit file is produced (e.g. async
  upload, or CLI fails before reporting).
- Bundle build now produces both dist/prelude.js and dist/postprocess.js.
- Tests: 9 new jest cases for parseJunit (entity decoding, nested
  properties, multi-suite, multiline failure messages); 4 new bats
  cases verifying the wiring end-to-end via a junit-emitting fake
  maestro shim.

Note: cancellationReason is not present in junit output, so it is
not reconstructed. SUCCESS/ERROR/WARNING/CANCELED/STOPPED + the
first failure message are preserved — matching v1's practical use.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…able

Action outputs aren't surfaced in workflow logs by default — we need
a downstream step to read them back to confirm they're populated.
Added a "Verify Android outputs" step (with if: always() so it runs
even if iOS fails) that echoes all three outputs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Composite actions don't auto-expose their steps' $GITHUB_OUTPUT writes
as the action's outputs — they require an explicit top-level outputs:
block in action.yml that maps to a step's outputs. Without it,
\${{ steps.<id>.outputs.MAESTRO_CLOUD_* }} reads as empty in the
caller workflow.

The validation run revealed this: validate-local.yml's "Verify Android
outputs" step printed empty values for all three outputs even though
run-cloud.sh wrote them to GITHUB_OUTPUT correctly.

- Tagged the third step with id: run so we can reference it.
- Added outputs: block for MAESTRO_CLOUD_APP_BINARY_ID,
  MAESTRO_CLOUD_CONSOLE_URL, MAESTRO_CLOUD_FLOW_RESULTS.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@proksh proksh changed the base branch from deprecate-android-api-level-and-ios-version to main May 1, 2026 08:20
@proksh proksh requested a review from amanjeetsingh150 May 5, 2026 07:26
Comment thread .github/workflows/ci.yml
node-version: 20
- run: npm ci
- run: npm test
- run: npm run build
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QQ: we don't need npm install now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI now uses npm ci (cleaner reproducible install). This is an intentional swap.

steps:
- uses: actions/checkout@v6

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, if I understand the purpose of this? Do we dispatch this workflow manually from local to check if its working against a git commit reference?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a manual workflow_dispatch smoke test against a real commit/CLI version. Let me add it as a comment as well.

Comment thread action.yml Outdated
required: false
android-api-level:
description: "Android API level to run your flow against"
description: "[Deprecated] Android API level. Use 'device-os' instead (e.g. android-33)."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will users see this message on latest version?

Is this displayed and prelude message both are displayed? Then users would see duplicated deprecation messages.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

You're right, that was three places saying the same thing. Consolidated to one: deprecationMessage in action.yml is now the only deprecation surface. GitHub natively renders it as a warning annotation in the run, so we don't need core.warning duplicating it from prelude.ts. Also softened the input description from [Deprecated] prefix to a "Prefer device-os" hint.

Comment thread action.yml
shell: bash
env:
MDEV_CI: github
run: bash "${{ github.action_path }}/scripts/run-cloud.sh"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like we missed:

  1. MAESTRO_CLOUD_UPLOAD_STATUS that sets on non async mode, its going to output empty in all cases?
  2. Seems like MAESTRO_CLOUD_FLOW_RESULTS have shape in readme that expects cancellationReason and now its in different shape?

Thoughts on this: what would be best way to reproduce this via a test? Lets say if we want to write a failing test for MAESTRO_CLOUD_UPLOAD_STATUS should not be empty for non async mode or even this issue later:

#28

Our testing strategy here should fulfill that.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking JUnitTestSuiteReporter.kt in maestro-cli - the emitter drops cancellationReason entirely during JUnit serialization (it's only on the in-memory UploadStatus.FlowResult model). So: cancellationReason is unrecoverable from JUnit. Dropped from FlowResult and updated README to match. We can restore it once the CLI's JUnit emitter writes it (or by switching to a richer format later).

Comment thread action.yml
MAESTRO_VERSION: ${{ inputs.maestro-cli-version }}
run: |
curl -Ls --retry 3 --retry-all-errors "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means using action-maestro-cloud, would automatically download latest maestro cloud and do the cli command now.

Is there a way in workflow dispatch we can test this for a cli version or latest release?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread action.yml
run: node "${{ github.action_path }}/dist/prelude.js"

- name: Run maestro cloud
id: run
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When we change this we have to also verify that run-cloud script is compatible with all type of runners since consumers of action-maestro-cloud could be ubuntu, macOS as well. Putting what claude said, might be just ubuntu specific and we need to be careful about:

  • run-cloud.sh:18mktemp -t maestro-junit.XXXXXX. On BSD (macOS) -t is a prefix, on GNU it's a template. Behavior differs.
    - run-cloud.sh:57sed -E 's/\x1b\[[0-9;]*m//g'. BSD sed does not interpret \x1b; on a macOS runner this will silently fail to strip ANSI, breaking the APP_BINARY_ID / CONSOLE_URL parsing at run-cloud.sh:63-64. Either use a
    portable form (printf '\033' literal, or tr -d) or restore at least one macOS leg in validate-local.yml.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed both:

  • mktemp -texplicit ${TMPDIR:-/tmp}/maestro-junit.XXXXXX template (BSD and GNU both treat this as a template).
  • ANSI strip uses a literal ESC byte from printf '\033' injected into the sed pattern, instead of \x1b which BSD sed would read literally and silently fail to strip - that would break APP_BINARY_ID / CONSOLE_URL parsing.

Added macos-latest as a parallel matrix entry to both validate.yml and validate-local.yml (with fail-fast: false) so we'll catch this kind of regression.

@@ -6,40 +6,47 @@ on:
jobs:
validate:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be worth checking following cases here as well:

  • app-binary-id chaining (the headline pattern in README:298-313, and the only path where the binary-id fallback at run-cloud.sh:68-70 ever matters).
  • device-model and device-os is set.
  • env: | multiline — biggest regression surface since you rewrote the parser.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread scripts/run-cloud.sh
--format junit
--output "$JUNIT_FILE"
"${env_args[@]+"${env_args[@]}"}"
--flows "${MDEV_WORKSPACE:-.maestro}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Do we had default of junit before, is there reason to default to that?
  • If we pass both android-api-level and deviceOS here and both are non null, the logic to pick deviceOS is on cli right?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(a) JUnit is forced because CLI has no JSON format and we need it to reconstruct MAESTRO_CLOUD_FLOW_RESULTS

(b) Yes, cli takes care of picking the right deviceOS

Comment thread README.md Outdated
iOS example:

```yaml
- uses: mobile-dev-inc/action-maestro-cloud@v2.0.2
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, what would be this version seems like v3 ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it will v3 since its a major change

fail)
echo "Some failure happened"
exit 1
;;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like complicated logic of parsing junit, did we had this before by default?

Writing what claude raised about this:

  • postprocess.ts:38 only matches . Maestro CLI's junit emitter uses for infra failures and for assertion failures. An infra-failed flow currently reports errors: [].
  • postprocess.ts:38 doesn't strip wrappers. If the CLI wraps messages with special chars in CDATA (it often does), users get in their errors array.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't need this logic before because we were using the response from curl request directly. Now its CLI.

Reading JUnitTestSuiteReporter.kt in maestro-cli: the emitter only writes . It never emits or .

Swapped the regex-based parser for fast-xml-parser. Even with the simpler scope (only ), it removes manual entity decoding and gives us free CDATA handling - protection against future emitter changes. Added one CDATA test as a defensive regression check.

Copy link
Copy Markdown
Contributor Author

@proksh proksh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ran https://github.com/mobile-dev-inc/action-maestro-cloud/actions/runs/25483317566, and its working. Failure is because of test failure on cloud which is expected.

Comment thread .github/workflows/ci.yml
node-version: 20
- run: npm ci
- run: npm test
- run: npm run build
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CI now uses npm ci (cleaner reproducible install). This is an intentional swap.

steps:
- uses: actions/checkout@v6

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a manual workflow_dispatch smoke test against a real commit/CLI version. Let me add it as a comment as well.

Comment thread scripts/run-cloud.sh
--format junit
--output "$JUNIT_FILE"
"${env_args[@]+"${env_args[@]}"}"
--flows "${MDEV_WORKSPACE:-.maestro}"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(a) JUnit is forced because CLI has no JSON format and we need it to reconstruct MAESTRO_CLOUD_FLOW_RESULTS

(b) Yes, cli takes care of picking the right deviceOS

Comment thread README.md Outdated
iOS example:

```yaml
- uses: mobile-dev-inc/action-maestro-cloud@v2.0.2
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it will v3 since its a major change

Comment thread action.yml Outdated
required: false
android-api-level:
description: "Android API level to run your flow against"
description: "[Deprecated] Android API level. Use 'device-os' instead (e.g. android-33)."
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch.

You're right, that was three places saying the same thing. Consolidated to one: deprecationMessage in action.yml is now the only deprecation surface. GitHub natively renders it as a warning annotation in the run, so we don't need core.warning duplicating it from prelude.ts. Also softened the input description from [Deprecated] prefix to a "Prefer device-os" hint.

fail)
echo "Some failure happened"
exit 1
;;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We didn't need this logic before because we were using the response from curl request directly. Now its CLI.

Reading JUnitTestSuiteReporter.kt in maestro-cli: the emitter only writes . It never emits or .

Swapped the regex-based parser for fast-xml-parser. Even with the simpler scope (only ), it removes manual entity decoding and gives us free CDATA handling - protection against future emitter changes. Added one CDATA test as a defensive regression check.

Comment thread action.yml
shell: bash
env:
MDEV_CI: github
run: bash "${{ github.action_path }}/scripts/run-cloud.sh"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checking JUnitTestSuiteReporter.kt in maestro-cli - the emitter drops cancellationReason entirely during JUnit serialization (it's only on the in-memory UploadStatus.FlowResult model). So: cancellationReason is unrecoverable from JUnit. Dropped from FlowResult and updated README to match. We can restore it once the CLI's JUnit emitter writes it (or by switching to a richer format later).

Comment thread prelude.ts Outdated
}

// 7. Files
if (appFile) core.exportVariable('MDEV_APP_FILE', appFile)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Restored glob expansion in prelude.ts via @actions/glob.

@@ -6,40 +6,47 @@ on:
jobs:
validate:
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

Comment thread action.yml
MAESTRO_VERSION: ${{ inputs.maestro-cli-version }}
run: |
curl -Ls --retry 3 --retry-all-errors "https://get.maestro.mobile.dev" | bash
echo "$HOME/.maestro/bin" >> "$GITHUB_PATH"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added

@proksh proksh requested a review from amanjeetsingh150 May 7, 2026 08:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants