Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,87 @@ jobs:
-destination 'platform=iOS Simulator,name=iPhone 17' \
-only-testing:IOSAutomationServerTests

ios-release-build:
name: iOS Release Build
runs-on: macos-26
timeout-minutes: 20

steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

- name: Select Xcode Version
run: sudo xcode-select -switch /Applications/Xcode.app

- name: Show Xcode version
run: xcodebuild -version

- name: Cache SPM dependencies
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
with:
path: |
ios-automation-server/IOSAutomationServer.xcodeproj/project.xcworkspace/xcshareddata/swiftpm
~/Library/Developer/Xcode/DerivedData/**/SourcePackages
Comment thread
docer1990 marked this conversation as resolved.
build/SourcePackages
key: spm-${{ hashFiles('ios-automation-server/IOSAutomationServer.xcodeproj/project.pbxproj') }}
restore-keys: spm-

- name: Build for testing
run: |
xcodebuild build-for-testing \
-project ios-automation-server/IOSAutomationServer.xcodeproj \
-scheme IOSAutomationServer \
-destination 'platform=iOS Simulator,name=iPhone 17' \
Comment thread
docer1990 marked this conversation as resolved.
-derivedDataPath build/

- name: Verify __TESTROOT__ placeholders in xctestrun
run: |
XCTESTRUN=$(find build/Build/Products -name '*.xctestrun' -print -quit)
if [ -z "$XCTESTRUN" ]; then
echo "Error: No .xctestrun file found"
exit 1
fi
echo "Found xctestrun: $XCTESTRUN"
# Convert plist to XML first — Xcode may emit binary plists, making plain grep unreliable
XML_PLIST=$(plutil -convert xml1 -o - "$XCTESTRUN") || {
echo "Error: Failed to convert .xctestrun plist to XML"
exit 1
}
if grep -q '__TESTROOT__' <<< "$XML_PLIST"; then
echo "xctestrun uses __TESTROOT__ placeholders (portable)"
else
echo "Error: xctestrun does not contain __TESTROOT__ placeholders — bundle will not be portable"
exit 1
fi
# Reject CI-specific absolute paths that would break on user machines
if grep -qE '/Users/' <<< "$XML_PLIST"; then
echo "Error: xctestrun contains non-portable /Users/ paths"
grep -nE '/Users/' <<< "$XML_PLIST" || true
exit 1
fi

Comment thread
docer1990 marked this conversation as resolved.
- name: Archive iOS test bundle
run: |
cd build/Build/Products
tar -czf "$GITHUB_WORKSPACE/ios-automation-server.tar.gz" \
*.xctestrun \
Debug-iphonesimulator/IOSAutomationServer.app \
Debug-iphonesimulator/IOSAutomationServerUITests-Runner.app

- name: Generate checksum
run: shasum -a 256 ios-automation-server.tar.gz > ios-automation-server.tar.gz.sha256

- name: Upload iOS bundle artifact
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ios-automation-server
path: |
ios-automation-server.tar.gz
ios-automation-server.tar.gz.sha256

release:
name: Build & Release
needs: [mcp-server-tests, automation-server-tests, ios-automation-tests]
needs: [mcp-server-tests, automation-server-tests, ios-automation-tests, ios-release-build]
runs-on: ubuntu-latest
timeout-minutes: 15

Expand Down Expand Up @@ -133,6 +211,12 @@ jobs:
- name: Verify JAR exists
run: ls -lh app/build/libs/visiontest.jar

- name: Download iOS bundle artifact
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
with:
name: ios-automation-server
path: release-staging/

