Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
60 commits
Select commit Hold shift + click to select a range
7645e81
Attempting to do CI to run unit tests on all PRs.
LowAmmo Mar 19, 2026
96581e0
Specify "iPhone 17"
LowAmmo Mar 19, 2026
c82e40f
Adding .xctestplans into the xcode project file and remo
LowAmmo Mar 19, 2026
c93cd9f
Generate code coverage
LowAmmo Apr 7, 2026
78d6363
Add code coverage results
LowAmmo Apr 7, 2026
31c0f50
Upload xcresult as an xcresult
LowAmmo Apr 8, 2026
4c1efa3
Attempting to indent the imbedded python script
LowAmmo Apr 8, 2026
fd2ac21
Debugging around the xcrun simctl command
LowAmmo Apr 8, 2026
9ae206a
Try to NOT escape out the back slashes in the regex strings
LowAmmo Apr 8, 2026
b9db292
Trim up the output.
LowAmmo Apr 8, 2026
36f0788
Fix model name
LowAmmo Apr 8, 2026
c696a83
no udid variable...dummy
LowAmmo Apr 8, 2026
0f75a18
I made myself laugh!
LowAmmo Apr 8, 2026
2ca5e82
Prefer arm64
LowAmmo Apr 8, 2026
a6ecc72
Update to cleanly support Node.js 24 (and 20)
LowAmmo Apr 8, 2026
232308f
Attempting to publish up the code coverage results for pull requests
LowAmmo Apr 8, 2026
cf15580
Better string manipulation
LowAmmo Apr 8, 2026
9d84000
Clean up
LowAmmo Apr 8, 2026
b7a7f14
Attempt to publish coverage to the pull request
LowAmmo Apr 8, 2026
dd4443e
more clean up
LowAmmo Apr 8, 2026
5658976
Try to fix the combined code coverage logic
LowAmmo Apr 8, 2026
8b41cb5
Muck with the indentation
LowAmmo Apr 8, 2026
86fb1f0
Clean up the code coverage summary handling logic
LowAmmo Apr 8, 2026
83d71f6
Hopefully fix the indentation issue
LowAmmo Apr 8, 2026
a4dc7cc
Fixing more indents
LowAmmo Apr 8, 2026
dfa0882
remove some indents
LowAmmo Apr 8, 2026
283d219
trying again
LowAmmo Apr 8, 2026
ec9138b
getting desperate
LowAmmo Apr 8, 2026
91c2426
WTF?!?!?
LowAmmo Apr 8, 2026
ecfc277
getting ridiculous
LowAmmo Apr 8, 2026
2335b8d
Going Plaid!
LowAmmo Apr 8, 2026
505397f
All this indenting!
LowAmmo Apr 8, 2026
9250d5a
Getting fancy
LowAmmo Apr 8, 2026
18b8f53
Clean up code coverage comment
LowAmmo Apr 8, 2026
5a1c470
Calculate coverage 1 time
LowAmmo Apr 8, 2026
3cc7782
"mapfile" not available
LowAmmo Apr 8, 2026
beadc23
Print coverage results to the github action
LowAmmo Apr 8, 2026
d241e62
Update to also build main/master and add badges to the readme.
LowAmmo Apr 8, 2026
cf58a5e
Use a random device for testing
LowAmmo Apr 10, 2026
692ccbe
Don't try to publish coverage anywhere. Keep it local for now.
LowAmmo Apr 10, 2026
b14a70b
Trying some reusable github actions
LowAmmo Apr 17, 2026
ee365e0
Attempt to separate out a "pick-my-xcode-tricorder" reusable action.
LowAmmo Apr 17, 2026
c957494
enhance coverage calculation logic to properly handle multiple xcresu…
LowAmmo Apr 17, 2026
a530865
Making a github action to run unit tests
LowAmmo Apr 17, 2026
0c7eec7
environment variables?
LowAmmo Apr 17, 2026
fad3db2
hopefully upload the directory of xcresults now...
LowAmmo Apr 17, 2026
88ade5b
An action just to combine code coverage info
LowAmmo Apr 17, 2026
5afede0
Create a json file to be more re-usable
LowAmmo Apr 17, 2026
c86e035
Attempting a little clean up
LowAmmo Apr 17, 2026
3b93b1b
Maybe checkout...
LowAmmo Apr 17, 2026
31f15a1
Setting up to do unit testing of the shareable github actions
LowAmmo Apr 17, 2026
5f4e06b
Moving around the python unit testing smarts
LowAmmo Apr 17, 2026
3c78794
Renaming actions...yes again
LowAmmo Apr 21, 2026
fbd1d45
Update published github action versions
LowAmmo Apr 21, 2026
a3713c8
Making more reusable workflows.
LowAmmo Apr 21, 2026
1666345
Fixing list inputs
LowAmmo Apr 21, 2026
8848bb3
More clean up
LowAmmo Apr 21, 2026
5e091c9
Lists as JSON objects
LowAmmo Apr 21, 2026
5d6e313
Better naming
LowAmmo Apr 21, 2026
007d4cb
Resolve simulator destinations on the same server that is going to ru…
LowAmmo Apr 21, 2026
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
1 change: 0 additions & 1 deletion .coveralls.yml

