-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
chore(scripts): add Windows fixes verification script #1108
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
Open
youngmrz
wants to merge
13
commits into
AndyMik90:develop
Choose a base branch
from
youngmrz:util/windows-test-script
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+384
β0
Open
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
c85667c
chore(scripts): add Windows fixes verification script
youngmrz ba3d36d
fix: address code review feedback for test script
youngmrz 884be60
Merge branch 'develop' into util/windows-test-script
youngmrz 6be321d
fix: exit with code 1 for unknown PR numbers
youngmrz 2e2e6b5
chore(scripts): add Windows fixes verification script
youngmrz 8b7bc89
fix: address code review feedback for test script
youngmrz 4502f00
fix: exit with code 1 for unknown PR numbers
youngmrz c2fc9c4
docs: add JSDoc comments to logging helper functions
youngmrz 82d972d
fix: skip PR #4 test gracefully when hot-reload code is not present
youngmrz ac9cafd
Merge remote-tracking branch 'upstream/develop' into util/windows-tesβ¦
youngmrz dfe6bcf
Merge origin/util/windows-test-script with develop (keep JSDoc comments)
youngmrz aec4b0d
Merge remote-tracking branch 'upstream/develop' into util/windows-tesβ¦
youngmrz 801cf84
Merge remote-tracking branch 'upstream/develop' into util/windows-tesβ¦
youngmrz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,384 @@ | ||
| #!/usr/bin/env node | ||
| /** | ||
| * Windows Fixes Verification Script | ||
| * ================================== | ||
| * Quick verification for Windows-specific fixes in the Auto-Claude fork. | ||
| * | ||
| * Usage: | ||
| * node scripts/test-windows-fixes.js | ||
| * node scripts/test-windows-fixes.js --pr 1 # Test specific PR | ||
| * node scripts/test-windows-fixes.js --all # Run full test suite | ||
| */ | ||
|
|
||
| const fs = require('fs'); | ||
| const os = require('os'); | ||
| const path = require('path'); | ||
| const { execSync } = require('child_process'); | ||
|
|
||
| const COLORS = { | ||
| reset: '\x1b[0m', | ||
| green: '\x1b[32m', | ||
| red: '\x1b[31m', | ||
| yellow: '\x1b[33m', | ||
| blue: '\x1b[34m', | ||
| cyan: '\x1b[36m', | ||
| }; | ||
|
|
||
| /** | ||
| * Log a message with optional color formatting. | ||
| * @param {string} msg - The message to log | ||
| * @param {string} [color='reset'] - Color key from COLORS object | ||
| */ | ||
| function log(msg, color = 'reset') { | ||
| console.log(`${COLORS[color]}${msg}${COLORS.reset}`); | ||
| } | ||
|
|
||
| /** | ||
| * Log a success message with green checkmark. | ||
| * @param {string} msg - The success message | ||
| */ | ||
| function success(msg) { log(`β ${msg}`, 'green'); } | ||
|
|
||
| /** | ||
| * Log an error message with red X mark. | ||
| * @param {string} msg - The error message | ||
| */ | ||
| function error(msg) { log(`β ${msg}`, 'red'); } | ||
|
|
||
| /** | ||
| * Log an informational message with blue info icon. | ||
| * @param {string} msg - The info message | ||
| */ | ||
| function info(msg) { log(`βΉ ${msg}`, 'blue'); } | ||
|
|
||
| /** | ||
| * Log a warning message with yellow warning icon. | ||
| * @param {string} msg - The warning message | ||
| */ | ||
| function warn(msg) { log(`β ${msg}`, 'yellow'); } | ||
|
|
||
| /** | ||
| * PR #1: Windows marketplace initialization fix | ||
| * Verifies that known_marketplaces.json is properly created | ||
| */ | ||
| function testPR1_MarketplaceInit() { | ||
| log('\n--- PR #1: Windows Marketplace Fix ---', 'cyan'); | ||
|
|
||
| // Cross-platform app data directory resolution | ||
| let appDataDir; | ||
| if (process.platform === 'win32') { | ||
| appDataDir = process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'); | ||
| } else if (process.platform === 'darwin') { | ||
| appDataDir = path.join(os.homedir(), 'Library', 'Application Support'); | ||
| } else { | ||
| appDataDir = process.env.XDG_CONFIG_HOME || path.join(os.homedir(), '.config'); | ||
| } | ||
| const autoClaudeDir = path.join(appDataDir, 'auto-claude'); | ||
| const marketplaceFile = path.join(autoClaudeDir, 'known_marketplaces.json'); | ||
|
|
||
| info(`Checking marketplace file at: ${marketplaceFile}`); | ||
|
|
||
| // Check if directory exists | ||
| if (!fs.existsSync(autoClaudeDir)) { | ||
| warn('Auto-Claude config directory does not exist yet (will be created on first run)'); | ||
| return { passed: true, skipped: true }; | ||
| } | ||
|
|
||
| // Check if file exists and is valid JSON | ||
| if (fs.existsSync(marketplaceFile)) { | ||
| try { | ||
| const content = fs.readFileSync(marketplaceFile, 'utf8'); | ||
| const data = JSON.parse(content); | ||
| if (Array.isArray(data)) { | ||
| success(`Marketplace file exists and contains ${data.length} entries`); | ||
| return { passed: true }; | ||
| } else { | ||
| error('Marketplace file exists but is not an array'); | ||
| return { passed: false }; | ||
| } | ||
| } catch (e) { | ||
| error(`Marketplace file exists but contains invalid JSON: ${e.message}`); | ||
| return { passed: false }; | ||
| } | ||
| } else { | ||
| info('Marketplace file does not exist yet (will be created on first run)'); | ||
| return { passed: true, skipped: true }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * PR #2: Error surfacing fix | ||
| * Verifies that agent-process.ts has stderr collection | ||
| */ | ||
| function testPR2_ErrorSurfacing() { | ||
| log('\n--- PR #2: Error Surfacing Fix ---', 'cyan'); | ||
|
|
||
| const agentProcessPath = path.join(__dirname, '../apps/frontend/src/main/agent/agent-process.ts'); | ||
|
|
||
| if (!fs.existsSync(agentProcessPath)) { | ||
| error(`Agent process file not found at: ${agentProcessPath}`); | ||
| return { passed: false }; | ||
| } | ||
|
|
||
| const content = fs.readFileSync(agentProcessPath, 'utf8'); | ||
|
|
||
| // Check for stderr collection variable | ||
| const hasStderrCollected = content.includes('stderrCollected'); | ||
| const hasErrorPatterns = content.includes('errorPatterns'); | ||
|
|
||
| if (hasStderrCollected && hasErrorPatterns) { | ||
| success('Error surfacing code is present (stderrCollected + errorPatterns)'); | ||
| return { passed: true }; | ||
| } else if (hasStderrCollected && !hasErrorPatterns) { | ||
| warn('stderrCollected present but errorPatterns missing'); | ||
| return { passed: false }; | ||
| } else if (!hasStderrCollected && hasErrorPatterns) { | ||
| warn('errorPatterns present but stderrCollected missing'); | ||
| return { passed: false }; | ||
| } else { | ||
| info('Error surfacing code not present (PR #2 may not be merged yet)'); | ||
| return { passed: true, skipped: true }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * PR #3: Windows path normalization fix (Errno 22) | ||
| * Verifies that path normalization utilities exist | ||
| */ | ||
| function testPR3_WindowsPathFix() { | ||
| log('\n--- PR #3: Windows Path Fix (Errno 22) ---', 'cyan'); | ||
|
|
||
| // Test path normalization on Windows-specific characters | ||
| const testCases = [ | ||
| { input: 'C:\\Users\\test', desc: 'Backslash path' }, | ||
| { input: 'C:/Users/test', desc: 'Forward slash path' }, | ||
| { input: 'path/with spaces/file.txt', desc: 'Path with spaces' }, | ||
| { input: 'path\\with\\mixed/slashes', desc: 'Mixed slashes' }, | ||
| ]; | ||
|
|
||
| let allPassed = true; | ||
|
|
||
| for (const test of testCases) { | ||
| try { | ||
| // Use path.normalize which should work on all platforms | ||
| const normalized = path.normalize(test.input); | ||
| success(`${test.desc}: "${test.input}" β "${normalized}"`); | ||
| } catch (e) { | ||
| error(`${test.desc}: Failed to normalize "${test.input}": ${e.message}`); | ||
| allPassed = false; | ||
| } | ||
| } | ||
|
|
||
| // Check for Windows reserved name handling | ||
| const reservedNames = ['CON', 'PRN', 'AUX', 'NUL', 'COM1', 'LPT1']; | ||
| info('Windows reserved names check:'); | ||
| for (const name of reservedNames) { | ||
| if (process.platform === 'win32') { | ||
| info(` ${name} - would be problematic on Windows`); | ||
| } else { | ||
| info(` ${name} - safe on this platform`); | ||
| } | ||
| } | ||
|
|
||
| return { passed: allPassed }; | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /** | ||
| * PR #4: Token hot-reload fix | ||
| * Verifies that config reload IPC channel exists | ||
| */ | ||
| function testPR4_TokenHotReload() { | ||
| log('\n--- PR #4: Token Hot-Reload Fix ---', 'cyan'); | ||
|
|
||
| const ipcConstantsPath = path.join(__dirname, '../apps/frontend/src/shared/constants/ipc.ts'); | ||
| const settingsApiPath = path.join(__dirname, '../apps/frontend/src/preload/api/settings-api.ts'); | ||
| const settingsHandlersPath = path.join(__dirname, '../apps/frontend/src/main/ipc-handlers/settings-handlers.ts'); | ||
|
|
||
| const checks = [ | ||
| { path: ipcConstantsPath, search: 'CONFIG_RELOAD', name: 'IPC channel constant' }, | ||
| { path: settingsApiPath, search: 'reloadConfig', name: 'Settings API method' }, | ||
| { path: settingsHandlersPath, search: 'CONFIG_RELOAD', name: 'IPC handler' }, | ||
| ]; | ||
|
|
||
| let foundCount = 0; | ||
| let missingCount = 0; | ||
| let filesMissing = false; | ||
|
|
||
| for (const check of checks) { | ||
| if (!fs.existsSync(check.path)) { | ||
| warn(`File not found: ${check.path}`); | ||
| filesMissing = true; | ||
| continue; | ||
| } | ||
|
|
||
| const content = fs.readFileSync(check.path, 'utf8'); | ||
| if (content.includes(check.search)) { | ||
| success(`${check.name}: Found "${check.search}"`); | ||
| foundCount++; | ||
| } else { | ||
| info(`${check.name}: "${check.search}" not found`); | ||
| missingCount++; | ||
| } | ||
| } | ||
|
|
||
| // If all files are missing, skip the test | ||
| if (filesMissing && foundCount === 0) { | ||
| info('Required files not found (PR #4 may not be merged yet)'); | ||
| return { passed: true, skipped: true }; | ||
| } | ||
|
|
||
| // If no code was found but files exist, skip (feature not implemented) | ||
| if (foundCount === 0 && missingCount > 0) { | ||
| info('Token hot-reload code not present (PR #4 may not be merged yet)'); | ||
| return { passed: true, skipped: true }; | ||
| } | ||
|
|
||
| // If some code was found but not all, it's a partial implementation (fail) | ||
| if (foundCount > 0 && missingCount > 0) { | ||
| warn('Partial implementation detected - some hot-reload code is missing'); | ||
| return { passed: false }; | ||
| } | ||
|
|
||
| // All checks passed | ||
| return { passed: true }; | ||
| } | ||
|
|
||
| /** | ||
| * Run TypeScript compilation check | ||
| */ | ||
| function testTypeScriptCompilation() { | ||
| log('\n--- TypeScript Compilation Check ---', 'cyan'); | ||
|
|
||
| try { | ||
| info('Running TypeScript type check (this may take a moment)...'); | ||
| execSync('npx tsc --noEmit', { | ||
| cwd: path.join(__dirname, '..', 'apps', 'frontend'), | ||
| stdio: 'pipe', | ||
| timeout: 120000, | ||
| }); | ||
| success('TypeScript compilation passed'); | ||
| return { passed: true }; | ||
| } catch (e) { | ||
| error(`TypeScript compilation failed: ${e.message}`); | ||
| if (e.stdout) console.log(e.stdout.toString()); | ||
| if (e.stderr) console.log(e.stderr.toString()); | ||
| return { passed: false }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Run frontend tests | ||
| */ | ||
| function testFrontendTests() { | ||
| log('\n--- Frontend Tests ---', 'cyan'); | ||
|
|
||
| try { | ||
| info('Running frontend tests (this may take a moment)...'); | ||
| execSync('npm test', { | ||
| cwd: path.join(__dirname, '..', 'apps', 'frontend'), | ||
| stdio: 'inherit', | ||
| timeout: 300000, | ||
| }); | ||
| success('Frontend tests passed'); | ||
| return { passed: true }; | ||
| } catch (e) { | ||
| error('Frontend tests failed'); | ||
| return { passed: false }; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Main execution | ||
| */ | ||
| function main() { | ||
| log('\nββββββββββββββββββββββββββββββββββββββββββββββββββ', 'cyan'); | ||
| log('β Auto-Claude Windows Fixes Verification Tool β', 'cyan'); | ||
| log('ββββββββββββββββββββββββββββββββββββββββββββββββββ', 'cyan'); | ||
|
|
||
| info(`Platform: ${process.platform}`); | ||
| info(`Node.js: ${process.version}`); | ||
| info(`Working directory: ${process.cwd()}`); | ||
|
|
||
| const args = process.argv.slice(2); | ||
| const runAll = args.includes('--all'); | ||
|
|
||
| // Parse --pr argument with validation | ||
| let specificPR = null; | ||
| const prEqualsArg = args.find(a => /^--pr=\d+$/.test(a)); | ||
| const prArgIndex = args.indexOf('--pr'); | ||
|
|
||
| if (prEqualsArg) { | ||
| // Handle --pr=N format | ||
| specificPR = parseInt(prEqualsArg.split('=')[1], 10); | ||
| } else if (prArgIndex !== -1) { | ||
| // Handle --pr N format | ||
| const nextArg = args[prArgIndex + 1]; | ||
| if (nextArg && /^\d+$/.test(nextArg)) { | ||
| specificPR = parseInt(nextArg, 10); | ||
| } else { | ||
| error('--pr requires a valid PR number (e.g., --pr 1 or --pr=1)'); | ||
| process.exit(1); | ||
| } | ||
| } | ||
|
|
||
| const results = []; | ||
|
|
||
| // Run specific PR test or all quick tests | ||
| if (specificPR) { | ||
| info(`Testing PR #${specificPR} only`); | ||
| switch (specificPR) { | ||
| case 1: results.push({ name: 'PR #1', ...testPR1_MarketplaceInit() }); break; | ||
| case 2: results.push({ name: 'PR #2', ...testPR2_ErrorSurfacing() }); break; | ||
| case 3: results.push({ name: 'PR #3', ...testPR3_WindowsPathFix() }); break; | ||
| case 4: results.push({ name: 'PR #4', ...testPR4_TokenHotReload() }); break; | ||
| default: | ||
| error(`Unknown PR number: ${specificPR}. Valid PR numbers are 1-4.`); | ||
| process.exit(1); | ||
| } | ||
| } else { | ||
| // Run all quick verification tests | ||
| results.push({ name: 'PR #1 (Marketplace)', ...testPR1_MarketplaceInit() }); | ||
| results.push({ name: 'PR #2 (Error Surfacing)', ...testPR2_ErrorSurfacing() }); | ||
| results.push({ name: 'PR #3 (Windows Path)', ...testPR3_WindowsPathFix() }); | ||
| results.push({ name: 'PR #4 (Hot-Reload)', ...testPR4_TokenHotReload() }); | ||
|
|
||
| if (runAll) { | ||
| results.push({ name: 'TypeScript', ...testTypeScriptCompilation() }); | ||
| results.push({ name: 'Frontend Tests', ...testFrontendTests() }); | ||
| } | ||
| } | ||
|
|
||
| // Summary | ||
| log('\nββββββββββββββββββββββββββββββββββββββββββββββββββ', 'cyan'); | ||
| log(' SUMMARY ', 'cyan'); | ||
| log('ββββββββββββββββββββββββββββββββββββββββββββββββββ', 'cyan'); | ||
|
|
||
| let passedCount = 0; | ||
| let failedCount = 0; | ||
| let skippedCount = 0; | ||
|
|
||
| for (const result of results) { | ||
| if (result.skipped) { | ||
| warn(`${result.name}: SKIPPED`); | ||
| skippedCount++; | ||
| } else if (result.passed) { | ||
| success(`${result.name}: PASSED`); | ||
| passedCount++; | ||
| } else { | ||
| error(`${result.name}: FAILED`); | ||
| failedCount++; | ||
| } | ||
| } | ||
|
|
||
| log(''); | ||
| log(`Total: ${passedCount} passed, ${failedCount} failed, ${skippedCount} skipped`, | ||
| failedCount > 0 ? 'red' : 'green'); | ||
|
|
||
| if (!runAll) { | ||
| info('\nRun with --all to include TypeScript and test suite verification'); | ||
| } | ||
|
|
||
| process.exit(failedCount > 0 ? 1 : 0); | ||
| } | ||
|
|
||
| main(); | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This comment was marked as outdated.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.