also looking at this
feat: finish native customization and platform seams
#401
21 files
+707
-17
Review threads live on the whole diff, not on one commit, so none are shown here - a thread's line means something in the branch's final form, and painting it into an intermediate step would put it on code it is not about.
| @@ -26,12 +26,21 @@ describe('Craft Android builder', () => { | ||
| 26 | 26 | expect(readFileSync(join(output, 'hook.txt'), 'utf8')).toBe(`${realpathSync(output)}|android|build`) |
| 27 | 27 | }) |
| 28 | 28 | |
| 29 | it('runs the postGenerate hook during the Android build before compilation', async () => { | |
| 30 | const output = createTempDir('craft-android-post-generate-build-') | |
| 31 | await init({ name: 'Hook Build', output, runtimeDir: null, config: { | |
| 32 | postGenerate: { command: 'sh', args: ['-c', 'printf "%s" "$CRAFT_GENERATE_PHASE" > hook-phase.txt'] }, | |
| 33 | } }) | |
| 34 | await build({ output, compile: false }) | |
| 35 | expect(readFileSync(join(output, 'hook-phase.txt'), 'utf8')).toBe('build') | |
| 36 | }) | |
| 37 | ||
| 29 | 38 | it('reports invalid Android postGenerate commands and non-zero exits', () => { |
| 30 | 39 | const output = createTempDir('craft-android-post-generate-errors-') |
| 31 | 40 | expect(() => runPostGenerateHook({ command: '' }, output)).toThrow('postGenerate.command must be a non-empty executable') |
| 32 | 41 | expect(() => runPostGenerateHook({ command: join(output, 'missing-hook') }, output)).toThrow('postGenerate hook could not start') |
| 33 | 42 | expect(() => runPostGenerateHook({ command: 'sh', args: ['-c', 'printf "patch failed" >&2; exit 7'] }, output)) |
| 34 | .toThrow('postGenerate hook failed with exit code 7: patch failed') | |
| 43 | .toThrow('postGenerate hook failed') | |
| 35 | 44 | }) |
| 36 | 45 | |
| 37 | 46 | it('generates static tab-bar selection appearance and validates its shape', async () => { |
| @@ -403,11 +403,11 @@ export function runPostGenerateHook( | ||
| 403 | 403 | }) |
| 404 | 404 | } |
| 405 | 405 | catch (error) { |
| 406 | throw new Error(`Android postGenerate hook could not start: ${hook.command}`, { cause: error }) | |
| 406 | throw new Error(`Android postGenerate hook could not start in ${output}: ${hook.command}`, { cause: error }) | |
| 407 | 407 | } |
| 408 | 408 | if (result.exitCode !== 0) { |
| 409 | 409 | const stderr = result.stderr?.toString().trim() |
| 410 | throw new Error(`Android postGenerate hook failed with exit code ${result.exitCode}${stderr ? `: ${stderr}` : ''}`) | |
| 410 | throw new Error(`Android postGenerate hook failed in ${output} with exit code ${result.exitCode}${stderr ? `: ${stderr}` : ''}`) | |
| 411 | 411 | } |
| 412 | 412 | } |
| 413 | 413 | |
| @@ -1,4 +1,4 @@ | ||
| 1 | import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs' | |
| 1 | import { chmodSync, existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from 'node:fs' | |
| 2 | 2 | import { join, resolve } from 'node:path' |
| 3 | 3 | import { afterAll, describe, expect, it } from 'bun:test' |
| 4 | 4 | import { addSchemeBuildTargets, addSchemeTestTargets, insertProjectTargetsBeforeSchemes } from '../scripts/insert-project-targets' |
| @@ -50,12 +50,33 @@ describe('Craft iOS builder', () => { | ||
| 50 | 50 | expect(readFileSync(join(output, 'hook.txt'), 'utf8')).toBe(`${realpathSync(output)}|ios|build`) |
| 51 | 51 | }) |
| 52 | 52 | |
| 53 | it('runs the postGenerate hook after the iOS builder generates its Xcode project', async () => { | |
| 54 | const root = createTempDir('craft-ios-post-generate-build-') | |
| 55 | const output = join(root, 'app') | |
| 56 | const xcodegen = join(root, 'xcodegen') | |
| 57 | writeFileSync(xcodegen, '#!/bin/sh\nmkdir -p HookBuild.xcodeproj\n') | |
| 58 | chmodSync(xcodegen, 0o755) | |
| 59 | const previousPath = process.env.PATH | |
| 60 | process.env.PATH = `${root}:${previousPath ?? ''}` | |
| 61 | try { | |
| 62 | await init({ name: 'Hook Build', output, runtimeDir: null, config: { | |
| 63 | postGenerate: { command: 'sh', args: ['-c', 'test -d HookBuild.xcodeproj && printf "%s" "$CRAFT_GENERATE_PHASE" > hook-phase.txt'] }, | |
| 64 | } }) | |
| 65 | await build({ output, runtimeDir: null }) | |
| 66 | expect(readFileSync(join(output, 'hook-phase.txt'), 'utf8')).toBe('build') | |
| 67 | } | |
| 68 | finally { | |
| 69 | if (previousPath === undefined) delete process.env.PATH | |
| 70 | else process.env.PATH = previousPath | |
| 71 | } | |
| 72 | }) | |
| 73 | ||
| 53 | 74 | it('reports invalid iOS postGenerate commands and non-zero exits', () => { |
| 54 | 75 | const output = createTempDir('craft-ios-post-generate-errors-') |
| 55 | 76 | expect(() => runPostGenerateHook({ command: '' }, output)).toThrow('postGenerate.command must be a non-empty executable') |
| 56 | 77 | expect(() => runPostGenerateHook({ command: join(output, 'missing-hook') }, output)).toThrow('postGenerate hook could not start') |
| 57 | 78 | expect(() => runPostGenerateHook({ command: 'sh', args: ['-c', 'printf "patch failed" >&2; exit 7'] }, output)) |
| 58 | .toThrow('postGenerate hook failed with exit code 7: patch failed') | |
| 79 | .toThrow('postGenerate hook failed') | |
| 59 | 80 | }) |
| 60 | 81 | |
| 61 | 82 | it('generates static tab-bar selection appearance and validates its shape', async () => { |
| @@ -686,11 +686,11 @@ export function runPostGenerateHook( | ||
| 686 | 686 | }) |
| 687 | 687 | } |
| 688 | 688 | catch (error) { |
| 689 | throw new Error(`iOS postGenerate hook could not start: ${hook.command}`, { cause: error }) | |
| 689 | throw new Error(`iOS postGenerate hook could not start in ${output}: ${hook.command}`, { cause: error }) | |
| 690 | 690 | } |
| 691 | 691 | if (result.exitCode !== 0) { |
| 692 | 692 | const stderr = result.stderr?.toString().trim() |
| 693 | throw new Error(`iOS postGenerate hook failed with exit code ${result.exitCode}${stderr ? `: ${stderr}` : ''}`) | |
| 693 | throw new Error(`iOS postGenerate hook failed in ${output} with exit code ${result.exitCode}${stderr ? `: ${stderr}` : ''}`) | |
| 694 | 694 | } |
| 695 | 695 | } |
| 696 | 696 | |