This file was deleted.

42 changes: 42 additions & 0 deletions .github/actions-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Actions Tests

This folder contains the Python unit-test harness for the reusable GitHub Actions under `.github/actions`.
The subfolder layout mirrors the action names so each action's tests live beside the corresponding action name under `.github/actions-tests`.

## Local setup

1. Run the setup script:

```bash
./.github/actions-tests/setup_tests.sh
```

2. Run the tests and generate coverage artifacts:

```bash
./.github/actions-tests/run_tests.sh
```

If `.github/actions-tests/.venv` exists, the test runner will automatically use it.

To use a specific Python interpreter during setup, set `PYTHON_ACTION_TEST_SETUP_PYTHON_BIN`:

```bash
PYTHON_ACTION_TEST_SETUP_PYTHON_BIN=python3.13 ./.github/actions-tests/setup_tests.sh
```

## Generated artifacts

By default, test artifacts are written under `.github/actions-tests/build/python-action-test-results/`:

- `junit.xml`
- `coverage.xml`
- `htmlcov/`

## Optional coverage threshold

To fail the test run if total coverage drops below a minimum percentage:

```bash
PYTHON_ACTION_TEST_COVERAGE_FAIL_UNDER=90 ./.github/actions-tests/run_tests.sh
```
92 changes: 92 additions & 0 deletions .github/actions-tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import importlib.util
import sys
from pathlib import Path

import pytest


def determine_repo_root() -> Path:
current_path = Path(__file__).resolve()
for candidate in current_path.parents:
if (candidate / ".git").exists():
return candidate

raise RuntimeError("Unable to determine repository root for Python action tests")


REPO_ROOT = determine_repo_root()


@pytest.fixture(scope="session")
def repo_root() -> Path:
return REPO_ROOT


@pytest.fixture(scope="session")
def python_executable() -> str:
return sys.executable


def load_module(module_name: str, relative_path: str):
module_path = REPO_ROOT / relative_path
spec = importlib.util.spec_from_file_location(module_name, module_path)
if spec is None or spec.loader is None:
raise RuntimeError(f"Unable to load module: {module_path}")

module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module)
return module


@pytest.fixture(scope="session")
def pick_simulator_module():
return load_module(
"test_pick_simulator_module",
".github/actions/simctl-tricorder-selector/pick_simulator.py",
)


@pytest.fixture(scope="session")
def run_xcode_tests_module():
return load_module(
"test_run_xcode_tests_module",
".github/actions/xcode-tricorder-tester/run_xcode_tests.py",
)


@pytest.fixture(scope="session")
def coverage_summary_module():
return load_module(
"test_generate_coverage_summary_module",
".github/actions/xccov-warp-bubble/generate_coverage_summary.py",
)


@pytest.fixture()
def sample_devices_payload():
return {
"devices": {
"com.apple.CoreSimulator.SimRuntime.iOS-18-0": [
{"name": "iPhone 16", "udid": "IPHONE16", "isAvailable": True},
{"name": "iPhone 16 Pro Max", "udid": "IPHONE16PM", "isAvailable": True},
{"name": "iPad Pro 13-inch (M4)", "udid": "IPADPRO", "isAvailable": True},
{"name": "iPhone 14", "udid": "IPHONE14", "isAvailable": False},
],
"com.apple.CoreSimulator.SimRuntime.iOS-17-5": [
{"name": "iPhone SE (3rd generation)", "udid": "IPHONESE", "isAvailable": True},
],
"com.apple.CoreSimulator.SimRuntime.macOS-15-0": [
{"name": "My Mac", "udid": "MYMAC", "isAvailable": True},
],
"com.apple.CoreSimulator.SimRuntime.watchOS-11-0": [
{"name": "Apple Watch Series 10 (42mm)", "udid": "WATCH10", "isAvailable": True},
],
"com.apple.CoreSimulator.SimRuntime.visionOS-2-0": [
{"name": "Apple Vision Pro", "udid": "VISIONPRO", "isAvailable": True},
],
"com.apple.CoreSimulator.SimRuntime.tvOS-18-0": [
{"name": "Apple TV", "udid": "TV", "isAvailable": True},
],
}
}
26 changes: 26 additions & 0 deletions .github/actions-tests/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[tool.pytest.ini_options]
testpaths = [
"simctl-tricorder-selector",
"xcode-tricorder-tester",
"xccov-warp-bubble",
]
python_files = ["*_tests.py"]
junit_family = "xunit2"
addopts = ["-ra"]

