diff --git a/CHANGELOG.md b/CHANGELOG.md index 74de427db6..beeed7cff9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ This is the log of notable changes to EAS CLI and related packages. - [eas-cli] Fix workflow:logs for builds using built-in EAS build steps. ([#3523](https://github.com/expo/eas-cli/pull/3523) by [@douglowder](https://github.com/douglowder)) - [build-tools][worker] Read Expo app config with `expo config` CLI invocation before falling back to `@expo/config` ([#3536](https://github.com/expo/eas-cli/pull/3536) by [@kitten](https://github.com/kitten)) +- Fix workflow detection for tracked `.gitignore`d native projects when `requireCommit` is disabled. ([#3561](https://github.com/expo/eas-cli/pull/3561) by [@sjchmiela](https://github.com/sjchmiela)) ### 🧹 Chores @@ -64,6 +65,8 @@ This is the log of notable changes to EAS CLI and related packages. - Remove --environment flag requirement for update:configure. ([#3440](https://github.com/expo/eas-cli/pull/3440) by [@douglowder](https://github.com/douglowder)) - Fix login spinner interfering with prompts in `eas go` command when not logged in. ([#3451](https://github.com/expo/eas-cli/pull/3451) by [@byronkarlen](https://github.com/byronkarlen)) +### 🧹 Chores + ## [18.0.6](https://github.com/expo/eas-cli/releases/tag/v18.0.6) - 2026-02-27 ## [18.0.5](https://github.com/expo/eas-cli/releases/tag/v18.0.5) - 2026-02-25 diff --git a/packages/eas-cli/src/project/__tests__/workflow-git.test.ts b/packages/eas-cli/src/project/__tests__/workflow-git.test.ts new file mode 100644 index 0000000000..9c6d49cd14 --- /dev/null +++ b/packages/eas-cli/src/project/__tests__/workflow-git.test.ts @@ -0,0 +1,63 @@ +import spawnAsync from '@expo/spawn-async'; +import { Platform, Workflow } from '@expo/eas-build-job'; +import fs from 'fs/promises'; +import os from 'os'; +import path from 'path'; + +import GitClient from '../../vcs/clients/git'; +import { resolveWorkflowAsync } from '../workflow'; + +describe('resolveWorkflowAsync with GitClient', () => { + let repoRoot: string; + + beforeEach(async () => { + repoRoot = await fs.realpath( + await fs.mkdtemp(path.join(os.tmpdir(), 'eas-cli-workflow-test-')) + ); + await spawnAsync('git', ['init'], { cwd: repoRoot }); + await spawnAsync('git', ['config', 'user.email', 'test@example.com'], { cwd: repoRoot }); + await spawnAsync('git', ['config', 'user.name', 'Test User'], { cwd: repoRoot }); + }); + + afterEach(async () => { + await fs.rm(repoRoot, { recursive: true, force: true }); + }); + + it('treats tracked gitignored native projects as managed when requireCommit is false', async () => { + const vcsClient = new GitClient({ + requireCommit: false, + maybeCwdOverride: repoRoot, + }); + + await fs.mkdir(path.join(repoRoot, 'ios', 'app.xcodeproj'), { recursive: true }); + await fs.writeFile(path.join(repoRoot, 'ios', 'app.xcodeproj', 'project.pbxproj'), 'fake'); + await fs.writeFile(path.join(repoRoot, '.gitignore'), 'ios/\n'); + + await spawnAsync('git', ['add', '.gitignore'], { cwd: repoRoot }); + await spawnAsync('git', ['add', '-f', 'ios/app.xcodeproj/project.pbxproj'], { cwd: repoRoot }); + await spawnAsync('git', ['commit', '-m', 'test setup'], { cwd: repoRoot }); + + await expect(resolveWorkflowAsync(repoRoot, Platform.IOS, vcsClient)).resolves.toBe( + Workflow.MANAGED + ); + }); + + it('treats tracked gitignored native projects as generic when requireCommit is true', async () => { + const vcsClient = new GitClient({ + requireCommit: true, + maybeCwdOverride: repoRoot, + }); + + await fs.mkdir(path.join(repoRoot, 'ios', 'app.xcodeproj'), { recursive: true }); + await fs.writeFile(path.join(repoRoot, 'ios', 'app.xcodeproj', 'project.pbxproj'), 'fake'); + await fs.writeFile(path.join(repoRoot, '.gitignore'), 'ios/\n'); + + await spawnAsync('git', ['add', '.gitignore'], { cwd: repoRoot }); + await spawnAsync('git', ['add', '-f', 'ios/app.xcodeproj/project.pbxproj'], { cwd: repoRoot }); + await spawnAsync('git', ['commit', '-m', 'test setup'], { cwd: repoRoot }); + + await expect(resolveWorkflowAsync(repoRoot, Platform.IOS, vcsClient)).resolves.toBe( + Workflow.GENERIC + ); + }); +}); diff --git a/packages/eas-cli/src/vcs/clients/__tests__/git.test.ts b/packages/eas-cli/src/vcs/clients/__tests__/git.test.ts index 4e7fec8cdf..03322346a2 100644 --- a/packages/eas-cli/src/vcs/clients/__tests__/git.test.ts +++ b/packages/eas-cli/src/vcs/clients/__tests__/git.test.ts @@ -91,14 +91,14 @@ describe('git', () => { await fs.rm(`${repoRoot}/.gitignore`); }); - it.each(testFiles.filter(file => file.gitignore && !file.commit))( + it.each(testFiles.filter(file => file.gitignore))( '$filename should be ignored', async file => { expect(await vcs.isFileIgnoredAsync(file.filename)).toBe(true); } ); - it.each(testFiles.filter(file => !file.gitignore || file.commit))( + it.each(testFiles.filter(file => !file.gitignore))( '$filename should not be ignored', async file => { expect(await vcs.isFileIgnoredAsync(file.filename)).toBe(false); diff --git a/packages/eas-cli/src/vcs/clients/git.ts b/packages/eas-cli/src/vcs/clients/git.ts index ffb8140660..4ece6f6a1e 100644 --- a/packages/eas-cli/src/vcs/clients/git.ts +++ b/packages/eas-cli/src/vcs/clients/git.ts @@ -376,12 +376,18 @@ export default class GitClient extends Client { return wouldNotBeCopiedToClone && (!isTracked || wouldBeDeletedFromClone); } - if (isTracked) { - return false; // Tracked files aren't ignored even if they match ignore patterns + if (isTracked && this.requireCommit) { + // With requireCommit=true we rely on a Git checkout, so tracked files are included + // even if they match ignore patterns. + return false; } try { - await spawnAsync('git', ['check-ignore', '-q', filePath], { cwd: rootPath }); + await spawnAsync( + 'git', + ['check-ignore', '-q', ...(this.requireCommit ? [] : ['--no-index']), filePath], + { cwd: rootPath } + ); return true; } catch { return false;