Skip to content

Commit 1bfcd37

Browse files
Cleanup
1 parent 624a1b3 commit 1bfcd37

File tree

3 files changed

+17
-174
lines changed

3 files changed

+17
-174
lines changed

src/cli/command-tree.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { configureTelemetry, type ConfigureTelemetryOptions } from './commands/c
3838
import { selfUpdate, type SelfUpdateOptions } from './commands/self-update/self-update';
3939
import { parseInteger } from './commands/_common/parsing';
4040
import { MAX_PAGE_SIZE } from '../sonarqube/projects';
41+
import type { ResolvedAuth } from '../lib/auth-resolver';
4142

4243
const DEFAULT_PAGE_SIZE = MAX_PAGE_SIZE;
4344
const HELP_BANNER_WIDTH = 28;
@@ -109,7 +110,9 @@ integrateCommand
109110
'--global',
110111
'Install hook globally for all repositories (sets git config --global core.hooksPath)',
111112
)
112-
.authenticatedAction((auth, options: IntegrateGitOptions) => integrateGit(options, auth));
113+
.authenticatedAction((_auth: ResolvedAuth, options: IntegrateGitOptions) =>
114+
integrateGit(options),
115+
);
113116

114117
// List Sonar resources
115118
const list = COMMAND_TREE.command('list').description('List Sonar resources');

src/cli/commands/_common/git-repo.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { CommandFailedError } from './error';
2626
import { spawnProcess } from '../../../lib/process';
2727

2828
const PRE_COMMIT_CONFIG_FILE = '.pre-commit-config.yaml';
29-
export const toForwardSlash = (p: string) => p.replaceAll('\\', '/');
29+
export const toForwardSlash = (p: string): string => p.replaceAll('\\', '/');
3030

3131
/**
3232
* Resolves the directory git uses for hooks (core.hooksPath or .git/hooks).

tests/unit/integrate-git.test.ts

Lines changed: 12 additions & 172 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@ const TEMP_DIR = join(process.cwd(), 'tests', 'unit', '.integrate-git-tmp');
4848
/** Simulate `git config core.hooksPath` returning "not set" (exit code 1). */
4949
const NO_HOOKS_PATH = { exitCode: 1, stdout: '', stderr: '' };
5050

51+
const MOCK_RESOLVED_AUTH = {
52+
token: 'tok',
53+
serverUrl: 'https://sonar.example.com',
54+
connectionType: 'cloud' as const,
55+
};
56+
5157
describe('isGitHookType', () => {
5258
it('returns true for valid hook types and false otherwise', () => {
5359
expect(isGitHookType('pre-commit')).toBe(true);
@@ -503,169 +509,6 @@ describe('integrateGit', () => {
503509
let findGitRootSpy: ReturnType<typeof spyOn>;
504510
let performSecretInstallSpy: ReturnType<typeof spyOn>;
505511

506-
try {
507-
const result = await detectHookInstallation(TEMP_DIR);
508-
expect(result.gitPreCommit).toBe(true);
509-
expect(result.gitPrePush).toBe(true);
510-
expect(result.huskyPreCommit).toBe(false);
511-
expect(result.huskyPrePush).toBe(false);
512-
expect(result.preCommitConfig).toBe(false);
513-
expect(result.hooksDir).toBe(join(TEMP_DIR, '.git', 'hooks'));
514-
} finally {
515-
spawnSpy.mockRestore();
516-
rmSync(TEMP_DIR, { recursive: true, force: true });
517-
}
518-
});
519-
520-
it('returns all false when no hooks are installed', async () => {
521-
mkdirSync(join(TEMP_DIR, '.git', 'hooks'), { recursive: true });
522-
523-
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
524-
525-
try {
526-
const result = await detectHookInstallation(TEMP_DIR);
527-
expect(result.gitPreCommit).toBe(false);
528-
expect(result.gitPrePush).toBe(false);
529-
expect(result.huskyPreCommit).toBe(false);
530-
expect(result.huskyPrePush).toBe(false);
531-
expect(result.preCommitConfig).toBe(false);
532-
expect(result.hooksDir).toBe(join(TEMP_DIR, '.git', 'hooks'));
533-
} finally {
534-
spawnSpy.mockRestore();
535-
rmSync(TEMP_DIR, { recursive: true, force: true });
536-
}
537-
});
538-
539-
it('returns gitPreCommit and gitPrePush false when hook files exist but have no marker', async () => {
540-
mkdirSync(join(TEMP_DIR, '.git', 'hooks'), { recursive: true });
541-
writeFileSync(join(TEMP_DIR, '.git', 'hooks', 'pre-commit'), '#!/bin/sh\necho hello\n');
542-
writeFileSync(join(TEMP_DIR, '.git', 'hooks', 'pre-push'), '#!/bin/sh\necho hello\n');
543-
544-
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
545-
546-
try {
547-
const result = await detectHookInstallation(TEMP_DIR);
548-
expect(result.gitPreCommit).toBe(false);
549-
expect(result.gitPrePush).toBe(false);
550-
expect(result.huskyPreCommit).toBe(false);
551-
expect(result.huskyPrePush).toBe(false);
552-
expect(result.preCommitConfig).toBe(false);
553-
expect(result.hooksDir).toBe(join(TEMP_DIR, '.git', 'hooks'));
554-
} finally {
555-
spawnSpy.mockRestore();
556-
rmSync(TEMP_DIR, { recursive: true, force: true });
557-
}
558-
});
559-
560-
it('sets huskyPreCommit and huskyPrePush when husky is used', async () => {
561-
mkdirSync(join(TEMP_DIR, '.husky'), { recursive: true });
562-
writeFileSync(join(TEMP_DIR, '.husky', 'pre-commit'), `#!/bin/sh\n# ${HOOK_MARKER}\n`);
563-
writeFileSync(join(TEMP_DIR, '.husky', 'pre-push'), `#!/bin/sh\n# ${HOOK_MARKER}\n`);
564-
565-
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue({
566-
exitCode: 0,
567-
stdout: '.husky\n',
568-
stderr: '',
569-
});
570-
571-
try {
572-
const result = await detectHookInstallation(TEMP_DIR);
573-
expect(result.huskyPreCommit).toBe(true);
574-
expect(result.huskyPrePush).toBe(true);
575-
expect(result.gitPreCommit).toBe(false);
576-
expect(result.gitPrePush).toBe(false);
577-
expect(result.preCommitConfig).toBe(false);
578-
expect(result.hooksDir).toBe(join(TEMP_DIR, '.husky'));
579-
} finally {
580-
spawnSpy.mockRestore();
581-
rmSync(TEMP_DIR, { recursive: true, force: true });
582-
}
583-
});
584-
585-
it('sets preCommitConfig true when .pre-commit-config.yaml contains sonar-secrets hook', async () => {
586-
mkdirSync(TEMP_DIR, { recursive: true });
587-
writeFileSync(
588-
join(TEMP_DIR, PRE_COMMIT_CONFIG_FILE),
589-
'repos:\n - repo: local\n hooks:\n - id: sonar-secrets\n name: Sonar secrets scan\n entry: sonar analyze secrets\n language: system\n',
590-
);
591-
592-
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
593-
594-
try {
595-
const result = await detectHookInstallation(TEMP_DIR);
596-
expect(result.preCommitConfig).toBe(true);
597-
expect(result.gitPreCommit).toBe(false);
598-
expect(result.gitPrePush).toBe(false);
599-
} finally {
600-
spawnSpy.mockRestore();
601-
rmSync(TEMP_DIR, { recursive: true, force: true });
602-
}
603-
});
604-
605-
it('sets preCommitConfig false when .pre-commit-config.yaml exists but has no sonar-secrets hook', async () => {
606-
mkdirSync(TEMP_DIR, { recursive: true });
607-
writeFileSync(
608-
join(TEMP_DIR, PRE_COMMIT_CONFIG_FILE),
609-
'repos:\n - repo: local\n hooks:\n - id: some-other-hook\n name: Some other hook\n entry: echo hello\n language: system\n',
610-
);
611-
612-
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
613-
614-
try {
615-
const result = await detectHookInstallation(TEMP_DIR);
616-
expect(result.preCommitConfig).toBe(false);
617-
} finally {
618-
spawnSpy.mockRestore();
619-
rmSync(TEMP_DIR, { recursive: true, force: true });
620-
}
621-
});
622-
});
623-
624-
describe('resolveHookType', () => {
625-
it('returns pre-commit when --hook pre-commit is passed', async () => {
626-
const result = await resolveHookType({ hook: 'pre-commit' });
627-
expect(result).toBe('pre-commit');
628-
});
629-
630-
it('returns pre-push when --hook pre-push is passed', async () => {
631-
const result = await resolveHookType({ hook: 'pre-push' });
632-
expect(result).toBe('pre-push');
633-
});
634-
635-
it('returns pre-commit when the user selects it from the prompt', async () => {
636-
setMockUi(true);
637-
queueMockResponse('pre-commit');
638-
try {
639-
const result = await resolveHookType({});
640-
expect(result).toBe('pre-commit');
641-
} finally {
642-
setMockUi(false);
643-
}
644-
});
645-
646-
it('returns pre-push when the user selects it from the prompt', async () => {
647-
setMockUi(true);
648-
queueMockResponse('pre-push');
649-
try {
650-
const result = await resolveHookType({});
651-
expect(result).toBe('pre-push');
652-
} finally {
653-
setMockUi(false);
654-
}
655-
});
656-
657-
it('throws CommandFailedError when the user cancels the prompt', () => {
658-
setMockUi(true);
659-
queueMockResponse(null);
660-
try {
661-
expect(resolveHookType({})).rejects.toThrow('Installation cancelled');
662-
} finally {
663-
setMockUi(false);
664-
}
665-
});
666-
});
667-
668-
describe('showPostInstallInfo', () => {
669512
beforeEach(() => {
670513
setMockUi(true);
671514
clearMockUiCalls();
@@ -684,13 +527,13 @@ describe('showPostInstallInfo', () => {
684527
});
685528

686529
it('throws CommandFailedError when not inside a git repository', () => {
687-
resolveAuthSpy.mockResolvedValue({ token: 'tok', serverUrl: 'https://sonar.example.com' });
530+
resolveAuthSpy.mockResolvedValue(MOCK_RESOLVED_AUTH);
688531
findGitRootSpy.mockReturnValue({ gitRoot: '/not-a-repo', isGit: false });
689532
expect(integrateGit({ nonInteractive: true })).rejects.toThrow('No git repository found');
690533
});
691534

692535
it('asks for confirmation showing the repository path when a git repo is found', async () => {
693-
resolveAuthSpy.mockResolvedValue({ token: 'tok', serverUrl: 'https://sonar.example.com' });
536+
resolveAuthSpy.mockResolvedValue(MOCK_RESOLVED_AUTH);
694537
findGitRootSpy.mockReturnValue({ gitRoot: '/my/project', isGit: true });
695538
queueMockResponse(null); // user cancels at the confirm prompt
696539
try {
@@ -709,7 +552,7 @@ describe('showPostInstallInfo', () => {
709552

710553
it('calls installViaHusky when core.hooksPath points to .husky', async () => {
711554
mkdirSync(join(TEMP_DIR, '.husky'), { recursive: true });
712-
resolveAuthSpy.mockResolvedValue({ token: 'tok', serverUrl: 'https://sonar.example.com' });
555+
resolveAuthSpy.mockResolvedValue(MOCK_RESOLVED_AUTH);
713556
findGitRootSpy.mockReturnValue({ gitRoot: TEMP_DIR, isGit: true });
714557
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue({
715558
exitCode: 0,
@@ -733,7 +576,7 @@ describe('showPostInstallInfo', () => {
733576
join(TEMP_DIR, PRE_COMMIT_CONFIG_FILE),
734577
'repos:\n - repo: local\n hooks:\n - id: some-other-hook\n entry: echo hello\n language: system\n',
735578
);
736-
resolveAuthSpy.mockResolvedValue({ token: 'tok', serverUrl: 'https://sonar.example.com' });
579+
resolveAuthSpy.mockResolvedValue(MOCK_RESOLVED_AUTH);
737580
findGitRootSpy.mockReturnValue({ gitRoot: TEMP_DIR, isGit: true });
738581
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
739582
const preCommitSpy = spyOn(preCommitModule, 'installViaPreCommitFramework').mockResolvedValue(
@@ -751,7 +594,7 @@ describe('showPostInstallInfo', () => {
751594

752595
it('calls installViaGitHooks (native) when no husky or pre-commit config is present', async () => {
753596
mkdirSync(join(TEMP_DIR, '.git', 'hooks'), { recursive: true });
754-
resolveAuthSpy.mockResolvedValue({ token: 'tok', serverUrl: 'https://sonar.example.com' });
597+
resolveAuthSpy.mockResolvedValue(MOCK_RESOLVED_AUTH);
755598
findGitRootSpy.mockReturnValue({ gitRoot: TEMP_DIR, isGit: true });
756599
const spawnSpy = spyOn(processLib, 'spawnProcess').mockResolvedValue(NO_HOOKS_PATH);
757600
try {
@@ -771,10 +614,7 @@ describe('integrateGitGlobal', () => {
771614
beforeEach(() => {
772615
setMockUi(true);
773616
clearMockUiCalls();
774-
resolveAuthSpy = spyOn(authResolver, 'resolveAuth').mockResolvedValue({
775-
token: 'tok',
776-
serverUrl: 'https://sonar.example.com',
777-
});
617+
resolveAuthSpy = spyOn(authResolver, 'resolveAuth').mockResolvedValue(MOCK_RESOLVED_AUTH);
778618
performSecretInstallSpy = spyOn(secretsInstall, 'performSecretInstall').mockResolvedValue(
779619
'/usr/local/bin/sonar-secrets',
780620
);

0 commit comments

Comments
 (0)