[tool.coverage.run]
branch = true
relative_files = true
patch = ["subprocess"]
source = [
".github/actions/simctl-tricorder-selector",
".github/actions/xccov-warp-bubble",
".github/actions/xcode-tricorder-tester",
]
omit = [".github/actions-tests/*"]

[tool.coverage.report]
show_missing = true
skip_empty = true
precision = 2
omit = [".github/actions-tests/*"]
2 changes: 2 additions & 0 deletions .github/actions-tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pytest>=8.0,<9
pytest-cov>=5.0,<7
65 changes: 65 additions & 0 deletions .github/actions-tests/run_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/usr/bin/env bash

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
repo_root="$(cd "$script_dir/../.." && pwd)"

results_dir="${PYTHON_ACTION_TEST_RESULTS_DIR:-$script_dir/build/python-action-test-results}"
coverage_fail_under="${PYTHON_ACTION_TEST_COVERAGE_FAIL_UNDER:-}"
python_bin="${PYTHON_ACTION_TEST_PYTHON_BIN:-}"

if [[ -z "$python_bin" && -x "$script_dir/.venv/bin/python" ]]; then
python_bin="$script_dir/.venv/bin/python"
fi

if [[ -z "$python_bin" ]]; then
python_bin="python3"
fi

mkdir -p "$results_dir"
cd "$repo_root"
export COVERAGE_FILE="$script_dir/.coverage"
rm -f "$script_dir"/.coverage "$script_dir"/.coverage.*

cleanup_python_caches() {
find "$repo_root" -type d \( -name "__pycache__" -o -name ".pytest_cache" \) -prune -exec rm -rf {} +
}

trap cleanup_python_caches EXIT

pytest_args=(
"-c" "$script_dir/pyproject.toml"
"$script_dir/simctl-tricorder-selector"
"$script_dir/xcode-tricorder-tester"
"$script_dir/xccov-warp-bubble"
"--junitxml=$results_dir/junit.xml"
"--cov=.github/actions/simctl-tricorder-selector"
"--cov=.github/actions/xcode-tricorder-tester"
"--cov=.github/actions/xccov-warp-bubble"
"--cov-branch"
"--cov-report="
)

if [[ -n "$coverage_fail_under" ]]; then
pytest_args+=("--cov-fail-under=$coverage_fail_under")
fi

set +e
"$python_bin" -m pytest "${pytest_args[@]}"
pytest_exit_code=$?
set -e

shopt -s nullglob
coverage_shards=( "$script_dir"/.coverage.* )
shopt -u nullglob

if [[ ${#coverage_shards[@]} -gt 0 ]]; then
"$python_bin" -m coverage combine "$script_dir"
fi

"$python_bin" -m coverage report --skip-covered --show-missing
"$python_bin" -m coverage xml -o "$results_dir/coverage.xml"
"$python_bin" -m coverage html -d "$results_dir/htmlcov"

exit "$pytest_exit_code"
17 changes: 17 additions & 0 deletions .github/actions-tests/setup_tests.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash

set -euo pipefail

script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

python_bin="${PYTHON_ACTION_TEST_SETUP_PYTHON_BIN:-python3}"
venv_dir="${PYTHON_ACTION_TEST_VENV_DIR:-$script_dir/.venv}"
venv_python="$venv_dir/bin/python"

if [[ ! -d "$venv_dir" ]]; then
"$python_bin" -m venv "$venv_dir"
fi

"$venv_python" -m pip install -r "$script_dir/requirements.txt"

echo "Python action test environment is ready: $venv_dir"
Loading
Loading