@@ -2,16 +2,6 @@ name: Builds - macOS
22
33on :
44 workflow_dispatch :
5- inputs :
6- mode :
7- description : ' Run the cleanup contract, one organization smoke, or the upstream full matrix.'
8- required : true
9- default : contract-only
10- type : choice
11- options :
12- - contract-only
13- - smoke
14- - upstream-full
155
166concurrency :
177 group : ${{ github.workflow }}-${{ github.ref }}
@@ -25,303 +15,23 @@ jobs:
2515 name : macOS resource cleanup proof contract
2616 runs-on : macos-14
2717 steps :
28- - uses : actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
18+ - uses : actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
2919 - name : Exercise private return evidence fixtures
3020 run : bash scripts/test-macos-resource-proof.sh
3121
32- boundedOrganizationMacOSCanary :
33- name : StandaloneOSX on 2022.3.62f3 (bounded organization canary)
34- if : github.repository == 'Ambiguous-Interactive/unity-builder' && inputs.mode == 'smoke'
35- needs : [resource-cleanup-proof-contract]
36- runs-on : macos-14
37- # Explicit step budgets total 144 minutes; keep a 21-minute job-level
38- # reserve so verification and post cleanup survive a near-budget build.
39- timeout-minutes : 165
40- steps :
41- - uses : actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
42- timeout-minutes : 5
43- with :
44- lfs : true
45-
46- - uses : actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
47- timeout-minutes : 5
48- with :
49- path : test-project/Library
50- key : Library-test-project-macos-StandaloneOSX-2022.3.62f3
51- restore-keys : |
52- Library-test-project-macos-StandaloneOSX-
53- Library-test-project-macos-
54- Library-test-project-
55-
56- - name : Set scripting backend to IL2CPP
57- timeout-minutes : 1
58- run : >-
59- mv -f ./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset
60- ./test-project/ProjectSettings/ProjectSettings.asset
61-
62- - name : Require isolated return-process support
63- id : return-isolation
64- timeout-minutes : 1
65- run : python3 -c 'import os; assert hasattr(os, "setsid")'
66-
67- - name : Acquire organization Unity lock
68- id : acquire-build-lock
69- timeout-minutes : 45
70- uses : Ambiguous-Interactive/ambiguous-organization-build-lock/.github/actions/acquire-build-lock-with-cleanup@59a2fa98224569e5a697f271a3ac4b866c53ac2c # v1.8.3
71- with :
72- lock-name : wallstop-organization-builds
73- lock-repository : Ambiguous-Interactive/ambiguous-organization-build-lock
74- runner-id : ${{ runner.name }}
75- holder-id-suffix : ${{ github.job }}
76- timeout-minutes : ' 40'
77- require-resource-lifecycle : ' true'
78- minimum-release-cooldown-seconds : ' 1'
79- env :
80- BUILD_LOCK_APP_ID : ${{ secrets.BUILD_LOCK_APP_ID }}
81- BUILD_LOCK_APP_PRIVATE_KEY : ${{ secrets.BUILD_LOCK_APP_PRIVATE_KEY }}
82-
83- - name : Build bounded macOS smoke
84- id : build
85- if : ${{ steps.acquire-build-lock.outputs.acquired == 'true' }}
86- continue-on-error : true
87- timeout-minutes : 70
88- uses : ./
89- env :
90- UNITY_EMAIL : ${{ secrets.UNITY_EMAIL }}
91- UNITY_LICENSE : ${{ secrets.UNITY_LICENSE }}
92- UNITY_PASSWORD : ${{ secrets.UNITY_PASSWORD }}
93- UNITY_SERIAL : ${{ secrets.UNITY_SERIAL }}
94- with :
95- allowDirtyBuild : true
96- buildName : ' GameCI Test Build'
97- customParameters : -profile SomeProfile -someBoolean -someValue exampleValue
98- projectPath : test-project
99- targetPlatform : StandaloneOSX
100- unityVersion : 2022.3.62f3
101-
102- - name : Return macOS Unity license on the same runner
103- id : return-license
104- if : ${{ always() && steps.acquire-build-lock.outputs.acquired == 'true' && steps.build.outputs.resourceCleanupStatus != 'confirmed' }}
105- continue-on-error : true
106- timeout-minutes : 5
107- env :
108- UNITY_EMAIL : ${{ secrets.UNITY_EMAIL }}
109- UNITY_PASSWORD : ${{ secrets.UNITY_PASSWORD }}
110- UNITY_SERIAL : ${{ secrets.UNITY_SERIAL }}
111- run : |
112- set -euo pipefail
113- attempt="$(mktemp -d "${RUNNER_TEMP}/unity-builder-fallback-return.XXXXXX")"
114- trap 'rm -rf -- "${attempt}"' EXIT
115- mkdir -p "${attempt}/project"
116- export ACTION_FOLDER="${GITHUB_WORKSPACE}/dist"
117- export ACTIVATE_LICENSE_PATH="${attempt}/project"
118- export UNITY_VERSION=2022.3.62f3
119- export UNITY_LICENSING_SERVER=''
120- export UNITY_BUILDER_RESOURCE_RETURN_LOG_PATH="${attempt}/return.log"
121- export UNITY_BUILDER_RESOURCE_STATUS_PATH="${attempt}/return.status"
122- export UNITY_BUILDER_RETURN_TIMEOUT_SECONDS=180
123- export UNITY_BUILDER_RETURN_KILL_GRACE_SECONDS=10
124- fallback_nonce="$(uuidgen | tr '[:upper:]' '[:lower:]')"
125- export UNITY_BUILDER_RESOURCE_PROOF_NONCE="${fallback_nonce}"
126- export UNITY_BUILDER_RESOURCE_PROOF_PATH="${attempt}/proof"
127- source dist/platforms/mac/steps/return_license.sh
128-
129- status="$(cat "${attempt}/return.status" 2>/dev/null || true)"
130- cleanup_status=unknown
131- resource_health=healthy
132- resource_reason=return-missing-positive-evidence
133- if awk 'BEGIN { found=0 } { line=tolower($0); if (line ~ /20111/ && line ~ /(licen[cs]|activation|entitlement)/ && line ~ /(error|fail|limit|maximum|blocked|return|code)/) found=1 } END { exit !found }' "${attempt}/return.log"; then
134- resource_health=blocked
135- resource_reason=unity-account-limit-20111
136- elif [[ "${status}" == completed:0 ]] &&
137- [[ "$(cat "${attempt}/proof" 2>/dev/null || true)" == "resource-safe=${fallback_nonce}" ]] &&
138- grep -Eq '^(\[Licensing::Module\] )?Successfully returned the entitlement license$' "${attempt}/return.log" &&
139- grep -Eq '^(Serial number unavailable for ULF return|\[Licensing::Client\] Successfully returned ULF license with serial number[[:space:]]*:[[:space:]]*[^[:space:]]+)$' "${attempt}/return.log"; then
140- cleanup_status=confirmed
141- resource_reason=cleanup-confirmed
142- elif [[ "${status}" == timeout ]]; then
143- resource_reason=return-timeout
144- elif [[ "${status}" == terminated ]]; then
145- resource_reason=return-terminated
146- fi
147- evidence_digest="$(printf '%s' "${fallback_nonce}:${status}:${cleanup_status}:${resource_health}:${resource_reason}" | shasum -a 256 | awk '{print $1}')"
148- {
149- echo "cleanup-status=${cleanup_status}"
150- echo "resource-health=${resource_health}"
151- echo "resource-reason=${resource_reason}"
152- echo "evidence-digest=${evidence_digest}"
153- } >>"${GITHUB_OUTPUT}"
154-
155- - name : Release organization Unity lock
156- id : release-build-lock
157- if : ${{ always() }}
158- timeout-minutes : 5
159- uses : Ambiguous-Interactive/ambiguous-organization-build-lock/.github/actions/release-build-lock@59a2fa98224569e5a697f271a3ac4b866c53ac2c # v1.8.3
160- with :
161- lock-name : wallstop-organization-builds
162- lock-repository : Ambiguous-Interactive/ambiguous-organization-build-lock
163- runner-id : ${{ runner.name }}
164- holder-id-suffix : ${{ github.job }}
165- holder-id : ${{ steps.acquire-build-lock.outputs.holder-id }}
166- resource-cleanup-status : ${{ steps.return-license.outputs.cleanup-status || steps.build.outputs.resourceCleanupStatus || 'unknown' }}
167- resource-health : ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'blocked' || 'healthy' }}
168- resource-reason : ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'unity-account-limit-20111' || steps.return-license.outputs.resource-reason || steps.build.outputs.resourceReason || steps.acquire-build-lock.outputs.resource-reason || 'cleanup-evidence-unknown' }}
169- env :
170- BUILD_LOCK_APP_ID : ${{ secrets.BUILD_LOCK_APP_ID }}
171- BUILD_LOCK_APP_PRIVATE_KEY : ${{ secrets.BUILD_LOCK_APP_PRIVATE_KEY }}
172-
173- - name : Require a successful build and exact cleanup evidence
174- id : verify-cleanup
175- if : ${{ always() }}
176- timeout-minutes : 2
177- env :
178- ACQUIRED : ${{ steps.acquire-build-lock.outputs.acquired }}
179- BUILD_OUTCOME : ${{ steps.build.outcome }}
180- CLEANUP_STATUS : ${{ steps.return-license.outputs.cleanup-status || steps.build.outputs.resourceCleanupStatus }}
181- EVIDENCE_DIGEST : ${{ steps.return-license.outputs.evidence-digest || steps.build.outputs.resourceEvidenceDigest }}
182- ACQUIRE_HOLDER_ID : ${{ steps.acquire-build-lock.outputs.holder-id }}
183- RELEASE_AVAILABLE_AT : ${{ steps.release-build-lock.outputs.available-at }}
184- RELEASE_CLEANUP_RESULT : ${{ steps.release-build-lock.outputs.cleanup-result }}
185- RELEASE_HOLDER_ID : ${{ steps.release-build-lock.outputs.holder-id }}
186- RELEASE_OUTCOME : ${{ steps.release-build-lock.outcome }}
187- RELEASED : ${{ steps.release-build-lock.outputs.released }}
188- RELEASE_RESERVATION_STATE : ${{ steps.release-build-lock.outputs.reservation-state }}
189- RESOURCE_HEALTH : ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'blocked' || 'healthy' }}
190- RESOURCE_REASON : ${{ (steps.acquire-build-lock.outputs.resource-health == 'blocked' || steps.build.outputs.resourceHealth == 'blocked' || steps.return-license.outputs.resource-health == 'blocked') && 'unity-account-limit-20111' || steps.return-license.outputs.resource-reason || steps.build.outputs.resourceReason || steps.acquire-build-lock.outputs.resource-reason }}
191- run : |
192- set -euo pipefail
193- if [[ "${RESOURCE_HEALTH}" == blocked || "${RESOURCE_REASON}" == unity-account-limit-20111 ]]; then
194- echo '::error::Unity reported the account-limit 20111 incident.'
195- exit 1
196- fi
197- if [[ "${ACQUIRED}" != true || "${BUILD_OUTCOME}" != success ]]; then
198- echo '::error::Bounded macOS build did not succeed after lock admission.'
199- exit 1
200- fi
201- if [[ "${CLEANUP_STATUS}" != confirmed || "${RESOURCE_HEALTH}" != healthy || "${RESOURCE_REASON}" != cleanup-confirmed ]]; then
202- echo '::error::macOS cleanup did not produce the exact confirmed/healthy/cleanup-confirmed tuple.'
203- exit 1
204- fi
205- if [[ "${RELEASE_OUTCOME}" != success ]]; then
206- echo "::error::Schema-5 lock release finished with ${RELEASE_OUTCOME}."
207- exit 1
208- fi
209- if [[ "${RELEASED}" != true || "${RELEASE_CLEANUP_RESULT}" != cooldown-started || "${RELEASE_RESERVATION_STATE}" != cooldown ]]; then
210- echo '::error::Release did not remove the holder into the required cooldown.'
211- exit 1
212- fi
213- if [[ -z "${ACQUIRE_HOLDER_ID}" || "${RELEASE_HOLDER_ID}" != "${ACQUIRE_HOLDER_ID}" || -z "${RELEASE_AVAILABLE_AT}" ]]; then
214- echo '::error::Release outputs do not prove exact holder removal and cooldown availability.'
215- exit 1
216- fi
217- if [[ ! "${EVIDENCE_DIGEST}" =~ ^[0-9a-f]{64}$ ]]; then
218- echo '::error::macOS cleanup evidence digest is missing or malformed.'
219- exit 1
220- fi
221- echo "::notice::macOS cleanup evidence reason=${RESOURCE_REASON} evidence-digest=${EVIDENCE_DIGEST}"
222-
223- - uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
224- if : ${{ success() }}
225- timeout-minutes : 5
226- with :
227- name : Build StandaloneOSX on macOS (2022.3.62f3)
228- path : build
229- retention-days : 14
230-
231- buildForAllPlatformsMacOS :
232- name : ${{ matrix.targetPlatform }} on ${{ matrix.unityVersion }}
233- if : ${{ github.repository == 'game-ci/unity-builder' && inputs.mode == 'upstream-full' }}
234- needs : [resource-cleanup-proof-contract]
235- runs-on : macos-latest
236- strategy :
237- fail-fast : false
238- max-parallel : 1
239- matrix :
240- projectPath :
241- - test-project
242- unityVersion :
243- - 2021.3.45f2
244- - 2022.3.62f3
245- - 2023.2.22f1
246- targetPlatform :
247- - StandaloneOSX
248- - iOS
249- include :
250- - unityVersion : 6000.0.36f1
251- targetPlatform : StandaloneOSX
252- - unityVersion : 6000.0.36f1
253- targetPlatform : StandaloneOSX
254- buildProfile : ' Assets/Settings/Build Profiles/Sample macOS Build Profile.asset'
255- steps :
256- - uses : actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
257- with :
258- lfs : true
259- - uses : actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830
260- with :
261- path : ${{ matrix.projectPath }}/Library
262- key : Library-${{ matrix.projectPath }}-macos-${{ matrix.targetPlatform }}
263- restore-keys : |
264- Library-${{ matrix.projectPath }}-macos-
265- Library-
266- - name : Set scripting backend to IL2CPP
267- run : >-
268- mv -f ./test-project/ProjectSettings/ProjectSettingsIl2cpp.asset
269- ./test-project/ProjectSettings/ProjectSettings.asset
270- - uses : ./
271- env :
272- UNITY_EMAIL : ${{ secrets.UNITY_EMAIL }}
273- UNITY_LICENSE : ${{ secrets.UNITY_LICENSE }}
274- UNITY_PASSWORD : ${{ secrets.UNITY_PASSWORD }}
275- UNITY_SERIAL : ${{ secrets.UNITY_SERIAL }}
276- with :
277- allowDirtyBuild : true
278- buildName : ' GameCI Test Build'
279- buildProfile : ${{ matrix.buildProfile }}
280- customParameters : -profile SomeProfile -someBoolean -someValue exampleValue
281- projectPath : ${{ matrix.projectPath }}
282- targetPlatform : ${{ matrix.targetPlatform }}
283- unityVersion : ${{ matrix.unityVersion }}
284- - uses : actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
285- with :
286- name : Build ${{ matrix.targetPlatform }} on macOS (${{ matrix.unityVersion }})${{ matrix.buildProfile && ' With Build Profile' || '' }}
287- path : build
288- retention-days : 14
289-
290- macos-license-ci :
291- name : macOS cleanup contract and licensed coverage
22+ macos-cleanup-contract :
23+ name : macOS cleanup contract
29224 if : ${{ always() }}
293- needs :
294- - resource-cleanup-proof-contract
295- - boundedOrganizationMacOSCanary
296- - buildForAllPlatformsMacOS
25+ needs : [resource-cleanup-proof-contract]
29726 runs-on : ubuntu-latest
29827 steps :
299- - name : Require the exact requested coverage
28+ - name : Require cleanup fixture coverage
30029 env :
301- CANARY_RESULT : ${{ needs.boundedOrganizationMacOSCanary.result }}
30230 CONTRACT_RESULT : ${{ needs.resource-cleanup-proof-contract.result }}
303- MODE : ${{ inputs.mode }}
304- REPOSITORY : ${{ github.repository }}
305- UPSTREAM_RESULT : ${{ needs.buildForAllPlatformsMacOS.result }}
30631 run : |
30732 set -euo pipefail
30833 if [[ "${CONTRACT_RESULT}" != success ]]; then
30934 echo "::error::macOS cleanup fixtures finished with ${CONTRACT_RESULT}."
31035 exit 1
31136 fi
312- case "${REPOSITORY}:${MODE}" in
313- Ambiguous-Interactive/unity-builder:contract-only|game-ci/unity-builder:contract-only)
314- [[ "${CANARY_RESULT}" == skipped && "${UPSTREAM_RESULT}" == skipped ]]
315- echo 'No licensed macOS coverage was requested; cleanup contract fixtures passed.'
316- ;;
317- Ambiguous-Interactive/unity-builder:smoke)
318- [[ "${CANARY_RESULT}" == success && "${UPSTREAM_RESULT}" == skipped ]]
319- ;;
320- game-ci/unity-builder:upstream-full)
321- [[ "${CANARY_RESULT}" == skipped && "${UPSTREAM_RESULT}" == success ]]
322- ;;
323- *)
324- echo "::error::Repository ${REPOSITORY} is not enrolled for licensed macOS coverage."
325- exit 1
326- ;;
327- esac
37+ echo 'The fork runs cleanup fixtures without organization Unity credentials.'
0 commit comments