Skip to content

ci: route Maestro e2e selection through sniffler impact analysis - #7476

Merged
diegolmello merged 5 commits into
developfrom
rich-albertosaurus
Aug 4, 2026
Merged

ci: route Maestro e2e selection through sniffler impact analysis#7476
diegolmello merged 5 commits into
developfrom
rich-albertosaurus

Conversation

@diegolmello

@diegolmello diegolmello commented Jul 9, 2026

Copy link
Copy Markdown
Member

Proposed changes

E2E test selection now runs through sniffler impact analysis, so a regular dev PR only executes the Maestro flows its diff actually touches instead of the full 14-shard suite every time. Release-cut PRs (base master or a release label) still run all 14. The design's hard rule is that under-selection is impossible — every uncertainty (no base ref, shallow clone, sniffler error, unparseable output, a runAllWhenChanged hit, a release lane) falls back to the full suite; the optimization only ever narrows, never risks missing coverage.

CI (build-pr.yml)

  • e2e-shards now runs first and narrows the shard matrix via select-impacted-shards.sh. All six fail-safe guards fall back to the full 14.
  • A confident zero (no impacted flow — e.g. a docs-only PR) sets should_run=false and skips the whole e2e stage: no manual approval, no native build, no flows.
  • A new always() e2e-result job is the single required e2e check: green on a confident-zero skip, green when both run jobs pass, red otherwise. It never hangs "Waiting for status".

Local

  • pnpm e2e:changed <android|ios> runs the impacted flows against a booted device with the app installed. It is working-tree-aware (committed + uncommitted + untracked) and mirrors CI's util / wrong-platform tag excludes.

Coverage + freshness

  • .sniffler/config.json + test-map.json map the runtime-decoupled surface the import graph can't trace: domain sagas anchored to their flows; global sagas, notification/stream routers, navigation stacks, the root container, the store, and the root reducer in runAllWhenChanged.
  • validate-test-map.js (wired into eslint.yml) fails a PR on orphan flows, dangling globs, stale globals, or any uncovered saga/stack, and warns on uncovered views — so the map can't silently rot.

Tests

  • Jest unit tests for the selection tooling — select-impacted-shards.sh, e2e-changed.sh, and validate-test-map.js — so the logic that gates e2e is exercised on every ESLint and Test run, not just verified by hand. A shell harness stubs the external deps (sniffler / git / maestro) on $PATH; per-branch fixture maps drive each validator check.
  • Each validator failure mode (orphan flow, dangling glob, uncovered view, stale global, decoupled gap) has a dedicated fixture, plus a clean-pass fixture.

