( ctx: XcodeStateReaderContext, )
| 80 | } |
| 81 | |
| 82 | export async function findXcodeStateFile( |
| 83 | ctx: XcodeStateReaderContext, |
| 84 | ): Promise<string | undefined> { |
| 85 | const { executor, cwd, searchRoot, workspacePath, projectPath } = ctx; |
| 86 | |
| 87 | const userResult = await executor(['whoami'], 'Get username', false); |
| 88 | if (!userResult.success) { |
| 89 | log('warn', `[xcode-state] Failed to get username: ${userResult.error}`); |
| 90 | return undefined; |
| 91 | } |
| 92 | const username = userResult.output.trim(); |
| 93 | |
| 94 | if (workspacePath || projectPath) { |
| 95 | const basePath = workspacePath ?? projectPath; |
| 96 | const xcuserstatePath = buildXcuserstatePath(basePath!, username); |
| 97 | const testResult = await executor( |
| 98 | ['test', '-f', xcuserstatePath], |
| 99 | 'Check xcuserstate exists', |
| 100 | false, |
| 101 | ); |
| 102 | if (testResult.success) { |
| 103 | log('debug', `[xcode-state] Found xcuserstate from config: ${xcuserstatePath}`); |
| 104 | return xcuserstatePath; |
| 105 | } |
| 106 | log('debug', `[xcode-state] Configured path xcuserstate not found: ${xcuserstatePath}`); |
| 107 | } |
| 108 | |
| 109 | const discoveredPaths = new Set<string>(); |
| 110 | |
| 111 | const descendantsResult = await executor( |
| 112 | buildFindProjectsCommand(cwd, 6), |
| 113 | 'Find Xcode project/workspace in cwd descendants', |
| 114 | false, |
| 115 | ); |
| 116 | if (descendantsResult.success && descendantsResult.output.trim()) { |
| 117 | for (const path of collectFindPaths(descendantsResult.output)) { |
| 118 | discoveredPaths.add(path); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | const parentSearchBoundary = searchRoot ?? cwd; |
| 123 | for (const parentDir of listParentDirectories(cwd, parentSearchBoundary)) { |
| 124 | const parentResult = await executor( |
| 125 | buildFindProjectsCommand(parentDir, 1), |
| 126 | 'Find Xcode project/workspace in parent directory', |
| 127 | false, |
| 128 | ); |
| 129 | if (!parentResult.success || !parentResult.output.trim()) { |
| 130 | continue; |
| 131 | } |
| 132 | for (const path of collectFindPaths(parentResult.output)) { |
| 133 | discoveredPaths.add(path); |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | if (discoveredPaths.size === 0) { |
| 138 | log( |
| 139 | 'debug', |
no test coverage detected