-
Notifications
You must be signed in to change notification settings - Fork 2
feat: Added doctor command to test if all requirements are install. #20
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| import { jest } from '@jest/globals'; | ||
| import { execa } from 'execa'; | ||
|
|
||
| // Mock execa | ||
| jest.mock('execa'); | ||
|
|
||
| const mockedExeca = execa as jest.MockedFunction<typeof execa>; | ||
|
|
||
| describe('doctor command', () => { | ||
| beforeEach(() => { | ||
| jest.clearAllMocks(); | ||
| // Mock process.version | ||
| Object.defineProperty(process, 'version', { | ||
| value: 'v20.0.0', | ||
| writable: true, | ||
| }); | ||
| }); | ||
|
|
||
| it('should pass all checks when requirements are met', async () => { | ||
| // Mock successful corepack and gh commands | ||
| mockedExeca.mockResolvedValue({ | ||
| stdout: 'gh version 2.0.0', | ||
| stderr: '', | ||
| exitCode: 0, | ||
| } as any); | ||
|
|
||
| const { runDoctor } = await import('../doctor.js'); | ||
| await expect(runDoctor(false)).resolves.not.toThrow(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every test just asserts
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something like: |
||
| }); | ||
|
|
||
| it('should detect when Node.js version is too old', async () => { | ||
| Object.defineProperty(process, 'version', { | ||
| value: 'v18.0.0', | ||
| writable: true, | ||
| }); | ||
|
|
||
| const { runDoctor } = await import('../doctor.js'); | ||
| await expect(runDoctor(false)).resolves.not.toThrow(); | ||
| }); | ||
|
|
||
| it('should detect when corepack is not enabled', async () => { | ||
| mockedExeca.mockImplementation((command: string) => { | ||
| if (command === 'corepack') { | ||
| throw new Error('Command not found'); | ||
| } | ||
| return Promise.resolve({ | ||
| stdout: 'gh version 2.0.0', | ||
| stderr: '', | ||
| exitCode: 0, | ||
| } as any); | ||
| }); | ||
|
|
||
| const { runDoctor } = await import('../doctor.js'); | ||
| await expect(runDoctor(false)).resolves.not.toThrow(); | ||
| }); | ||
|
|
||
| it('should detect when GitHub CLI is not installed', async () => { | ||
| mockedExeca.mockImplementation((command: string) => { | ||
| if (command === 'gh') { | ||
| throw new Error('Command not found'); | ||
| } | ||
| return Promise.resolve({ | ||
| stdout: '0.28.0', | ||
| stderr: '', | ||
| exitCode: 0, | ||
| } as any); | ||
| }); | ||
|
|
||
| const { runDoctor } = await import('../doctor.js'); | ||
| await expect(runDoctor(false)).resolves.not.toThrow(); | ||
| }); | ||
| }); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,204 @@ | ||
| import { execa } from 'execa'; | ||
| import * as os from 'os'; | ||
|
|
||
| interface CheckResult { | ||
| passed: boolean; | ||
| message: string; | ||
| } | ||
|
|
||
| /** Check if Node.js version is >= 20 */ | ||
| async function checkNodeVersion(): Promise<CheckResult> { | ||
| const version = process.version; | ||
| const majorVersion = parseInt(version.slice(1).split('.')[0] || '0', 10); | ||
|
|
||
| if (majorVersion >= 20) { | ||
| return { | ||
| passed: true, | ||
| message: `✅ Node.js version ${version} (>= 20)`, | ||
| }; | ||
| } | ||
|
|
||
| return { | ||
| passed: false, | ||
| message: `❌ Node.js version ${version} is not supported. Please install Node.js >= 20 from https://nodejs.org/`, | ||
| }; | ||
| } | ||
|
|
||
| /** Check if corepack is enabled */ | ||
| async function checkCorepack(): Promise<CheckResult> { | ||
| try { | ||
| await execa('corepack', ['--version'], { stdio: 'pipe' }); | ||
| return { | ||
| passed: true, | ||
| message: '✅ Corepack is enabled', | ||
| }; | ||
| } catch { | ||
| return { | ||
| passed: false, | ||
| message: '❌ Corepack is not enabled', | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| /** Enable corepack */ | ||
| async function enableCorepack(): Promise<void> { | ||
| console.log('\n🔧 Enabling corepack...'); | ||
| try { | ||
| await execa('corepack', ['enable'], { stdio: 'inherit' }); | ||
| console.log('✅ Corepack enabled successfully\n'); | ||
| } catch (error) { | ||
| throw new Error('Failed to enable corepack. You may need to run this command with elevated privileges (sudo).'); | ||
| } | ||
| } | ||
|
|
||
| /** Check if GitHub CLI is installed */ | ||
| async function checkGitHubCLI(): Promise<CheckResult> { | ||
| try { | ||
| const { stdout } = await execa('gh', ['--version'], { stdio: 'pipe' }); | ||
| const version = stdout.split('\n')[0]; | ||
| return { | ||
| passed: true, | ||
| message: `✅ GitHub CLI is installed (${version})`, | ||
| }; | ||
| } catch { | ||
| return { | ||
| passed: false, | ||
| message: '❌ GitHub CLI is not installed', | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| /** Get OS-specific installation instructions for GitHub CLI */ | ||
| function getGitHubCLIInstallCommand(): { command: string; args: string[]; description: string } | null { | ||
| const platform = os.platform(); | ||
|
|
||
| switch (platform) { | ||
| case 'darwin': // macOS | ||
| return { | ||
| command: 'brew', | ||
| args: ['install', 'gh'], | ||
| description: 'Installing GitHub CLI via Homebrew', | ||
| }; | ||
| case 'linux': { | ||
| // Try to detect the Linux distribution | ||
| try { | ||
| const fs = require('fs'); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
| if (fs.existsSync('/etc/debian_version')) { | ||
| // Debian/Ubuntu | ||
| return { | ||
| command: 'sudo', | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| args: ['apt', 'install', 'gh', '-y'], | ||
| description: 'Installing GitHub CLI via apt', | ||
| }; | ||
| } else if (fs.existsSync('/etc/redhat-release')) { | ||
| // Red Hat/Fedora/CentOS | ||
| return { | ||
| command: 'sudo', | ||
| args: ['dnf', 'install', 'gh', '-y'], | ||
| description: 'Installing GitHub CLI via dnf', | ||
| }; | ||
| } | ||
| } catch { | ||
| // If we can't detect, return null | ||
| } | ||
| return null; | ||
| } | ||
| case 'win32': // Windows | ||
| return { | ||
| command: 'winget', | ||
| args: ['install', '--id', 'GitHub.cli'], | ||
| description: 'Installing GitHub CLI via winget', | ||
| }; | ||
| default: | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| /** Install GitHub CLI */ | ||
| async function installGitHubCLI(): Promise<void> { | ||
| const installCommand = getGitHubCLIInstallCommand(); | ||
|
|
||
| if (!installCommand) { | ||
| console.log('\n⚠️ Unable to automatically install GitHub CLI for your operating system.'); | ||
| console.log('Please visit https://cli.github.com/ for installation instructions.\n'); | ||
| return; | ||
| } | ||
|
|
||
| console.log(`\n🔧 ${installCommand.description}...`); | ||
| try { | ||
| await execa(installCommand.command, installCommand.args, { stdio: 'inherit' }); | ||
| console.log('✅ GitHub CLI installed successfully\n'); | ||
| } catch (error) { | ||
| console.error(`\n❌ Failed to install GitHub CLI automatically.`); | ||
| console.error('Please visit https://cli.github.com/ for manual installation instructions.\n'); | ||
| if (error instanceof Error) { | ||
| console.error(`Error: ${error.message}`); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** Run the doctor command to check and fix requirements */ | ||
| export async function runDoctor(autoFix: boolean = false): Promise<void> { | ||
| console.log('\n🏥 Running Patternfly CLI Doctor...\n'); | ||
| console.log('Checking requirements...\n'); | ||
|
|
||
| const results: CheckResult[] = []; | ||
| let allPassed = true; | ||
|
|
||
| // Check Node.js version | ||
| const nodeResult = await checkNodeVersion(); | ||
| results.push(nodeResult); | ||
| console.log(nodeResult.message); | ||
| if (!nodeResult.passed) { | ||
| allPassed = false; | ||
| } | ||
|
|
||
| // Check corepack | ||
| const corepackResult = await checkCorepack(); | ||
| results.push(corepackResult); | ||
| console.log(corepackResult.message); | ||
| if (!corepackResult.passed) { | ||
| allPassed = false; | ||
| if (autoFix) { | ||
| try { | ||
| await enableCorepack(); | ||
| console.log('✅ Corepack is now enabled'); | ||
| } catch (error) { | ||
| if (error instanceof Error) { | ||
| console.error(`❌ ${error.message}`); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // Check GitHub CLI | ||
| const ghResult = await checkGitHubCLI(); | ||
| results.push(ghResult); | ||
| console.log(ghResult.message); | ||
| if (!ghResult.passed) { | ||
| allPassed = false; | ||
| if (autoFix) { | ||
| await installGitHubCLI(); | ||
| } | ||
| } | ||
|
|
||
| console.log('\n' + '─'.repeat(60) + '\n'); | ||
|
|
||
| if (allPassed) { | ||
| console.log('✨ All requirements are satisfied! You are ready to use Patternfly CLI.\n'); | ||
| } else { | ||
| console.log('⚠️ Some requirements are not satisfied.\n'); | ||
|
|
||
| // Check if Node.js version failed | ||
| if (!nodeResult.passed) { | ||
| console.log('📌 Node.js must be manually installed or updated.'); | ||
| console.log(' Download from: https://nodejs.org/ (LTS version recommended)\n'); | ||
| } | ||
|
|
||
| if (!autoFix) { | ||
| console.log('Run with --fix to automatically install missing requirements:\n'); | ||
| console.log(' patternfly-cli doctor --fix\n'); | ||
| console.log('Note: --fix can install corepack and GitHub CLI, but NOT Node.js.\n'); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: unnecessary comment. There are a few of these - where the comment doesn't add value - just repeats what the line below easily reads on its own.