- name: Stage APKs and generate checksums
run: |
STAGING="release-staging"
Expand All @@ -159,7 +243,8 @@ jobs:
# Verify all files exist
for f in visiontest.jar visiontest.jar.sha256 \
automation-server.apk automation-server.apk.sha256 \
automation-server-test.apk automation-server-test.apk.sha256; do
automation-server-test.apk automation-server-test.apk.sha256 \
ios-automation-server.tar.gz ios-automation-server.tar.gz.sha256; do
if [ ! -f "$f" ]; then
echo "Error: $f not created"
exit 1
Expand All @@ -177,5 +262,7 @@ jobs:
release-staging/automation-server.apk.sha256
release-staging/automation-server-test.apk
release-staging/automation-server-test.apk.sha256
release-staging/ios-automation-server.tar.gz
release-staging/ios-automation-server.tar.gz.sha256
Comment thread
docer1990 marked this conversation as resolved.
install.sh
run-visiontest.sh
13 changes: 7 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,16 @@ Users install with `curl -fsSL https://github.com/docer1990/visiontest/releases/
3. Fetches latest release tag from GitHub API, validates format (`v[0-9][0-9A-Za-z._-]*`) and rejects dangerous characters
4. Downloads `visiontest.jar` + SHA-256 checksum, verifies integrity
5. Downloads Android APKs (`automation-server.apk`, `automation-server-test.apk`) + checksums, verifies integrity
6. Installs JAR and APKs to `~/.local/share/visiontest/` (customizable via `VISIONTEST_DIR` env var, must be under `$HOME`)
7. Creates wrapper script at `~/.local/bin/visiontest`, ensures PATH
8. Does not modify Claude Desktop configuration; use `run-visiontest.sh` or manual setup for Claude integration.
6. On macOS arm64: downloads `ios-automation-server.tar.gz` + checksum, extracts pre-built iOS XCUITest bundle to `ios-automation-server/` subdirectory (skipped on Linux and macOS x86_64)
7. Installs JAR, APKs, and iOS bundle to `~/.local/share/visiontest/` (customizable via `VISIONTEST_DIR` env var, must be under `$HOME`)
8. Creates wrapper script at `~/.local/bin/visiontest`, ensures PATH
9. Does not modify Claude Desktop configuration; use `run-visiontest.sh` or manual setup for Claude integration.

**Security hardening:** `umask 077`, explicit `chmod` on all files/dirs, tag validation, checksum verification, install path restricted to `$HOME`.

### Release Workflow (`.github/workflows/release.yaml`)

Triggered by git tags matching `v*`. The workflow runs the test suite, builds the fat JAR via `shadowJar` and Android APKs, generates SHA-256 checksums, and creates a GitHub Release with the following assets: `visiontest.jar`, `visiontest.jar.sha256`, `automation-server.apk`, `automation-server.apk.sha256`, `automation-server-test.apk`, `automation-server-test.apk.sha256`, `install.sh`, `run-visiontest.sh`.
Triggered by git tags matching `v*`. The workflow runs the test suite, builds the fat JAR via `shadowJar`, Android APKs, and the pre-built iOS XCUITest bundle (on a macOS runner), generates SHA-256 checksums, and creates a GitHub Release with the following assets: `visiontest.jar`, `visiontest.jar.sha256`, `automation-server.apk`, `automation-server.apk.sha256`, `automation-server-test.apk`, `automation-server-test.apk.sha256`, `ios-automation-server.tar.gz`, `ios-automation-server.tar.gz.sha256`, `install.sh`, `run-visiontest.sh`.

All GitHub Actions in both workflows are pinned to commit SHAs for supply-chain security. When updating or adding actions, always use SHA-pinned references instead of floating version tags.

Expand Down Expand Up @@ -236,7 +237,7 @@ Native iOS app providing XCUITest access via JSON-RPC. Uses **XCUITest framework
| `ios_stop_automation_server` | Stop the running XCUITest server |

**Typical iOS Automation Workflow:**
1. `ios_start_automation_server` - Build and start XCUITest server (handles build + install)
1. `ios_start_automation_server` - Start XCUITest server (uses pre-built bundle if available, otherwise builds from source)
2. `ios_get_interactive_elements` - Get filtered list of interactive elements (preferred)
- OR `ios_get_ui_hierarchy` - Get full XML hierarchy (when you need all elements)
3. `ios_tap_by_coordinates` - Tap using centerX/centerY from interactive elements
Expand Down Expand Up @@ -429,7 +430,7 @@ See `.claude/unit-testing-strategy.md` for the full testing roadmap (Plans 1-7).
- JDK 17+
- macOS or Linux (arm64 or x86_64)
- Android Platform Tools (ADB) in PATH — for Android automation
- Xcode Command Line Tools — for iOS simulator support (macOS only)
- Xcode Command Line Tools — for iOS simulator support (macOS only). Pre-built iOS bundle requires the same Xcode major version used in CI (see release notes). For source builds or Intel Macs, the full Xcode IDE is needed.
- Android SDK — only needed for building the automation-server module from source

> **Quick start:** Users who just need the MCP server can run `curl -fsSL https://github.com/docer1990/visiontest/releases/latest/download/install.sh | bash` — only Java 17+ is required.
Expand Down
Loading
Loading