@osfactory/har 0.62.1 → 0.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +0 -19
- package/README.md +3 -2
- package/dist/index.js +2178 -1208
- package/dist/templates/agent-skills/setup-har.md +20 -6
- package/dist/templates/agent-skills/skills.manifest.json +1 -1
- package/dist/templates/har-boilerplate/provision-toolchain.sh +121 -1
- package/dist/templates/har-boilerplate-cli/provision-toolchain.sh +121 -1
- package/dist/templates/har-boilerplate-ios/ADAPT-PROMPT.md +6 -0
- package/dist/templates/har-boilerplate-ios/README.md +1 -1
- package/dist/templates/har-boilerplate-ios/harness.env +6 -0
- package/dist/templates/har-boilerplate-ios/provision-toolchain.sh +121 -1
- package/dist/templates/har-boilerplate-ios/verify.sh +11 -5
- package/dist/templates/runtime-bundles/shared-kernel/provision-toolchain.sh +121 -1
- package/package.json +13 -4
|
@@ -14,7 +14,21 @@ If missing, install it and re-check:
|
|
|
14
14
|
npm install -g @osfactory/har
|
|
15
15
|
```
|
|
16
16
|
|
|
17
|
-
## 2.
|
|
17
|
+
## 2. Check Docker
|
|
18
|
+
|
|
19
|
+
Docker is required: Mission Control runs as a container and harness infrastructure
|
|
20
|
+
(databases, queues, browsers) starts through Docker Compose.
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
docker info
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
If the command fails, tell the user Docker must be installed and running
|
|
27
|
+
(https://docs.docker.com/get-started/get-docker/). You can still scaffold the
|
|
28
|
+
harness, but say clearly that Mission Control and containerized infra stay
|
|
29
|
+
unavailable until Docker works.
|
|
30
|
+
|
|
31
|
+
## 3. Pick a harness profile
|
|
18
32
|
|
|
19
33
|
Inspect the repository and choose the profile that matches how agents will run it:
|
|
20
34
|
|
|
@@ -26,7 +40,7 @@ Inspect the repository and choose the profile that matches how agents will run i
|
|
|
26
40
|
|
|
27
41
|
Tell the user which profile you picked and why before continuing.
|
|
28
42
|
|
|
29
|
-
##
|
|
43
|
+
## 4. Initialize the harness
|
|
30
44
|
|
|
31
45
|
```bash
|
|
32
46
|
har env init --profile <profile> # omit --profile for default
|
|
@@ -34,11 +48,11 @@ har env init --profile <profile> # omit --profile for default
|
|
|
34
48
|
|
|
35
49
|
If `.har/` already exists, stop and suggest `/har-maintain` instead.
|
|
36
50
|
|
|
37
|
-
##
|
|
51
|
+
## 5. Perform the adaptation yourself
|
|
38
52
|
|
|
39
53
|
`har env init` prints an adaptation prompt and writes it to `.har/ADAPT-PROMPT.md`. Read that file and **execute its instructions yourself, now, in this session** — tailor `.har/` scripts (`launch.sh`, `verify.sh`, `setup-infra.sh`, `harness.env`, `stages.json`) and `AGENTS.md` to this repository's real stack, ports, and commands.
|
|
40
54
|
|
|
41
|
-
##
|
|
55
|
+
## 6. Register the project's checks as stages
|
|
42
56
|
|
|
43
57
|
Convert the repository's real check commands (test, lint, typecheck, whatever CI runs) into registered stages so they run in `verify --full` and are visible to every agent. Read `.har/STAGES.md` for the contract, then:
|
|
44
58
|
|
|
@@ -49,7 +63,7 @@ har env add-stage unit-tests --custom --kind test --command "npm test" --verific
|
|
|
49
63
|
- Use `--command` for one-liner checks; use `--script` when a check needs the slot's env, ports, or artifacts (then implement the scaffolded `.har/stages/<id>.sh`).
|
|
50
64
|
- Rich integrations ship as **plugins**: `har env add-plugin --list`, then e.g. `har env add-plugin playwright` (web) or `har env add-plugin rocketsim` (iOS). Plugins install stages; agents only talk to the stage registry.
|
|
51
65
|
|
|
52
|
-
##
|
|
66
|
+
## 7. Prove the harness works
|
|
53
67
|
|
|
54
68
|
```bash
|
|
55
69
|
har env launch 1
|
|
@@ -58,7 +72,7 @@ har env verify 1
|
|
|
58
72
|
|
|
59
73
|
Fix the harness scripts until both pass. Then tear down or keep the slot as the user prefers (`har env teardown 1` keeps the branch).
|
|
60
74
|
|
|
61
|
-
##
|
|
75
|
+
## 8. Commit
|
|
62
76
|
|
|
63
77
|
After the user confirms, commit the harness:
|
|
64
78
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"name": "setup-har",
|
|
11
11
|
"description": "Install the har CLI and scaffold the .har/ agent harness in this repository (init, adapt, launch, verify, commit). User-invoked onboarding.",
|
|
12
12
|
"disable-model-invocation": true,
|
|
13
|
-
"allowed-tools": "Bash(har *) Bash(npm *) Bash(git *) Read Grep Glob Edit Write"
|
|
13
|
+
"allowed-tools": "Bash(har *) Bash(npm *) Bash(git *) Bash(docker *) Read Grep Glob Edit Write"
|
|
14
14
|
}
|
|
15
15
|
},
|
|
16
16
|
"cursor": { "command": true },
|
|
@@ -586,9 +586,129 @@ provision_ruby() {
|
|
|
586
586
|
append_path_prefix "$dir/vendor/bundle/bin"
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
# ── iOS Xcode project helpers ─────────────────────────────────────────────────
|
|
590
|
+
# Tuist, XcodeGen and CocoaPods treat the .xcodeproj / .xcworkspace as a build
|
|
591
|
+
# product rather than a tracked file, so a fresh worktree has nothing for
|
|
592
|
+
# xcodebuild to open. Generate it here — and fail naming the missing generator,
|
|
593
|
+
# instead of letting xcodebuild report an opaque "scheme not found" later.
|
|
594
|
+
|
|
595
|
+
# First project file of a kind in the work dir. Runs from inside the dir so a dot
|
|
596
|
+
# in the worktree path itself cannot trip the dotfile filter, and skips both the
|
|
597
|
+
# project.xcworkspace every .xcodeproj carries inside it and whatever CocoaPods
|
|
598
|
+
# generates under Pods/.
|
|
599
|
+
har_ios_find_project_file() {
|
|
600
|
+
local dir="$1"
|
|
601
|
+
local pattern="$2"
|
|
602
|
+
local match=""
|
|
603
|
+
match="$(cd "$dir" 2>/dev/null && find . -maxdepth 2 -name "$pattern" \
|
|
604
|
+
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1)" || true
|
|
605
|
+
[ -n "$match" ] || return 1
|
|
606
|
+
echo "${match#./}"
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
# True when this worktree already has something xcodebuild can open. Adapt-time
|
|
610
|
+
# HARNESS_XCODE_WORKSPACE / HARNESS_XCODE_PROJECT decide it when set: they name
|
|
611
|
+
# the generated file, so a missing one means the generator still has to run.
|
|
612
|
+
har_ios_has_project() {
|
|
613
|
+
local dir="$1"
|
|
614
|
+
|
|
615
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ]; then
|
|
616
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] && [ -e "$dir/$HARNESS_XCODE_WORKSPACE" ]; then
|
|
617
|
+
return 0
|
|
618
|
+
fi
|
|
619
|
+
if [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$dir/$HARNESS_XCODE_PROJECT" ]; then
|
|
620
|
+
return 0
|
|
621
|
+
fi
|
|
622
|
+
return 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
if har_ios_find_project_file "$dir" '*.xcworkspace' >/dev/null; then return 0; fi
|
|
626
|
+
if har_ios_find_project_file "$dir" '*.xcodeproj' >/dev/null; then return 0; fi
|
|
627
|
+
return 1
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
# Generator this repo declares, or empty. A Podfile counts: `pod install` is what
|
|
631
|
+
# writes the .xcworkspace for a CocoaPods project.
|
|
632
|
+
har_ios_project_generator() {
|
|
633
|
+
local dir="$1"
|
|
634
|
+
if [ -f "$dir/Project.swift" ] || [ -f "$dir/Workspace.swift" ]; then echo tuist; return; fi
|
|
635
|
+
if [ -f "$dir/project.yml" ] || [ -f "$dir/project.yaml" ]; then echo xcodegen; return; fi
|
|
636
|
+
if [ -f "$dir/Podfile" ]; then echo pod; return; fi
|
|
637
|
+
echo ""
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
har_ios_generate_project() {
|
|
641
|
+
local dir="$1"
|
|
642
|
+
local generator=""
|
|
643
|
+
|
|
644
|
+
if har_ios_has_project "$dir"; then
|
|
645
|
+
return 0
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
generator="$(har_ios_project_generator "$dir")"
|
|
649
|
+
if [ -z "$generator" ]; then
|
|
650
|
+
pt_log "No .xcodeproj/.xcworkspace found and no generator manifest (Project.swift, project.yml, Podfile) — set HARNESS_XCODE_PROJECT/HARNESS_XCODE_WORKSPACE or HARNESS_INSTALL_CMD in harness.env"
|
|
651
|
+
return 0
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
if ! command -v "$generator" >/dev/null 2>&1; then
|
|
655
|
+
local label="$generator"
|
|
656
|
+
[ "$generator" = "pod" ] && label="CocoaPods (pod)"
|
|
657
|
+
pt_log "ERROR: this repo generates its Xcode project with ${label}, which is not on PATH."
|
|
658
|
+
pt_log " Install ${label}, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
659
|
+
return 1
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
case "$generator" in
|
|
663
|
+
tuist)
|
|
664
|
+
pt_log "Generating the Xcode project with tuist..."
|
|
665
|
+
if ! (cd "$dir" && tuist generate --no-open); then
|
|
666
|
+
pt_log "tuist generate --no-open failed — retrying without the flag"
|
|
667
|
+
(cd "$dir" && tuist generate)
|
|
668
|
+
fi
|
|
669
|
+
;;
|
|
670
|
+
xcodegen)
|
|
671
|
+
pt_log "Generating the Xcode project with xcodegen..."
|
|
672
|
+
(cd "$dir" && xcodegen generate)
|
|
673
|
+
;;
|
|
674
|
+
pod)
|
|
675
|
+
# har_ios_pod_install writes the workspace right after this.
|
|
676
|
+
:
|
|
677
|
+
;;
|
|
678
|
+
esac
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
# CocoaPods dependencies. Independent of project generation: a tracked
|
|
682
|
+
# .xcworkspace still cannot build when Pods/ is missing in a fresh worktree.
|
|
683
|
+
har_ios_pod_install() {
|
|
684
|
+
local dir="$1"
|
|
685
|
+
|
|
686
|
+
[ -f "$dir/Podfile" ] || return 0
|
|
687
|
+
[ -d "$dir/Pods" ] && return 0
|
|
688
|
+
|
|
689
|
+
if ! command -v pod >/dev/null 2>&1; then
|
|
690
|
+
pt_log "ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH."
|
|
691
|
+
pt_log " Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
692
|
+
return 1
|
|
693
|
+
fi
|
|
694
|
+
|
|
695
|
+
pt_log "Installing CocoaPods dependencies..."
|
|
696
|
+
(cd "$dir" && pod install)
|
|
697
|
+
}
|
|
698
|
+
|
|
589
699
|
provision_ios() {
|
|
590
700
|
local dir="$1"
|
|
591
|
-
|
|
701
|
+
|
|
702
|
+
# An explicit HARNESS_INSTALL_CMD owns provisioning outright: the default
|
|
703
|
+
# generators stay out of the way, and a failing override fails the launch
|
|
704
|
+
# rather than being papered over.
|
|
705
|
+
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
706
|
+
run_install_cmd "$dir"
|
|
707
|
+
else
|
|
708
|
+
har_ios_generate_project "$dir"
|
|
709
|
+
har_ios_pod_install "$dir"
|
|
710
|
+
fi
|
|
711
|
+
|
|
592
712
|
append_env "HARNESS_ECOSYSTEM" "ios"
|
|
593
713
|
append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
|
|
594
714
|
if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
|
|
@@ -586,9 +586,129 @@ provision_ruby() {
|
|
|
586
586
|
append_path_prefix "$dir/vendor/bundle/bin"
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
# ── iOS Xcode project helpers ─────────────────────────────────────────────────
|
|
590
|
+
# Tuist, XcodeGen and CocoaPods treat the .xcodeproj / .xcworkspace as a build
|
|
591
|
+
# product rather than a tracked file, so a fresh worktree has nothing for
|
|
592
|
+
# xcodebuild to open. Generate it here — and fail naming the missing generator,
|
|
593
|
+
# instead of letting xcodebuild report an opaque "scheme not found" later.
|
|
594
|
+
|
|
595
|
+
# First project file of a kind in the work dir. Runs from inside the dir so a dot
|
|
596
|
+
# in the worktree path itself cannot trip the dotfile filter, and skips both the
|
|
597
|
+
# project.xcworkspace every .xcodeproj carries inside it and whatever CocoaPods
|
|
598
|
+
# generates under Pods/.
|
|
599
|
+
har_ios_find_project_file() {
|
|
600
|
+
local dir="$1"
|
|
601
|
+
local pattern="$2"
|
|
602
|
+
local match=""
|
|
603
|
+
match="$(cd "$dir" 2>/dev/null && find . -maxdepth 2 -name "$pattern" \
|
|
604
|
+
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1)" || true
|
|
605
|
+
[ -n "$match" ] || return 1
|
|
606
|
+
echo "${match#./}"
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
# True when this worktree already has something xcodebuild can open. Adapt-time
|
|
610
|
+
# HARNESS_XCODE_WORKSPACE / HARNESS_XCODE_PROJECT decide it when set: they name
|
|
611
|
+
# the generated file, so a missing one means the generator still has to run.
|
|
612
|
+
har_ios_has_project() {
|
|
613
|
+
local dir="$1"
|
|
614
|
+
|
|
615
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ]; then
|
|
616
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] && [ -e "$dir/$HARNESS_XCODE_WORKSPACE" ]; then
|
|
617
|
+
return 0
|
|
618
|
+
fi
|
|
619
|
+
if [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$dir/$HARNESS_XCODE_PROJECT" ]; then
|
|
620
|
+
return 0
|
|
621
|
+
fi
|
|
622
|
+
return 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
if har_ios_find_project_file "$dir" '*.xcworkspace' >/dev/null; then return 0; fi
|
|
626
|
+
if har_ios_find_project_file "$dir" '*.xcodeproj' >/dev/null; then return 0; fi
|
|
627
|
+
return 1
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
# Generator this repo declares, or empty. A Podfile counts: `pod install` is what
|
|
631
|
+
# writes the .xcworkspace for a CocoaPods project.
|
|
632
|
+
har_ios_project_generator() {
|
|
633
|
+
local dir="$1"
|
|
634
|
+
if [ -f "$dir/Project.swift" ] || [ -f "$dir/Workspace.swift" ]; then echo tuist; return; fi
|
|
635
|
+
if [ -f "$dir/project.yml" ] || [ -f "$dir/project.yaml" ]; then echo xcodegen; return; fi
|
|
636
|
+
if [ -f "$dir/Podfile" ]; then echo pod; return; fi
|
|
637
|
+
echo ""
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
har_ios_generate_project() {
|
|
641
|
+
local dir="$1"
|
|
642
|
+
local generator=""
|
|
643
|
+
|
|
644
|
+
if har_ios_has_project "$dir"; then
|
|
645
|
+
return 0
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
generator="$(har_ios_project_generator "$dir")"
|
|
649
|
+
if [ -z "$generator" ]; then
|
|
650
|
+
pt_log "No .xcodeproj/.xcworkspace found and no generator manifest (Project.swift, project.yml, Podfile) — set HARNESS_XCODE_PROJECT/HARNESS_XCODE_WORKSPACE or HARNESS_INSTALL_CMD in harness.env"
|
|
651
|
+
return 0
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
if ! command -v "$generator" >/dev/null 2>&1; then
|
|
655
|
+
local label="$generator"
|
|
656
|
+
[ "$generator" = "pod" ] && label="CocoaPods (pod)"
|
|
657
|
+
pt_log "ERROR: this repo generates its Xcode project with ${label}, which is not on PATH."
|
|
658
|
+
pt_log " Install ${label}, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
659
|
+
return 1
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
case "$generator" in
|
|
663
|
+
tuist)
|
|
664
|
+
pt_log "Generating the Xcode project with tuist..."
|
|
665
|
+
if ! (cd "$dir" && tuist generate --no-open); then
|
|
666
|
+
pt_log "tuist generate --no-open failed — retrying without the flag"
|
|
667
|
+
(cd "$dir" && tuist generate)
|
|
668
|
+
fi
|
|
669
|
+
;;
|
|
670
|
+
xcodegen)
|
|
671
|
+
pt_log "Generating the Xcode project with xcodegen..."
|
|
672
|
+
(cd "$dir" && xcodegen generate)
|
|
673
|
+
;;
|
|
674
|
+
pod)
|
|
675
|
+
# har_ios_pod_install writes the workspace right after this.
|
|
676
|
+
:
|
|
677
|
+
;;
|
|
678
|
+
esac
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
# CocoaPods dependencies. Independent of project generation: a tracked
|
|
682
|
+
# .xcworkspace still cannot build when Pods/ is missing in a fresh worktree.
|
|
683
|
+
har_ios_pod_install() {
|
|
684
|
+
local dir="$1"
|
|
685
|
+
|
|
686
|
+
[ -f "$dir/Podfile" ] || return 0
|
|
687
|
+
[ -d "$dir/Pods" ] && return 0
|
|
688
|
+
|
|
689
|
+
if ! command -v pod >/dev/null 2>&1; then
|
|
690
|
+
pt_log "ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH."
|
|
691
|
+
pt_log " Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
692
|
+
return 1
|
|
693
|
+
fi
|
|
694
|
+
|
|
695
|
+
pt_log "Installing CocoaPods dependencies..."
|
|
696
|
+
(cd "$dir" && pod install)
|
|
697
|
+
}
|
|
698
|
+
|
|
589
699
|
provision_ios() {
|
|
590
700
|
local dir="$1"
|
|
591
|
-
|
|
701
|
+
|
|
702
|
+
# An explicit HARNESS_INSTALL_CMD owns provisioning outright: the default
|
|
703
|
+
# generators stay out of the way, and a failing override fails the launch
|
|
704
|
+
# rather than being papered over.
|
|
705
|
+
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
706
|
+
run_install_cmd "$dir"
|
|
707
|
+
else
|
|
708
|
+
har_ios_generate_project "$dir"
|
|
709
|
+
har_ios_pod_install "$dir"
|
|
710
|
+
fi
|
|
711
|
+
|
|
592
712
|
append_env "HARNESS_ECOSYSTEM" "ios"
|
|
593
713
|
append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
|
|
594
714
|
if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
|
|
@@ -21,6 +21,12 @@ structure, then make the changes listed below. Commit when done.
|
|
|
21
21
|
| `HARNESS_SIMULATOR_NAME` | Display name exactly as shown in `xcrun simctl list devices` (e.g. `iPhone 16`). |
|
|
22
22
|
| `HARNESS_BUNDLE_ID` | App bundle identifier from the Xcode target (e.g. `com.example.myapp`). |
|
|
23
23
|
|
|
24
|
+
If the project is generated (`Project.swift`, `project.yml`, or a `Podfile` with no
|
|
25
|
+
tracked `.xcworkspace`), still set the path the generator produces — launch runs
|
|
26
|
+
`tuist generate` / `xcodegen generate` / `pod install` when the file is absent from
|
|
27
|
+
a fresh worktree. Use `HARNESS_INSTALL_CMD` only when that default is wrong; it then
|
|
28
|
+
owns provisioning outright.
|
|
29
|
+
|
|
24
30
|
Run `./.har/setup-infra.sh` after editing to confirm the simulator boots.
|
|
25
31
|
|
|
26
32
|
## 3 — Verify `.har/verify.sh` builds and tests correctly
|
|
@@ -21,7 +21,7 @@ Generated and maintained by [`har`](https://github.com/os-factory/har). Run `har
|
|
|
21
21
|
| `setup-infra.sh` | Check the toolchain; start optional Docker services |
|
|
22
22
|
| `simulator.sh` | Create, boot and delete one iOS Simulator per agent slot |
|
|
23
23
|
| `launch.sh` | Launch one agent slot (git worktree, toolchain provisioning, simulator, env file) |
|
|
24
|
-
| `provision-toolchain.sh` |
|
|
24
|
+
| `provision-toolchain.sh` | Generate the Xcode project when it is a build product (Tuist / XcodeGen / CocoaPods) and write Xcode paths (`XCODEBUILD_BIN`, …) to `.env.agent.<id>` |
|
|
25
25
|
| `verify.sh` | Verification pipeline (build smoke by default; --full adds tests, lint, flows) |
|
|
26
26
|
| `teardown.sh` | Tear down one agent slot (worktree + env file) |
|
|
27
27
|
| `agent-cli.sh` | Inspect slot status, run xcodebuild commands, install/launch app |
|
|
@@ -9,6 +9,12 @@ export HARNESS_AGENT_SLOT_MAX=3
|
|
|
9
9
|
|
|
10
10
|
# Toolchain provisioning — launch writes Xcode/simulator paths into .env.agent.<id>
|
|
11
11
|
export HARNESS_ECOSYSTEM="ios"
|
|
12
|
+
# Generated projects: when the worktree has no .xcodeproj/.xcworkspace, launch runs
|
|
13
|
+
# the generator this repo declares — tuist generate (Project.swift), xcodegen
|
|
14
|
+
# generate (project.yml) — plus pod install when a Podfile is present and Pods/ is
|
|
15
|
+
# missing. A missing generator fails the launch by name.
|
|
16
|
+
# HARNESS_INSTALL_CMD owns provisioning outright: set it and no default generator
|
|
17
|
+
# runs, and its failure fails the launch.
|
|
12
18
|
# export HARNESS_INSTALL_CMD="xcodebuild -resolvePackageDependencies ..."
|
|
13
19
|
# Node package manager: auto-detected from package.json "packageManager" and the
|
|
14
20
|
# lockfile (bun.lock → bun, pnpm-lock.yaml → pnpm, yarn.lock → yarn, else npm),
|
|
@@ -586,9 +586,129 @@ provision_ruby() {
|
|
|
586
586
|
append_path_prefix "$dir/vendor/bundle/bin"
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
# ── iOS Xcode project helpers ─────────────────────────────────────────────────
|
|
590
|
+
# Tuist, XcodeGen and CocoaPods treat the .xcodeproj / .xcworkspace as a build
|
|
591
|
+
# product rather than a tracked file, so a fresh worktree has nothing for
|
|
592
|
+
# xcodebuild to open. Generate it here — and fail naming the missing generator,
|
|
593
|
+
# instead of letting xcodebuild report an opaque "scheme not found" later.
|
|
594
|
+
|
|
595
|
+
# First project file of a kind in the work dir. Runs from inside the dir so a dot
|
|
596
|
+
# in the worktree path itself cannot trip the dotfile filter, and skips both the
|
|
597
|
+
# project.xcworkspace every .xcodeproj carries inside it and whatever CocoaPods
|
|
598
|
+
# generates under Pods/.
|
|
599
|
+
har_ios_find_project_file() {
|
|
600
|
+
local dir="$1"
|
|
601
|
+
local pattern="$2"
|
|
602
|
+
local match=""
|
|
603
|
+
match="$(cd "$dir" 2>/dev/null && find . -maxdepth 2 -name "$pattern" \
|
|
604
|
+
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1)" || true
|
|
605
|
+
[ -n "$match" ] || return 1
|
|
606
|
+
echo "${match#./}"
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
# True when this worktree already has something xcodebuild can open. Adapt-time
|
|
610
|
+
# HARNESS_XCODE_WORKSPACE / HARNESS_XCODE_PROJECT decide it when set: they name
|
|
611
|
+
# the generated file, so a missing one means the generator still has to run.
|
|
612
|
+
har_ios_has_project() {
|
|
613
|
+
local dir="$1"
|
|
614
|
+
|
|
615
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ]; then
|
|
616
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] && [ -e "$dir/$HARNESS_XCODE_WORKSPACE" ]; then
|
|
617
|
+
return 0
|
|
618
|
+
fi
|
|
619
|
+
if [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$dir/$HARNESS_XCODE_PROJECT" ]; then
|
|
620
|
+
return 0
|
|
621
|
+
fi
|
|
622
|
+
return 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
if har_ios_find_project_file "$dir" '*.xcworkspace' >/dev/null; then return 0; fi
|
|
626
|
+
if har_ios_find_project_file "$dir" '*.xcodeproj' >/dev/null; then return 0; fi
|
|
627
|
+
return 1
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
# Generator this repo declares, or empty. A Podfile counts: `pod install` is what
|
|
631
|
+
# writes the .xcworkspace for a CocoaPods project.
|
|
632
|
+
har_ios_project_generator() {
|
|
633
|
+
local dir="$1"
|
|
634
|
+
if [ -f "$dir/Project.swift" ] || [ -f "$dir/Workspace.swift" ]; then echo tuist; return; fi
|
|
635
|
+
if [ -f "$dir/project.yml" ] || [ -f "$dir/project.yaml" ]; then echo xcodegen; return; fi
|
|
636
|
+
if [ -f "$dir/Podfile" ]; then echo pod; return; fi
|
|
637
|
+
echo ""
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
har_ios_generate_project() {
|
|
641
|
+
local dir="$1"
|
|
642
|
+
local generator=""
|
|
643
|
+
|
|
644
|
+
if har_ios_has_project "$dir"; then
|
|
645
|
+
return 0
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
generator="$(har_ios_project_generator "$dir")"
|
|
649
|
+
if [ -z "$generator" ]; then
|
|
650
|
+
pt_log "No .xcodeproj/.xcworkspace found and no generator manifest (Project.swift, project.yml, Podfile) — set HARNESS_XCODE_PROJECT/HARNESS_XCODE_WORKSPACE or HARNESS_INSTALL_CMD in harness.env"
|
|
651
|
+
return 0
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
if ! command -v "$generator" >/dev/null 2>&1; then
|
|
655
|
+
local label="$generator"
|
|
656
|
+
[ "$generator" = "pod" ] && label="CocoaPods (pod)"
|
|
657
|
+
pt_log "ERROR: this repo generates its Xcode project with ${label}, which is not on PATH."
|
|
658
|
+
pt_log " Install ${label}, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
659
|
+
return 1
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
case "$generator" in
|
|
663
|
+
tuist)
|
|
664
|
+
pt_log "Generating the Xcode project with tuist..."
|
|
665
|
+
if ! (cd "$dir" && tuist generate --no-open); then
|
|
666
|
+
pt_log "tuist generate --no-open failed — retrying without the flag"
|
|
667
|
+
(cd "$dir" && tuist generate)
|
|
668
|
+
fi
|
|
669
|
+
;;
|
|
670
|
+
xcodegen)
|
|
671
|
+
pt_log "Generating the Xcode project with xcodegen..."
|
|
672
|
+
(cd "$dir" && xcodegen generate)
|
|
673
|
+
;;
|
|
674
|
+
pod)
|
|
675
|
+
# har_ios_pod_install writes the workspace right after this.
|
|
676
|
+
:
|
|
677
|
+
;;
|
|
678
|
+
esac
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
# CocoaPods dependencies. Independent of project generation: a tracked
|
|
682
|
+
# .xcworkspace still cannot build when Pods/ is missing in a fresh worktree.
|
|
683
|
+
har_ios_pod_install() {
|
|
684
|
+
local dir="$1"
|
|
685
|
+
|
|
686
|
+
[ -f "$dir/Podfile" ] || return 0
|
|
687
|
+
[ -d "$dir/Pods" ] && return 0
|
|
688
|
+
|
|
689
|
+
if ! command -v pod >/dev/null 2>&1; then
|
|
690
|
+
pt_log "ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH."
|
|
691
|
+
pt_log " Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
692
|
+
return 1
|
|
693
|
+
fi
|
|
694
|
+
|
|
695
|
+
pt_log "Installing CocoaPods dependencies..."
|
|
696
|
+
(cd "$dir" && pod install)
|
|
697
|
+
}
|
|
698
|
+
|
|
589
699
|
provision_ios() {
|
|
590
700
|
local dir="$1"
|
|
591
|
-
|
|
701
|
+
|
|
702
|
+
# An explicit HARNESS_INSTALL_CMD owns provisioning outright: the default
|
|
703
|
+
# generators stay out of the way, and a failing override fails the launch
|
|
704
|
+
# rather than being papered over.
|
|
705
|
+
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
706
|
+
run_install_cmd "$dir"
|
|
707
|
+
else
|
|
708
|
+
har_ios_generate_project "$dir"
|
|
709
|
+
har_ios_pod_install "$dir"
|
|
710
|
+
fi
|
|
711
|
+
|
|
592
712
|
append_env "HARNESS_ECOSYSTEM" "ios"
|
|
593
713
|
append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
|
|
594
714
|
if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
|
|
@@ -58,12 +58,18 @@ xc_target_flags() {
|
|
|
58
58
|
elif [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$WORK_DIR/${HARNESS_XCODE_PROJECT}" ]; then
|
|
59
59
|
echo "-project $WORK_DIR/${HARNESS_XCODE_PROJECT}"
|
|
60
60
|
else
|
|
61
|
-
# Auto-detect: prefer workspace (CocoaPods), then project
|
|
61
|
+
# Auto-detect: prefer workspace (CocoaPods), then project. Runs from inside
|
|
62
|
+
# WORK_DIR so a dot in the worktree path itself cannot trip the dotfile
|
|
63
|
+
# filter, and skips both the project.xcworkspace every .xcodeproj carries
|
|
64
|
+
# inside it and the CocoaPods project under Pods/ — either would point
|
|
65
|
+
# xcodebuild at the wrong target.
|
|
62
66
|
local ws prj
|
|
63
|
-
ws="$(
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
ws="$(cd "$WORK_DIR" && find . -maxdepth 2 -name "*.xcworkspace" \
|
|
68
|
+
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1 || true)"
|
|
69
|
+
prj="$(cd "$WORK_DIR" && find . -maxdepth 2 -name "*.xcodeproj" \
|
|
70
|
+
! -path "./.*" ! -path "*/Pods/*" 2>/dev/null | head -1 || true)"
|
|
71
|
+
if [ -n "$ws" ]; then echo "-workspace $WORK_DIR/${ws#./}"
|
|
72
|
+
elif [ -n "$prj" ]; then echo "-project $WORK_DIR/${prj#./}"
|
|
67
73
|
fi
|
|
68
74
|
fi
|
|
69
75
|
}
|
|
@@ -586,9 +586,129 @@ provision_ruby() {
|
|
|
586
586
|
append_path_prefix "$dir/vendor/bundle/bin"
|
|
587
587
|
}
|
|
588
588
|
|
|
589
|
+
# ── iOS Xcode project helpers ─────────────────────────────────────────────────
|
|
590
|
+
# Tuist, XcodeGen and CocoaPods treat the .xcodeproj / .xcworkspace as a build
|
|
591
|
+
# product rather than a tracked file, so a fresh worktree has nothing for
|
|
592
|
+
# xcodebuild to open. Generate it here — and fail naming the missing generator,
|
|
593
|
+
# instead of letting xcodebuild report an opaque "scheme not found" later.
|
|
594
|
+
|
|
595
|
+
# First project file of a kind in the work dir. Runs from inside the dir so a dot
|
|
596
|
+
# in the worktree path itself cannot trip the dotfile filter, and skips both the
|
|
597
|
+
# project.xcworkspace every .xcodeproj carries inside it and whatever CocoaPods
|
|
598
|
+
# generates under Pods/.
|
|
599
|
+
har_ios_find_project_file() {
|
|
600
|
+
local dir="$1"
|
|
601
|
+
local pattern="$2"
|
|
602
|
+
local match=""
|
|
603
|
+
match="$(cd "$dir" 2>/dev/null && find . -maxdepth 2 -name "$pattern" \
|
|
604
|
+
! -path "./.*" ! -path "*.xcodeproj/*" ! -path "*/Pods/*" 2>/dev/null | head -1)" || true
|
|
605
|
+
[ -n "$match" ] || return 1
|
|
606
|
+
echo "${match#./}"
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
# True when this worktree already has something xcodebuild can open. Adapt-time
|
|
610
|
+
# HARNESS_XCODE_WORKSPACE / HARNESS_XCODE_PROJECT decide it when set: they name
|
|
611
|
+
# the generated file, so a missing one means the generator still has to run.
|
|
612
|
+
har_ios_has_project() {
|
|
613
|
+
local dir="$1"
|
|
614
|
+
|
|
615
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] || [ -n "${HARNESS_XCODE_PROJECT:-}" ]; then
|
|
616
|
+
if [ -n "${HARNESS_XCODE_WORKSPACE:-}" ] && [ -e "$dir/$HARNESS_XCODE_WORKSPACE" ]; then
|
|
617
|
+
return 0
|
|
618
|
+
fi
|
|
619
|
+
if [ -n "${HARNESS_XCODE_PROJECT:-}" ] && [ -e "$dir/$HARNESS_XCODE_PROJECT" ]; then
|
|
620
|
+
return 0
|
|
621
|
+
fi
|
|
622
|
+
return 1
|
|
623
|
+
fi
|
|
624
|
+
|
|
625
|
+
if har_ios_find_project_file "$dir" '*.xcworkspace' >/dev/null; then return 0; fi
|
|
626
|
+
if har_ios_find_project_file "$dir" '*.xcodeproj' >/dev/null; then return 0; fi
|
|
627
|
+
return 1
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
# Generator this repo declares, or empty. A Podfile counts: `pod install` is what
|
|
631
|
+
# writes the .xcworkspace for a CocoaPods project.
|
|
632
|
+
har_ios_project_generator() {
|
|
633
|
+
local dir="$1"
|
|
634
|
+
if [ -f "$dir/Project.swift" ] || [ -f "$dir/Workspace.swift" ]; then echo tuist; return; fi
|
|
635
|
+
if [ -f "$dir/project.yml" ] || [ -f "$dir/project.yaml" ]; then echo xcodegen; return; fi
|
|
636
|
+
if [ -f "$dir/Podfile" ]; then echo pod; return; fi
|
|
637
|
+
echo ""
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
har_ios_generate_project() {
|
|
641
|
+
local dir="$1"
|
|
642
|
+
local generator=""
|
|
643
|
+
|
|
644
|
+
if har_ios_has_project "$dir"; then
|
|
645
|
+
return 0
|
|
646
|
+
fi
|
|
647
|
+
|
|
648
|
+
generator="$(har_ios_project_generator "$dir")"
|
|
649
|
+
if [ -z "$generator" ]; then
|
|
650
|
+
pt_log "No .xcodeproj/.xcworkspace found and no generator manifest (Project.swift, project.yml, Podfile) — set HARNESS_XCODE_PROJECT/HARNESS_XCODE_WORKSPACE or HARNESS_INSTALL_CMD in harness.env"
|
|
651
|
+
return 0
|
|
652
|
+
fi
|
|
653
|
+
|
|
654
|
+
if ! command -v "$generator" >/dev/null 2>&1; then
|
|
655
|
+
local label="$generator"
|
|
656
|
+
[ "$generator" = "pod" ] && label="CocoaPods (pod)"
|
|
657
|
+
pt_log "ERROR: this repo generates its Xcode project with ${label}, which is not on PATH."
|
|
658
|
+
pt_log " Install ${label}, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
659
|
+
return 1
|
|
660
|
+
fi
|
|
661
|
+
|
|
662
|
+
case "$generator" in
|
|
663
|
+
tuist)
|
|
664
|
+
pt_log "Generating the Xcode project with tuist..."
|
|
665
|
+
if ! (cd "$dir" && tuist generate --no-open); then
|
|
666
|
+
pt_log "tuist generate --no-open failed — retrying without the flag"
|
|
667
|
+
(cd "$dir" && tuist generate)
|
|
668
|
+
fi
|
|
669
|
+
;;
|
|
670
|
+
xcodegen)
|
|
671
|
+
pt_log "Generating the Xcode project with xcodegen..."
|
|
672
|
+
(cd "$dir" && xcodegen generate)
|
|
673
|
+
;;
|
|
674
|
+
pod)
|
|
675
|
+
# har_ios_pod_install writes the workspace right after this.
|
|
676
|
+
:
|
|
677
|
+
;;
|
|
678
|
+
esac
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
# CocoaPods dependencies. Independent of project generation: a tracked
|
|
682
|
+
# .xcworkspace still cannot build when Pods/ is missing in a fresh worktree.
|
|
683
|
+
har_ios_pod_install() {
|
|
684
|
+
local dir="$1"
|
|
685
|
+
|
|
686
|
+
[ -f "$dir/Podfile" ] || return 0
|
|
687
|
+
[ -d "$dir/Pods" ] && return 0
|
|
688
|
+
|
|
689
|
+
if ! command -v pod >/dev/null 2>&1; then
|
|
690
|
+
pt_log "ERROR: this repo uses CocoaPods (Podfile, no Pods/) and pod is not on PATH."
|
|
691
|
+
pt_log " Install CocoaPods, or set HARNESS_INSTALL_CMD in harness.env to provision the project another way."
|
|
692
|
+
return 1
|
|
693
|
+
fi
|
|
694
|
+
|
|
695
|
+
pt_log "Installing CocoaPods dependencies..."
|
|
696
|
+
(cd "$dir" && pod install)
|
|
697
|
+
}
|
|
698
|
+
|
|
589
699
|
provision_ios() {
|
|
590
700
|
local dir="$1"
|
|
591
|
-
|
|
701
|
+
|
|
702
|
+
# An explicit HARNESS_INSTALL_CMD owns provisioning outright: the default
|
|
703
|
+
# generators stay out of the way, and a failing override fails the launch
|
|
704
|
+
# rather than being papered over.
|
|
705
|
+
if [ -n "${HARNESS_INSTALL_CMD:-}" ]; then
|
|
706
|
+
run_install_cmd "$dir"
|
|
707
|
+
else
|
|
708
|
+
har_ios_generate_project "$dir"
|
|
709
|
+
har_ios_pod_install "$dir"
|
|
710
|
+
fi
|
|
711
|
+
|
|
592
712
|
append_env "HARNESS_ECOSYSTEM" "ios"
|
|
593
713
|
append_env "XCODEBUILD_BIN" "$(command -v xcodebuild 2>/dev/null || echo xcodebuild)"
|
|
594
714
|
if [ -n "${HARNESS_XCODE_SCHEME:-}" ]; then
|