[build-tools] Humanize Appium command summaries - #4227
Conversation
Translate raw Appium command names (e.g. getWindowRect, getScreenshot)
into short human-readable summaries ("Read the screen size", "Took a
screenshot") for the session event timeline. The raw command is kept in
each event's data.command.
Unknown commands fall back to a camelCase humanizer. A generated snapshot
of @appium/base-driver's command set (added as a devDependency) backs a
coverage test so newly added Appium commands don't slip through
uncategorized.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
6e5841b to
79fc04a
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4227 +/- ##
==========================================
+ Coverage 63.53% 63.73% +0.21%
==========================================
Files 1030 1031 +1
Lines 47253 47452 +199
Branches 9919 9978 +59
==========================================
+ Hits 30017 30241 +224
+ Misses 17135 17110 -25
Partials 101 101 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
- Give every upstream Appium command a curated summary; the coverage test now requires full coverage instead of allowing a fallback list. - Stop humanizing unknown commands: show the raw command name when there is no curated summary, rather than guessing a phrasing. - Add a weekly GitHub Actions workflow that bumps @appium/base-driver, regenerates the command list, and opens a PR so new commands surface (the coverage test then fails until each is given a summary). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ation Drop @appium/base-driver as a devDependency. The generator script now installs it into a temp directory on demand (like repack) and cleans up, so nothing heavy ships with @expo/build-tools. The command list is still committed as a generated snapshot, so tests never need the package. The weekly workflow no longer bumps the dependency (the script always pulls the latest supported base-driver) and requests review from @sjchmiela on the PRs it opens. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the runtime coverage test with type-level assertions: the generated command list is now a readonly tuple (`as const`) and APPIUM_COMMAND_SUMMARIES uses `satisfies`, so `tsc` fails and names any upstream command that lacks a curated summary (and any curated command that is not a real upstream/driver-level one). Also drop the unused `permissions:` block from the workflow — every step authenticates with EXPO_BOT_PAT, so the default GITHUB_TOKEN is unused. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Type APPIUM_COMMAND_SUMMARIES as Record<AppiumCommand, string> so tsc enforces full coverage directly (missing or unknown command -> error), instead of the bespoke AssertNever checks. The generated file now exports a `UpstreamAppiumCommand` union type rather than a runtime const array. Also drop the changelog entry (internal, experimental feature). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
⏩ The changelog entry check has been skipped since the "no changelog" label is present. |
| run: yarn workspace @expo/build-tools generate-appium-commands | ||
| - name: Open a pull request when the command list changed | ||
| env: | ||
| GH_TOKEN: ${{ secrets.EXPO_BOT_PAT }} |
There was a problem hiding this comment.
Isolate dependency execution from EXPO_BOT_PAT
The generator installs the latest Appium and driver packages and then imports them, which executes npm lifecycle scripts and package module code in this job. Limiting GH_TOKEN to this step does not provide isolation: code from an earlier step can modify the same runner—for example, by installing a Git hook that executes during git commit and inherits GH_TOKEN.
Please split this into two jobs: a secretless generate job that uploads only appiumCommands.generated.ts, and a publish job on a fresh runner that downloads and commits that artifact. The publish job should not execute any code from the artifact.
| ]; | ||
|
|
||
| function renderCommandType(typeName, commands) { | ||
| return `export type ${typeName} =\n${commands.map(command => ` | '${command}'`).join('\n')};`; |
There was a problem hiding this comment.
Escape command names when generating TypeScript
command comes from the installed Appium packages and is interpolated directly into a single-quoted TypeScript literal. A command containing a quote, backslash, or newline would produce invalid or injected source.
Please serialize the value instead, for example:
commands.map(command => | ${JSON.stringify(command)})
| * unchanged — we intentionally do not guess a phrasing. | ||
| */ | ||
| export function humanizeAppiumCommand(command: string): string { | ||
| return (APPIUM_COMMAND_SUMMARIES as Record<string, string>)[command] ?? command; |
There was a problem hiding this comment.
Only return own properties from the summary map
This indexed access also searches Object.prototype. Because command is an unconstrained string from the Appium response, values such as toString, constructor, or __proto__ return inherited functions or objects instead of falling back to the raw command. That also violates this function's declared string return type at runtime.
Please check Object.hasOwn(APPIUM_COMMAND_SUMMARIES, command) before reading the value, and add regression tests for at least toString and constructor.
| env: | ||
| GH_TOKEN: ${{ secrets.EXPO_BOT_PAT }} | ||
| run: | | ||
| if git diff --quiet; then |
There was a problem hiding this comment.
Scope change detection to the generated file
This checks the entire tracked working tree, but only appiumCommands.generated.ts is staged below. If dependency installation modifies another tracked file while the generated file is unchanged, this condition proceeds and git commit fails because nothing was staged.
Please scope the check to the generated file:
git diff --quiet -- packages/build-tools/src/steps/utils/appiumCommands.generated.ts
Why
We currently present Appium session events as HTTP methods which is not too human-readable (
getWindowRect).How
Added a GHA workflow which runs weekly and submits a pull request adding to an
AppiumCommandtype so TSC fails and we need to add descriptions to commands.Test Plan
CI should pass.