Other

  • sniffler is pinned to an exact version — it decides what e2e runs, so range drift should be an explicit reviewed change.
  • Fixed an uncovered-view false negative in validate-test-map.js: the prefix match let a view dir cover-match a longer sibling (e.g. SomeView vs SomeViewExtra/**); it now anchors on a trailing slash, with a fixture proving it.
  • .github/README.md updated for the new e2e-shards preflight, the e2e-result required check, and the now-conditional approve_e2e_testing gate.

Issue(s)

https://rocketchat.atlassian.net/browse/NATIVE-1405

How to test or reproduce

CI evidence

Real build-pr.yml runs, exercised on a throwaway branch stacked on this PR (opened/closed as #7477 — do not look for it, it's gone):

Scenario Diff e2e-shards decision Run
Narrow (dev PR) app/views/RoomView/index.tsx should_run=true, matrix narrowed to shards [3,7,9,11,12,13,14] (7 of 14) on both Android + iOS; E2E Hold approved and green 29026229497
Confident-zero skip docs-only (README.md) should_run=false; E2E Hold and the whole e2e stage skipped — no approval, no build, no flows 29025872392
Run-all package.json (this PR's own run) should_run=true, full 14-shard suite queued behind the manual approve_e2e_testing gate 29039554853

The narrow run's shard list is visible directly in the E2E Run Android/iOS (N) matrix job names; the skip run shows E2E Hold and downstream e2e jobs as skipped.

Local verification

Against the live sniffler@0.4.0 binary (exact-restore, nothing left in the tree):

  1. Release laneIS_RELEASE_LANE=true → all 14, short-circuits before sniffler.
  2. Local paritypnpm e2e:changed android on the same RoomView edit → the exact same flows the dev-PR shards cover, no under-selection.
  3. Decoupled surfacesniffler impact on AppContainer.tsx, each nav stack, lib/store/index.ts, reducers/index.js → all select the full 55 flows.
  4. Validatornode .github/scripts/validate-test-map.js → exit 0 (0 errors, 8 uncovered-view warnings); trips to exit 1 on a synthetic orphan / dangling glob / decoupled gap.
  5. Automated suiteTZ=UTC pnpm test --testPathPattern='.github/scripts/__tests__' → all pass; runs as part of the normal ESLint and Test job.

Screenshots

N/A — CI + tooling only, no user-facing UI.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • Improvement (non-breaking change which improves a current function)
  • New feature (non-breaking change which adds functionality)
  • Documentation update (if none of the other choices apply)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

Branch protection: no change required on merge. develop's required checks are license/cla, ESLint and Test, and CodeRabbit — no per-shard or native-build context is required, and e2e gates through a manual approval environment rather than a required status check. So a confident-zero PR can't hang "Waiting for status". Optionally, to make e2e a hard merge gate, add E2E Result to the required checks — it's safe with confident-zero because the job is always() and reports green on a skip. Do not add the per-shard (E2E Run Android (N)…) or native-build contexts: they zero out on a narrowed run. That optional follow-up (to be done only after merge) is tracked in https://rocketchat.atlassian.net/browse/NATIVE-1408.

Seam choice: shard-level narrowing (not per-flow) in CI keeps run-maestro.sh, both maestro-*.yml, and the retry loop untouched — over-selection at shard granularity is acceptable since selection is a dev-speed optimization, never a correctness gate.

Summary by CodeRabbit

  • New Features
    • Added smarter E2E handling that runs only impacted test flows and shards when possible.
    • Added automated test-map and coverage validation to detect missing or outdated mappings.
  • Bug Fixes
    • Improved fallback behavior to run the full E2E suite when impact detection is uncertain.
    • Skips E2E cleanly when no relevant changes are detected.
    • Added consolidated E2E status reporting for clearer CI results.
  • Documentation
    • Updated CI documentation to reflect the new gated E2E flow.

diegolmello and others added 2 commits July 9, 2026 10:05
Regular dev PRs (and local runs) now execute only the Maestro flows
sniffler flags as impacted; release-cut PRs still run the full 14-shard
suite. Under-selection is impossible — every uncertainty falls back to
the full suite.

CI (build-pr.yml):
- e2e-shards runs first and narrows the shard matrix via
  select-impacted-shards.sh (release-lane / no-base / merge-base-fail /
  sniffler-error / bad-JSON / run-all all fall back to full 14).
- A confident zero (no impacted flow, e.g. docs-only) sets
  should_run=false, skipping the whole e2e stage (no approval, no native
  build, no flows).
- New always() e2e-result job is the single required e2e check: green on
  a confident-zero skip, green iff both run jobs pass, red otherwise —
  never hangs "Waiting for status".

Local: pnpm e2e:changed <android|ios> runs the impacted flows against a
booted device, working-tree-aware, mirroring CI's tag excludes.

Coverage: .sniffler config maps runtime-decoupled files the import graph
can't trace — domain sagas anchored to their flows, global sagas /
routers / nav stacks / root container / store / root reducer in
runAllWhenChanged.

Freshness: validate-test-map.js (wired into eslint.yml) fails a PR on
orphan flows, dangling globs, stale globals, or any uncovered saga/stack
(decoupled gap); warns on uncovered views.

NOTE for whoever merges: branch-protection must be reconfigured to
require the e2e-result check and de-require the per-shard + build
contexts, or a confident-zero PR hangs on missing contexts.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8ddbd767-f799-475c-8509-62d6c2014a0d

📥 Commits

Reviewing files that changed from the base of the PR and between 74385d5 and 87f3280.

📒 Files selected for processing (3)
  • .github/README.md
  • .github/workflows/build-pr.yml
  • .github/workflows/eslint.yml
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/eslint.yml
  • .github/README.md
📜 Recent review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: E2E Shard Preflight
  • GitHub Check: format
⚠️ CI failures not shown inline (1)

GitHub Check: Layne Security Scan: Layne — failure

Conclusion: failure

View job details

Found 2 issue(s): 0 critical, 2 high, 0 medium, 0 low.
Blocking findings:
- LAYNE-bad4b10f7ead3086 [semgrep/app.config.semgrep.rules.nodejs.child-process-execution] .github/scripts/__tests__/validate-test-map.test.js:16
- LAYNE-75189201c2aac8e2 [semgrep/app.config.semgrep.rules.nodejs.child-process-execution] .github/scripts/__tests__/validate-test-map.test.js:70
To approve, post a comment:
/layne exception-approve LAYNE-bad4b10f7ead3086 LAYNE-75189201c2aac8e2 reason: <explanation>
🧰 Additional context used
🪛 zizmor (1.29.0)
.github/workflows/build-pr.yml

[warning] 121-121: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)


[warning] 145-145: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)

🔇 Additional comments (1)
.github/workflows/build-pr.yml (1)

12-12: LGTM!

Also applies to: 51-53, 63-65, 72-110, 116-138, 140-162, 164-198


Walkthrough

Adds Sniffler-based impacted-test selection for local E2E runs and CI. It adds test-map validation, scenario coverage, and workflow gates for conditional Maestro execution.

Changes

Impacted E2E selection

Layer / File(s) Summary
Sniffler configuration and test-map data
.sniffler/*, .gitignore, .github/scripts/testlib/fixtures/maps/*, .github/scripts/__tests__/fixtures/flows/*
Defines source roots, run-all triggers, Maestro-to-source mappings, cache handling, and validation fixtures.
Local changed-flow E2E runner
.github/scripts/e2e-changed.sh, .github/scripts/testlib/runScript.js, .github/scripts/__tests__/changed-runner.test.js, package.json
Collects changed paths, selects impacted flows, runs platform-specific Maestro tests, and validates command behavior.
CI impacted-shard selection
.github/scripts/select-impacted-shards.sh, .github/scripts/__tests__/select-impacted-shards.test.js, .github/scripts/__tests__/coverage.test.js, .github/scripts/__tests__/fixtures/scenario-catalog.json
Emits selected shards and should_run, with full-suite fallback, confident-zero skipping, and scenario coverage.
Test-map freshness validation
.github/scripts/validate-test-map.js, .github/scripts/__tests__/validate-test-map.test.js
Checks orphan flows, dangling globs, uncovered views, stale global paths, and decoupled saga or stack files.
CI workflow integration
.github/workflows/build-pr.yml, .github/workflows/eslint.yml, .github/README.md
Adds the E2E preflight, gates Android and iOS jobs, aggregates results, runs map validation, and updates CI documentation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant build_pr as build-pr.yml
  participant select as select-impacted-shards.sh
  participant sniffler as sniffler impact
  participant hold as e2e-hold
  participant e2e as Android/iOS E2E jobs
  participant result as e2e-result

  build_pr->>select: Run E2E preflight
  select->>sniffler: Request impacted tests
  sniffler-->>select: Return recommendedTests
  alt should_run=true
    select-->>build_pr: Emit shards and should_run=true
    build_pr->>hold: Request approval
    hold->>e2e: Run selected platform jobs
    e2e-->>result: Return platform outcomes
  else should_run=false
    select-->>build_pr: Emit empty shards and should_run=false
    build_pr->>result: Skip E2E jobs
  end
  result-->>build_pr: Report aggregate status
Loading

Possibly related PRs

Suggested labels: type: feature

Suggested reviewers: otaviostasiak

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: routing Maestro E2E selection through Sniffler impact analysis.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (2)
  • NATIVE-1405: Request failed with status code 401
  • NATIVE-1408: Request failed with status code 401

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/scripts/select-impacted-shards.sh:
- Around line 46-62: The `select-impacted-shards.sh` logic only checks that
`recommendedTests` exists, so a `null` value can slip through and make the
`.recommendedTests[]` queries in the run-all and paths handling behave like “no
tests,” causing an incorrect confident-zero skip. Update the validation around
the `recommendedTests` check in this script to require that `recommendedTests`
is an array before proceeding, and keep malformed payloads on the
full/emit-false path rather than letting `paths` become empty. Use the existing
`recommendedTests` handling block and the `paths`/`emit` flow to place the type
guard so under-selection cannot happen.

In @.github/scripts/validate-test-map.js:
- Around line 69-70: The uncovered-view check in validate-test-map.js is using a
prefix match that can falsely treat sibling directories as covered. Update the
uncovered calculation around allDependsOn and viewDirs so it only matches an
exact view anchor or a true descendant path, not any string that merely starts
with the directory name. Keep the fix localized to the coverage filter logic and
preserve the intended warning behavior for real uncovered view directories.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9a0aea5b-415f-4839-88ba-cb5624c68c9d

📥 Commits

Reviewing files that changed from the base of the PR and between 1a2c8c6 and 60de378.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (9)
  • .github/scripts/e2e-changed.sh
  • .github/scripts/select-impacted-shards.sh
  • .github/scripts/validate-test-map.js
  • .github/workflows/build-pr.yml
  • .github/workflows/eslint.yml
  • .gitignore
  • .sniffler/config.json
  • .sniffler/test-map.json
  • package.json
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: E2E Shard Preflight
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-02-05T13:55:00.974Z
Learnt from: Rohit3523
Repo: RocketChat/Rocket.Chat.ReactNative PR: 6930
File: package.json:101-101
Timestamp: 2026-02-05T13:55:00.974Z
Learning: In this repository, the dependency on react-native-image-crop-picker should reference the RocketChat fork (RocketChat/react-native-image-crop-picker) with explicit commit pins, not the upstream ivpusic/react-native-image-crop-picker. Update package.json dependencies (and any lockfile) to point to the fork URL and a specific commit, ensuring edge-to-edge Android fixes are included. This pattern should apply to all package.json files in the repo that declare this dependency.

Applied to files:

  • package.json
📚 Learning: 2026-05-07T17:47:14.516Z
Learnt from: diegolmello
Repo: RocketChat/Rocket.Chat.ReactNative PR: 7303
File: package.json:5-5
Timestamp: 2026-05-07T17:47:14.516Z
Learning: When reviewing pnpm `packageManager` version pins in any `package.json` (e.g., `"packageManager": "pnpm@<version>"`), don’t rely solely on web-search results to determine whether a version exists. For very recently published versions, cross-check the target version against the official pnpm release page (https://github.com/pnpm/pnpm/releases) and the npm registry page for pnpm (https://www.npmjs.com/package/pnpm) before flagging the pinned version as non-existent.

Applied to files:

  • package.json
🪛 ast-grep (0.44.1)
.github/scripts/validate-test-map.js

[warning] 34-34: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(TEST_MAP_PATH, 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename)


[warning] 35-35: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(CONFIG_PATH, 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename)


[warning] 40-40: Filesystem path is not a string literal; a request-/variable-derived path can enable path traversal. Validate and normalize the path before use.
Context: fs.readFileSync(f, 'utf8')
Note: [CWE-22] Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal').

(detect-non-literal-fs-filename)

🪛 zizmor (1.26.1)
.github/workflows/build-pr.yml

[warning] 74-77: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[warning] 107-107: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)


[warning] 127-127: secrets unconditionally inherited by called workflow (secrets-inherit): this reusable workflow

(secrets-inherit)

🔇 Additional comments (8)
.github/scripts/e2e-changed.sh (1)

1-54: LGTM!

package.json (2)

22-22: LGTM!


216-220: Check sniffler's published version
package.json pins sniffler to ^0.4.0, and the lockfile currently resolves sniffler@0.4.0. Keep this only if that release is the intended published version.

.sniffler/config.json (1)

1-33: LGTM!

.sniffler/test-map.json (1)

1-336: LGTM!

.gitignore (1)

98-98: LGTM!

.github/workflows/build-pr.yml (1)

63-177: LGTM!

.github/workflows/eslint.yml (1)

22-24: LGTM!

Comment thread .github/scripts/select-impacted-shards.sh
Comment thread .github/scripts/validate-test-map.js Outdated
- Add unit tests for select-impacted-shards.sh, e2e-changed.sh and
  validate-test-map.js: per-branch fixture maps plus a shell harness
  that stubs external deps (sniffler/git/maestro) on $PATH. They wire
  into the existing jest run, so CI's ESLint-and-test job exercises the
  selection tooling the PR previously only verified by hand.
- Fix an uncovered-view false negative in validate-test-map.js: the
  prefix match let a view dir cover-match a longer dir (SomeView vs
  SomeViewExtra/**); anchor it on a trailing slash. Add a fixture that
  proves it.
- Add a TESTMAP_ROOT override so the validator can run against fixtures.
- Pin sniffler to an exact version: it gates what e2e runs, so range
  drift should be an explicit reviewed change (matches fast-glob's pin).
- Update .github/README.md for the new e2e-shards preflight, the
  e2e-result required check, and the conditional approve_e2e_testing gate.

@coderabbitai coderabbitai Bot left a comment

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.

🧹 Nitpick comments (1)
.github/scripts/testlib/runScript.js (1)

45-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider escaping the key before interpolating into the RegExp.

The get function interpolates key directly into a RegExp constructor. Current callers only pass shards and should_run (no metacharacters), so this is safe today. Adding a simple escape would future-proof the helper against accidental misuse.

♻️ Optional refactor
 const get = key => {
-  const m = output.match(new RegExp(`^${key}=(.*)$`, 'm'));
+  const escaped = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+  const m = output.match(new RegExp(`^${escaped}=(.*)$`, 'm'));
   return m ? m[1] : undefined;
 };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/scripts/testlib/runScript.js around lines 45 - 48, The get helper in
runScript.js interpolates key directly into the RegExp pattern, so update that
lookup logic to escape any regex metacharacters in key before building the
expression. Keep the change scoped to the get function so callers like the
shards and should_run lookups continue to work, but future keys cannot
accidentally change the match behavior. Ensure the escaped key is used in the
RegExp constructor and the rest of the parsing logic stays the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/scripts/testlib/runScript.js:
- Around line 45-48: The get helper in runScript.js interpolates key directly
into the RegExp pattern, so update that lookup logic to escape any regex
metacharacters in key before building the expression. Keep the change scoped to
the get function so callers like the shards and should_run lookups continue to
work, but future keys cannot accidentally change the match behavior. Ensure the
escaped key is used in the RegExp constructor and the rest of the parsing logic
stays the same.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c0bdd7dc-adbf-47db-b80f-ed91a78bf69f

📥 Commits

Reviewing files that changed from the base of the PR and between 60de378 and 74385d5.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (42)
  • .github/README.md
  • .github/scripts/__tests__/changed-runner.test.js
  • .github/scripts/__tests__/coverage.test.js
  • .github/scripts/__tests__/fixtures/flows/no-tag.yaml
  • .github/scripts/__tests__/fixtures/scenario-catalog.json
  • .github/scripts/__tests__/select-impacted-shards.test.js
  • .github/scripts/__tests__/validate-test-map.test.js
  • .github/scripts/testlib/fixtures/maps/clean-pass/.maestro/tests/foo.yaml
  • .github/scripts/testlib/fixtures/maps/clean-pass/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/clean-pass/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/sagas/foo.js
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/stacks/bar.tsx
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/views/Foo/placeholder.txt
  • .github/scripts/testlib/fixtures/maps/dangling-glob/.maestro/tests/.gitkeep
  • .github/scripts/testlib/fixtures/maps/dangling-glob/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/dangling-glob/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/dangling-glob/app/views/.gitkeep
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/.maestro/tests/.gitkeep
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/app/sagas/foo.js
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/app/views/.gitkeep
  • .github/scripts/testlib/fixtures/maps/orphan-flow/.maestro/tests/orphan.yaml
  • .github/scripts/testlib/fixtures/maps/orphan-flow/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/orphan-flow/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/orphan-flow/app/views/.gitkeep
  • .github/scripts/testlib/fixtures/maps/prefix-collision/.maestro/tests/some.yaml
  • .github/scripts/testlib/fixtures/maps/prefix-collision/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/prefix-collision/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/prefix-collision/app/views/SomeView/placeholder.txt
  • .github/scripts/testlib/fixtures/maps/prefix-collision/app/views/SomeViewExtra/placeholder.txt
  • .github/scripts/testlib/fixtures/maps/stale-global/.maestro/tests/.gitkeep
  • .github/scripts/testlib/fixtures/maps/stale-global/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/stale-global/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/stale-global/app/views/.gitkeep
  • .github/scripts/testlib/fixtures/maps/uncovered-view/.maestro/tests/.gitkeep
  • .github/scripts/testlib/fixtures/maps/uncovered-view/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/uncovered-view/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/uncovered-view/app/views/SomeView/placeholder.txt
  • .github/scripts/testlib/runScript.js
  • .github/scripts/validate-test-map.js
  • package.json
✅ Files skipped from review due to trivial changes (18)
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/stale-global/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/uncovered-view/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/prefix-collision/.maestro/tests/some.yaml
  • .github/scripts/testlib/fixtures/maps/clean-pass/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/stacks/bar.tsx
  • .github/scripts/testlib/fixtures/maps/uncovered-view/app/views/SomeView/placeholder.txt
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/sagas/foo.js
  • .github/scripts/testlib/fixtures/maps/prefix-collision/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/clean-pass/app/views/Foo/placeholder.txt
  • .github/scripts/testlib/fixtures/maps/stale-global/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/clean-pass/.maestro/tests/foo.yaml
  • .github/scripts/testlib/fixtures/maps/dangling-glob/.sniffler/test-map.json
  • .github/scripts/testlib/fixtures/maps/orphan-flow/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/dangling-glob/.sniffler/config.json
  • .github/scripts/testlib/fixtures/maps/orphan-flow/.maestro/tests/orphan.yaml
  • .github/scripts/testlib/fixtures/maps/decoupled-gap/app/sagas/foo.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • .github/scripts/validate-test-map.js
📜 Review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: E2E Shard Preflight
  • GitHub Check: ESLint and Test / run-eslint-and-test
  • GitHub Check: format
🔇 Additional comments (12)
.github/scripts/__tests__/fixtures/flows/no-tag.yaml (1)

1-5: LGTM!

.github/scripts/__tests__/fixtures/scenario-catalog.json (1)

1-164: LGTM!

.github/scripts/testlib/fixtures/maps/clean-pass/.sniffler/test-map.json (1)

1-7: LGTM!

.github/scripts/__tests__/select-impacted-shards.test.js (1)

1-187: LGTM!

.github/scripts/__tests__/coverage.test.js (1)

1-93: LGTM!

.github/scripts/__tests__/validate-test-map.test.js (1)

1-74: LGTM!

.github/scripts/testlib/fixtures/maps/orphan-flow/.sniffler/test-map.json (1)

1-1: LGTM!

.github/scripts/testlib/fixtures/maps/prefix-collision/.sniffler/test-map.json (1)

1-6: LGTM!

.github/scripts/testlib/fixtures/maps/uncovered-view/.sniffler/test-map.json (1)

1-1: LGTM!

.github/scripts/__tests__/changed-runner.test.js (1)

1-198: LGTM!

.github/README.md (2)

9-9: 📐 Maintainability & Code Quality

Document the release-cut full-suite bypass. The CI docs should mention the release-cut path (master / release label) runs the full 14-shard suite instead of the sniffler-selected subset.


48-63: Outdated E2E job names in the diagram. The current workflow uses e2e-run-android and e2e-run-ios, not e2e-result, so the missing-edge concern no longer applies.

			> Likely an incorrect or invalid review comment.

@julio-rocketchat

Copy link
Copy Markdown
Member

/layne exception-approve LAYNE-bad4b10f7ead3086 LAYNE-75189201c2aac8e2 reason: hardcoded scripts

@rc-layne

rc-layne Bot commented Aug 4, 2026

Copy link
Copy Markdown

✅ Exception recorded for LAYNE-bad4b10f7ead3086, LAYNE-75189201c2aac8e2 by @julio-rocketchat: "hardcoded scripts". Re-running scan...

@diegolmello
diegolmello merged commit 576377d into develop Aug 4, 2026
8 of 11 checks passed
@diegolmello
diegolmello deleted the rich-albertosaurus branch August 4, 2026 20:38
diegolmello added a commit that referenced this pull request Aug 31, 2026
* fix: render mentions, emojis, and inline elements inside headings (#6911)

* chore: OXC (#7515)

* chore: replace ESLint with Oxlint

Migrate linting from ESLint 8 to Oxlint. `pnpm lint` drops from ~1min to
~0.6s and 17 eslint packages are removed from devDependencies.

Config lives in `.oxlintrc.json`, generated with `@oxlint/migrate` from the
old `.eslintrc.js` and then tuned:

- `eslint-plugin-react-native` is loaded through `jsPlugins`, since Oxlint has
  no built-in equivalent.
- `import/extensions` is off. Its old options (`js: 'warning'`, ...) were not
  valid values for the rule, so it never reported anything under ESLint.
- `no-unused-vars` sets `caughtErrors: 'none'` to match the ESLint 8 default.
- `import/no-cycle` and the React Compiler rules report as warnings. They
  surface findings ESLint never showed, so they are not gated yet.

Rules with no Oxlint equivalent are dropped: `no-restricted-syntax` (the ban
on `React.*` member syntax), `import/order`, `import/no-unresolved` and
`import/named`.

ESLint 8 skipped dot-directories, so files under `.rnstorybook/` and
`.maestro/` were never linted. Oxlint does lint them, which surfaced four
violations that are fixed here.

The CI workflow keeps its filename and job id so branch protection checks
stay valid.

* chore: replace Prettier with Oxfmt

Migrate formatting from Prettier 2.8.8 to Oxfmt via `oxfmt --migrate prettier`.

- `.oxfmtrc.json` carries every previous Prettier option unchanged (tabs,
  single quotes, printWidth 130, no trailing comma, avoid arrow parens,
  bracketSameLine) plus the `.prettierignore` patterns as `ignorePatterns`.
  `sortPackageJson` is disabled to match previous behavior.
- `.prettierrc.js` and `.prettierignore` removed; `prettier` dropped from
  devDependencies.
- `prettier-lint` script renamed to `format-lint` and now runs `oxfmt`.
- 44 files reformatted: Oxfmt follows Prettier 3 style, so nested ternaries
  and `extends`/type-argument wrapping indent differently than under
  Prettier 2. No semantic changes.
- prettier.yml still ran `eslint --fix`, missed in the Oxlint migration; it
  now runs `oxfmt` and `oxlint --fix`. `react/exhaustive-deps` is allowed
  there because its autofix rewrites dependency arrays, which changes
  behavior and must not land unreviewed from CI.
- Workflow filename kept as prettier.yml to avoid disturbing branch
  protection checks, same as eslint.yml.

Verified: `pnpm lint` exit 0 (0 errors), `tsc` clean, 217/217 suites and
2032/2032 tests pass, `oxfmt --check` clean.

* chore: update lockfile for oxfmt

* chore: migrate typecheck to TypeScript 7.0 (#7516)

* chore: bump TypeScript to 6.0

Baseline hop ahead of the TypeScript 7.0 (native compiler) migration, so the
7.0 cut is a version swap against a config that is already 7.0-shaped.

TypeScript 6.0 raises both `moduleResolution: node10` and `baseUrl` as errors
rather than warnings, and `ignoreDeprecations: "6.0"` stops working in 7.0, so
clearing them properly is the only route:

- `moduleResolution` -> `bundler` (Metro is a bundler), which requires an
  esnext-shaped `module`.
- `baseUrl` removed. Exactly one import relied on it; it is now relative.
- `types` enumerated, since a resolution mode that honours package `exports`
  no longer auto-includes every `@types` package. `@types/node` becomes an
  explicit devDependency.

Honouring `exports` also stranded the bundled `.d.ts` of three dependencies
whose maps expose only JavaScript. Each gets a `types` condition via
patch-package; this is visible to the type checker only, as Metro ignores that
condition. A `paths` mapping was tried first and rejected, because the
jest-expo resolver reads `paths` and then loads those `.d.ts` files at runtime.

The inherited block of commented-out option documentation is dropped.

* chore: migrate typecheck to TypeScript 7.0

Replaces TypeScript 6.0.3 with the native Go compiler. The version is pinned
exactly, since the platform binaries ship as version-matched optional
dependencies; the lockfile records the linux-x64 target CI resolves.

Typecheck wall time drops from 5.77s on 5.9.3 to ~1.0s. No configuration
change was required: the 6.0 hop already left tsconfig in a 7.0-shaped state,
and the default parallelism saturates without `--checkers`.

`@react-navigation/core` needs a patch to type-check. TypeScript 7.0.2
resolves the mutual recursion between `StaticParamList` and
`ParamListForScreens` eagerly where earlier versions defer it, reports the
alias as circular, and degrades it to a non-generic symbol -- surfacing as
`TS2315: Type 'StaticParamList' is not generic` at our call sites. The patch
drops a `FlatType<>` wrapper from the alias, which only flattens intersections
for editor display, so the type is unchanged and the misfire stops.

* chore: Bump version to 4.76.0 (#7542)

* chore(ci): apply least privilege permission to GitHub Actions (#7350)

* chore: switch React Compiler to infer mode (#7545)

* ci: route Maestro e2e selection through sniffler impact analysis (#7476)

* fix(iOS): RoomItem Swipe not working after scroll (#7532)

* fix(ci): select shards for changes outside app and honor the release label (#7555)

* fix: delete background taller than its row on ServersHistory (#7536)

* fix: delete background taller than its row on server items

* chore: code improvements

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>

* fix: UIKit block messages rendering with smaller font size (#7531)

* fix: UIKit block messages rendering with smaller font size

* fix: snapshot

* fix(db): move deleteMessage finds and prepares inside the writer lock (#7550)

* fix: quote has no effect on older thread messages (#7535)

* fix: Quote has no effect on older thread messages

* fix: Quote has no effect on older thread messages

* chore: e2e test

* fix: e2e test

* chore: format code and fix lint issues

* fix(MessageComposer): resolve quoted thread messages and guard stale lookups

* fix: test

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(db): move persistMessage lookups and prepares inside the writer lock (#7551)

* fix:  test case 11 and 12 flaky tests (#7564)

* fix: test

* fix: room last messa test

* fix: jumptomessage test

* chore: remove comments

* fix: jump to message e2e test iOS

* remove unused comment

* fix(db): move sendMessage reads and prepares inside the writer lock (#7546)

* fix(db): move sendMessage reads and prepares inside the writer lock

* fix: test improvements

* chore: remove comments

* fix: Admin Panel content hidden behind bottom navigation bar (#7538)

* feat: add tabular numbers (#7568)

* feat: tabular numbers across the app, upgrade Inter to 4.1

* update snapshot

* chore: pin @rocket.chat/sdk to a specific commit hash (#7569)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE (#7554)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE

* code improvements

* removed unused comment

* fix: run handleDelete finds and prepares inside the writer lock (#7552)

* fix: run handleDelete finds and prepares inside the writer lock

* chore: reuse mockWMDB

* fix: crop screen hidden behind navigation bar on iOS 26 (#7529)

* fix: re-fetch message inside the write in getThreadName (#7557)

* fix: re-fetch message inside the write in getThreadName

* fix: re-fetch message inside the write in getThreadName

* chore: new test cases

* remove unecessary async

* fix(db): move decryptPendingMessages prepares inside the writer lock (#7548)

* fix(db): move decryptPendingMessages prepares inside the writer lock

* code improvements

* chore: new test case encryption

* chore: format code and fix lint issues

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(android): VideoConf notification accept and decline button hidden and touch not working (#7533)

* fix: in-app notification buttons ignoring taps on Android

* fix: Decline and Accept invisible on the incoming call notification

* fix: UIKit buttons not responding on some Android devices (#7573)

* fix: force Google account chooser on OAuth login (#7572)

* fix: ISO format support in markdown component (#6943)

* fix: resolve deep links by room id for channels and groups (#7111)

* Merge pull request #7570 from RocketChat/deeplink-saml-auth

feat: SAML deeplink auth

* fix: grant pull-requests write to build call sites in build-develop (#7599)

The reusable workflows build-android.yml and build-ios.yml declare
pull-requests: write on their upload jobs. GitHub validates these at
call time regardless of job conditionals, so build-develop.yml
(caller) must grant the permission or the workflow fails validation.
build-pr.yml already grants it; this mirrors that.

---------

Co-authored-by: Rohit Bansal <40559587+Rohit3523@users.noreply.github.com>
Co-authored-by: Yasmim Nagat <117310290+yasnagat@users.noreply.github.com>
Co-authored-by: Otávio Stasiak <91474186+OtavioStasiak@users.noreply.github.com>
Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>
Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
diegolmello added a commit that referenced this pull request Aug 31, 2026
* fix: render mentions, emojis, and inline elements inside headings (#6911)

* chore: OXC (#7515)

* chore: replace ESLint with Oxlint

Migrate linting from ESLint 8 to Oxlint. `pnpm lint` drops from ~1min to
~0.6s and 17 eslint packages are removed from devDependencies.

Config lives in `.oxlintrc.json`, generated with `@oxlint/migrate` from the
old `.eslintrc.js` and then tuned:

- `eslint-plugin-react-native` is loaded through `jsPlugins`, since Oxlint has
  no built-in equivalent.
- `import/extensions` is off. Its old options (`js: 'warning'`, ...) were not
  valid values for the rule, so it never reported anything under ESLint.
- `no-unused-vars` sets `caughtErrors: 'none'` to match the ESLint 8 default.
- `import/no-cycle` and the React Compiler rules report as warnings. They
  surface findings ESLint never showed, so they are not gated yet.

Rules with no Oxlint equivalent are dropped: `no-restricted-syntax` (the ban
on `React.*` member syntax), `import/order`, `import/no-unresolved` and
`import/named`.

ESLint 8 skipped dot-directories, so files under `.rnstorybook/` and
`.maestro/` were never linted. Oxlint does lint them, which surfaced four
violations that are fixed here.

The CI workflow keeps its filename and job id so branch protection checks
stay valid.

* chore: replace Prettier with Oxfmt

Migrate formatting from Prettier 2.8.8 to Oxfmt via `oxfmt --migrate prettier`.

- `.oxfmtrc.json` carries every previous Prettier option unchanged (tabs,
  single quotes, printWidth 130, no trailing comma, avoid arrow parens,
  bracketSameLine) plus the `.prettierignore` patterns as `ignorePatterns`.
  `sortPackageJson` is disabled to match previous behavior.
- `.prettierrc.js` and `.prettierignore` removed; `prettier` dropped from
  devDependencies.
- `prettier-lint` script renamed to `format-lint` and now runs `oxfmt`.
- 44 files reformatted: Oxfmt follows Prettier 3 style, so nested ternaries
  and `extends`/type-argument wrapping indent differently than under
  Prettier 2. No semantic changes.
- prettier.yml still ran `eslint --fix`, missed in the Oxlint migration; it
  now runs `oxfmt` and `oxlint --fix`. `react/exhaustive-deps` is allowed
  there because its autofix rewrites dependency arrays, which changes
  behavior and must not land unreviewed from CI.
- Workflow filename kept as prettier.yml to avoid disturbing branch
  protection checks, same as eslint.yml.

Verified: `pnpm lint` exit 0 (0 errors), `tsc` clean, 217/217 suites and
2032/2032 tests pass, `oxfmt --check` clean.

* chore: update lockfile for oxfmt

* chore: migrate typecheck to TypeScript 7.0 (#7516)

* chore: bump TypeScript to 6.0

Baseline hop ahead of the TypeScript 7.0 (native compiler) migration, so the
7.0 cut is a version swap against a config that is already 7.0-shaped.

TypeScript 6.0 raises both `moduleResolution: node10` and `baseUrl` as errors
rather than warnings, and `ignoreDeprecations: "6.0"` stops working in 7.0, so
clearing them properly is the only route:

- `moduleResolution` -> `bundler` (Metro is a bundler), which requires an
  esnext-shaped `module`.
- `baseUrl` removed. Exactly one import relied on it; it is now relative.
- `types` enumerated, since a resolution mode that honours package `exports`
  no longer auto-includes every `@types` package. `@types/node` becomes an
  explicit devDependency.

Honouring `exports` also stranded the bundled `.d.ts` of three dependencies
whose maps expose only JavaScript. Each gets a `types` condition via
patch-package; this is visible to the type checker only, as Metro ignores that
condition. A `paths` mapping was tried first and rejected, because the
jest-expo resolver reads `paths` and then loads those `.d.ts` files at runtime.

The inherited block of commented-out option documentation is dropped.

* chore: migrate typecheck to TypeScript 7.0

Replaces TypeScript 6.0.3 with the native Go compiler. The version is pinned
exactly, since the platform binaries ship as version-matched optional
dependencies; the lockfile records the linux-x64 target CI resolves.

Typecheck wall time drops from 5.77s on 5.9.3 to ~1.0s. No configuration
change was required: the 6.0 hop already left tsconfig in a 7.0-shaped state,
and the default parallelism saturates without `--checkers`.

`@react-navigation/core` needs a patch to type-check. TypeScript 7.0.2
resolves the mutual recursion between `StaticParamList` and
`ParamListForScreens` eagerly where earlier versions defer it, reports the
alias as circular, and degrades it to a non-generic symbol -- surfacing as
`TS2315: Type 'StaticParamList' is not generic` at our call sites. The patch
drops a `FlatType<>` wrapper from the alias, which only flattens intersections
for editor display, so the type is unchanged and the misfire stops.

* chore: Bump version to 4.76.0 (#7542)

* chore(ci): apply least privilege permission to GitHub Actions (#7350)

* chore: switch React Compiler to infer mode (#7545)

* ci: route Maestro e2e selection through sniffler impact analysis (#7476)

* fix(iOS): RoomItem Swipe not working after scroll (#7532)

* fix(ci): select shards for changes outside app and honor the release label (#7555)

* fix: delete background taller than its row on ServersHistory (#7536)

* fix: delete background taller than its row on server items

* chore: code improvements

---------

Co-authored-by: Diego Mello <diegolmello@gmail.com>

* fix: UIKit block messages rendering with smaller font size (#7531)

* fix: UIKit block messages rendering with smaller font size

* fix: snapshot

* fix(db): move deleteMessage finds and prepares inside the writer lock (#7550)

* fix: quote has no effect on older thread messages (#7535)

* fix: Quote has no effect on older thread messages

* fix: Quote has no effect on older thread messages

* chore: e2e test

* fix: e2e test

* chore: format code and fix lint issues

* fix(MessageComposer): resolve quoted thread messages and guard stale lookups

* fix: test

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(db): move persistMessage lookups and prepares inside the writer lock (#7551)

* fix:  test case 11 and 12 flaky tests (#7564)

* fix: test

* fix: room last messa test

* fix: jumptomessage test

* chore: remove comments

* fix: jump to message e2e test iOS

* remove unused comment

* fix(db): move sendMessage reads and prepares inside the writer lock (#7546)

* fix(db): move sendMessage reads and prepares inside the writer lock

* fix: test improvements

* chore: remove comments

* fix: Admin Panel content hidden behind bottom navigation bar (#7538)

* feat: add tabular numbers (#7568)

* feat: tabular numbers across the app, upgrade Inter to 4.1

* update snapshot

* chore: pin @rocket.chat/sdk to a specific commit hash (#7569)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE (#7554)

* fix(e2ee): re-fetch subscription inside the write in toggleRoomE2EE

* code improvements

* removed unused comment

* fix: run handleDelete finds and prepares inside the writer lock (#7552)

* fix: run handleDelete finds and prepares inside the writer lock

* chore: reuse mockWMDB

* fix: crop screen hidden behind navigation bar on iOS 26 (#7529)

* fix: re-fetch message inside the write in getThreadName (#7557)

* fix: re-fetch message inside the write in getThreadName

* fix: re-fetch message inside the write in getThreadName

* chore: new test cases

* remove unecessary async

* fix(db): move decryptPendingMessages prepares inside the writer lock (#7548)

* fix(db): move decryptPendingMessages prepares inside the writer lock

* code improvements

* chore: new test case encryption

* chore: format code and fix lint issues

---------

Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>

* fix(android): VideoConf notification accept and decline button hidden and touch not working (#7533)

* fix: in-app notification buttons ignoring taps on Android

* fix: Decline and Accept invisible on the incoming call notification

* fix: UIKit buttons not responding on some Android devices (#7573)

* fix: force Google account chooser on OAuth login (#7572)

* fix: ISO format support in markdown component (#6943)

* fix: resolve deep links by room id for channels and groups (#7111)

* Merge pull request #7570 from RocketChat/deeplink-saml-auth

feat: SAML deeplink auth

* fix: grant pull-requests write to build call sites in build-develop (#7599)

The reusable workflows build-android.yml and build-ios.yml declare
pull-requests: write on their upload jobs. GitHub validates these at
call time regardless of job conditionals, so build-develop.yml
(caller) must grant the permission or the workflow fails validation.
build-pr.yml already grants it; this mirrors that.

---------

Co-authored-by: Rohit Bansal <40559587+Rohit3523@users.noreply.github.com>
Co-authored-by: Yasmim Nagat <117310290+yasnagat@users.noreply.github.com>
Co-authored-by: Otávio Stasiak <91474186+OtavioStasiak@users.noreply.github.com>
Co-authored-by: OtavioStasiak <OtavioStasiak@users.noreply.github.com>
Co-authored-by: Yash Rajpal <58601732+yash-rajpal@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants