diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000..5eec04a --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +./scripts/pre-commit.sh diff --git a/amplify.yml b/amplify.yml index 9f7406e..d910215 100644 --- a/amplify.yml +++ b/amplify.yml @@ -11,6 +11,7 @@ frontend: commands: - npm run build - cp -r .next/static .next/standalone/.next/ + - cp .next/standalone/.next/required-server-files.json .next/standalone/ artifacts: baseDirectory: .next/standalone files: diff --git a/package-lock.json b/package-lock.json index bfdba9a..55d3165 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "eslint": "^8.55.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", + "husky": "^9.1.7", "jest": "^30.0.0", "jest-environment-jsdom": "^30.0.0", "postcss": "^8.4.32", @@ -6043,6 +6044,22 @@ "node": ">=10.17.0" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", diff --git a/package.json b/package.json index 57a906a..05fecdd 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,9 @@ "lint": "next lint", "test": "jest", "test:watch": "jest --watch", - "security:check": "node scripts/security-check.js" + "security:check": "node scripts/security-check.js", + "test:build": "node scripts/test-build.js", + "prepare": "husky" }, "dependencies": { "@types/cheerio": "^0.22.35", @@ -32,6 +34,7 @@ "eslint": "^8.55.0", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.5", + "husky": "^9.1.7", "jest": "^30.0.0", "jest-environment-jsdom": "^30.0.0", "postcss": "^8.4.32", diff --git a/scripts/pre-commit.sh b/scripts/pre-commit.sh new file mode 100755 index 0000000..08a5af8 --- /dev/null +++ b/scripts/pre-commit.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +echo "๐Ÿ” Running pre-commit checks..." + +# Run security check +echo "๐Ÿ” Checking for credential leaks..." +npm run security:check +if [ $? -ne 0 ]; then + echo "โŒ Security check failed!" + exit 1 +fi + +# Run build test +echo "๐Ÿ—๏ธ Testing build..." +node scripts/test-build.js +if [ $? -ne 0 ]; then + echo "โŒ Build test failed!" + exit 1 +fi + +# Run tests +echo "๐Ÿงช Running tests..." +npm test -- --passWithNoTests +if [ $? -ne 0 ]; then + echo "โŒ Tests failed!" + exit 1 +fi + +echo "โœ… All pre-commit checks passed!" \ No newline at end of file diff --git a/scripts/test-build.js b/scripts/test-build.js new file mode 100755 index 0000000..ac76fc7 --- /dev/null +++ b/scripts/test-build.js @@ -0,0 +1,69 @@ +#!/usr/bin/env node + +const { execSync } = require('child_process'); +const fs = require('fs'); +const path = require('path'); + +console.log('๐Ÿงช Testing build locally...\n'); + +// Clean previous build +console.log('๐Ÿงน Cleaning previous build...'); +try { + execSync('rm -rf .next', { stdio: 'inherit' }); +} catch (e) { + // Ignore if doesn't exist +} + +// Run build +console.log('\n๐Ÿ”จ Running build...'); +try { + execSync('npm run build', { stdio: 'inherit' }); +} catch (e) { + console.error('โŒ Build failed!'); + process.exit(1); +} + +// Check for required files +console.log('\n๐Ÿ” Checking build output...'); +const checks = [ + { path: '.next/standalone/server.js', name: 'Standalone server' }, + { path: '.next/standalone/.next/required-server-files.json', name: 'Required server files' }, + { path: '.next/static', name: 'Static directory' }, +]; + +let allPassed = true; +for (const check of checks) { + if (fs.existsSync(check.path)) { + console.log(`โœ… ${check.name}: Found`); + } else { + console.error(`โŒ ${check.name}: Missing at ${check.path}`); + allPassed = false; + } +} + +// Test the copy command +console.log('\n๐Ÿ“‹ Testing copy command...'); +try { + execSync('cp -r .next/static .next/standalone/.next/', { stdio: 'inherit' }); + console.log('โœ… Copy command successful'); +} catch (e) { + console.error('โŒ Copy command failed'); + allPassed = false; +} + +// Check final structure +console.log('\n๐Ÿ“ Final structure check...'); +const finalPath = '.next/standalone/.next/static'; +if (fs.existsSync(finalPath)) { + console.log('โœ… Static files copied successfully'); +} else { + console.error('โŒ Static files not in final location'); + allPassed = false; +} + +if (!allPassed) { + console.error('\nโŒ Build test failed! Do not push.'); + process.exit(1); +} else { + console.log('\nโœ… All build tests passed!'); +} \ No newline at end of file