Compare commits
366 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d6ee41d6d5 | |
|
|
741758b9ba | |
|
|
f03344599b | |
|
|
16e9ad7d00 | |
|
|
85b77e41bc | |
|
|
9be4b9dc86 | |
|
|
46050816d8 | |
|
|
d358da6f50 | |
|
|
b4926493fb | |
|
|
c166ec1698 | |
|
|
3d6445b446 | |
|
|
f5a7e1e631 | |
|
|
0a9ad1a419 | |
|
|
cd2d1c6698 | |
|
|
65519d3874 | |
|
|
71b405bd0c | |
|
|
2be4479694 | |
|
|
206d99a672 | |
|
|
0ad265b76d | |
|
|
154a7604f9 | |
|
|
5a2d4fd8cc | |
|
|
70cb4395fe | |
|
|
7360b62106 | |
|
|
e46673151d | |
|
|
5e65e3e712 | |
|
|
5cf26631b9 | |
|
|
0d8fe3156a | |
|
|
69866eb29b | |
|
|
f2e700cda3 | |
|
|
494e62f0b8 | |
|
|
27def7c5ce | |
|
|
f9c2b3c122 | |
|
|
7132d10945 | |
|
|
33e373e65b | |
|
|
cfa9e2361c | |
|
|
09fce08792 | |
|
|
01365193b9 | |
|
|
1414d3bf4b | |
|
|
fbaec2adaa | |
|
|
f47f8bf08c | |
|
|
d56bd82e5d | |
|
|
4b95c2c93f | |
|
|
75924563a8 | |
|
|
f3319b8eb8 | |
|
|
5ee829f2c8 | |
|
|
64d9651dca | |
|
|
0682bdb108 | |
|
|
3abe5ef330 | |
|
|
36c1f1d9b7 | |
|
|
413eb891fe | |
|
|
be895f2507 | |
|
|
9115ef2553 | |
|
|
11b22ea0d0 | |
|
|
062ecd3e0e | |
|
|
329c3e137e | |
|
|
e681fe0983 | |
|
|
2e6e2dfb6e | |
|
|
0652373c8c | |
|
|
082799eb6f | |
|
|
3b47c8dfc6 | |
|
|
69ed3fe0fa | |
|
|
256b8cc1c8 | |
|
|
d7752dd971 | |
|
|
64b8b7407b | |
|
|
91c8fbf624 | |
|
|
aec76f172d | |
|
|
a2b4e1ebfe | |
|
|
1f481f72c7 | |
|
|
463004bc84 | |
|
|
6755f3d245 | |
|
|
aa8af495d1 | |
|
|
4232c64336 | |
|
|
f4565a71c7 | |
|
|
971a78c341 | |
|
|
4f13a88f28 | |
|
|
ba783a5bc7 | |
|
|
db71c44bc1 | |
|
|
5ed6926ec7 | |
|
|
95ee5a5656 | |
|
|
ea02816fa7 | |
|
|
e6a57fc713 | |
|
|
17dc1dab05 | |
|
|
b86acf6821 | |
|
|
537b590859 | |
|
|
45c214692c | |
|
|
b94738812f | |
|
|
2d4e5b9968 | |
|
|
24607711dc | |
|
|
081c8ac4e3 | |
|
|
d0f94cc4c8 | |
|
|
fe19dc9f17 | |
|
|
6f8ae07451 | |
|
|
16a5100187 | |
|
|
7058092d82 | |
|
|
0d3b4f4efd | |
|
|
aad3ba254d | |
|
|
0c0a90071d | |
|
|
276b6dde65 | |
|
|
5e8c823ef0 | |
|
|
b6445b9d3a | |
|
|
ad9ce34d12 | |
|
|
9746337eeb | |
|
|
f7880705ec | |
|
|
bc67673068 | |
|
|
393d7c615b | |
|
|
f292033e59 | |
|
|
e3cf995511 | |
|
|
3c3581a46f | |
|
|
2fbdfd6186 | |
|
|
a806b2d4ef | |
|
|
c48cab887b | |
|
|
d5d126deaa | |
|
|
ac6cbef9a6 | |
|
|
9736671744 | |
|
|
2ec40d16cb | |
|
|
ce496aa3ad | |
|
|
660eac6ae0 | |
|
|
530036c1bc | |
|
|
69ca3f729a | |
|
|
e70eea50c4 | |
|
|
3ac0f46b3e | |
|
|
63e44895a7 | |
|
|
c1d543be58 | |
|
|
ca553f0b1d | |
|
|
b9ffc31440 | |
|
|
0b4954f232 | |
|
|
f2d0330eec | |
|
|
6ae3ffd75f | |
|
|
64f4871059 | |
|
|
5f35113643 | |
|
|
9ec94173b3 | |
|
|
0eafad7bcf | |
|
|
1fd4c5e3ae | |
|
|
cfed2eac90 | |
|
|
7be8facd36 | |
|
|
6f66644628 | |
|
|
2401e19f34 | |
|
|
1a09db706a | |
|
|
99ef3f49c7 | |
|
|
7d267ec27b | |
|
|
7dc9dd706d | |
|
|
6a21d56c86 | |
|
|
f64d712020 | |
|
|
7b41df79bd | |
|
|
bf4ddcee86 | |
|
|
56a1ec662e | |
|
|
1b15ebd8b2 | |
|
|
1271f59338 | |
|
|
3c4bbd340d | |
|
|
92a5e245cc | |
|
|
ec6a446fc1 | |
|
|
4206908127 | |
|
|
d42ba4a1e1 | |
|
|
005b272792 | |
|
|
ec0c478a02 | |
|
|
ad419122b2 | |
|
|
2335029721 | |
|
|
c3819d6d35 | |
|
|
1f9fdd5630 | |
|
|
447a46c522 | |
|
|
345b223e76 | |
|
|
5f66cb1ca2 | |
|
|
0542253d49 | |
|
|
cdc53f0a12 | |
|
|
99e619e634 | |
|
|
946adbfc95 | |
|
|
e134909aa8 | |
|
|
998bbf8ca8 | |
|
|
5a55351c81 | |
|
|
64b1190f65 | |
|
|
4df29efc66 | |
|
|
b205e70322 | |
|
|
c18ef9c553 | |
|
|
cec270adb3 | |
|
|
6d14eaee8c | |
|
|
f1a9e22ed2 | |
|
|
2545826772 | |
|
|
0b49ba6651 | |
|
|
e5474440fc | |
|
|
0c165a93d2 | |
|
|
d3ad77c873 | |
|
|
40128d40e2 | |
|
|
7920f0cda2 | |
|
|
b3b4dafc83 | |
|
|
ae70c6052d | |
|
|
1ea5f77e35 | |
|
|
8392fd1b30 | |
|
|
fdff7d8daf | |
|
|
6a01707630 | |
|
|
49718082b2 | |
|
|
5b17f4e264 | |
|
|
14fb85f5b3 | |
|
|
c8a1e808b6 | |
|
|
8c1f0c213f | |
|
|
9875d24c4b | |
|
|
8425f62a71 | |
|
|
7ebaf88c48 | |
|
|
639b46cb2f | |
|
|
77cc104d6d | |
|
|
159d4c1c36 | |
|
|
2a0a476e3b | |
|
|
74040f6870 | |
|
|
9f061dacb4 | |
|
|
f8fd129df6 | |
|
|
80bedb81db | |
|
|
7692f27396 | |
|
|
2bd3a78831 | |
|
|
39e0ccf2e4 | |
|
|
e3cad7e8c2 | |
|
|
47f36a33f8 | |
|
|
c198ef9957 | |
|
|
d038ed85d2 | |
|
|
da102cc5e6 | |
|
|
b0520dfd1d | |
|
|
37c77845c8 | |
|
|
9a16028831 | |
|
|
cd817762c5 | |
|
|
32c59db145 | |
|
|
8dcd824d76 | |
|
|
200bc65efb | |
|
|
74aca70ef6 | |
|
|
1e710b24b9 | |
|
|
26c6575d1c | |
|
|
63e491fbf8 | |
|
|
600cb89e35 | |
|
|
dbde34c6a8 | |
|
|
ef6d97a77e | |
|
|
760e04e340 | |
|
|
b863116992 | |
|
|
444b21aba2 | |
|
|
525f51a54e | |
|
|
5c7259d9a9 | |
|
|
24ff639c4d | |
|
|
0be36e7056 | |
|
|
ed0b1e4c15 | |
|
|
489255bec4 | |
|
|
92c70a2e79 | |
|
|
5de5e0997b | |
|
|
127683c285 | |
|
|
98a8ed97a4 | |
|
|
3d76cfe25e | |
|
|
4a45e89e9f | |
|
|
f887c42ab1 | |
|
|
cabda00d2a | |
|
|
118270dd45 | |
|
|
c80a91a5bf | |
|
|
da6beb5b44 | |
|
|
7a36c811f9 | |
|
|
07be5a66be | |
|
|
61f4dee507 | |
|
|
fbcbf4cbfe | |
|
|
c90679131d | |
|
|
c9a92d7a31 | |
|
|
2793f40e9a | |
|
|
7a7778be0f | |
|
|
6f7ef84825 | |
|
|
d594e1add0 | |
|
|
d50adeeaa2 | |
|
|
5d1abcb935 | |
|
|
8151177d8f | |
|
|
2cd59ec2b4 | |
|
|
2dcf12940d | |
|
|
acd0ec5913 | |
|
|
f2d703668c | |
|
|
54a41a1e0a | |
|
|
57a0eb2d30 | |
|
|
c73a2a5fe9 | |
|
|
989b0d8f1a | |
|
|
415bb40956 | |
|
|
9ccac855c3 | |
|
|
31bc126bc4 | |
|
|
7932133d6f | |
|
|
c254792f80 | |
|
|
00fd234514 | |
|
|
df763eb2d6 | |
|
|
e1755912e6 | |
|
|
f1715dca7b | |
|
|
e89c673a33 | |
|
|
264c3e8fb0 | |
|
|
0215733c42 | |
|
|
d3f7a8f37d | |
|
|
7026060433 | |
|
|
9b2a899ea8 | |
|
|
08d9f601e4 | |
|
|
8b0607128f | |
|
|
bf9f6a6146 | |
|
|
d367ab61c8 | |
|
|
f06b997060 | |
|
|
5b625c9167 | |
|
|
03e06aff01 | |
|
|
7849005130 | |
|
|
c03e2f3253 | |
|
|
882cbe2344 | |
|
|
0cc9b01623 | |
|
|
9940dd3705 | |
|
|
a1a1fd7d36 | |
|
|
fc41a4d619 | |
|
|
a80bae15d9 | |
|
|
104e432eb4 | |
|
|
002717156a | |
|
|
13071e71be | |
|
|
fb83953b1b | |
|
|
19ccfde91c | |
|
|
4b3f94df8d | |
|
|
5aa1d63f6a | |
|
|
a63fb03f2e | |
|
|
8f93e8eae2 | |
|
|
8b9f6ce141 | |
|
|
a9d8536f46 | |
|
|
73dea7bcb0 | |
|
|
e5f5edca05 | |
|
|
21522999bb | |
|
|
664d47260e | |
|
|
67a57c3064 | |
|
|
fabd89cead | |
|
|
b19d3fa66c | |
|
|
3f1850ad07 | |
|
|
4b7ac1f76f | |
|
|
98b522dbfa | |
|
|
41b20ab533 | |
|
|
b28936faa2 | |
|
|
3e3e6818f3 | |
|
|
47695a9abd | |
|
|
6555932569 | |
|
|
4513f2adad | |
|
|
0a4f436302 | |
|
|
277b13fb59 | |
|
|
19a8271935 | |
|
|
ba158f524c | |
|
|
a34d6d3e51 | |
|
|
59624221fe | |
|
|
ac0d6efcf5 | |
|
|
4e75d95247 | |
|
|
7fcf10afd6 | |
|
|
0f7f741d45 | |
|
|
f0e06a7c5e | |
|
|
21e5a3eb86 | |
|
|
a2d379b619 | |
|
|
5d00757016 | |
|
|
04eaf0415f | |
|
|
fc12391db4 | |
|
|
62bb71fc2c | |
|
|
4625de36fc | |
|
|
7221de2158 | |
|
|
3ac3ec803c | |
|
|
620771594e | |
|
|
a7907e34db | |
|
|
0f02d0a14f | |
|
|
7be84bd9d9 | |
|
|
8c1d1b889a | |
|
|
703e5f8e35 | |
|
|
94dc6c6d03 | |
|
|
7e5b78ae4c | |
|
|
42b40752b5 | |
|
|
072558f6ab | |
|
|
e4af3c70c1 | |
|
|
55ec020db9 | |
|
|
a7bdd003d4 | |
|
|
19ff55570e | |
|
|
4d038de343 | |
|
|
8faf32710b | |
|
|
be1be002c4 | |
|
|
920aa01e4f | |
|
|
b24d5c0ffb | |
|
|
1629c949a6 | |
|
|
5828bf5b7c |
47
.cirrus.yml
47
.cirrus.yml
|
|
@ -1,47 +0,0 @@
|
|||
task:
|
||||
name: "Update Base Image"
|
||||
only_if: $CIRRUS_CRON != ""
|
||||
persistent_worker:
|
||||
labels:
|
||||
name: dev-mini
|
||||
env:
|
||||
TART_REGISTRY_USERNAME: fkorotkov # GitHub supports only PATs
|
||||
TART_REGISTRY_PASSWORD: ENCRYPTED[!82ed873afdf627284305afef4958c85a8f73127b09978a9786ac521559630ea6c9a5ab6e7f8315abf9ead09b6eff6eae!]
|
||||
update_script: brew update && brew upgrade
|
||||
info_script:
|
||||
- tart --version
|
||||
- packer --version
|
||||
build_script:
|
||||
- packer init templates/base.pkr.hcl
|
||||
- packer build -var-file="variables.pkrvars.hcl" templates/base.pkr.hcl
|
||||
push_script:
|
||||
- tart push ventura-base ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
always:
|
||||
cleanup_script:
|
||||
- tart delete ventura-base
|
||||
|
||||
task:
|
||||
name: "Release Xcode $CIRRUS_TAG"
|
||||
only_if: $CIRRUS_TAG != ""
|
||||
persistent_worker:
|
||||
labels:
|
||||
name: dev-mini
|
||||
env:
|
||||
TART_REGISTRY_USERNAME: fkorotkov # GitHub supports only PATs
|
||||
TART_REGISTRY_PASSWORD: ENCRYPTED[!82ed873afdf627284305afef4958c85a8f73127b09978a9786ac521559630ea6c9a5ab6e7f8315abf9ead09b6eff6eae!]
|
||||
update_script: brew update && brew upgrade
|
||||
info_script:
|
||||
- tart --version
|
||||
- packer --version
|
||||
pull_base_script:
|
||||
- tart pull ghcr.io/cirruslabs/macos-ventura-base:latest
|
||||
- tart clone ghcr.io/cirruslabs/macos-ventura-base:latest ventura-base
|
||||
build_script:
|
||||
- packer init templates/xcode.pkr.hcl
|
||||
- packer build -var-file="variables.pkrvars.hcl" -var xcode_version="$CIRRUS_TAG" templates/xcode.pkr.hcl
|
||||
push_script:
|
||||
- tart push ventura-xcode:$CIRRUS_TAG ghcr.io/cirruslabs/macos-ventura-xcode:$CIRRUS_TAG ghcr.io/cirruslabs/macos-ventura-xcode:latest
|
||||
always:
|
||||
cleanup_script:
|
||||
- tart delete ventura-base || true
|
||||
- tart delete ventura-xcode:$CIRRUS_TAG || true
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
name: Monthly Images
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 8 * * 6"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: tart-image-builds
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
TART_REGISTRY_HOSTNAME: ghcr.io
|
||||
TART_REGISTRY_USERNAME: ${{ github.actor }}
|
||||
TART_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
should-run:
|
||||
name: Check Monthly Cadence
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
outputs:
|
||||
build: ${{ steps.cadence.outputs.build }}
|
||||
steps:
|
||||
- name: Check first Saturday
|
||||
id: cadence
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
build=false
|
||||
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||
build=true
|
||||
else
|
||||
day="$(date -u +%d)"
|
||||
if (( 10#$day <= 7 )); then
|
||||
build=true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "build=$build" >> "$GITHUB_OUTPUT"
|
||||
if [[ "$build" != "true" ]]; then
|
||||
echo "Not the first Saturday of the month; skipping image rebuilds."
|
||||
fi
|
||||
|
||||
update-base:
|
||||
name: Update Base Images (${{ matrix.macos_version }})
|
||||
needs: should-run
|
||||
if: needs.should-run.outputs.build == 'true'
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- macos_version: sonoma
|
||||
disable_sip_template: disable-sip.pkr.hcl
|
||||
- macos_version: sequoia
|
||||
disable_sip_template: disable-sip-with-username.pkr.hcl
|
||||
- macos_version: tahoe
|
||||
disable_sip_template: disable-sip-with-username.pkr.hcl
|
||||
env:
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
DISABLE_SIP_TEMPLATE: ${{ matrix.disable_sip_template }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Tool versions
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull vanilla image
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:latest"
|
||||
tart clone "ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:latest" "$MACOS_VERSION-base"
|
||||
|
||||
- name: Disable SIP
|
||||
run: |
|
||||
packer init "templates/$DISABLE_SIP_TEMPLATE"
|
||||
packer build -var "vm_name=$MACOS_VERSION-base" "templates/$DISABLE_SIP_TEMPLATE"
|
||||
|
||||
- name: Build base image
|
||||
run: |
|
||||
packer init templates/base.pkr.hcl
|
||||
packer build -var "vm_name=$MACOS_VERSION-base" templates/base.pkr.hcl
|
||||
|
||||
- name: Push base image
|
||||
run: |
|
||||
tart push "$MACOS_VERSION-base" "ghcr.io/cirruslabs/macos-$MACOS_VERSION-base:latest"
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-base" || true
|
||||
|
||||
update-xcode:
|
||||
name: Update Xcode Images (${{ matrix.macos_version }} ${{ matrix.xcode_version }})
|
||||
needs:
|
||||
- should-run
|
||||
- update-base
|
||||
if: needs.should-run.outputs.build == 'true'
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- macos_version: tahoe
|
||||
xcode_version: "26.2"
|
||||
xcode_components: '"MetalToolchain"'
|
||||
latest: true
|
||||
- macos_version: tahoe
|
||||
xcode_version: "26.1.1"
|
||||
xcode_components: '"MetalToolchain"'
|
||||
latest: false
|
||||
- macos_version: tahoe
|
||||
xcode_version: "26.0.1"
|
||||
xcode_components: '"MetalToolchain"'
|
||||
latest: false
|
||||
- macos_version: sequoia
|
||||
xcode_version: "16.4"
|
||||
xcode_components: ""
|
||||
latest: true
|
||||
- macos_version: sequoia
|
||||
xcode_version: "16.3"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
- macos_version: sequoia
|
||||
xcode_version: "16.2"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
- macos_version: sequoia
|
||||
xcode_version: "16.1"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
- macos_version: sequoia
|
||||
xcode_version: "16"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
- macos_version: sonoma
|
||||
xcode_version: "16.1"
|
||||
xcode_components: ""
|
||||
latest: true
|
||||
- macos_version: sonoma
|
||||
xcode_version: "16"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
- macos_version: sonoma
|
||||
xcode_version: "15.4"
|
||||
xcode_components: ""
|
||||
latest: false
|
||||
env:
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
XCODE_COMPONENTS: ${{ matrix.xcode_components }}
|
||||
XCODE_VERSION: ${{ matrix.xcode_version }}
|
||||
LATEST: ${{ matrix.latest }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Tool versions
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull base image
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-base:latest"
|
||||
|
||||
- name: Build Xcode image
|
||||
run: |
|
||||
packer init templates/xcode.pkr.hcl
|
||||
packer build \
|
||||
-var "macos_version=$MACOS_VERSION" \
|
||||
-var "xcode_version=[\"$XCODE_VERSION\"]" \
|
||||
-var "xcode_components=[$XCODE_COMPONENTS]" \
|
||||
templates/xcode.pkr.hcl
|
||||
|
||||
- name: Push Xcode image
|
||||
run: |
|
||||
if [[ "$LATEST" == "true" ]]; then
|
||||
tart push "$MACOS_VERSION-xcode:$XCODE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:$XCODE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:latest"
|
||||
else
|
||||
tart push "$MACOS_VERSION-xcode:$XCODE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:$XCODE_VERSION"
|
||||
fi
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-xcode:$XCODE_VERSION" || true
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
name: Release Images
|
||||
|
||||
on:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
xcode_version:
|
||||
description: "Xcode version/tag to release"
|
||||
required: true
|
||||
type: string
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: tart-image-builds
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
TART_REGISTRY_HOSTNAME: ghcr.io
|
||||
TART_REGISTRY_USERNAME: ${{ github.actor }}
|
||||
TART_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
XCODE_RELEASE_VERSION: ${{ github.event.release.tag_name || inputs.xcode_version }}
|
||||
|
||||
jobs:
|
||||
release-xcode:
|
||||
name: Release Xcode ${{ github.event.release.tag_name || inputs.xcode_version }} (${{ matrix.macos_version }})
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
macos_version:
|
||||
- tahoe
|
||||
- sequoia
|
||||
env:
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
XCODE_COMPONENTS: '"MetalToolchain"'
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Validate release version
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -z "$XCODE_RELEASE_VERSION" ]]; then
|
||||
echo "XCODE_RELEASE_VERSION is required."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Tool versions
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull base image
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-base:latest"
|
||||
|
||||
- name: Build release image
|
||||
run: |
|
||||
packer init templates/xcode.pkr.hcl
|
||||
packer build \
|
||||
-var "macos_version=$MACOS_VERSION" \
|
||||
-var "xcode_version=[\"$XCODE_RELEASE_VERSION\"]" \
|
||||
-var "xcode_components=[$XCODE_COMPONENTS]" \
|
||||
templates/xcode.pkr.hcl
|
||||
|
||||
- name: Push release image
|
||||
run: |
|
||||
if [[ "$XCODE_RELEASE_VERSION" == *beta* ]]; then
|
||||
tart push "$MACOS_VERSION-xcode:$XCODE_RELEASE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:$XCODE_RELEASE_VERSION"
|
||||
else
|
||||
tart push "$MACOS_VERSION-xcode:$XCODE_RELEASE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:$XCODE_RELEASE_VERSION" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-xcode:latest"
|
||||
fi
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-xcode:$XCODE_RELEASE_VERSION" || true
|
||||
|
||||
release-runner:
|
||||
name: Update Runner Image (${{ matrix.macos_version }})
|
||||
# Keep runner refreshes independent from the release-xcode matrix so one
|
||||
# Xcode image failure does not skip the runner matrix.
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- macos_version: sequoia
|
||||
xcode_versions: '"26.0.1",16.4,16.3,16.2,16.1,16'
|
||||
additional_ios_builds: "18.5,18.4,18.2,17.5"
|
||||
additional_tvos_builds: "17.5"
|
||||
xcode_components: '"MetalToolchain"'
|
||||
disk_size: 380
|
||||
- macos_version: tahoe
|
||||
xcode_versions: '"26.6","27-beta-4","26.5","27-beta","26.4.1","26.3","26.2","26.1.1","26.0.1"'
|
||||
additional_ios_builds: "18.6"
|
||||
additional_tvos_builds: ""
|
||||
xcode_components: '"MetalToolchain"'
|
||||
disk_size: 520
|
||||
env:
|
||||
ADDITIONAL_IOS_BUILDS: ${{ matrix.additional_ios_builds }}
|
||||
ADDITIONAL_TVOS_BUILDS: ${{ matrix.additional_tvos_builds }}
|
||||
DISK_SIZE: ${{ matrix.disk_size }}
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
XCODE_COMPONENTS: ${{ matrix.xcode_components }}
|
||||
XCODE_VERSIONS: ${{ matrix.xcode_versions }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Tool versions
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull base image
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-base:latest"
|
||||
|
||||
- name: Build runner image
|
||||
run: |
|
||||
packer init templates/xcode.pkr.hcl
|
||||
packer build \
|
||||
-var tag=runner \
|
||||
-var "disk_size=$DISK_SIZE" \
|
||||
-var disk_free_mb=100000 \
|
||||
-var "macos_version=$MACOS_VERSION" \
|
||||
-var "xcode_version=[$XCODE_VERSIONS]" \
|
||||
-var "additional_ios_builds=[$ADDITIONAL_IOS_BUILDS]" \
|
||||
-var "additional_tvos_builds=[$ADDITIONAL_TVOS_BUILDS]" \
|
||||
-var "xcode_components=[$XCODE_COMPONENTS]" \
|
||||
-var "expected_runtimes_file=data/expected.$MACOS_VERSION.runtimes.txt" \
|
||||
templates/xcode.pkr.hcl
|
||||
|
||||
- name: Finalize runner image
|
||||
run: |
|
||||
if [[ -f "scripts/finalize-$MACOS_VERSION.sh" ]]; then
|
||||
packer build \
|
||||
-var "vm_name=$MACOS_VERSION-xcode:runner" \
|
||||
-var "script_path=scripts/finalize-$MACOS_VERSION.sh" \
|
||||
templates/exex-script.pkr.hcl
|
||||
else
|
||||
echo "Skipping prepare script for $MACOS_VERSION"
|
||||
fi
|
||||
|
||||
- name: Push runner image
|
||||
run: |
|
||||
tart push "$MACOS_VERSION-xcode:runner" "ghcr.io/cirruslabs/macos-runner:$MACOS_VERSION"
|
||||
|
||||
- name: Cleanup
|
||||
if: always()
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-xcode:runner" || true
|
||||
|
|
@ -0,0 +1,381 @@
|
|||
name: Template Builds
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/monthly.yml"
|
||||
- ".github/workflows/release.yml"
|
||||
- ".github/workflows/template-validation.yml"
|
||||
- "data/**"
|
||||
- "scripts/**"
|
||||
- "templates/**"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: read
|
||||
|
||||
concurrency:
|
||||
group: template-builds-${{ github.event.pull_request.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FASTLANE_SESSION: ${{ secrets.FASTLANE_SESSION }}
|
||||
FASTLANE_USER: ${{ secrets.FASTLANE_USER }}
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
HOMEBREW_NO_INSTALL_CLEANUP: 1
|
||||
PACKER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TART_REGISTRY_HOSTNAME: ghcr.io
|
||||
TART_REGISTRY_USERNAME: ${{ github.actor }}
|
||||
TART_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
packer-validate:
|
||||
name: Packer Validate
|
||||
runs-on: macos-15
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Packer
|
||||
uses: hashicorp/setup-packer@v3
|
||||
|
||||
- name: Install validation dependencies
|
||||
run: |
|
||||
brew install ansible
|
||||
|
||||
- name: Prepare validation inputs
|
||||
run: |
|
||||
mkdir -p "$HOME/XcodesCache"
|
||||
touch "$HOME/XcodesCache/Xcode_26.6.xip"
|
||||
|
||||
- name: Validate templates
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
validate() {
|
||||
local template="$1"
|
||||
shift
|
||||
|
||||
packer init "$template"
|
||||
packer validate "$@" "$template"
|
||||
}
|
||||
|
||||
for template in templates/vanilla-*.pkr.hcl; do
|
||||
validate "$template"
|
||||
done
|
||||
|
||||
validate templates/base.pkr.hcl \
|
||||
-var vm_name=template-validation-base
|
||||
|
||||
validate templates/disable-sip.pkr.hcl \
|
||||
-var vm_name=template-validation-disable-sip
|
||||
|
||||
validate templates/disable-sip-with-username.pkr.hcl \
|
||||
-var vm_name=template-validation-disable-sip-user
|
||||
|
||||
validate templates/exex-script.pkr.hcl \
|
||||
-var vm_name=template-validation-exec \
|
||||
-var script_path=scripts/finalize-tahoe.sh
|
||||
|
||||
validate templates/resolve-macos-number.pkr.hcl \
|
||||
-var vm_base_name=template-validation-base \
|
||||
-var vm_name=template-validation-resolve \
|
||||
-var resolve_file=macos-version.txt
|
||||
|
||||
validate templates/xcode.pkr.hcl \
|
||||
-var macos_version=tahoe \
|
||||
-var 'xcode_version=["26.6"]' \
|
||||
-var expected_runtimes_file=data/expected.tahoe.runtimes.txt
|
||||
|
||||
build-vanilla:
|
||||
name: Build Vanilla Image (${{ matrix.macos_version }})
|
||||
needs: packer-validate
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
macos_version:
|
||||
- golden-gate
|
||||
- tahoe
|
||||
- sequoia
|
||||
- sonoma
|
||||
- monterey
|
||||
env:
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Select image
|
||||
id: select
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > changed-files.txt
|
||||
|
||||
build=false
|
||||
if grep -Fxq "templates/vanilla-$MACOS_VERSION.pkr.hcl" changed-files.txt; then
|
||||
build=true
|
||||
fi
|
||||
|
||||
echo "build=$build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Tool versions
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Build vanilla image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer init "templates/vanilla-$MACOS_VERSION.pkr.hcl"
|
||||
packer build "templates/vanilla-$MACOS_VERSION.pkr.hcl"
|
||||
|
||||
- name: Cleanup
|
||||
if: always() && steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-vanilla" || true
|
||||
|
||||
build-base:
|
||||
name: Build Base Image (${{ matrix.macos_version }})
|
||||
needs: packer-validate
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- macos_version: sonoma
|
||||
disable_sip_template: disable-sip.pkr.hcl
|
||||
- macos_version: sequoia
|
||||
disable_sip_template: disable-sip-with-username.pkr.hcl
|
||||
- macos_version: tahoe
|
||||
disable_sip_template: disable-sip-with-username.pkr.hcl
|
||||
env:
|
||||
DISABLE_SIP_TEMPLATE: ${{ matrix.disable_sip_template }}
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Select image
|
||||
id: select
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > changed-files.txt
|
||||
|
||||
build=false
|
||||
if grep -Eq '^(templates/base\.pkr\.hcl|templates/disable-sip.*\.pkr\.hcl|data/(github_known_hosts|limit\.maxfiles\.plist|setup-info-template\.json|tart-guest-.*\.plist)|scripts/(install-actions-runner|update-tcc-database)\.sh|ansible/)' changed-files.txt; then
|
||||
build=true
|
||||
fi
|
||||
|
||||
echo "build=$build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Tool versions
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull vanilla image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:latest"
|
||||
tart clone "ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:latest" "$MACOS_VERSION-base"
|
||||
|
||||
- name: Disable SIP
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer init "templates/$DISABLE_SIP_TEMPLATE"
|
||||
packer build -var "vm_name=$MACOS_VERSION-base" "templates/$DISABLE_SIP_TEMPLATE"
|
||||
|
||||
- name: Build base image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer init templates/base.pkr.hcl
|
||||
packer build -var "vm_name=$MACOS_VERSION-base" templates/base.pkr.hcl
|
||||
|
||||
- name: Cleanup
|
||||
if: always() && steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-base" || true
|
||||
|
||||
build-runner:
|
||||
name: Build Runner Image (${{ matrix.macos_version }})
|
||||
needs: packer-validate
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
include:
|
||||
- macos_version: tahoe
|
||||
xcode_versions: '"26.6","27-beta-2","26.5","27-beta","26.4.1","26.3","26.2","26.1.1","26.0.1"'
|
||||
additional_ios_builds: "18.6"
|
||||
additional_tvos_builds: ""
|
||||
xcode_components: '"MetalToolchain"'
|
||||
disk_size: 520
|
||||
- macos_version: sequoia
|
||||
xcode_versions: '"26.0.1",16.4,16.3,16.2,16.1,16'
|
||||
additional_ios_builds: "18.5,18.4,18.2,17.5"
|
||||
additional_tvos_builds: "17.5"
|
||||
xcode_components: '"MetalToolchain"'
|
||||
disk_size: 380
|
||||
env:
|
||||
ADDITIONAL_IOS_BUILDS: ${{ matrix.additional_ios_builds }}
|
||||
ADDITIONAL_TVOS_BUILDS: ${{ matrix.additional_tvos_builds }}
|
||||
DISK_SIZE: ${{ matrix.disk_size }}
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
XCODE_COMPONENTS: ${{ matrix.xcode_components }}
|
||||
XCODE_VERSIONS: ${{ matrix.xcode_versions }}
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Select image
|
||||
id: select
|
||||
env:
|
||||
BASE_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
git diff --name-only "$BASE_SHA" "$HEAD_SHA" > changed-files.txt
|
||||
|
||||
build=false
|
||||
if grep -Fxq ".github/workflows/release.yml" changed-files.txt; then
|
||||
build=true
|
||||
elif grep -Fxq "data/expected.$MACOS_VERSION.runtimes.txt" changed-files.txt; then
|
||||
build=true
|
||||
elif grep -Fxq "scripts/finalize-$MACOS_VERSION.sh" changed-files.txt; then
|
||||
build=true
|
||||
elif grep -Eq '^(templates/xcode\.pkr\.hcl|data/setup-info-template\.json|scripts/install-actions-runner\.sh)$' changed-files.txt; then
|
||||
build=true
|
||||
fi
|
||||
|
||||
echo "build=$build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Tool versions
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Pull base image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart pull "ghcr.io/cirruslabs/macos-$MACOS_VERSION-base:latest"
|
||||
|
||||
- name: Prepare Xcode archives
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
source ~/.zprofile || true
|
||||
|
||||
if ! command -v xcodes >/dev/null; then
|
||||
brew install xcodes
|
||||
fi
|
||||
|
||||
mkdir -p "$HOME/XcodesCache"
|
||||
IFS=',' read -ra versions <<< "$XCODE_VERSIONS"
|
||||
|
||||
for raw_version in "${versions[@]}"; do
|
||||
version="${raw_version//\"/}"
|
||||
target="$HOME/XcodesCache/Xcode_${version}.xip"
|
||||
|
||||
if [[ -f "$target" ]]; then
|
||||
echo "Using cached Xcode $version at $target"
|
||||
continue
|
||||
fi
|
||||
|
||||
echo "Downloading Xcode $version"
|
||||
if [[ -z "${FASTLANE_SESSION:-}" ]]; then
|
||||
echo "::error::Missing $target and FASTLANE_SESSION is not configured. Pre-cache the Xcode archive on the runner or add Apple Developer auth secrets."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
download_args=(download "$version" --directory "$HOME/XcodesCache" --use-fastlane-auth)
|
||||
if [[ -n "${FASTLANE_USER:-}" ]]; then
|
||||
download_args+=(--fastlane-user "$FASTLANE_USER")
|
||||
fi
|
||||
xcodes "${download_args[@]}"
|
||||
|
||||
candidate=""
|
||||
case "$version" in
|
||||
27-beta-2)
|
||||
candidate="$HOME/XcodesCache/Xcode_27_beta_2.xip"
|
||||
;;
|
||||
27-beta)
|
||||
candidate="$HOME/XcodesCache/Xcode_27_beta.xip"
|
||||
;;
|
||||
*)
|
||||
candidate="$(find "$HOME/XcodesCache" -maxdepth 1 -type f -name "Xcode_${version}*.xip" -print -quit)"
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ -n "$candidate" && -f "$candidate" && "$candidate" != "$target" ]]; then
|
||||
mv "$candidate" "$target"
|
||||
fi
|
||||
|
||||
test -f "$target"
|
||||
done
|
||||
|
||||
- name: Build runner image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer init templates/xcode.pkr.hcl
|
||||
packer build \
|
||||
-var tag=runner \
|
||||
-var "disk_size=$DISK_SIZE" \
|
||||
-var disk_free_mb=100000 \
|
||||
-var "macos_version=$MACOS_VERSION" \
|
||||
-var "xcode_version=[$XCODE_VERSIONS]" \
|
||||
-var "additional_ios_builds=[$ADDITIONAL_IOS_BUILDS]" \
|
||||
-var "additional_tvos_builds=[$ADDITIONAL_TVOS_BUILDS]" \
|
||||
-var "xcode_components=[$XCODE_COMPONENTS]" \
|
||||
-var "expected_runtimes_file=data/expected.$MACOS_VERSION.runtimes.txt" \
|
||||
templates/xcode.pkr.hcl
|
||||
|
||||
- name: Finalize runner image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
if [[ -f "scripts/finalize-$MACOS_VERSION.sh" ]]; then
|
||||
packer build \
|
||||
-var "vm_name=$MACOS_VERSION-xcode:runner" \
|
||||
-var "script_path=scripts/finalize-$MACOS_VERSION.sh" \
|
||||
templates/exex-script.pkr.hcl
|
||||
else
|
||||
echo "Skipping prepare script for $MACOS_VERSION"
|
||||
fi
|
||||
|
||||
- name: Cleanup
|
||||
if: always() && steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-xcode:runner" || true
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
name: Vanilla Images
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- "templates/vanilla-*.pkr.hcl"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
macos_version:
|
||||
description: "macOS vanilla image to build"
|
||||
required: true
|
||||
default: all
|
||||
type: choice
|
||||
options:
|
||||
- all
|
||||
- golden-gate
|
||||
- tahoe
|
||||
- sequoia
|
||||
- sonoma
|
||||
- monterey
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
concurrency:
|
||||
group: tart-image-builds
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
TART_REGISTRY_HOSTNAME: ghcr.io
|
||||
TART_REGISTRY_USERNAME: ${{ github.actor }}
|
||||
TART_REGISTRY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
jobs:
|
||||
update-vanilla:
|
||||
name: Update Vanilla Image (${{ matrix.macos_version }})
|
||||
if: >-
|
||||
${{
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
github.ref == format('refs/heads/{0}', github.event.repository.default_branch)
|
||||
}}
|
||||
runs-on: [self-hosted, macOS, ARM64]
|
||||
timeout-minutes: 180
|
||||
strategy:
|
||||
fail-fast: false
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
macos_version:
|
||||
- golden-gate
|
||||
- tahoe
|
||||
- sequoia
|
||||
- sonoma
|
||||
- monterey
|
||||
env:
|
||||
MACOS_VERSION: ${{ matrix.macos_version }}
|
||||
RESOLVE_VM_NAME: resolve-macos-number-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.macos_version }}
|
||||
RESOLVE_FILE: resolve-macos-number-${{ github.run_id }}-${{ github.run_attempt }}-${{ matrix.macos_version }}.txt
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Select image
|
||||
id: select
|
||||
env:
|
||||
BEFORE_SHA: ${{ github.event.before }}
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
INPUT_MACOS_VERSION: ${{ inputs.macos_version || 'all' }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
build=false
|
||||
if [[ "$EVENT_NAME" == "workflow_dispatch" ]]; then
|
||||
if [[ "$INPUT_MACOS_VERSION" == "all" || "$INPUT_MACOS_VERSION" == "$MACOS_VERSION" ]]; then
|
||||
build=true
|
||||
fi
|
||||
else
|
||||
if [[ "$BEFORE_SHA" =~ ^0+$ ]]; then
|
||||
git diff-tree --no-commit-id --name-only -r "$GITHUB_SHA" > changed-files.txt
|
||||
else
|
||||
git diff --name-only "$BEFORE_SHA" "$GITHUB_SHA" > changed-files.txt
|
||||
fi
|
||||
|
||||
if grep -Fxq "templates/vanilla-$MACOS_VERSION.pkr.hcl" changed-files.txt; then
|
||||
build=true
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "build=$build" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Tool versions
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart --version
|
||||
packer --version
|
||||
|
||||
- name: Build vanilla image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer init "templates/vanilla-$MACOS_VERSION.pkr.hcl"
|
||||
packer build "templates/vanilla-$MACOS_VERSION.pkr.hcl"
|
||||
|
||||
- name: Resolve macOS version
|
||||
id: resolve
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
packer build \
|
||||
-var "vm_base_name=$MACOS_VERSION-vanilla" \
|
||||
-var "vm_name=$RESOLVE_VM_NAME" \
|
||||
-var "resolve_file=$RESOLVE_FILE" \
|
||||
templates/resolve-macos-number.pkr.hcl
|
||||
echo "macos_number=$(cat "$RESOLVE_FILE")" >> "$GITHUB_OUTPUT"
|
||||
rm -f "$RESOLVE_FILE"
|
||||
|
||||
- name: Push vanilla image
|
||||
if: steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart push "$MACOS_VERSION-vanilla" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:latest" \
|
||||
"ghcr.io/cirruslabs/macos-$MACOS_VERSION-vanilla:${{ steps.resolve.outputs.macos_number }}"
|
||||
|
||||
- name: Cleanup
|
||||
if: always() && steps.select.outputs.build == 'true'
|
||||
run: |
|
||||
tart delete "$MACOS_VERSION-vanilla" || true
|
||||
tart delete "$RESOLVE_VM_NAME" || true
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
## Building Vanilla Image
|
||||
|
||||
To build `macos-sonoma-vanilla`:
|
||||
|
||||
```bash
|
||||
packer build templates/vanilla-sonoma.pkr.hcl
|
||||
```
|
||||
|
||||
Optionally, SIP can be disabled for each image by running the following commands:
|
||||
|
||||
```bash
|
||||
packer build -var vm_name=sonoma-vanilla templates/disable-sip.pkr.hcl
|
||||
```
|
||||
|
||||
## Building Base Image
|
||||
|
||||
```bash
|
||||
packer build -var vm_name=sonoma-vanilla templates/base.pkr.hcl
|
||||
```
|
||||
|
||||
## Building Xcode Image
|
||||
|
||||
```bash
|
||||
packer build -var macos_version=sonoma -var xcode_version="[15.4]" templates/xcode.pkr.hcl
|
||||
```
|
||||
52
README.md
52
README.md
|
|
@ -1,45 +1,25 @@
|
|||
## macOS Packer Templates for Cirrus CI
|
||||
## macOS Packer Templates for Tart
|
||||
|
||||
Repository with Packer templates to build [Tart VMs](https://github.com/cirruslabs/tart) to use with [Cirrus CI](https://cirrus-ci.org/guide/macOS/).
|
||||
Repository with Packer templates to build macOS [Tart](https://tart.run/) virtual machines to use with self-hosted
|
||||
GitHub Actions runners, [Cirrus Runners](https://cirrus-runners.app/) or [any other automation](https://tart.run/integrations/cirrus-cli/).
|
||||
|
||||
* `macos-{monterey,ventura}-vanilla` image has nothing pre-installed
|
||||
* `macos-{monterey,ventura}-base` image has only `brew` pre-installed
|
||||
* `macos-{monterey,ventura}-xcode:N` image is based on `macos-{monterey,ventura}-base` image and has `Xcode N` with [`Flutter`](https://flutter.dev/) pre-installed
|
||||
The following image variants are currently available:
|
||||
|
||||
See a full list of VMs available on Cirrus CI [here](https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos-).
|
||||
* `macos-{golden-gate,tahoe,sequoia,sonoma}-vanilla` — a vanilla macOS installation with helpful tweaks such as auto-login, but no additional software preinstalled
|
||||
* `macos-{tahoe,sequoia,sonoma}-base` — based on `macos-{tahoe,sequoia,sonoma}-vanilla` image, it comes with `brew` and [other useful software](https://github.com/cirruslabs/macos-image-templates/blob/main/templates/base.pkr.hcl) pre-installed, but without Xcode
|
||||
* `macos-{tahoe,sequoia,sonoma}-xcode:N` — based on `macos-{tahoe,sequoia,sonoma}-base` image and has `Xcode N` with [`Flutter`](https://flutter.dev/) pre-installed
|
||||
* `macos-runner:{tahoe,sequoia,sonoma}` — a variant of `xcode:N` with several versions of `Xcode` pre-installed and [`xcodes` tool](https://github.com/XcodesOrg/xcodes) to switch between them.
|
||||
|
||||
## Building Vanilla Image
|
||||
See a full list of VMs available [here](https://github.com/orgs/cirruslabs/packages?tab=packages&q=macos-).
|
||||
|
||||
To build `macos-monterey-vanilla`:
|
||||
## Release Cadence
|
||||
|
||||
```bash
|
||||
packer build templates/vanilla-monterey.pkr.hcl
|
||||
```
|
||||
Once a new version of Xcode is released, we will initiate a GitHub release which will automatically build and push
|
||||
a new version of the `macos-{tahoe,sequoia}-xcode:N`. This generally happens the next weekend after a release.
|
||||
Please watch this repository releases to get notified about new images.
|
||||
|
||||
To build `macos-ventura-vanilla`:
|
||||
## Update Cadence
|
||||
|
||||
```bash
|
||||
packer build templates/vanilla-ventura.pkr.hcl
|
||||
```
|
||||
Some of the images are regularly getting rebuild in order to update the pre-installed packages.
|
||||
|
||||
Optionally, SIP can be disabled for each image by running the following commands:
|
||||
|
||||
```bash
|
||||
packer build -var vm_name=monterey-vanilla templates/disable-sip.pkr.hcl
|
||||
```
|
||||
|
||||
```bash
|
||||
packer build -var vm_name=ventura-vanilla templates/disable-sip.pkr.hcl
|
||||
```
|
||||
|
||||
## Building Base Image
|
||||
|
||||
```bash
|
||||
packer build -var-file="variables.pkrvars.hcl" templates/base.pkr.hcl
|
||||
```
|
||||
|
||||
## Building Xcode Image
|
||||
|
||||
```bash
|
||||
packer build -var-file="variables.pkrvars.hcl" templates/xcode.pkr.hcl
|
||||
```
|
||||
[This workflow](.github/workflows/monthly.yml) defines images that are getting rebuilt monthly on the first Saturday of the month.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
- hosts: default
|
||||
roles:
|
||||
- system-updater
|
||||
vars:
|
||||
ansible_password: admin
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
- name: Perform first "softwareupdate" invocation
|
||||
include_tasks: softwareupdate.yml
|
||||
|
||||
# Needed after a major macOS update, otherwise things like
|
||||
# Command Line Tools won't be updated
|
||||
- name: Perform second "softwareupdate" invocation
|
||||
include_tasks: softwareupdate.yml
|
||||
|
||||
# This one looks weird, but unfortunately there's no other way around, because Homebrew
|
||||
# is not designed to run as root (see https://gist.github.com/irazasyed/7732946
|
||||
# for more details).
|
||||
- name: fix up /usr/local permissions for Homebrew
|
||||
file:
|
||||
path: /usr/local/share/man
|
||||
state: directory
|
||||
owner: "{{ ansible_user_id }}"
|
||||
recurse: yes
|
||||
become: yes
|
||||
|
||||
- name: "ensure that there are no more software updates available: check for available updates"
|
||||
command:
|
||||
cmd: "softwareupdate --all --list"
|
||||
register: software_updates_result
|
||||
|
||||
- name: "ensure that there are no more software updates available: parse available updates"
|
||||
set_fact:
|
||||
software_updates: "{{ software_updates_result.stdout | regex_findall('\\* Label: (.*)\\n\\tTitle: (.*), Version: (.*), Size: (.*), Recommended: (.*), Action: (.*), .*') | map('zip', ['label', 'title', 'version', 'size', 'recommended', 'action']) | map('map', 'reverse') | map('community.general.dict') }}"
|
||||
|
||||
- name: "ensure that there are no more software updates available: print available updates"
|
||||
debug:
|
||||
var: software_updates
|
||||
|
||||
- name: "ensure that there are no more software updates available: fail if some updates were not installed"
|
||||
fail:
|
||||
msg: "Found unapplied update: {{ item.label }}"
|
||||
loop: "{{ software_updates }}"
|
||||
when: "not item.label.startswith('macOS') or item.version.split('.')[0] == ansible_facts['distribution_version'].split('.')[0]"
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
- name: check for available updates
|
||||
command:
|
||||
cmd: "softwareupdate --all --list"
|
||||
register: software_updates_result
|
||||
|
||||
- name: parse available updates
|
||||
set_fact:
|
||||
software_updates: "{{ software_updates_result.stdout | regex_findall('\\* Label: (.*)\\n\\tTitle: (.*), Version: (.*), Size: (.*), Recommended: (.*), Action: (.*), .*') | map('zip', ['label', 'title', 'version', 'size', 'recommended', 'action']) | map('map', 'reverse') | map('community.general.dict') }}"
|
||||
|
||||
- name: print available updates
|
||||
debug:
|
||||
var: software_updates
|
||||
|
||||
# It seems that we must always pass "--restart" command-line argument to "softwareupdate",
|
||||
# otherwise on the OS update the "softwareupdate" will be stuck at "Downloaded: macOS [...]"
|
||||
- name: install available update
|
||||
command:
|
||||
cmd: "softwareupdate --install --agree-to-license --force --restart --user admin --stdinpass {{ stdinpass | default('') }} '{{ item.label }}'"
|
||||
stdin: "{{ ansible_password }}"
|
||||
register: update_result
|
||||
# Work around the following:
|
||||
# > Data could not be sent to remote host [...].
|
||||
# > Make sure this host can be reached over ssh:
|
||||
# > ssh: connect to host [...] port 22: Connection refused.
|
||||
ignore_unreachable: yes
|
||||
# Ignore SIGTERM/SIGKILL sent "softwareupdate" process
|
||||
# when the system reboots due to --restart and any other errors,
|
||||
# since we'll check whether the update was installed in main.yml
|
||||
# anyway.
|
||||
ignore_errors: yes
|
||||
become: yes
|
||||
loop: "{{ software_updates }}"
|
||||
when: "not item.label.startswith('macOS') or item.version.split('.')[0] == ansible_facts['distribution_version'].split('.')[0]"
|
||||
|
||||
# Wait for the connection since the previous command could restart the host
|
||||
- name: wait for connection
|
||||
wait_for_connection:
|
||||
# We need to wait long enough for the "softwareupdate" to initiate the reboot,
|
||||
# otherwise it's possible that we'll interrupt the process by running
|
||||
# the commands below on a non-restarted system.
|
||||
delay: 60
|
||||
timeout: 1800
|
||||
when: update_result is defined and not update_result.skipped | default(false)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
== Runtimes ==
|
||||
iOS 17.5 (17.5 - 21F79) - com.apple.CoreSimulator.SimRuntime.iOS-17-5
|
||||
iOS 18.0 (18.0 - 22A3351) - com.apple.CoreSimulator.SimRuntime.iOS-18-0
|
||||
iOS 18.1 (18.1 - 22B81) - com.apple.CoreSimulator.SimRuntime.iOS-18-1
|
||||
iOS 18.2 (18.2 - 22C150) - com.apple.CoreSimulator.SimRuntime.iOS-18-2
|
||||
iOS 18.3 (18.3.1 - 22D8075) - com.apple.CoreSimulator.SimRuntime.iOS-18-3
|
||||
iOS 18.4 (18.4 - 22E238) - com.apple.CoreSimulator.SimRuntime.iOS-18-4
|
||||
iOS 18.5 (18.5 - 22F77) - com.apple.CoreSimulator.SimRuntime.iOS-18-5
|
||||
iOS 18.6 (18.6 - 22G86) - com.apple.CoreSimulator.SimRuntime.iOS-18-6
|
||||
iOS 26.0 (26.0.1 - 23A8464) - com.apple.CoreSimulator.SimRuntime.iOS-26-0
|
||||
tvOS 17.5 (17.5 - 21L569) - com.apple.CoreSimulator.SimRuntime.tvOS-17-5
|
||||
tvOS 18.4 (18.4 - 22L254) - com.apple.CoreSimulator.SimRuntime.tvOS-18-4
|
||||
tvOS 18.5 (18.5 - 22L572) - com.apple.CoreSimulator.SimRuntime.tvOS-18-5
|
||||
tvOS 26.0 (26.0 - 23J352) - com.apple.CoreSimulator.SimRuntime.tvOS-26-0
|
||||
watchOS 11.4 (11.4 - 22T250) - com.apple.CoreSimulator.SimRuntime.watchOS-11-4
|
||||
watchOS 11.5 (11.5 - 22T572) - com.apple.CoreSimulator.SimRuntime.watchOS-11-5
|
||||
watchOS 26.0 (26.0 - 23R353) - com.apple.CoreSimulator.SimRuntime.watchOS-26-0
|
||||
visionOS 2.4 (2.4 - 22O237) - com.apple.CoreSimulator.SimRuntime.xrOS-2-4
|
||||
visionOS 2.5 (2.5 - 22O473) - com.apple.CoreSimulator.SimRuntime.xrOS-2-5
|
||||
visionOS 26.0 (26.0 - 23M336) - com.apple.CoreSimulator.SimRuntime.xrOS-26-0
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
== Runtimes ==
|
||||
iOS 18.0 (18.0 - 22A3351) - com.apple.CoreSimulator.SimRuntime.iOS-18-0
|
||||
iOS 18.1 (18.1 - 22B81) - com.apple.CoreSimulator.SimRuntime.iOS-18-1
|
||||
tvOS 18.0 (18.0 - 22J356) - com.apple.CoreSimulator.SimRuntime.tvOS-18-0
|
||||
tvOS 18.1 (18.1 - 22J578) - com.apple.CoreSimulator.SimRuntime.tvOS-18-1
|
||||
watchOS 11.0 (11.0 - 22R349) - com.apple.CoreSimulator.SimRuntime.watchOS-11-0
|
||||
watchOS 11.1 (11.1 - 22R581) - com.apple.CoreSimulator.SimRuntime.watchOS-11-1
|
||||
visionOS 2.0 (2.0 - 22N318) - com.apple.CoreSimulator.SimRuntime.xrOS-2-0
|
||||
visionOS 2.1 (2.1 - 22N580) - com.apple.CoreSimulator.SimRuntime.xrOS-2-1
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
== Runtimes ==
|
||||
iOS 18.6 (18.6 - 22G86) - com.apple.CoreSimulator.SimRuntime.iOS-18-6
|
||||
iOS 26.0 (26.0.1 - 23A8464) - com.apple.CoreSimulator.SimRuntime.iOS-26-0
|
||||
iOS 26.1 (26.1 - 23B86) - com.apple.CoreSimulator.SimRuntime.iOS-26-1
|
||||
iOS 26.3 (26.3.1 - 23D8133) - com.apple.CoreSimulator.SimRuntime.iOS-26-3
|
||||
iOS 26.4 (26.4.1 - 23E254a) - com.apple.CoreSimulator.SimRuntime.iOS-26-4
|
||||
iOS 26.5 (26.5 - 23F77) - com.apple.CoreSimulator.SimRuntime.iOS-26-5
|
||||
iOS 27.0 (27.0 - 24A5355p) - com.apple.CoreSimulator.SimRuntime.iOS-27-0
|
||||
iOS 27.0 (27.0 - 24A5370g) - com.apple.CoreSimulator.SimRuntime.iOS-27-0
|
||||
tvOS 26.5 (26.5 - 23L470) - com.apple.CoreSimulator.SimRuntime.tvOS-26-5
|
||||
tvOS 27.0 (27.0 - 24J5305f) - com.apple.CoreSimulator.SimRuntime.tvOS-27-0
|
||||
watchOS 26.5 (26.5 - 23T570) - com.apple.CoreSimulator.SimRuntime.watchOS-26-5
|
||||
watchOS 27.0 (27.0 - 24R5305f) - com.apple.CoreSimulator.SimRuntime.watchOS-27-0
|
||||
visionOS 26.5 (26.5 - 23O470) - com.apple.CoreSimulator.SimRuntime.xrOS-26-5
|
||||
visionOS 27.0 (27.0 - 24M5306g) - com.apple.CoreSimulator.SimRuntime.xrOS-27-0
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl
|
||||
github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg=
|
||||
github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
|
||||
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>limit.maxfiles</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>launchctl</string>
|
||||
<string>limit</string>
|
||||
<string>maxfiles</string>
|
||||
<string>65536</string>
|
||||
<string>524288</string>
|
||||
</array>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>ServiceIPC</key>
|
||||
<false/>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
[
|
||||
{
|
||||
"group": "Runner Detail",
|
||||
"detail": [
|
||||
{
|
||||
"name": "OS Information",
|
||||
"script": "echo \"macOS $(sw_vers -productVersion) ($(sw_vers -buildVersion))\""
|
||||
},
|
||||
{
|
||||
"name": "Build Date",
|
||||
"script": "date +\"%Y-%m-%d\""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Software Detail",
|
||||
"detail": [
|
||||
{
|
||||
"name": "Xcode Versions",
|
||||
"script": "xcodes installed --no-color || echo \"Xcode not installed\""
|
||||
},
|
||||
{
|
||||
"name": "Python Version",
|
||||
"script": "python3 --version"
|
||||
},
|
||||
{
|
||||
"name": "Node Version",
|
||||
"script": "node --version"
|
||||
},
|
||||
{
|
||||
"name": "Ruby Version",
|
||||
"script": "ruby --version"
|
||||
},
|
||||
{
|
||||
"name": "Bundler Version",
|
||||
"script": "bundler --version"
|
||||
},
|
||||
{
|
||||
"name": "CocoaPods Version",
|
||||
"script": "pod --version"
|
||||
},
|
||||
{
|
||||
"name": "Fastlane Version",
|
||||
"script": "fastlane --version"
|
||||
},
|
||||
{
|
||||
"name": "SwiftLint Version",
|
||||
"script": "swiftlint --version"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.cirruslabs.tart-guest-agent</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/opt/homebrew/bin/tart-guest-agent</string>
|
||||
<string>--run-agent</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/bin:/usr/bin:/usr/sbin:/usr/local/bin:/opt/homebrew/bin</string>
|
||||
<key>TERM</key>
|
||||
<string>xterm-256color</string>
|
||||
</dict>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/Users/admin</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/tart-guest-agent.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/tart-guest-agent.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>org.cirruslabs.tart-guest-daemon</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/opt/homebrew/bin/tart-guest-agent</string>
|
||||
<string>--run-daemon</string>
|
||||
</array>
|
||||
<key>EnvironmentVariables</key>
|
||||
<dict>
|
||||
<key>PATH</key>
|
||||
<string>/bin:/usr/bin:/usr/sbin:/usr/local/bin:/opt/homebrew/bin</string>
|
||||
</dict>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/var/empty</string>
|
||||
<key>RunAtLoad</key>
|
||||
<true/>
|
||||
<key>KeepAlive</key>
|
||||
<true/>
|
||||
<key>StandardOutPath</key>
|
||||
<string>/tmp/tart-guest-daemon.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>/tmp/tart-guest-daemon.log</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/expect -f
|
||||
|
||||
spawn automationmodetool enable-automationmode-without-authentication
|
||||
expect "Enter the password for user 'admin':"
|
||||
send "admin\n"
|
||||
expect "Setting up machine to allow Automation Mode without requiring user authentication... succeeded."
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
#!/bin/bash
|
||||
|
||||
source ~/.zprofile
|
||||
|
||||
# Set shell options to enable fail-fast behavior
|
||||
#
|
||||
# * -e: fail the script when an error occurs or command fails
|
||||
# * -u: fail the script when attempting to reference unset parameters
|
||||
# * -o pipefail: by default an exit status of a pipeline is that of its
|
||||
# last command, this fails the pipe early if an error in
|
||||
# any of its commands occurs
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
# Wait until `xcrun simctl list devices -v` no longer reports any devices as "unavailable".
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 - Success: no devices are marked as unavailable within the timeout window
|
||||
# 1 - Failure: timed out waiting for devices to become available
|
||||
# 2 - Failure: prerequisites missing (e.g., xcrun not found)
|
||||
|
||||
DEFAULT_TIMEOUT_MINUTES=60
|
||||
TIMEOUT_MINUTES=${1:-$DEFAULT_TIMEOUT_MINUTES}
|
||||
|
||||
if ! [[ "$TIMEOUT_MINUTES" =~ ^[0-9]+$ ]]; then
|
||||
echo "[wait-simulators] ERROR: TIMEOUT_MINUTES must be an integer number of minutes (got: '$TIMEOUT_MINUTES')." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
SECONDS_TOTAL=$(( TIMEOUT_MINUTES * 60 ))
|
||||
DEADLINE=$(( $(date +%s) + SECONDS_TOTAL ))
|
||||
SLEEP_SECONDS=15
|
||||
|
||||
# Print a one-line status snapshot of current unavailable devices (if any)
|
||||
print_status() {
|
||||
if xcrun simctl list devices -v | grep -qi "unavailable"; then
|
||||
echo "[wait-simulators] Still seeing 'unavailable' devices at $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
# Show a concise list of unavailable lines for debugging
|
||||
xcrun simctl list devices -v | grep -i "unavailable" | sed 's/^/[wait-simulators] /'
|
||||
else
|
||||
echo "[wait-simulators] No 'unavailable' devices detected at $(date '+%Y-%m-%d %H:%M:%S')"
|
||||
fi
|
||||
}
|
||||
|
||||
trap 'echo "[wait-simulators] Interrupted" >&2; exit 130' INT TERM
|
||||
|
||||
echo "[wait-simulators] Waiting up to ${TIMEOUT_MINUTES} minute(s) for simulators to become available..."
|
||||
|
||||
while true; do
|
||||
if ! xcrun simctl list devices -v | grep -qi "unavailable"; then
|
||||
echo "[wait-simulators] All simulators are available."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
NOW=$(date +%s)
|
||||
if (( NOW >= DEADLINE )); then
|
||||
echo "[wait-simulators] TIMEOUT after ${TIMEOUT_MINUTES} minute(s). Some simulators remain 'unavailable'." >&2
|
||||
echo "[wait-simulators] Final snapshot of unavailable devices:" >&2
|
||||
xcrun simctl list devices -v | grep -i "unavailable" | sed 's/^/[wait-simulators] /' >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
print_status
|
||||
REMAIN=$(( DEADLINE - NOW ))
|
||||
# Sleep in chunks to allow quicker exit when they become available
|
||||
SLEEP=$SLEEP_SECONDS
|
||||
if (( REMAIN < SLEEP_SECONDS )); then SLEEP=$REMAIN; fi
|
||||
sleep "$SLEEP"
|
||||
# Loop and re-check
|
||||
done
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Set shell options to enable fail-fast behavior
|
||||
#
|
||||
# * -e: fail the script when an error occurs or command fails
|
||||
# * -u: fail the script when attempting to reference unset parameters
|
||||
# * -o pipefail: by default an exit status of a pipeline is that of its
|
||||
# last command, this fails the pipe early if an error in
|
||||
# any of its commands occurs
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
source ~/.zprofile
|
||||
brew install jq
|
||||
|
||||
DOWNLOAD_URL=$(curl -sS 'https://api.github.com/repos/actions/runner/releases/latest' | jq --raw-output '.assets[] | select(.name | test("actions-runner-osx-arm64-[0-9.]+.tar.gz")) | .browser_download_url')
|
||||
|
||||
rm -rf actions-runner && mkdir actions-runner && cd actions-runner
|
||||
|
||||
wget -O - "${DOWNLOAD_URL}" | tar xz
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#!/bin/bash
|
||||
|
||||
source ~/.zprofile
|
||||
|
||||
# Set shell options to enable fail-fast behavior
|
||||
#
|
||||
# * -e: fail the script when an error occurs or command fails
|
||||
# * -u: fail the script when attempting to reference unset parameters
|
||||
# * -o pipefail: by default an exit status of a pipeline is that of its
|
||||
# last command, this fails the pipe early if an error in
|
||||
# any of its commands occurs
|
||||
#
|
||||
set -euo pipefail
|
||||
|
||||
update_tcc_database() {
|
||||
local tart_guest_agent_path
|
||||
tart_guest_agent_path="$(realpath /opt/homebrew/bin/tart-guest-agent)"
|
||||
|
||||
sudo sqlite3 "$1" <<-EOF
|
||||
INSERT OR REPLACE
|
||||
INTO access (
|
||||
service,
|
||||
client_type,
|
||||
client,
|
||||
auth_value,
|
||||
auth_reason,
|
||||
auth_version,
|
||||
indirect_object_identifier_type,
|
||||
indirect_object_identifier
|
||||
) VALUES
|
||||
-- Indirect osascript invocation via SSH
|
||||
('kTCCServiceAccessibility', 1, '/usr/libexec/sshd-keygen-wrapper', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceScreenCapture', 1, '/usr/libexec/sshd-keygen-wrapper', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServicePostEvent', 1, '/usr/libexec/sshd-keygen-wrapper', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceAppleEvents', 1, '/usr/libexec/sshd-keygen-wrapper', 2, 0, 1, 0, 'com.apple.systemevents'),
|
||||
('kTCCServiceAppleEvents', 1, '/usr/libexec/sshd-keygen-wrapper', 2, 0, 1, 0, 'com.apple.Safari'),
|
||||
-- Direct osascript invocation
|
||||
('kTCCServiceAccessibility', 1, '/usr/bin/osascript', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceScreenCapture', 1, '/usr/bin/osascript', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServicePostEvent', 1, '/usr/bin/osascript', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceAppleEvents', 1, '/usr/bin/osascript', 2, 0, 1, 0, 'com.apple.systemevents'),
|
||||
('kTCCServiceAppleEvents', 1, '/usr/bin/osascript', 2, 0, 1, 0, 'com.apple.Safari'),
|
||||
-- Direct Python invocation
|
||||
('kTCCServiceAccessibility', 0, 'org.python.python', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceScreenCapture', 0, 'org.python.python', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceMicrophone', 0, 'org.python.python', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServicePostEvent', 0, 'org.python.python', 2, 0, 1, NULL, 'UNUSED'),
|
||||
-- Commands invoked through the Tart Guest Agent
|
||||
('kTCCServiceAccessibility', 1, '${tart_guest_agent_path}', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceScreenCapture', 1, '${tart_guest_agent_path}', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServiceMicrophone', 1, '${tart_guest_agent_path}', 2, 0, 1, NULL, 'UNUSED'),
|
||||
('kTCCServicePostEvent', 1, '${tart_guest_agent_path}', 2, 0, 1, NULL, 'UNUSED');
|
||||
EOF
|
||||
}
|
||||
|
||||
# Update TCC.db for all users
|
||||
update_tcc_database "/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
|
||||
# Update TCC.db for the current user
|
||||
update_tcc_database "${HOME}/Library/Application Support/com.apple.TCC/TCC.db"
|
||||
|
|
@ -1,23 +1,18 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 0.5.4"
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "macos_version" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "gha_version" {
|
||||
type = string
|
||||
variable "vm_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
vm_base_name = "ghcr.io/cirruslabs/macos-${var.macos_version}-vanilla:13.3"
|
||||
vm_name = "${var.macos_version}-base"
|
||||
vm_name = "${var.vm_name}"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
|
|
@ -29,17 +24,19 @@ source "tart-cli" "tart" {
|
|||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"echo 'Disabling spotlight...'",
|
||||
"sudo mdutil -a -i off",
|
||||
]
|
||||
provisioner "file" {
|
||||
source = "data/limit.maxfiles.plist"
|
||||
destination = "~/limit.maxfiles.plist"
|
||||
}
|
||||
|
||||
# setup DNS
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"networksetup -setdnsservers Ethernet 8.8.8.8 8.8.4.4 1.1.1.1",
|
||||
"echo 'Configuring maxfiles...'",
|
||||
"sudo mv ~/limit.maxfiles.plist /Library/LaunchDaemons/limit.maxfiles.plist",
|
||||
"sudo chown root:wheel /Library/LaunchDaemons/limit.maxfiles.plist",
|
||||
"sudo chmod 0644 /Library/LaunchDaemons/limit.maxfiles.plist",
|
||||
"echo 'Disabling spotlight...'",
|
||||
"sudo mdutil -a -i off",
|
||||
]
|
||||
}
|
||||
|
||||
|
|
@ -51,15 +48,6 @@ build {
|
|||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"cd $HOME",
|
||||
"mkdir actions-runner && cd actions-runner",
|
||||
"curl -O -L https://github.com/actions/runner/releases/download/v${var.gha_version}/actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
"tar xzf ./actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
"rm actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
]
|
||||
}
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"/bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"",
|
||||
|
|
@ -67,22 +55,78 @@ build {
|
|||
"echo 'eval \"$(/opt/homebrew/bin/brew shellenv)\"' >> ~/.zprofile",
|
||||
"echo \"export HOMEBREW_NO_AUTO_UPDATE=1\" >> ~/.zprofile",
|
||||
"echo \"export HOMEBREW_NO_INSTALL_CLEANUP=1\" >> ~/.zprofile",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew --version",
|
||||
"brew update",
|
||||
"brew install wget cmake gcc git-lfs jq gh",
|
||||
"brew install wget unzip zip ca-certificates cmake gcc git-lfs jq yq gh gitlab-runner",
|
||||
"brew install buildkite/buildkite/buildkite-agent@3",
|
||||
"brew install equinix-labs/otel-cli/otel-cli",
|
||||
"brew install curl || true", // doesn't work on Monterey
|
||||
"brew install --cask git-credential-manager",
|
||||
"git lfs install",
|
||||
"sudo softwareupdate --install-rosetta --agree-to-license"
|
||||
]
|
||||
}
|
||||
|
||||
// Add GitHub to known hosts
|
||||
// Similar to https://github.com/actions/runner-images/blob/main/images/macos/scripts/build/configure-ssh.sh
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"mkdir -p ~/.ssh"
|
||||
]
|
||||
}
|
||||
provisioner "file" {
|
||||
source = "data/github_known_hosts"
|
||||
destination = "~/.ssh/known_hosts"
|
||||
}
|
||||
|
||||
// Install the GitHub Actions runner
|
||||
provisioner "shell" {
|
||||
script = "scripts/install-actions-runner.sh"
|
||||
}
|
||||
|
||||
// Create a /Users/runner → /Users/admin symlink to support certain GitHub Actions
|
||||
// like ruby/setup-ruby that hard-code the "/Users/runner/hostedtoolcache" path[1]
|
||||
//
|
||||
// [1]: https://github.com/ruby/setup-ruby/blob/6bd3d993c602f6b675728ebaecb2b569ff86e99b/common.js#L268
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"sudo ln -s /Users/admin /Users/runner"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install libyaml", # https://github.com/rbenv/ruby-build/discussions/2118
|
||||
"brew install rbenv",
|
||||
"echo 'if which rbenv > /dev/null; then eval \"$(rbenv init -)\"; fi' >> ~/.zprofile",
|
||||
"brew install mise",
|
||||
"source ~/.zprofile",
|
||||
"rbenv install 2.7.8", // latest 2.x.x before EOL
|
||||
"rbenv install -l | grep -v - | tail -2 | xargs -L1 rbenv install",
|
||||
"rbenv global $(rbenv install -l | grep -v - | tail -1)",
|
||||
"gem install bundler",
|
||||
]
|
||||
}
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install rbenv",
|
||||
"echo 'if which rbenv > /dev/null; then eval \"$(rbenv init -)\"; fi' >> ~/.zprofile",
|
||||
"brew install node@24",
|
||||
"echo 'export PATH=\"/opt/homebrew/opt/node@24/bin:$PATH\"' >> ~/.zprofile",
|
||||
"source ~/.zprofile",
|
||||
"rbenv install 3.0.5",
|
||||
"rbenv global 3.0.5",
|
||||
"gem install bundler",
|
||||
"node --version",
|
||||
"npm install --global yarn pnpm",
|
||||
"echo 'export PNPM_HOME=\"$HOME/Library/pnpm\"' >> ~/.zprofile",
|
||||
"echo 'export PATH=\"$PNPM_HOME:$PATH\"' >> ~/.zprofile",
|
||||
"source ~/.zprofile",
|
||||
"yarn --version",
|
||||
"pnpm --version",
|
||||
]
|
||||
}
|
||||
provisioner "shell" {
|
||||
|
|
@ -90,4 +134,56 @@ build {
|
|||
"sudo safaridriver --enable",
|
||||
]
|
||||
}
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install awscli"
|
||||
]
|
||||
}
|
||||
|
||||
# Enable UI automation, see https://github.com/cirruslabs/macos-image-templates/issues/136
|
||||
provisioner "shell" {
|
||||
script = "scripts/automationmodetool.expect"
|
||||
}
|
||||
|
||||
// some other health checks
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"test -d /Users/runner",
|
||||
"test -f ~/.ssh/known_hosts"
|
||||
]
|
||||
}
|
||||
|
||||
// Guest agent for Tart VMs
|
||||
provisioner "file" {
|
||||
source = "data/tart-guest-daemon.plist"
|
||||
destination = "~/tart-guest-daemon.plist"
|
||||
}
|
||||
provisioner "file" {
|
||||
source = "data/tart-guest-agent.plist"
|
||||
destination = "~/tart-guest-agent.plist"
|
||||
}
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Install Tart Guest Agent
|
||||
"source ~/.zprofile",
|
||||
"brew install openai/tools/tart-guest-agent",
|
||||
|
||||
# Install daemon variant of the Tart Guest Agent
|
||||
"sudo mv ~/tart-guest-daemon.plist /Library/LaunchDaemons/org.cirruslabs.tart-guest-daemon.plist",
|
||||
"sudo chown root:wheel /Library/LaunchDaemons/org.cirruslabs.tart-guest-daemon.plist",
|
||||
"sudo chmod 0644 /Library/LaunchDaemons/org.cirruslabs.tart-guest-daemon.plist",
|
||||
|
||||
# Install agent variant of the Tart Guest Agent
|
||||
"sudo mv ~/tart-guest-agent.plist /Library/LaunchAgents/org.cirruslabs.tart-guest-agent.plist",
|
||||
"sudo chown root:wheel /Library/LaunchAgents/org.cirruslabs.tart-guest-agent.plist",
|
||||
"sudo chmod 0644 /Library/LaunchAgents/org.cirruslabs.tart-guest-agent.plist",
|
||||
]
|
||||
}
|
||||
|
||||
# Update TCC.db and allow automation tools
|
||||
provisioner "shell" {
|
||||
script = "scripts/update-tcc-database.sh"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "vm_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
vm_name = "${var.vm_name}"
|
||||
recovery = true
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
communicator = "none"
|
||||
boot_command = [
|
||||
# Skip over "Macintosh" and select "Options"
|
||||
# to boot into macOS Recovery
|
||||
"<wait60s><right><right><enter>",
|
||||
# Open Terminal
|
||||
"<wait10s><leftAltOn>T<leftAltOff>",
|
||||
# Disable SIP
|
||||
"<wait10s>csrutil disable<enter>",
|
||||
"<wait10s>y<enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
# Shutdown
|
||||
"<wait10s>halt<enter>"
|
||||
]
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 0.5.4"
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
|
|
@ -22,11 +22,8 @@ source "tart-cli" "tart" {
|
|||
# Skip over "Macintosh" and select "Options"
|
||||
# to boot into macOS Recovery
|
||||
"<wait60s><right><right><enter>",
|
||||
# Select default language
|
||||
"<wait10s><enter>",
|
||||
# Open Terminal
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff>",
|
||||
"<right><right><right><right><down><down><down><enter>",
|
||||
"<wait10s><leftAltOn>T<leftAltOff>",
|
||||
# Disable SIP
|
||||
"<wait10s>csrutil disable<enter>",
|
||||
"<wait10s>y<enter>",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "vm_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "script_path" {
|
||||
type = string
|
||||
description = "Path to a local script that should be uploaded and executed inside the VM."
|
||||
}
|
||||
|
||||
variable "pause_before" {
|
||||
type = string
|
||||
default = "60s"
|
||||
description = "How long Packer should wait before running the uploaded script."
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
vm_name = "${var.vm_name}"
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "120s"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
script = var.script_path
|
||||
pause_before = var.pause_before
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "vm_base_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "vm_name" {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "resolve_file" {
|
||||
type = string
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
vm_base_name = "${var.vm_base_name}"
|
||||
vm_name = "${var.vm_name}"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "120s"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Use "-productVersion" instead of "--productVersion"
|
||||
# to support old-style syntax used on macOS Monterey
|
||||
"sw_vers -productVersion > /tmp/sw-vers-product-version.txt",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
source = "/tmp/sw-vers-product-version.txt"
|
||||
destination = "${var.resolve_file}"
|
||||
direction = "download"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.16.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
from_ipsw = "https://updates.cdn-apple.com/2026SummerSeed/fullrestores/140-55718/5809AFC6-1923-4590-AAFC-904A0283E659/UniversalMac_27.0_26A5388g_Restore.ipsw"
|
||||
vm_name = "golden-gate-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
disk_format = "asif"
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "180s"
|
||||
// Requires Tart 2.33.0+ and macOS 27+ on both the host and guest VM
|
||||
run_extra_args = [
|
||||
"--provisioning-opts=${join(",", [
|
||||
"fullName=Managed via Tart",
|
||||
"username=admin",
|
||||
"password=admin",
|
||||
"logsInAutomatically=true",
|
||||
"enablesRemoteLogin=true",
|
||||
])}",
|
||||
]
|
||||
boot_command = [
|
||||
# Wait for first-boot provisioning to finish automatic login
|
||||
"<wait120s>",
|
||||
# Enable Keyboard navigation
|
||||
# This is so that we can navigate the System Settings app using the keyboard
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>Terminal<wait10s><enter>",
|
||||
"<wait10s><wait10s>defaults write NSGlobalDomain AppleKeyboardUIMode -int 3<enter>",
|
||||
# Disable Gatekeeper (1/2)
|
||||
"<wait10s>sudo spctl --global-disable<enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
# Disable Gatekeeper (2/2)
|
||||
# On Tahoe opening System Settings through Spotlight is not very reliable, sometimes opens System information
|
||||
"<wait10s>open '/System/Applications/System Settings.app'<enter>",
|
||||
# Wait for System Settings to fully open before navigating with the keyboard
|
||||
"<wait120s>",
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff><right><right><right><down>Privacy & Security<enter>",
|
||||
"<wait10s><leftShiftOn><tab><tab><tab><tab><tab><tab><leftShiftOff>",
|
||||
"<wait10s><down><wait1s><down><wait1s><enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><wait1s><spacebar>",
|
||||
# Quit System Settings
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
]
|
||||
|
||||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
// Enable passwordless sudo
|
||||
"echo admin | sudo -S sh -c \"mkdir -p /etc/sudoers.d/; echo 'admin ALL=(ALL) NOPASSWD: ALL' | EDITOR=tee visudo /etc/sudoers.d/admin-nopasswd\"",
|
||||
// Enable Screen Sharing for "tart run --vnc"
|
||||
"sudo launchctl enable system/com.apple.screensharing",
|
||||
// Use the same timezone as the previous Setup Assistant flow
|
||||
"sudo systemsetup -settimezone GMT 2>/dev/null",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
// i.e. not on login screen.
|
||||
"sysadminctl -screenLock off -password admin",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Ensure that Gatekeeper is disabled
|
||||
"spctl --status | grep -q 'assessments disabled'",
|
||||
# Ensure that FileVault remains disabled by default
|
||||
"sudo fdesetup status | grep -q 'FileVault is Off'",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,37 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 0.5.4"
|
||||
version = ">= 1.2.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
# You can find macOS IPSW URLs on various websites like https://ipsw.me/
|
||||
# and https://www.theiphonewiki.com/wiki/Beta_Firmware/Mac/13.x
|
||||
from_ipsw = "https://updates.cdn-apple.com/2022FallFCS/fullrestores/012-40537/0EC7C669-13E9-49FB-BD64-9EECC1D174B2/UniversalMac_12.6_21G115_Restore.ipsw"
|
||||
from_ipsw = "https://updates.cdn-apple.com/2022FallFCS/fullrestores/012-66032/8D8D90C6-A876-4FFF-BBF4-D158939B3841/UniversalMac_12.6.1_21G217_Restore.ipsw"
|
||||
vm_name = "monterey-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 40
|
||||
disk_size_gb = 50
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "120s"
|
||||
boot_command = [
|
||||
# hello, hola, bonjour, etc.
|
||||
"<wait60s><spacebar>",
|
||||
# Language
|
||||
"<wait30s><enter>",
|
||||
# Language: most of the times we have a list of "English"[1], "English (UK)", etc. with
|
||||
# "English" language already selected. If we type "english", it'll cause us to switch
|
||||
# to the "English (UK)", which is not what we want. To solve this, we switch to some other
|
||||
# language first, e.g. "Italiano" and then switch back to "English". We'll then jump to the
|
||||
# first entry in a list of "english"-prefixed items, which will be "English".
|
||||
#
|
||||
# [1]: should be named "English (US)", but oh well 🤷
|
||||
"<wait30s>italiano<esc>english<enter>",
|
||||
# Select Your Country and Region
|
||||
"<wait30s>united states<leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Written and Spoken Languages
|
||||
|
|
@ -74,6 +83,9 @@ source "tart-cli" "tart" {
|
|||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
|
|
@ -90,18 +102,20 @@ build {
|
|||
"sudo defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser admin",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setdisplaysleep Off",
|
||||
"sudo systemsetup -setsleep Off",
|
||||
"sudo systemsetup -setcomputersleep Off",
|
||||
"sudo systemsetup -setdisplaysleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setcomputersleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"sleep 3",
|
||||
"kill -9 %1",
|
||||
// Enable Safari's remote automation and "Develop" menu
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
"defaults write com.apple.Safari.SandboxBroker ShowDevelopMenu -bool true",
|
||||
"defaults write com.apple.Safari IncludeDevelopMenu -bool true",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
|
|
@ -109,4 +123,26 @@ build {
|
|||
"sysadminctl -screenLock off -password admin",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Install command-line tools
|
||||
"touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
"softwareupdate --list | sed -n 's/.*Label: \\(Command Line Tools for Xcode-.*\\)/\\1/p' | xargs -I {} softwareupdate --install '{}'",
|
||||
"rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "ansible" {
|
||||
playbook_file = "ansible/playbook-system-updater.yml"
|
||||
extra_arguments = [
|
||||
"-vvv",
|
||||
"--extra-vars", "stdinpass=admin",
|
||||
]
|
||||
ansible_env_vars = [
|
||||
"ANSIBLE_TRANSPORT=paramiko",
|
||||
"ANSIBLE_HOST_KEY_CHECKING=False",
|
||||
]
|
||||
use_proxy = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.16.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
// will be update to 15.7.2
|
||||
from_ipsw = "https://updates.cdn-apple.com/2025SummerFCS/fullrestores/093-10809/CFD6DD38-DAF0-40DA-854F-31AAD1294C6F/UniversalMac_15.6.1_24G90_Restore.ipsw"
|
||||
vm_name = "sequoia-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "180s"
|
||||
boot_command = [
|
||||
# hello, hola, bonjour, etc.
|
||||
"<wait60s><spacebar>",
|
||||
# Language: most of the times we have a list of "English"[1], "English (UK)", etc. with
|
||||
# "English" language already selected. If we type "english", it'll cause us to switch
|
||||
# to the "English (UK)", which is not what we want. To solve this, we switch to some other
|
||||
# language first, e.g. "Italiano" and then switch back to "English". We'll then jump to the
|
||||
# first entry in a list of "english"-prefixed items, which will be "English".
|
||||
#
|
||||
# [1]: should be named "English (US)", but oh well 🤷
|
||||
"<wait30s>italiano<esc>english<enter>",
|
||||
# Select Your Country or Region
|
||||
"<wait30s><click 'Select Your Country or Region'><wait5s>united states<leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Transfer Your Data to This Mac
|
||||
"<wait10s><tab><tab><tab><spacebar><tab><tab><spacebar>",
|
||||
# Written and Spoken Languages
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Accessibility
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Data & Privacy
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Create a Mac Account
|
||||
"<wait10s>Managed via Tart<tab>admin<tab>admin<tab>admin<tab><tab><spacebar><tab><tab><spacebar>",
|
||||
# Enable Voice Over
|
||||
"<wait120s><leftAltOn><f5><leftAltOff>",
|
||||
# Sign In with Your Apple ID
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Are you sure you want to skip signing in with an Apple ID?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Terms and Conditions
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# I have read and agree to the macOS Software License Agreement
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Enable Location Services
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Are you sure you don't want to use Location Services?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Select Your Time Zone
|
||||
"<wait10s><tab><tab>UTC<enter><leftShiftOn><tab><tab><leftShiftOff><spacebar>",
|
||||
# Analytics
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Screen Time
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Siri
|
||||
"<wait10s><tab><spacebar><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Choose Your Look
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Update Mac Automatically
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Welcome to Mac
|
||||
"<wait10s><spacebar>",
|
||||
# Disable Voice Over
|
||||
"<leftAltOn><f5><leftAltOff>",
|
||||
# Enable Keyboard navigation
|
||||
# This is so that we can navigate the System Settings app using the keyboard
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>Terminal<enter>",
|
||||
"<wait10s>defaults write NSGlobalDomain AppleKeyboardUIMode -int 3<enter>",
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
# Now that the installation is done, open "System Settings"
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>System Settings<enter>",
|
||||
# Navigate to "Sharing"
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff><right><right><right><down>Sharing<enter>",
|
||||
# Navigate to "Screen Sharing" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Navigate to "Remote Login" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Quit System Settings
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
# Disable Gatekeeper (1/2)
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>Terminal<enter>",
|
||||
"<wait10s>sudo spctl --global-disable<enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
# Disable Gatekeeper (2/2)
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>System Settings<enter>",
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff><right><right><right><down>Privacy & Security<enter>",
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff>",
|
||||
"<wait10s><down><wait1s><down><wait1s><enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><wait1s><spacebar>",
|
||||
# Quit System Settings
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
]
|
||||
|
||||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
// Enable passwordless sudo
|
||||
"echo admin | sudo -S sh -c \"mkdir -p /etc/sudoers.d/; echo 'admin ALL=(ALL) NOPASSWD: ALL' | EDITOR=tee visudo /etc/sudoers.d/admin-nopasswd\"",
|
||||
// Enable auto-login
|
||||
//
|
||||
// See https://github.com/xfreebird/kcpassword for details.
|
||||
"echo '00000000: 1ced 3f4a bcbc ba2c caca 4e82' | sudo xxd -r - /etc/kcpassword",
|
||||
"sudo defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser admin",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
// i.e. not on login screen.
|
||||
"sysadminctl -screenLock off -password admin",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Ensure that Gatekeeper is disabled
|
||||
"spctl --status | grep -q 'assessments disabled'"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Install command-line tools
|
||||
"touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
"softwareupdate --list | sed -n 's/.*Label: \\(Command Line Tools for Xcode-.*\\)/\\1/p' | xargs -I {} softwareupdate --install '{}'",
|
||||
"rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "ansible" {
|
||||
playbook_file = "ansible/playbook-system-updater.yml"
|
||||
extra_arguments = [
|
||||
"-vvv",
|
||||
]
|
||||
ansible_env_vars = [
|
||||
"ANSIBLE_TRANSPORT=paramiko",
|
||||
"ANSIBLE_HOST_KEY_CHECKING=False",
|
||||
]
|
||||
use_proxy = false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,147 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
// will be update to 14.8.2
|
||||
from_ipsw = "https://updates.cdn-apple.com/2024SummerFCS/fullrestores/062-52859/932E0A8F-6644-4759-82DA-F8FA8DEA806A/UniversalMac_14.6.1_23G93_Restore.ipsw"
|
||||
vm_name = "sonoma-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "180s"
|
||||
boot_command = [
|
||||
# hello, hola, bonjour, etc.
|
||||
"<wait60s><spacebar>",
|
||||
# Language: most of the times we have a list of "English"[1], "English (UK)", etc. with
|
||||
# "English" language already selected. If we type "english", it'll cause us to switch
|
||||
# to the "English (UK)", which is not what we want. To solve this, we switch to some other
|
||||
# language first, e.g. "Italiano" and then switch back to "English". We'll then jump to the
|
||||
# first entry in a list of "english"-prefixed items, which will be "English".
|
||||
#
|
||||
# [1]: should be named "English (US)", but oh well 🤷
|
||||
"<wait30s>italiano<esc>english<enter>",
|
||||
# Select Your Country and Region
|
||||
"<wait30s>united states<leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Written and Spoken Languages
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Accessibility
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Data & Privacy
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Migration Assistant
|
||||
"<wait10s><tab><tab><tab><spacebar>",
|
||||
# Sign In with Your Apple ID
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Are you sure you want to skip signing in with an Apple ID?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Terms and Conditions
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# I have read and agree to the macOS Software License Agreement
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Create a Computer Account
|
||||
"<wait10s>admin<tab><tab>admin<tab>admin<tab><tab><tab><spacebar>",
|
||||
# Enable Location Services
|
||||
"<wait30s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Are you sure you don't want to use Location Services?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Select Your Time Zone
|
||||
"<wait10s><tab>UTC<enter><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Analytics
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Screen Time
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Siri
|
||||
"<wait10s><tab><spacebar><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Choose Your Look
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Enable Voice Over
|
||||
"<wait10s><leftAltOn><f5><leftAltOff><wait5s>v",
|
||||
# Now that the installation is done, open "System Settings"
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>System Settings<enter>",
|
||||
# Navigate to "Sharing"
|
||||
"<wait10s><leftAltOn>f<leftAltOff>sharing<enter>",
|
||||
# Navigate to "Screen Sharing" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Navigate to "Remote Login" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Disable Voice Over
|
||||
"<leftAltOn><f5><leftAltOff>",
|
||||
]
|
||||
|
||||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
// Enable passwordless sudo
|
||||
"echo admin | sudo -S sh -c \"mkdir -p /etc/sudoers.d/; echo 'admin ALL=(ALL) NOPASSWD: ALL' | EDITOR=tee visudo /etc/sudoers.d/admin-nopasswd\"",
|
||||
// Enable auto-login
|
||||
//
|
||||
// See https://github.com/xfreebird/kcpassword for details.
|
||||
"echo '00000000: 1ced 3f4a bcbc ba2c caca 4e82' | sudo xxd -r - /etc/kcpassword",
|
||||
"sudo defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser admin",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setdisplaysleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setcomputersleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
// i.e. not on login screen.
|
||||
"sysadminctl -screenLock off -password admin",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Install command-line tools
|
||||
"touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
"softwareupdate --list | sed -n 's/.*Label: \\(Command Line Tools for Xcode-.*\\)/\\1/p' | xargs -I {} softwareupdate --install '{}'",
|
||||
"rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "ansible" {
|
||||
playbook_file = "ansible/playbook-system-updater.yml"
|
||||
extra_arguments = [
|
||||
"-vvv",
|
||||
]
|
||||
ansible_env_vars = [
|
||||
"ANSIBLE_TRANSPORT=paramiko",
|
||||
"ANSIBLE_HOST_KEY_CHECKING=False",
|
||||
]
|
||||
use_proxy = false
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,163 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 1.16.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
from_ipsw = "https://updates.cdn-apple.com/2026SummerFCS/fullrestores/140-83079/25315EF6-AEAB-4588-9774-A3723774C47F/UniversalMac_26.6.1_25G76_Restore.ipsw"
|
||||
vm_name = "tahoe-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 50
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "180s"
|
||||
boot_command = [
|
||||
# hello, hola, bonjour, etc.
|
||||
"<wait60s><spacebar>",
|
||||
# Language: most of the times we have a list of "English"[1], "English (UK)", etc. with
|
||||
# "English" language already selected. If we type "english", it'll cause us to switch
|
||||
# to the "English (UK)", which is not what we want. To solve this, we switch to some other
|
||||
# language first, e.g. "Italiano" and then switch back to "English". We'll then jump to the
|
||||
# first entry in a list of "english"-prefixed items, which will be "English".
|
||||
#
|
||||
# [1]: should be named "English (US)", but oh well 🤷
|
||||
"<wait30s>italiano<esc>english<enter>",
|
||||
# Select Your Country or Region
|
||||
"<wait60s><click 'Select Your Country or Region'><wait5s>united states<leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Transfer Your Data to This Mac
|
||||
"<wait10s><tab><tab><tab><spacebar><tab><tab><spacebar>",
|
||||
# Written and Spoken Languages
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Accessibility
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Data & Privacy
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Create a Mac Account
|
||||
"<wait10s><tab><tab><tab><tab><tab><tab>Managed via Tart<tab>admin<tab>admin<tab>admin<tab><tab><spacebar><tab><tab><spacebar>",
|
||||
# Enable Voice Over
|
||||
"<wait120s><leftAltOn><f5><leftAltOff>",
|
||||
# Sign In with Your Apple ID
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar><up><spacebar>",
|
||||
# Are you sure you want to skip signing in with an Apple ID?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Terms and Conditions
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# I have read and agree to the macOS Software License Agreement
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Age Range -> Adult
|
||||
"<wait10s><tab><tab><tab><spacebar>",
|
||||
# Enable Location Services
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Are you sure you don't want to use Location Services?
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Select Your Time Zone
|
||||
"<wait10s><tab><tab><tab>UTC<enter><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Analytics
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Screen Time
|
||||
"<wait10s><tab><tab><spacebar>",
|
||||
# Siri
|
||||
"<wait10s><tab><spacebar><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# You Mac is Ready for FileVault
|
||||
"<wait10s><leftShiftOn><tab><tab><leftShiftOff><spacebar>",
|
||||
# Mac Data Will Not Be Securely Encrypted
|
||||
"<wait10s><tab><spacebar>",
|
||||
# Choose Your Look
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Update Mac Automatically
|
||||
"<wait10s><tab><tab><spacebar>",
|
||||
# Welcome to Mac
|
||||
"<wait30s><spacebar>",
|
||||
# Disable Voice Over
|
||||
"<wait10s><leftAltOn><f5><leftAltOff>",
|
||||
# Enable Keyboard navigation
|
||||
# This is so that we can navigate the System Settings app using the keyboard
|
||||
"<wait10s><leftAltOn><spacebar><leftAltOff>Terminal<wait10s><enter>",
|
||||
"<wait10s><wait10s>defaults write NSGlobalDomain AppleKeyboardUIMode -int 3<enter>",
|
||||
# Now that the installation is done, open "System Settings"
|
||||
# On Tahoe opening System Settings through Spotlight is not very reliable, sometimes opens System information
|
||||
"<wait10s>open '/System/Applications/System Settings.app'<enter>",
|
||||
"<wait120s>",
|
||||
# Navigate to "Sharing"
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff><right><right><right><down>Sharing<enter>",
|
||||
# Navigate to "Screen Sharing" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Type in the password to allow enabling Screen Sharing
|
||||
"<wait10s>admin<enter>",
|
||||
# Navigate to "Remote Login" and enable it
|
||||
"<wait10s><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><tab><spacebar>",
|
||||
# Quit System Settings
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
# Disable Gatekeeper (1/2)
|
||||
"<wait10s>sudo spctl --global-disable<enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
# Disable Gatekeeper (2/2)
|
||||
# On Tahoe opening System Settings through Spotlight is not very reliable, sometimes opens System information
|
||||
"<wait10s>open '/System/Applications/System Settings.app'<enter>",
|
||||
"<wait10s><leftCtrlOn><f2><leftCtrlOff><right><right><right><down>Privacy & Security<enter>",
|
||||
"<wait10s><leftShiftOn><tab><tab><tab><tab><tab><tab><leftShiftOff>",
|
||||
"<wait10s><down><wait1s><down><wait1s><enter>",
|
||||
"<wait10s>admin<enter>",
|
||||
"<wait10s><leftShiftOn><tab><leftShiftOff><wait1s><spacebar>",
|
||||
# Quit System Settings
|
||||
"<wait10s><leftAltOn>q<leftAltOff>",
|
||||
]
|
||||
|
||||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
// Enable passwordless sudo
|
||||
"echo admin | sudo -S sh -c \"mkdir -p /etc/sudoers.d/; echo 'admin ALL=(ALL) NOPASSWD: ALL' | EDITOR=tee visudo /etc/sudoers.d/admin-nopasswd\"",
|
||||
// Enable auto-login
|
||||
//
|
||||
// See https://github.com/xfreebird/kcpassword for details.
|
||||
"echo '00000000: 1ced 3f4a bcbc ba2c caca 4e82' | sudo xxd -r - /etc/kcpassword",
|
||||
"sudo defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser admin",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
// i.e. not on login screen.
|
||||
"sysadminctl -screenLock off -password admin",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Ensure that Gatekeeper is disabled
|
||||
"spctl --status | grep -q 'assessments disabled'"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,38 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 0.5.4"
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
ansible = {
|
||||
version = "~> 1"
|
||||
source = "github.com/hashicorp/ansible"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
# You can find macOS IPSW URLs on various websites like https://ipsw.me/
|
||||
# and https://www.theiphonewiki.com/wiki/Beta_Firmware/Mac/13.x
|
||||
from_ipsw = "https://updates.cdn-apple.com/2023WinterSeed/fullrestores/002-75537/8250FA0E-0962-46D6-8A90-57A390B9FFD7/UniversalMac_13.3_22E252_Restore.ipsw"
|
||||
from_ipsw = "https://updates.cdn-apple.com/2023FallFCS/fullrestores/042-55833/C0830847-A2F8-458F-B680-967991820931/UniversalMac_13.6_22G120_Restore.ipsw"
|
||||
vm_name = "ventura-vanilla"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 40
|
||||
disk_size_gb = 50
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "120s"
|
||||
boot_command = [
|
||||
# hello, hola, bonjour, etc.
|
||||
"<wait60s><spacebar>",
|
||||
# Language
|
||||
"<wait30s>english<enter>",
|
||||
# Language: most of the times we have a list of "English"[1], "English (UK)", etc. with
|
||||
# "English" language already selected. If we type "english", it'll cause us to switch
|
||||
# to the "English (UK)", which is not what we want. To solve this, we switch to some other
|
||||
# language first, e.g. "Italiano" and then switch back to "English". We'll then jump to the
|
||||
# first entry in a list of "english"-prefixed items, which will be "English".
|
||||
#
|
||||
# [1]: should be named "English (US)", but oh well 🤷
|
||||
"<wait30s>italiano<esc>english<enter>",
|
||||
# Select Your Country and Region
|
||||
"<wait30s>united states<leftShiftOn><tab><leftShiftOff><spacebar>",
|
||||
# Written and Spoken Languages
|
||||
|
|
@ -80,6 +90,9 @@ source "tart-cli" "tart" {
|
|||
// A (hopefully) temporary workaround for Virtualization.Framework's
|
||||
// installation process not fully finishing in a timely manner
|
||||
create_grace_time = "30s"
|
||||
|
||||
// Keep the recovery partition, otherwise it's not possible to "softwareupdate"
|
||||
recovery_partition = "keep"
|
||||
}
|
||||
|
||||
build {
|
||||
|
|
@ -96,23 +109,47 @@ build {
|
|||
"sudo defaults write /Library/Preferences/com.apple.loginwindow autoLoginUser admin",
|
||||
// Disable screensaver at login screen
|
||||
"sudo defaults write /Library/Preferences/com.apple.screensaver loginWindowIdleTime 0",
|
||||
// Disable screensaver for admin user
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0",
|
||||
// Prevent the VM from sleeping
|
||||
"sudo systemsetup -setdisplaysleep Off",
|
||||
"sudo systemsetup -setsleep Off",
|
||||
"sudo systemsetup -setcomputersleep Off",
|
||||
"sudo systemsetup -setdisplaysleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setsleep Off 2>/dev/null",
|
||||
"sudo systemsetup -setcomputersleep Off 2>/dev/null",
|
||||
// Launch Safari to populate the defaults
|
||||
"/Applications/Safari.app/Contents/MacOS/Safari &",
|
||||
"SAFARI_PID=$!",
|
||||
"disown",
|
||||
"sleep 30",
|
||||
"kill -9 %1",
|
||||
// Enable Safari's remote automation and "Develop" menu
|
||||
"kill -9 $SAFARI_PID",
|
||||
// Enable Safari's remote automation
|
||||
"sudo safaridriver --enable",
|
||||
"defaults write com.apple.Safari.SandboxBroker ShowDevelopMenu -bool true",
|
||||
"defaults write com.apple.Safari IncludeDevelopMenu -bool true",
|
||||
// Disable screen lock
|
||||
//
|
||||
// Note that this only works if the user is logged-in,
|
||||
// i.e. not on login screen.
|
||||
"sysadminctl -screenLock off -password admin",
|
||||
"defaults -currentHost write com.apple.screensaver idleTime 0"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
# Install command-line tools
|
||||
"touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
"softwareupdate --list | sed -n 's/.*Label: \\(Command Line Tools for Xcode-.*\\)/\\1/p' | xargs -I {} softwareupdate --install '{}'",
|
||||
"rm /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "ansible" {
|
||||
playbook_file = "ansible/playbook-system-updater.yml"
|
||||
extra_arguments = [
|
||||
"-vvv",
|
||||
]
|
||||
ansible_env_vars = [
|
||||
"ANSIBLE_TRANSPORT=paramiko",
|
||||
"ANSIBLE_HOST_KEY_CHECKING=False",
|
||||
]
|
||||
use_proxy = false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +1,128 @@
|
|||
packer {
|
||||
required_plugins {
|
||||
tart = {
|
||||
version = ">= 0.5.4"
|
||||
version = ">= 1.12.0"
|
||||
source = "github.com/cirruslabs/tart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
variable "macos_version" {
|
||||
type = string
|
||||
type = string
|
||||
}
|
||||
|
||||
variable "xcode_version" {
|
||||
type = string
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable "gha_version" {
|
||||
type = string
|
||||
variable "additional_ios_builds" {
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "additional_tvos_builds" {
|
||||
type = list(string)
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "xcode_components" {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "Additional Xcode components to download."
|
||||
}
|
||||
|
||||
variable "expected_runtimes_file" {
|
||||
type = string
|
||||
default = ""
|
||||
description = "Path to file containing expected simulator runtimes. If empty, runtime verification is skipped."
|
||||
}
|
||||
|
||||
variable "tag" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
variable "disk_size" {
|
||||
type = number
|
||||
default = 140
|
||||
}
|
||||
|
||||
variable "disk_free_mb" {
|
||||
type = number
|
||||
default = 15000
|
||||
}
|
||||
|
||||
variable "android_sdk_tools_version" {
|
||||
type = string
|
||||
default = "9477386" # https://developer.android.com/studio/#command-tools
|
||||
type = string
|
||||
default = "14742923" # https://developer.android.com/studio#command-line-tools-only
|
||||
}
|
||||
|
||||
source "tart-cli" "tart" {
|
||||
vm_base_name = "${var.macos_version}-base"
|
||||
vm_name = "${var.macos_version}-xcode:${var.xcode_version}"
|
||||
vm_base_name = "ghcr.io/cirruslabs/macos-${var.macos_version}-base:latest"
|
||||
// use tag or the last element of the xcode_version list
|
||||
vm_name = "${var.macos_version}-xcode:${var.tag != "" ? var.tag : var.xcode_version[0]}"
|
||||
cpu_count = 4
|
||||
memory_gb = 8
|
||||
disk_size_gb = 90
|
||||
disk_size_gb = var.disk_size
|
||||
headless = true
|
||||
ssh_password = "admin"
|
||||
ssh_username = "admin"
|
||||
ssh_timeout = "120s"
|
||||
}
|
||||
|
||||
locals {
|
||||
xcode_install_provisioners = [
|
||||
for version in reverse(sort(var.xcode_version)) : {
|
||||
type = "shell"
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"sudo xcodes install ${version} --experimental-unxip --path /Users/admin/Downloads/Xcode_${version}.xip --select --empty-trash",
|
||||
// get selected xcode path, strip /Contents/Developer and move to GitHub compatible locations
|
||||
"INSTALLED_PATH=$(xcodes select -p)",
|
||||
"CONTENTS_DIR=$(dirname $INSTALLED_PATH)",
|
||||
"APP_DIR=$(dirname $CONTENTS_DIR)",
|
||||
"sudo mv $APP_DIR /Applications/Xcode_${version}.app",
|
||||
"sudo xcode-select -s /Applications/Xcode_${version}.app",
|
||||
"xcodebuild -downloadPlatform iOS",
|
||||
"xcodebuild -runFirstLaunch",
|
||||
"df -h",
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
build {
|
||||
sources = ["source.tart-cli.tart"]
|
||||
|
||||
// re-install the actions runner
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"cd $HOME",
|
||||
"rm -rf actions-runner",
|
||||
"mkdir actions-runner && cd actions-runner",
|
||||
"curl -O -L https://github.com/actions/runner/releases/download/v${var.gha_version}/actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
"tar xzf ./actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
"rm actions-runner-osx-arm64-${var.gha_version}.tar.gz",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew --version",
|
||||
"brew update",
|
||||
"brew upgrade",
|
||||
"brew install curl wget unzip zip ca-certificates",
|
||||
"sudo softwareupdate --install-rosetta --agree-to-license"
|
||||
"brew install codex",
|
||||
"brew install --cask claude-code",
|
||||
"brew install --cask amazon-q"
|
||||
]
|
||||
}
|
||||
|
||||
// Re-install the GitHub Actions runner
|
||||
provisioner "shell" {
|
||||
script = "scripts/install-actions-runner.sh"
|
||||
}
|
||||
|
||||
// make sure our workaround from base is still valid
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"sudo ln -s /Users/admin /Users/runner || true"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install homebrew/cask-versions/temurin11",
|
||||
"brew install openjdk@17",
|
||||
"echo 'export PATH=\"/opt/homebrew/opt/openjdk@17/bin:$PATH\"' >> ~/.zprofile",
|
||||
"echo 'export ANDROID_HOME=$HOME/android-sdk' >> ~/.zprofile",
|
||||
"echo 'export ANDROID_SDK_ROOT=$ANDROID_HOME' >> ~/.zprofile",
|
||||
"echo 'export PATH=$PATH:$ANDROID_HOME/cmdline-tools/latest/bin:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator' >> ~/.zprofile",
|
||||
|
|
@ -76,28 +133,140 @@ build {
|
|||
"rm android-sdk-tools.zip",
|
||||
"mv $ANDROID_HOME/cmdline-tools/cmdline-tools $ANDROID_HOME/cmdline-tools/latest",
|
||||
"yes | sdkmanager --licenses",
|
||||
"yes | sdkmanager 'platform-tools' 'platforms;android-33' 'build-tools;33.0.1' 'ndk;25.1.8937393'"
|
||||
"yes | sdkmanager 'platform-tools' 'platforms;android-36' 'build-tools;36.0.0' 'ndk;28.2.13676358'"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"echo 'export PATH=/usr/local/bin/:$PATH' >> ~/.zprofile",
|
||||
"source ~/.zprofile",
|
||||
"wget --quiet https://github.com/RobotsAndPencils/xcodes/releases/latest/download/xcodes.zip",
|
||||
"unzip xcodes.zip",
|
||||
"rm xcodes.zip",
|
||||
"chmod +x xcodes",
|
||||
"sudo mkdir -p /usr/local/bin/",
|
||||
"sudo mv xcodes /usr/local/bin/xcodes",
|
||||
"brew install xcodes",
|
||||
"xcodes version",
|
||||
"wget --quiet https://storage.googleapis.com/xcodes-cache/Xcode_${var.xcode_version}.xip",
|
||||
"xcodes install ${var.xcode_version} --experimental-unxip --path $PWD/Xcode_${var.xcode_version}.xip",
|
||||
"sudo rm -rf ~/.Trash/*",
|
||||
"xcodes select ${var.xcode_version}",
|
||||
"xcodebuild -downloadAllPlatforms",
|
||||
"xcodebuild -runFirstLaunch",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "file" {
|
||||
sources = [for version in var.xcode_version : pathexpand("~/XcodesCache/Xcode_${version}.xip")]
|
||||
destination = "/Users/admin/Downloads/"
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"df -h",
|
||||
]
|
||||
}
|
||||
|
||||
// iterate over all Xcode versions and install them
|
||||
// select the latest one as the default
|
||||
dynamic "provisioner" {
|
||||
for_each = local.xcode_install_provisioners
|
||||
labels = ["shell"]
|
||||
content {
|
||||
inline = provisioner.value.inline
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "provisioner" {
|
||||
for_each = length(var.xcode_version) > 2 ? [2] : []
|
||||
labels = ["shell"]
|
||||
content {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"sudo xcode-select -s /Applications/Xcode_${var.xcode_version[2]}.app/Contents/Developer",
|
||||
"xcodebuild -downloadAllPlatforms",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "provisioner" {
|
||||
for_each = length(var.xcode_version) > 1 ? [1] : []
|
||||
labels = ["shell"]
|
||||
content {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"sudo xcode-select -s /Applications/Xcode_${var.xcode_version[1]}.app/Contents/Developer",
|
||||
"xcodebuild -downloadAllPlatforms",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"sudo xcode-select -s /Applications/Xcode_${var.xcode_version[0]}.app/Contents/Developer",
|
||||
"xcodebuild -downloadAllPlatforms",
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = concat(
|
||||
["source ~/.zprofile"],
|
||||
[
|
||||
for runtime in var.additional_ios_builds : "xcodebuild -downloadPlatform iOS -buildVersion ${runtime}"
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = concat(
|
||||
["source ~/.zprofile"],
|
||||
[
|
||||
for runtime in var.additional_tvos_builds : "xcodebuild -downloadPlatform tvOS -buildVersion ${runtime}"
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = concat(
|
||||
["source ~/.zprofile"],
|
||||
[
|
||||
for component in var.xcode_components : "xcodebuild -downloadComponent ${component}"
|
||||
]
|
||||
)
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install libimobiledevice ideviceinstaller ios-deploy carthage",
|
||||
"brew install xcbeautify swiftformat swiftlint swiftgen licenseplist",
|
||||
"brew install mint",
|
||||
"git clone --depth 1 https://github.com/tuist/homebrew-tuist.git \"$(brew --repository)/Library/Taps/tuist/homebrew-tuist\"",
|
||||
"rm -rf \"$(brew --repository)/Library/Taps/tuist/homebrew-tuist/Casks\"",
|
||||
"tuist_version=$(ruby -ne 'if $_ =~ %r{/download/([^/]+)/}; puts $1; exit; end' \"$(brew --repository)/Library/Taps/tuist/homebrew-tuist/Aliases/tuist\") && brew trust --formula \"tuist/tuist/tuist@$tuist_version\" && brew install --formula \"tuist/tuist/tuist@$tuist_version\"",
|
||||
"gem update",
|
||||
"gem install fastlane",
|
||||
"gem install cocoapods",
|
||||
"gem install xcpretty",
|
||||
"gem uninstall --ignore-dependencies ffi && gem install ffi -- --enable-libffi-alloc"
|
||||
]
|
||||
}
|
||||
|
||||
// Copy expected runtimes file if provided
|
||||
dynamic "provisioner" {
|
||||
for_each = var.expected_runtimes_file != "" ? [1] : []
|
||||
labels = ["file"]
|
||||
content {
|
||||
source = var.expected_runtimes_file
|
||||
destination = "/Users/admin/runtimes.expected.txt"
|
||||
}
|
||||
}
|
||||
|
||||
// Verify simulator runtimes match expected list if file was provided
|
||||
dynamic "provisioner" {
|
||||
for_each = var.expected_runtimes_file != "" ? [1] : []
|
||||
labels = ["shell"]
|
||||
content {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"xcrun simctl list runtimes > /Users/admin/runtimes.actual.txt",
|
||||
"diff -q /Users/admin/runtimes.actual.txt /Users/admin/runtimes.expected.txt || (echo 'Simulator runtimes do not match expected list' && cat /Users/admin/runtimes.actual.txt && exit 1)",
|
||||
"rm /Users/admin/runtimes.actual.txt /Users/admin/runtimes.expected.txt"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
|
|
@ -112,34 +281,110 @@ build {
|
|||
"flutter precache",
|
||||
]
|
||||
}
|
||||
|
||||
# useful utils for mobile development
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install libimobiledevice ideviceinstaller ios-deploy fastlane carthage",
|
||||
"sudo gem update",
|
||||
"sudo gem install cocoapods",
|
||||
"sudo gem uninstall --ignore-dependencies ffi && sudo gem install ffi -- --enable-libffi-alloc"
|
||||
"brew install graphicsmagick imagemagick",
|
||||
"brew install wix/brew/applesimutils",
|
||||
"brew install gnupg"
|
||||
]
|
||||
}
|
||||
|
||||
# inspired by https://github.com/actions/runner-images/blob/fb3b6fd69957772c1596848e2daaec69eabca1bb/images/macos/provision/configuration/configure-machine.sh#L33-L61
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"sudo security delete-certificate -Z FF6797793A3CD798DC5B2ABEF56F73EDC9F83A64 /Library/Keychains/System.keychain",
|
||||
"curl -o add-certificate.swift https://raw.githubusercontent.com/actions/runner-images/fb3b6fd69957772c1596848e2daaec69eabca1bb/images/macos/provision/configuration/add-certificate.swift",
|
||||
"swiftc add-certificate.swift",
|
||||
"curl -o AppleWWDRCAG3.cer https://www.apple.com/certificateauthority/AppleWWDRCAG3.cer",
|
||||
"curl -o DeveloperIDG2CA.cer https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer",
|
||||
"curl -o add-certificate.swift https://raw.githubusercontent.com/actions/runner-images/fb3b6fd69957772c1596848e2daaec69eabca1bb/images/macos/provision/configuration/add-certificate.swift",
|
||||
"swiftc -suppress-warnings add-certificate.swift",
|
||||
"sudo ./add-certificate AppleWWDRCAG3.cer",
|
||||
"sudo ./add-certificate DeveloperIDG2CA.cer",
|
||||
"rm add-certificate* *.cer"
|
||||
]
|
||||
}
|
||||
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew doctor",
|
||||
"flutter doctor"
|
||||
]
|
||||
}
|
||||
|
||||
// check there is at least 15GB of free space and fail if not
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"df -h",
|
||||
"export FREE_MB=$(df -m | awk '{print $4}' | head -n 2 | tail -n 1)",
|
||||
"[[ $FREE_MB -gt ${var.disk_free_mb} ]] && echo OK || exit 1"
|
||||
]
|
||||
}
|
||||
|
||||
// some other health checks
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"test -d /Users/runner"
|
||||
]
|
||||
}
|
||||
|
||||
# Disable apsd[1][2] daemon as it causes high CPU usage after boot
|
||||
#
|
||||
# [1]: https://iboysoft.com/wiki/apsd-mac.html
|
||||
# [2]: https://discussions.apple.com/thread/4459153
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"sudo launchctl unload -w /System/Library/LaunchDaemons/com.apple.apsd.plist"
|
||||
]
|
||||
}
|
||||
|
||||
# Wait for the "update_dyld_sim_shared_cache" process[1][2] to finish
|
||||
# to avoid wasting CPU cycles after boot
|
||||
#
|
||||
# [1]: https://apple.stackexchange.com/questions/412101/update-dyld-sim-shared-cache-is-taking-up-a-lot-of-memory
|
||||
# [2]: https://stackoverflow.com/a/68394101/9316533
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"xcrun simctl runtime dyld_shared_cache update --all || sleep 180",
|
||||
"xcrun simctl list -v"
|
||||
]
|
||||
}
|
||||
|
||||
# Compatibility with GitHub Actions Runner Images, where
|
||||
# /usr/local/bin belongs to the default user. Also see [2].
|
||||
#
|
||||
# [1]: https://github.com/actions/runner-images/blob/6bbddd20d76d61606bea5a0133c950cc44c370d3/images/macos/scripts/build/configure-machine.sh#L96
|
||||
# [2]: https://github.com/actions/runner-images/discussions/7607
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"sudo chown admin /usr/local/bin"
|
||||
]
|
||||
}
|
||||
|
||||
// Install setup-info-generator
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"brew install cirruslabs/cli/setup-info-generator"
|
||||
]
|
||||
}
|
||||
|
||||
// Copy setup info template
|
||||
provisioner "file" {
|
||||
source = "data/setup-info-template.json"
|
||||
destination = "~/setup-info-template.json"
|
||||
}
|
||||
|
||||
// Generate setup info
|
||||
provisioner "shell" {
|
||||
inline = [
|
||||
"source ~/.zprofile",
|
||||
"cat ~/setup-info-template.json | setup-info-generator > ~/actions-runner/.setup_info",
|
||||
"rm ~/setup-info-template.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +0,0 @@
|
|||
macos_version = "ventura"
|
||||
gha_version = "2.303.0"
|
||||
xcode_version = "14.2"
|
||||
Loading…
Reference in New Issue