From 30cdac56a1843745109b67361bdeb7168a05fb9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=9B=D1=8F=D1=89=D1=83=D0=BA?= <40496434+prog-time@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:33:46 +0300 Subject: [PATCH 1/4] issues-18|add xcodebuild test CI snippet --- CI/tests/xcodebuild_test.yml | 72 ++++++++++++++++++++++++++ scripts/CI/tests/xcodebuild_test.yml | 15 ++++++ scripts/shell/tests/xcodebuild_test.sh | 58 +++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 CI/tests/xcodebuild_test.yml create mode 100644 scripts/CI/tests/xcodebuild_test.yml create mode 100644 scripts/shell/tests/xcodebuild_test.sh diff --git a/CI/tests/xcodebuild_test.yml b/CI/tests/xcodebuild_test.yml new file mode 100644 index 0000000..d713270 --- /dev/null +++ b/CI/tests/xcodebuild_test.yml @@ -0,0 +1,72 @@ +xcodebuild_test: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Select Xcode version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Install xcpretty + run: gem install xcpretty + + - name: Run xcodebuild test + run: | + set -euo pipefail + + # Guard: xcodebuild must be present + if ! command -v xcodebuild &>/dev/null; then + echo "::error::xcodebuild not found — this job must run on macos-latest" + exit 1 + fi + + # Guard: xcpretty must be present + if ! command -v xcpretty &>/dev/null; then + echo "::error::xcpretty not found — run: gem install xcpretty" + exit 1 + fi + + # Locate workspace or project at repo root (bash-3.2-safe — no mapfile) + workspace_count=0 + project_count=0 + found_path="" + + for f in *.xcworkspace; do + [ -e "$f" ] || continue + workspace_count=$((workspace_count + 1)) + found_path="$f" + done + + for f in *.xcodeproj; do + [ -e "$f" ] || continue + project_count=$((project_count + 1)) + found_path="$f" + done + + total_count=$((workspace_count + project_count)) + + if [ "$total_count" -eq 0 ]; then + echo "::error::No Xcode workspace or project found" + exit 1 + fi + + if [ "$total_count" -gt 1 ]; then + echo "::error::Multiple Xcode workspaces/projects found (specify via SCHEME/PROJECT env)" + exit 1 + fi + + # Resolve scheme: honour env var, fall back to basename without extension + if [ -z "${SCHEME:-}" ]; then + basename_no_ext="${found_path%.*}" + SCHEME="$basename_no_ext" + fi + + echo "ℹ️ Running xcodebuild test — scheme: $SCHEME" + + xcodebuild test \ + -scheme "$SCHEME" \ + -destination 'platform=iOS Simulator,name=iPhone 15' \ + | xcpretty \ + && echo "✅ xcodebuild tests passed" \ + || { echo "❌ xcodebuild tests failed"; exit 1; } diff --git a/scripts/CI/tests/xcodebuild_test.yml b/scripts/CI/tests/xcodebuild_test.yml new file mode 100644 index 0000000..985c4fa --- /dev/null +++ b/scripts/CI/tests/xcodebuild_test.yml @@ -0,0 +1,15 @@ +xcodebuild_test: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + + - name: Select Xcode version + uses: maxim-lobanov/setup-xcode@v1 + with: + xcode-version: latest-stable + + - name: Install xcpretty + run: gem install xcpretty + + - name: Run xcodebuild test + run: bash scripts/shell/tests/xcodebuild_test.sh diff --git a/scripts/shell/tests/xcodebuild_test.sh b/scripts/shell/tests/xcodebuild_test.sh new file mode 100644 index 0000000..4a40e25 --- /dev/null +++ b/scripts/shell/tests/xcodebuild_test.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Guard: xcodebuild must be present +if ! command -v xcodebuild &>/dev/null; then + echo "::error::xcodebuild not found — this job must run on macos-latest" + exit 1 +fi + +# Guard: xcpretty must be present +if ! command -v xcpretty &>/dev/null; then + echo "::error::xcpretty not found — run: gem install xcpretty" + exit 1 +fi + +# Locate workspace or project at repo root (bash-3.2-safe — no mapfile) +workspace_count=0 +project_count=0 +found_path="" + +for f in *.xcworkspace; do + [ -e "$f" ] || continue + workspace_count=$((workspace_count + 1)) + found_path="$f" +done + +for f in *.xcodeproj; do + [ -e "$f" ] || continue + project_count=$((project_count + 1)) + found_path="$f" +done + +total_count=$((workspace_count + project_count)) + +if [ "$total_count" -eq 0 ]; then + echo "::error::No Xcode workspace or project found" + exit 1 +fi + +if [ "$total_count" -gt 1 ]; then + echo "::error::Multiple Xcode workspaces/projects found (specify via SCHEME/PROJECT env)" + exit 1 +fi + +# Resolve scheme: honour env var, fall back to basename without extension +if [ -z "${SCHEME:-}" ]; then + basename_no_ext="${found_path%.*}" + SCHEME="$basename_no_ext" +fi + +echo "ℹ️ Running xcodebuild test — scheme: $SCHEME" + +xcodebuild test \ + -scheme "$SCHEME" \ + -destination 'platform=iOS Simulator,name=iPhone 15' \ + | xcpretty \ + && echo "✅ xcodebuild tests passed" \ + || { echo "❌ xcodebuild tests failed"; exit 1; } From dd570b9378013939fe67f4dc767c6bc0ea5cf7ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=9B=D1=8F=D1=89=D1=83=D0=BA?= <40496434+prog-time@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:33:48 +0300 Subject: [PATCH 2/4] issues-18|add BATS tests for xcodebuild test --- tests/tests/xcodebuild_test.bats | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/tests/xcodebuild_test.bats diff --git a/tests/tests/xcodebuild_test.bats b/tests/tests/xcodebuild_test.bats new file mode 100644 index 0000000..837b45b --- /dev/null +++ b/tests/tests/xcodebuild_test.bats @@ -0,0 +1,41 @@ +#!/usr/bin/env bats + +load "../helpers/common" + +SCRIPT="$BATS_TEST_DIRNAME/../../scripts/shell/tests/xcodebuild_test.sh" + +setup() { + setup_test_dir + mkdir -p "$TEST_DIR/bin" + export PATH="$TEST_DIR/bin:$PATH" + + # Stub xcodebuild and xcpretty so the guards pass in structural tests + cat > "$TEST_DIR/bin/xcodebuild" <<'EOF' +#!/usr/bin/env bash +exit 0 +EOF + chmod +x "$TEST_DIR/bin/xcodebuild" + + cat > "$TEST_DIR/bin/xcpretty" <<'EOF' +#!/usr/bin/env bash +cat +EOF + chmod +x "$TEST_DIR/bin/xcpretty" +} + +teardown() { + teardown_test_dir +} + +@test "no workspace or project: exits 1 with no-project error" { + run bash "$SCRIPT" + [ "$status" -eq 1 ] + [[ "$output" == *"::error::No Xcode workspace or project found"* ]] +} + +@test "two workspaces present: exits 1 with disambiguation error" { + mkdir -p "App.xcworkspace" "Other.xcworkspace" + run bash "$SCRIPT" + [ "$status" -eq 1 ] + [[ "$output" == *"::error::Multiple Xcode workspaces/projects found"* ]] +} From fbfc2b388ba23b470bbbca62b7d05aa6cec0b4ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=9B=D1=8F=D1=89=D1=83=D0=BA?= <40496434+prog-time@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:33:50 +0300 Subject: [PATCH 3/4] issues-18|document xcodebuild test in README --- README.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 5742528..4693eae 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,7 @@ that projects compose into their own workflows. | Laravel | tests | [CI/tests/laravel_tests.yml](https://github.com/prog-time/workflows/blob/main/CI/tests/laravel_tests.yml) | | pytest | tests | [CI/tests/pytest.yml](https://github.com/prog-time/workflows/blob/main/CI/tests/pytest.yml) | | RSpec | tests | [CI/tests/rspec.yml](https://github.com/prog-time/workflows/blob/main/CI/tests/rspec.yml) | +| xcodebuild test | tests | [CI/tests/xcodebuild_test.yml](https://github.com/prog-time/workflows/blob/main/CI/tests/xcodebuild_test.yml) (**macos-latest**) | --- @@ -110,7 +111,8 @@ Workflows/ │ │ ├── jest.yml │ │ ├── laravel_tests.yml │ │ ├── pytest.yml -│ │ └── rspec.yml +│ │ ├── rspec.yml +│ │ └── xcodebuild_test.yml │ └── shell/ # bash scripts (one per tool) │ ├── linters/ │ │ ├── clippy.sh @@ -138,7 +140,8 @@ Workflows/ │ │ └── trivy.sh │ └── tests/ │ ├── cargo_test.sh -│ └── jest.sh +│ ├── jest.sh +│ └── xcodebuild_test.sh │ ├── CI/ # assembled output (ready to use) │ ├── linters/ @@ -167,7 +170,8 @@ Workflows/ │ │ └── trivy.bats │ ├── tests/ │ │ ├── cargo_test.bats -│ │ └── jest.bats +│ │ ├── jest.bats +│ │ └── xcodebuild_test.bats │ └── helpers/ │ └── common.bash # shared test utilities (mocks, temp dirs) │ @@ -287,6 +291,7 @@ shellcheck: | `CI/tests/laravel_tests.yml` | Laravel test suite (PHP 8.2, SQLite, parallel) | | `CI/tests/pytest.yml` | Python test suite (pytest) | | `CI/tests/rspec.yml` | Ruby test suite (RSpec via Bundler) | +| `CI/tests/xcodebuild_test.yml` | Swift/iOS XCTest suite (`xcodebuild test` via xcpretty) — **must run on `macos-latest`** | --- From 756e01a9eeae7c4e1007f49b5161942b8a34afa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F=20=D0=9B=D1=8F=D1=89=D1=83=D0=BA?= <40496434+prog-time@users.noreply.github.com> Date: Thu, 23 Apr 2026 09:37:53 +0300 Subject: [PATCH 4/4] issues-18|shorten xcodebuild row to satisfy MD013 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4693eae..1c3f8e8 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ shellcheck: | `CI/tests/laravel_tests.yml` | Laravel test suite (PHP 8.2, SQLite, parallel) | | `CI/tests/pytest.yml` | Python test suite (pytest) | | `CI/tests/rspec.yml` | Ruby test suite (RSpec via Bundler) | -| `CI/tests/xcodebuild_test.yml` | Swift/iOS XCTest suite (`xcodebuild test` via xcpretty) — **must run on `macos-latest`** | +| `CI/tests/xcodebuild_test.yml` | Swift/iOS XCTest suite (`xcodebuild test` via xcpretty) — **macOS only** | ---