ci: list every composite action in the paths filters that use it #601
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Installers | |
| on: | |
| push: | |
| # Every branch, not just main: this repo squash-merges locally and opens no | |
| # pull requests of its own, so a feature branch has no other way to reach | |
| # this lane before it lands. `branches-ignore` rather than deleting the key — | |
| # a push trigger that names `tags` and omits `branches` fires ONLY on tags, | |
| # which would disable branch CI outright. Dependabot is excluded because it | |
| # pushes its branch AND opens a PR, and the two land in different | |
| # concurrency groups, so the push run is a pure duplicate of the PR run. | |
| branches-ignore: ['dependabot/**'] | |
| # The old 'feature/**' glob could not match the branch names actually used | |
| # here (feat/..., fix/...), so non-main pushes were effectively unbuilt. | |
| tags: ['v*'] | |
| paths: | |
| - 'Package.swift' | |
| - 'Sources/**' | |
| - 'Tests/**' | |
| - 'Resources/**' | |
| - 'mirroir.sh' | |
| - 'npm/**' | |
| - 'scripts/package-fake-app.sh' | |
| - '.github/actions/setup-embacle/**' | |
| - '.github/actions/setup-fake-mirroring/**' | |
| - '.github/workflows/installers.yml' | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - 'Package.swift' | |
| - 'Sources/**' | |
| - 'Tests/**' | |
| - 'Resources/**' | |
| - 'mirroir.sh' | |
| - 'npm/**' | |
| - 'scripts/package-fake-app.sh' | |
| - '.github/actions/setup-embacle/**' | |
| - '.github/actions/setup-fake-mirroring/**' | |
| - '.github/workflows/installers.yml' | |
| workflow_dispatch: | |
| # Cancel superseded runs on the same branch / PR — three macos-15 jobs run here, | |
| # so a superseded run is expensive to leave in flight. | |
| concurrency: | |
| group: installers-${{ github.head_ref || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| source-install: | |
| name: Source install (mirroir.sh) | |
| runs-on: macos-15 | |
| permissions: | |
| contents: read | |
| env: | |
| MIRROIR_BUNDLE_ID: com.jfarcand.FakeMirroring | |
| MIRROIR_PROCESS_NAME: FakeMirroring | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/actions/setup-embacle | |
| - name: Clone skills repo | |
| run: | | |
| git clone https://github.com/jfarcand/mirroir-skills.git ../mirroir-skills | |
| mkdir -p .mirroir-mcp | |
| ln -s "$(cd ../mirroir-skills && pwd)" .mirroir-mcp/skills | |
| - name: Run mirroir.sh | |
| run: ./mirroir.sh | |
| - name: Verify binaries built | |
| run: | | |
| test -x .build/release/mirroir-mcp | |
| # Verify mirroir CLI symlink was created (Homebrew bin dir) | |
| test -L /opt/homebrew/bin/mirroir || test -L /usr/local/bin/mirroir | |
| mirroir record --help 2>&1 | grep -q "Record user interactions" | |
| - name: Verify embacle FFI linked | |
| run: nm .build/release/mirroir-mcp | grep -q embacle_init | |
| - uses: ./.github/actions/setup-fake-mirroring | |
| - name: Integration tests (FakeMirroring) | |
| run: swift test --filter IntegrationTests | |
| - name: MCP initialize (installed binary) | |
| run: | | |
| echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \ | |
| | .build/release/mirroir-mcp 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| obj = json.loads(sys.stdin.readline()) | |
| assert obj['result']['serverInfo']['name'] == 'mirroir-mcp' | |
| print('MCP initialize: OK') | |
| " | |
| - name: MCP tools/call screenshot (installed binary + FakeMirroring) | |
| run: | | |
| printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"screenshot","arguments":{}}}\n' \ | |
| | .build/release/mirroir-mcp --dangerously-skip-permissions 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| lines = sys.stdin.readlines() | |
| resp = json.loads(lines[1]) | |
| content = resp['result']['content'] | |
| images = [c for c in content if c.get('type') == 'image'] | |
| assert len(images) > 0, f'Expected image in screenshot response, got: {content}' | |
| print(f'screenshot tool: OK ({len(images)} image block(s))') | |
| " | |
| homebrew-install: | |
| name: Homebrew install (local formula) | |
| runs-on: macos-15 | |
| permissions: | |
| contents: read | |
| env: | |
| MIRROIR_BUNDLE_ID: com.jfarcand.FakeMirroring | |
| MIRROIR_PROCESS_NAME: FakeMirroring | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/actions/setup-embacle | |
| - name: Clone skills repo | |
| run: | | |
| git clone https://github.com/jfarcand/mirroir-skills.git ../mirroir-skills | |
| mkdir -p .mirroir-mcp | |
| ln -s "$(cd ../mirroir-skills && pwd)" .mirroir-mcp/skills | |
| - name: Create source tarball | |
| run: | | |
| TAR_PATH="/tmp/mirroir-mcp-local.tar.gz" | |
| git archive --format=tar.gz --prefix=mirroir-mcp-local/ HEAD > "$TAR_PATH" | |
| SHA=$(shasum -a 256 "$TAR_PATH" | cut -d' ' -f1) | |
| echo "TARBALL_PATH=$TAR_PATH" >> $GITHUB_ENV | |
| echo "TARBALL_SHA=$SHA" >> $GITHUB_ENV | |
| - name: Create local tap with formula | |
| run: | | |
| brew tap-new local/test | |
| TAP_DIR="$(brew --repository)/Library/Taps/local/homebrew-test/Formula" | |
| mkdir -p "$TAP_DIR" | |
| cat > "$TAP_DIR/mirroir-mcp.rb" << RUBY | |
| class MirroirMcp < Formula | |
| desc "MCP server for controlling iPhone through macOS iPhone Mirroring" | |
| homepage "https://github.com/jfarcand/mirroir-mcp" | |
| url "file://${TARBALL_PATH}" | |
| version "0.0.0-ci" | |
| sha256 "${TARBALL_SHA}" | |
| license "Apache-2.0" | |
| depends_on :macos | |
| depends_on xcode: ["15.0", :build] | |
| depends_on "dravr-ai/tap/embacle-ffi" | |
| def install | |
| embacle_lib = Formula["embacle-ffi"].opt_lib | |
| system "swift", "build", "-c", "release", "--disable-sandbox", | |
| "-Xlinker", "-L#{embacle_lib}" | |
| bin.install ".build/release/mirroir-mcp" | |
| bin.install_symlink "mirroir-mcp" => "mirroir" | |
| end | |
| test do | |
| assert_match "mirroir-mcp", shell_output("#{bin}/mirroir-mcp --help 2>&1", 1) | |
| end | |
| end | |
| RUBY | |
| - name: Install from local tap | |
| run: brew install local/test/mirroir-mcp | |
| - name: Verify Homebrew-installed binaries | |
| run: | | |
| which mirroir-mcp | |
| which mirroir | |
| # Verify mirroir CLI works (symlink to mirroir-mcp) | |
| mirroir test --help 2>&1 | grep -q "mirroir-mcp test" | |
| - name: Verify embacle FFI linked | |
| run: nm "$(brew --prefix)/bin/mirroir-mcp" | grep -q embacle_init | |
| - uses: ./.github/actions/setup-fake-mirroring | |
| - name: Integration tests (FakeMirroring) | |
| run: swift test --filter IntegrationTests | |
| - name: MCP initialize (brew-installed binary) | |
| run: | | |
| echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \ | |
| | mirroir-mcp 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| obj = json.loads(sys.stdin.readline()) | |
| assert obj['result']['serverInfo']['name'] == 'mirroir-mcp' | |
| print('MCP initialize (brew path): OK') | |
| " | |
| - name: MCP tools/call screenshot (brew-installed binary + FakeMirroring) | |
| run: | | |
| printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"screenshot","arguments":{}}}\n' \ | |
| | mirroir-mcp --dangerously-skip-permissions 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| lines = sys.stdin.readlines() | |
| resp = json.loads(lines[1]) | |
| content = resp['result']['content'] | |
| images = [c for c in content if c.get('type') == 'image'] | |
| assert len(images) > 0, f'Expected image in screenshot response, got: {content}' | |
| print(f'screenshot tool: OK ({len(images)} image block(s))') | |
| " | |
| - name: Cleanup | |
| if: always() | |
| run: | | |
| sudo brew uninstall mirroir-mcp || true | |
| npx-install: | |
| name: NPX install (npm package) | |
| runs-on: macos-15 | |
| permissions: | |
| contents: read | |
| env: | |
| MIRROIR_BUNDLE_ID: com.jfarcand.FakeMirroring | |
| MIRROIR_PROCESS_NAME: FakeMirroring | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: ./.github/actions/setup-embacle | |
| - name: Clone skills repo | |
| run: | | |
| git clone https://github.com/jfarcand/mirroir-skills.git ../mirroir-skills | |
| mkdir -p .mirroir-mcp | |
| ln -s "$(cd ../mirroir-skills && pwd)" .mirroir-mcp/skills | |
| - name: Build release binaries | |
| run: swift build -c release | |
| - name: Verify embacle FFI linked | |
| run: nm .build/release/mirroir-mcp | grep -q embacle_init | |
| - name: Stage binaries into npm/bin/ (simulates install.js postinstall) | |
| run: | | |
| mkdir -p npm/bin | |
| cp .build/release/mirroir-mcp npm/bin/mirroir-mcp-native | |
| chmod +x npm/bin/mirroir-mcp-native | |
| - uses: ./.github/actions/setup-fake-mirroring | |
| - name: Integration tests (FakeMirroring) | |
| run: swift test --filter IntegrationTests | |
| - name: MCP initialize (npx wrapper) | |
| run: | | |
| echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \ | |
| | node npm/bin/mirroir-mcp 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| obj = json.loads(sys.stdin.readline()) | |
| assert obj['result']['serverInfo']['name'] == 'mirroir-mcp' | |
| print('MCP initialize (npx wrapper): OK') | |
| " | |
| - name: MCP tools/call screenshot (npx wrapper + FakeMirroring) | |
| run: | | |
| printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}\n{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"screenshot","arguments":{}}}\n' \ | |
| | node npm/bin/mirroir-mcp --dangerously-skip-permissions 2>/dev/null \ | |
| | python3 -c " | |
| import sys, json | |
| lines = sys.stdin.readlines() | |
| resp = json.loads(lines[1]) | |
| content = resp['result']['content'] | |
| images = [c for c in content if c.get('type') == 'image'] | |
| assert len(images) > 0, f'Expected image in screenshot response, got: {content}' | |
| print(f'screenshot tool: OK ({len(images)} image block(s))') | |
| " |