-
Notifications
You must be signed in to change notification settings - Fork 47
Add Docker image, multi-arch publish workflow, and usage guide #143
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
Changes from all commits
e64f309
94cd35e
8385848
bada4ac
2af8c6c
f100f0f
7e319cd
b0902d3
f7aee42
dfcb413
25ae845
bbd3356
ed6f46f
3501d6e
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,11 @@ | ||
| node_modules | ||
| .git | ||
| dist | ||
| *.log | ||
| coverage | ||
| playwright-report | ||
| test-results | ||
| .env | ||
| docs/superpowers | ||
| .DS_Store | ||
| *.tsbuildinfo |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,115 @@ | ||
| name: Publish Docker Image | ||
|
|
||
| on: | ||
| workflow_run: | ||
| workflows: ["Publish to npm"] | ||
| types: | ||
| - completed | ||
|
|
||
| jobs: | ||
| build-amd64: | ||
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| ref: ${{ github.event.workflow_run.head_sha }} | ||
| fetch-depth: 0 | ||
| - uses: docker/login-action@v3 | ||
Check failureCode scanning / CodeQL Checkout of untrusted code in a privileged context High
Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run Error loading related location Loading |
||
|
Comment on lines
+17
to
+21
|
||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Set version | ||
| id: version | ||
| run: | | ||
| TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }}) | ||
| echo "value=${TAG#v}" >> $GITHUB_OUTPUT | ||
| - uses: docker/setup-buildx-action@v3 | ||
| - uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| push: true | ||
| provenance: false | ||
| platforms: linux/amd64 | ||
| tags: ghcr.io/mobile-next/mobilewright:${{ steps.version.outputs.value }}-amd64 | ||
| build-args: MOBILEWRIGHT_VERSION=${{ steps.version.outputs.value }} | ||
|
|
||
| build-arm64: | ||
| if: ${{ github.event.workflow_run.conclusion == 'success' }} | ||
| runs-on: ubuntu-24.04-arm | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| ref: ${{ github.event.workflow_run.head_sha }} | ||
| fetch-depth: 0 | ||
| - uses: docker/login-action@v3 | ||
Check failureCode scanning / CodeQL Checkout of untrusted code in a privileged context High
Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines
+48
to
+52
|
||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Set version | ||
| id: version | ||
| run: | | ||
| TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }}) | ||
| echo "value=${TAG#v}" >> $GITHUB_OUTPUT | ||
| - uses: docker/setup-buildx-action@v3 | ||
| - uses: docker/build-push-action@v6 | ||
| with: | ||
| context: . | ||
| push: true | ||
| provenance: false | ||
| platforms: linux/arm64 | ||
| tags: ghcr.io/mobile-next/mobilewright:${{ steps.version.outputs.value }}-arm64 | ||
| build-args: MOBILEWRIGHT_VERSION=${{ steps.version.outputs.value }} | ||
|
|
||
| manifest: | ||
| runs-on: ubuntu-24.04 | ||
| needs: [build-amd64, build-arm64] | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| id-token: write | ||
| attestations: write | ||
| steps: | ||
| - uses: actions/checkout@v5 | ||
| with: | ||
| ref: ${{ github.event.workflow_run.head_sha }} | ||
| fetch-depth: 0 | ||
| - uses: docker/login-action@v3 | ||
Check failureCode scanning / CodeQL Checkout of untrusted code in a privileged context High
Checkout of untrusted code in a privileged workflow with later potential execution (event trigger:
workflow_run Error loading related location Loading |
||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
Comment on lines
+81
to
+85
|
||
| with: | ||
| registry: ghcr.io | ||
| username: ${{ github.actor }} | ||
| password: ${{ secrets.GITHUB_TOKEN }} | ||
| - name: Set version | ||
| id: version | ||
| run: | | ||
| TAG=$(git describe --tags --exact-match ${{ github.event.workflow_run.head_sha }}) | ||
| echo "value=${TAG#v}" >> $GITHUB_OUTPUT | ||
| - uses: docker/setup-buildx-action@v3 | ||
| - name: Create and push multi-arch manifest | ||
| run: | | ||
| VERSION=${{ steps.version.outputs.value }} | ||
| IMAGE=ghcr.io/mobile-next/mobilewright | ||
| docker buildx imagetools create \ | ||
| --tag "${IMAGE}:${VERSION}" \ | ||
| --tag "${IMAGE}:latest" \ | ||
| "${IMAGE}:${VERSION}-amd64" \ | ||
| "${IMAGE}:${VERSION}-arm64" | ||
| - name: Resolve manifest digest | ||
| id: digest | ||
| run: | | ||
| IMAGE=ghcr.io/mobile-next/mobilewright | ||
| DIGEST=$(docker buildx imagetools inspect "${IMAGE}:${{ steps.version.outputs.value }}" --format '{{.Manifest.Digest}}') | ||
| echo "value=${DIGEST}" >> $GITHUB_OUTPUT | ||
| - uses: actions/attest-build-provenance@v2 | ||
| with: | ||
| subject-name: ghcr.io/mobile-next/mobilewright | ||
| subject-digest: ${{ steps.digest.outputs.value }} | ||
| push-to-registry: true | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| FROM ubuntu:jammy | ||
|
|
||
| ARG DEBIAN_FRONTEND=noninteractive | ||
| ARG TZ=America/Los_Angeles | ||
| ARG NODE_VERSION=24 | ||
| ARG MOBILEWRIGHT_VERSION=latest | ||
|
|
||
| ENV LANG=C.UTF-8 | ||
| ENV LC_ALL=C.UTF-8 | ||
|
|
||
| # Install base deps, Node.js, and ADB client in a single layer | ||
| RUN apt-get update && \ | ||
| apt-get install -y --no-install-recommends curl gpg ca-certificates && \ | ||
| mkdir -p /etc/apt/keyrings && \ | ||
| curl -sL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg && \ | ||
| echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_VERSION}.x nodistro main" >> /etc/apt/sources.list.d/nodesource.list && \ | ||
| apt-get update && \ | ||
| apt-get install -y --no-install-recommends nodejs android-tools-adb && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| # Point ADB client at the host's ADB server. | ||
| # host.docker.internal resolves natively on macOS/Windows Docker Desktop. | ||
| # On Linux, pass --add-host=host.docker.internal:host-gateway to docker run. | ||
| ENV ANDROID_ADB_SERVER_HOST=host.docker.internal | ||
| ENV ANDROID_ADB_SERVER_PORT=5037 | ||
|
|
||
| # ADB does not natively read ANDROID_ADB_SERVER_HOST. This wrapper injects | ||
| # -H/-P so every adb call (doctor, mobilecli, etc.) reaches the host's server. | ||
| RUN printf '#!/bin/sh\nexec /usr/bin/adb -H "${ANDROID_ADB_SERVER_HOST:-127.0.0.1}" -P "${ANDROID_ADB_SERVER_PORT:-5037}" "$@"\n' \ | ||
| > /usr/local/bin/adb && chmod +x /usr/local/bin/adb | ||
|
|
||
| # Install mobilewright CLI globally (mobilecli binaries for all arches are | ||
| # bundled inside the mobilecli npm package — no optionalDependencies needed) | ||
| RUN npm install -g mobilewright@${MOBILEWRIGHT_VERSION} && \ | ||
| npm cache clean --force | ||
|
|
||
| # Non-root user (activated, unlike Playwright which only creates pwuser) | ||
| RUN adduser --disabled-password --gecos "" mwuser | ||
|
|
||
| USER mwuser | ||
| WORKDIR /home/mwuser | ||
|
|
||
| ENTRYPOINT ["mobilewright"] |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| --- | ||
| sidebar_position: 4 | ||
| title: Docker | ||
| --- | ||
|
|
||
| # Docker | ||
|
|
||
| The `ghcr.io/mobile-next/mobilewright` Docker image runs `mobilewright` commands inside a container — without installing Node.js or the Android SDK on your machine. It works two ways: | ||
|
|
||
| - **Local Android emulator** — connects to an emulator running on your host via ADB. | ||
| - **Cloud devices** — connects to real Android and iOS devices on [Mobile Next Cloud](https://mobilenext.ai). | ||
|
|
||
| The container runs Linux and cannot reach an iOS simulator running on your Mac host. To test iOS, use cloud devices. | ||
|
|
||
| ## Local Android emulator | ||
|
|
||
| The image ships the ADB client and points it at the ADB server running on your host, so an emulator started on your machine is visible inside the container. | ||
|
|
||
| ### Run `doctor` | ||
|
|
||
| Use `doctor` to verify the container can reach your host's ADB server. | ||
|
|
||
| #### macOS and Windows | ||
|
|
||
| `host.docker.internal` resolves automatically in Docker Desktop — no extra flags needed: | ||
|
|
||
| ```bash | ||
| docker run --rm ghcr.io/mobile-next/mobilewright doctor | ||
| ``` | ||
|
|
||
| #### Linux | ||
|
|
||
| Pass `--add-host` so `host.docker.internal` resolves to the host gateway: | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| --add-host=host.docker.internal:host-gateway \ | ||
| ghcr.io/mobile-next/mobilewright doctor | ||
| ``` | ||
|
|
||
| #### Expected output | ||
|
|
||
| All Android checks pass as long as your host ADB server is running and an emulator is connected. | ||
|
|
||
| ``` | ||
| mobilewright doctor v0.0.x | ||
| ──────────────────────────────────────────────────────────── | ||
|
|
||
| System | ||
| ✓ Node.js v24.x.x | ||
| ✓ npm x.x.x | ||
| ✓ mobilecli mobilecli version x.x.x | ||
| ✓ mobilecli devices 1 online device | ||
| emulator-5554 | ||
|
|
||
| Android | ||
| ✓ ADB (Android Debug Bridge) 1.0.41 | ||
| ``` | ||
|
|
||
| ### Run tests | ||
|
|
||
| Mount your project directory into the container at `/home/mwuser` and run `mobilewright test`. | ||
|
|
||
| #### macOS and Windows | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| ghcr.io/mobile-next/mobilewright test | ||
| ``` | ||
|
|
||
| #### Linux | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| --add-host=host.docker.internal:host-gateway \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| ghcr.io/mobile-next/mobilewright test | ||
| ``` | ||
|
|
||
| Test results, screenshots, and other output are written to the mounted directory and remain available after the container exits. | ||
|
|
||
| ### Capture a screenshot | ||
|
|
||
| Mount your current directory so the output file lands on the host. The screenshot is written to `--output` relative to the working directory (`/home/mwuser`), which maps directly to your mounted path. | ||
|
|
||
| #### macOS and Windows | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| ghcr.io/mobile-next/mobilewright screenshot | ||
| # → screenshot.png appears in the current directory | ||
| ``` | ||
|
|
||
| #### Linux | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| --add-host=host.docker.internal:host-gateway \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| ghcr.io/mobile-next/mobilewright screenshot | ||
| ``` | ||
|
|
||
| Use `--output` to specify a different filename: | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| ghcr.io/mobile-next/mobilewright screenshot --output before-login.png | ||
| ``` | ||
|
|
||
| ## Cloud devices | ||
|
|
||
| [Mobile Next Cloud](https://mobilenext.ai) gives the container access to real Android and iOS devices over the network. No host ADB server, emulator, or `--add-host` flag is needed, and the commands are identical on macOS, Windows, and Linux. | ||
|
|
||
| ### Configure the cloud driver | ||
|
|
||
| Point your `mobilewright.config.ts` at the cloud driver. Read the API key from an environment variable so it is never committed: | ||
|
|
||
| ```ts | ||
| import { defineConfig } from 'mobilewright'; | ||
|
|
||
| export default defineConfig({ | ||
| platform: 'ios', // or 'android' | ||
| driver: { | ||
| type: 'mobile-use', | ||
| apiKey: process.env.MOBILE_USE_API_KEY, | ||
| }, | ||
| }); | ||
| ``` | ||
|
|
||
| ### Run tests | ||
|
|
||
| Mount your project and pass the API key with `-e`: | ||
|
|
||
| ```bash | ||
| docker run --rm \ | ||
| -v "$(pwd):/home/mwuser" \ | ||
| -e MOBILE_USE_API_KEY="$MOBILE_USE_API_KEY" \ | ||
| ghcr.io/mobile-next/mobilewright test | ||
| ``` | ||
|
|
||
| This works for both Android and iOS — the devices run in the cloud, so nothing else is required on the host. | ||
|
|
||
| ## Volume and environment reference | ||
|
|
||
| | Option | Purpose | | ||
| |--------|---------| | ||
| | `-v "$(pwd):/home/mwuser"` | Mount your project so config, tests, and output are accessible on the host | | ||
| | `--add-host=host.docker.internal:host-gateway` | Local Android on Linux only — makes the host reachable as `host.docker.internal` | | ||
| | `-e MOBILE_USE_API_KEY=…` | Cloud devices only — authenticates with Mobile Next Cloud | | ||
|
|
||
| ## Limitations | ||
|
|
||
| - **No local iOS simulator.** The container runs Linux and cannot reach an iOS simulator running on your Mac host. Test iOS against [cloud devices](#cloud-devices), or run directly on macOS with `npx mobilewright test`. | ||
| - **`screenshot` is local-only.** The `mobilewright screenshot` command always uses the local ADB driver and cannot capture Mobile Next Cloud devices. Capture cloud-device screenshots from within a test run instead. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Uh oh!
There was an error while loading. Please reload this page.