Repository navigation
Run the iOS Maestro E2E tests on Linux against remote simulators #59135
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,121 @@ | ||
| name: E2E iOS on demand | ||
|
|
||
| # Runs the iOS Maestro E2E suites against a pull request when a maintainer | ||
| # comments `@react-native-bot e2e-tests` on it. The apps come from the | ||
| # artifacts a run of the pull request's head already built, the Maestro flows | ||
| # from the pull request, and the workflows and scripts from the default branch. | ||
|
|
||
| on: | ||
| issue_comment: | ||
| types: [created] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| # Only a trigger comment shares the pull request's group, so a newer request | ||
| # supersedes a running one and any other comment cancels nothing. | ||
| concurrency: | ||
| group: e2e-ios-on-demand-${{ github.event.issue.number }}-${{ startsWith(github.event.comment.body, '@react-native-bot e2e-tests') && 'run' || github.event.comment.id }} | ||
| cancel-in-progress: true | ||
|
Comment on lines
+17
to
+19
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not huge deal, but any other comments after the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You're right, of course 🤦♂️ |
||
|
|
||
| jobs: | ||
| request: | ||
| if: >- | ||
| github.event.issue.pull_request != null && | ||
| startsWith(github.event.comment.body, '@react-native-bot e2e-tests') && | ||
| contains(fromJson('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association) | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| pull-requests: write | ||
| outputs: | ||
| head-sha: ${{ steps.find.outputs.head-sha }} | ||
| run-id: ${{ steps.find.outputs.run-id }} | ||
| steps: | ||
| - name: Find the pull request's build | ||
| id: find | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| GH_REPO: ${{ github.repository }} | ||
| PR: ${{ github.event.issue.number }} | ||
| run: | | ||
| set -euo pipefail | ||
| sha=$(gh api "repos/$GH_REPO/pulls/$PR" --jq .head.sha) | ||
| needed="RNTesterApp-NewArch-Debug RNTesterApp-NewArch-Release RNTestProject-Debug RNTestProject-Release react-native-package" | ||
| run_id= | ||
| for id in $(gh api "repos/$GH_REPO/actions/runs?head_sha=$sha&per_page=30" --jq '.workflow_runs[].id'); do | ||
| have=$(gh api "repos/$GH_REPO/actions/runs/$id/artifacts?per_page=100" --jq '.artifacts[].name') | ||
| missing= | ||
| for name in $needed; do | ||
| grep -qx "$name" <<<"$have" || missing="$missing $name" | ||
| done | ||
| if [ -z "$missing" ]; then | ||
| run_id=$id | ||
| break | ||
| fi | ||
| done | ||
| if [ -z "$run_id" ]; then | ||
| echo "::error::no run of $sha has built all of: $needed" | ||
| exit 1 | ||
| fi | ||
| echo "head-sha=$sha" >> "$GITHUB_OUTPUT" | ||
| echo "run-id=$run_id" >> "$GITHUB_OUTPUT" | ||
| - name: Acknowledge the request | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| GH_REPO: ${{ github.repository }} | ||
| COMMENT: ${{ github.event.comment.id }} | ||
| run: gh api -X POST "repos/$GH_REPO/issues/comments/$COMMENT/reactions" -f content=rocket > /dev/null | ||
|
|
||
| rntester: | ||
| needs: request | ||
| uses: ./.github/workflows/e2e-ios-rntester.yml | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| id-token: write | ||
| with: | ||
| argent-label: facebook.e2e-ios-on-demand | ||
| artifact-run-id: ${{ needs.request.outputs.run-id }} | ||
| flows-ref: ${{ needs.request.outputs.head-sha }} | ||
| fail-on-error: true | ||
|
|
||
| templateapp: | ||
| needs: request | ||
| uses: ./.github/workflows/e2e-ios-templateapp.yml | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| id-token: write | ||
| with: | ||
| argent-label: facebook.e2e-ios-on-demand | ||
| artifact-run-id: ${{ needs.request.outputs.run-id }} | ||
| flows-ref: ${{ needs.request.outputs.head-sha }} | ||
| fail-on-error: true | ||
|
|
||
| report: | ||
| needs: [request, rntester, templateapp] | ||
| if: always() && needs.request.result != 'skipped' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| pull-requests: write | ||
| steps: | ||
| - name: Comment the results | ||
| env: | ||
| GH_TOKEN: ${{ secrets.REACT_NATIVE_BOT_GITHUB_TOKEN || github.token }} | ||
| GH_REPO: ${{ github.repository }} | ||
| PR: ${{ github.event.issue.number }} | ||
| REQUEST: ${{ needs.request.result }} | ||
| HEAD_SHA: ${{ needs.request.outputs.head-sha }} | ||
| RNTESTER: ${{ needs.rntester.outputs.status }} | ||
| TEMPLATEAPP: ${{ needs.templateapp.outputs.status }} | ||
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| run: | | ||
| set -euo pipefail | ||
| if [ "$REQUEST" != "success" ]; then | ||
| body="iOS E2E: no run of the pull request's head has built the apps yet, see [the request]($RUN_URL)." | ||
| else | ||
| body="iOS E2E on ${HEAD_SHA:0:7} ([run]($RUN_URL)): RNTester **${RNTESTER:-skipped}**, template app **${TEMPLATEAPP:-skipped}**." | ||
| fi | ||
| gh api -X POST "repos/$GH_REPO/issues/$PR/comments" -f body="$body" > /dev/null | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: Suggest the iOS E2E run | ||
|
|
||
| # Once a pull request's Test All run has built the apps, tells maintainers how | ||
| # to run the iOS Maestro E2E suites against them (see e2e-ios-on-demand.yml). | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: [Test All] | ||
| types: [completed] | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| suggest: | ||
| if: github.event.workflow_run.event == 'pull_request' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| actions: read | ||
| pull-requests: write | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - name: Find the pull request whose apps were built | ||
| id: find | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| GH_REPO: ${{ github.repository }} | ||
| RUN_ID: ${{ github.event.workflow_run.id }} | ||
| HEAD_SHA: ${{ github.event.workflow_run.head_sha }} | ||
| run: | | ||
| set -euo pipefail | ||
| have=$(gh api "repos/$GH_REPO/actions/runs/$RUN_ID/artifacts?per_page=100" --jq '.artifacts[].name') | ||
| for name in RNTesterApp-NewArch-Debug RNTesterApp-NewArch-Release RNTestProject-Debug RNTestProject-Release react-native-package; do | ||
| if ! grep -qx "$name" <<<"$have"; then | ||
| echo "$name was not built; nothing to suggest" | ||
| exit 0 | ||
| fi | ||
| done | ||
| pr=$(gh api "repos/$GH_REPO/commits/$HEAD_SHA/pulls" --jq '.[0].number // empty') | ||
| echo "pr=$pr" >> "$GITHUB_OUTPUT" | ||
| - name: Post the hint | ||
| if: steps.find.outputs.pr != '' | ||
| uses: ./.github/actions/post-pr-comment | ||
| with: | ||
| issue-number: ${{ steps.find.outputs.pr }} | ||
| marker: '<!-- e2e-ios-on-demand -->' | ||
| sections: '["Maintainers: to run the iOS Maestro E2E suites on remote simulators against this pull request, comment `@react-native-bot e2e-tests`"]' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to don't work for forked PRs right? We also can't invoke this with
pull_request_targetas we won't be able to test the code from the user PR then.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like I mentioned in the discussion on the contributors discord, we should be able to checkout the PR head even from the
pull_request_targettrigger, by passing the ref explicitly to the checkout action, while still running the workflow itself from the PR target....but then the build from the fork could access protected scopes (secrets, the OIDC token we create here, or even other OIDC tokens you may have set up), the same goes for the js helper scripts from the E2E flow.
I feel like it should be fine that way, since the only step that has defined access to anything would be the test step (so build cannot exfil any secrets/the token), but you could still try to do something in the maestro tests themselves to get access to Argent Cloud.
Maybe having a maintainer's manual approval for the workflow would be a good way to go about this, so that there's a pair of eyes that can verify there's no attempt to steal the token before the workflow runs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that the best would be to have something like a
@react-native-bot e2e-testscomment that triggers a workflow, running off oftarget_pull_requestwhich runs the tests. That workflow can then pull the .apk/.ipa from the artifacts of the PR and execute it isnide the remote simulator and report the results.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made the changes as suggested.