summaryrefslogtreecommitdiff
path: root/packages/cli/src/ui/commands/setupGithubCommand.test.ts
diff options
context:
space:
mode:
authorJerop Kipruto <[email protected]>2025-08-20 10:53:53 +0900
committerGitHub <[email protected]>2025-08-20 01:53:53 +0000
commit1049d388451120587a8643a401fd71430a8cd5fe (patch)
tree337bc2f3a15bcdd59920ba2ea09f0105276d7746 /packages/cli/src/ui/commands/setupGithubCommand.test.ts
parentc93c06711a383e92aa29eeb2555db400edeb16c7 (diff)
feat: update .gitignore in /setup-github (#6591)
Diffstat (limited to 'packages/cli/src/ui/commands/setupGithubCommand.test.ts')
-rw-r--r--packages/cli/src/ui/commands/setupGithubCommand.test.ts135
1 files changed, 134 insertions, 1 deletions
diff --git a/packages/cli/src/ui/commands/setupGithubCommand.test.ts b/packages/cli/src/ui/commands/setupGithubCommand.test.ts
index 38589e58..2dd9f97f 100644
--- a/packages/cli/src/ui/commands/setupGithubCommand.test.ts
+++ b/packages/cli/src/ui/commands/setupGithubCommand.test.ts
@@ -10,7 +10,7 @@ import fs from 'node:fs/promises';
import { vi, describe, expect, it, afterEach, beforeEach } from 'vitest';
import * as gitUtils from '../../utils/gitUtils.js';
-import { setupGithubCommand } from './setupGithubCommand.js';
+import { setupGithubCommand, updateGitignore } from './setupGithubCommand.js';
import { CommandContext, ToolActionReturn } from './types.js';
import * as commandUtils from '../utils/commandUtils.js';
@@ -102,5 +102,138 @@ describe('setupGithubCommand', async () => {
const contents = await fs.readFile(workflowFile, 'utf8');
expect(contents).toContain(workflow);
}
+
+ // Verify that .gitignore was created with the expected entries
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const gitignoreExists = await fs
+ .access(gitignorePath)
+ .then(() => true)
+ .catch(() => false);
+ expect(gitignoreExists).toBe(true);
+
+ if (gitignoreExists) {
+ const gitignoreContent = await fs.readFile(gitignorePath, 'utf8');
+ expect(gitignoreContent).toContain('.gemini/');
+ expect(gitignoreContent).toContain('gha-creds-*.json');
+ }
+ });
+});
+
+describe('updateGitignore', () => {
+ let scratchDir = '';
+
+ beforeEach(async () => {
+ scratchDir = await fs.mkdtemp(path.join(os.tmpdir(), 'update-gitignore-'));
+ });
+
+ afterEach(async () => {
+ if (scratchDir) await fs.rm(scratchDir, { recursive: true });
+ });
+
+ it('creates a new .gitignore file when none exists', async () => {
+ await updateGitignore(scratchDir);
+
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const content = await fs.readFile(gitignorePath, 'utf8');
+
+ expect(content).toBe('.gemini/\ngha-creds-*.json\n');
+ });
+
+ it('appends entries to existing .gitignore file', async () => {
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const existingContent = '# Existing content\nnode_modules/\n';
+ await fs.writeFile(gitignorePath, existingContent);
+
+ await updateGitignore(scratchDir);
+
+ const content = await fs.readFile(gitignorePath, 'utf8');
+
+ expect(content).toBe(
+ '# Existing content\nnode_modules/\n\n.gemini/\ngha-creds-*.json\n',
+ );
+ });
+
+ it('does not add duplicate entries', async () => {
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const existingContent = '.gemini/\nsome-other-file\ngha-creds-*.json\n';
+ await fs.writeFile(gitignorePath, existingContent);
+
+ await updateGitignore(scratchDir);
+
+ const content = await fs.readFile(gitignorePath, 'utf8');
+
+ expect(content).toBe(existingContent);
+ });
+
+ it('adds only missing entries when some already exist', async () => {
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const existingContent = '.gemini/\nsome-other-file\n';
+ await fs.writeFile(gitignorePath, existingContent);
+
+ await updateGitignore(scratchDir);
+
+ const content = await fs.readFile(gitignorePath, 'utf8');
+
+ // Should add only the missing gha-creds-*.json entry
+ expect(content).toBe('.gemini/\nsome-other-file\n\ngha-creds-*.json\n');
+ expect(content).toContain('gha-creds-*.json');
+ // Should not duplicate .gemini/ entry
+ expect((content.match(/\.gemini\//g) || []).length).toBe(1);
+ });
+
+ it('does not get confused by entries in comments or as substrings', async () => {
+ const gitignorePath = path.join(scratchDir, '.gitignore');
+ const existingContent = [
+ '# This is a comment mentioning .gemini/ folder',
+ 'my-app.gemini/config',
+ '# Another comment with gha-creds-*.json pattern',
+ 'some-other-gha-creds-file.json',
+ '',
+ ].join('\n');
+ await fs.writeFile(gitignorePath, existingContent);
+
+ await updateGitignore(scratchDir);
+
+ const content = await fs.readFile(gitignorePath, 'utf8');
+
+ // Should add both entries since they don't actually exist as gitignore rules
+ expect(content).toContain('.gemini/');
+ expect(content).toContain('gha-creds-*.json');
+
+ // Verify the entries were added (not just mentioned in comments)
+ const lines = content
+ .split('\n')
+ .map((line) => line.split('#')[0].trim())
+ .filter((line) => line);
+ expect(lines).toContain('.gemini/');
+ expect(lines).toContain('gha-creds-*.json');
+ expect(lines).toContain('my-app.gemini/config');
+ expect(lines).toContain('some-other-gha-creds-file.json');
+ });
+
+ it('handles file system errors gracefully', async () => {
+ // Try to update gitignore in a non-existent directory
+ const nonExistentDir = path.join(scratchDir, 'non-existent');
+
+ // This should not throw an error
+ await expect(updateGitignore(nonExistentDir)).resolves.toBeUndefined();
+ });
+
+ it('handles permission errors gracefully', async () => {
+ const consoleSpy = vi.spyOn(console, 'debug').mockImplementation(() => {});
+
+ const fsModule = await import('node:fs');
+ const writeFileSpy = vi
+ .spyOn(fsModule.promises, 'writeFile')
+ .mockRejectedValue(new Error('Permission denied'));
+
+ await expect(updateGitignore(scratchDir)).resolves.toBeUndefined();
+ expect(consoleSpy).toHaveBeenCalledWith(
+ 'Failed to update .gitignore:',
+ expect.any(Error),
+ );
+
+ writeFileSpy.mockRestore();
+ consoleSpy.mockRestore();
});
});