diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6cd76d5..0a34f34 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -38,6 +38,9 @@ jobs: - name: Run tests run: pnpm test + - name: Build project + run: pnpm build + - name: Integration test - Start node and test RPC shell: bash run: bash scripts/starting-node-test.sh diff --git a/scripts/create-test.sh b/scripts/create-test.sh index 6acb692..1b148e3 100755 --- a/scripts/create-test.sh +++ b/scripts/create-test.sh @@ -70,8 +70,25 @@ fi # Install offckb since create test need it echo "" echo "Installing offckb CLI tool..." -npm install -g @offckb/cli -echo "✓ offckb installed" +# Use the local build but install it globally for better compatibility +OFFCKB_CLI_PATH="$(pwd)/build/index.js" +if [ ! -f "$OFFCKB_CLI_PATH" ]; then + echo "✗ Local build not found at $OFFCKB_CLI_PATH" + echo "Please run 'pnpm build' first" + exit 1 +fi + +# Pack and install the local build globally +echo "Packing local build..." +PACKAGE_FILE=$(pnpm pack --pack-destination /tmp 2>&1 | tail -1) +if [ ! -f "$PACKAGE_FILE" ]; then + echo "✗ Failed to pack local build. Output: $PACKAGE_FILE" + exit 1 +fi +echo "Installing local package globally: $PACKAGE_FILE" +npm install -g "$PACKAGE_FILE" + +echo "✓ Local offckb CLI installed globally" # Create test project with non-interactive mode echo "" @@ -82,12 +99,13 @@ echo "Creating test project with offckb create..." # - --no-install: Skip automatic dependency installation (we'll do it explicitly) # - -l typescript: Use TypeScript language # - -c hello-world: Name the first contract 'hello-world' -pnpm start create "$TEST_PROJECT_DIR" \ +CONTRACT_NAME="hello-world" +offckb create "$TEST_PROJECT_DIR" \ --no-interactive \ --no-git \ --no-install \ -l typescript \ - -c hello-world + -c "$CONTRACT_NAME" # Check if project was created if [ ! -d "$TEST_PROJECT_DIR" ]; then @@ -162,10 +180,10 @@ echo "✓ Project built successfully" echo "" echo "Deploying the project..." cd "$TEST_PROJECT_DIR" -pnpm run deploy +pnpm run deploy -- --network devnet --yes # Check if deployment artifacts were created -if [ ! -f "$TEST_PROJECT_DIR/deployment/devnet.json" ]; then +if [ ! -f "$TEST_PROJECT_DIR/deployment/scripts.json" ]; then echo "✗ Deploy failed - deployment record not created" exit 1 fi @@ -175,10 +193,15 @@ echo "✓ Project deployed successfully" # Verify deployment record contains expected data echo "" echo "Verifying deployment record..." -DEPLOY_RECORD=$(cat "$TEST_PROJECT_DIR/deployment/devnet.json") +DEPLOY_RECORD=$(cat "$TEST_PROJECT_DIR/deployment/scripts.json") + +if ! echo "$DEPLOY_RECORD" | grep -q '"devnet"'; then + echo "✗ Deployment record is missing devnet section" + exit 1 +fi -if ! echo "$DEPLOY_RECORD" | grep -q '"contractName"'; then - echo "✗ Deployment record is missing contractName" +if ! echo "$DEPLOY_RECORD" | grep -q "\"${CONTRACT_NAME}.bc\""; then + echo "✗ Deployment record is missing ${CONTRACT_NAME}.bc contract" exit 1 fi diff --git a/src/templates/config.ts b/src/templates/config.ts index 5d73e77..60ebb7e 100644 --- a/src/templates/config.ts +++ b/src/templates/config.ts @@ -19,9 +19,11 @@ export const PACKAGE_JSON_CONFIG: PackageJsonConfig = { 'build:contract:debug': 'node scripts/build-contract.js --debug', build: 'node scripts/build-all.js', 'build:debug': 'node scripts/build-all.js --debug', - deploy: 'node scripts/build-all.js && node scripts/deploy.js', - 'deploy:debug': 'node scripts/build-all.js --debug && node scripts/deploy.js', - test: 'node scripts/build-all.js && jest', + deploy: 'node scripts/deploy.js', + 'deploy:build': 'run-s build deploy', + 'deploy:debug': 'run-s build:debug deploy', + test: 'run-s build test:only', + 'test:only': 'jest', 'add-contract': 'node scripts/add-contract.js', clean: 'rimraf dist', format: 'prettier --write .', @@ -36,6 +38,7 @@ export const PACKAGE_JSON_CONFIG: PackageJsonConfig = { '@ckb-ccc/core': '1.12.2', // lock to version compatible with ckb-testtool esbuild: '~0.25.8', jest: '~29.7.0', + 'npm-run-all': '^4.1.5', prettier: '^3.5.3', rimraf: '^6.0.1', }, diff --git a/templates/v4/base-template/scripts/build-all.js b/templates/v4/base-template/scripts/build-all.js index 9c01bd4..0c8ff3e 100644 --- a/templates/v4/base-template/scripts/build-all.js +++ b/templates/v4/base-template/scripts/build-all.js @@ -27,7 +27,8 @@ function buildAllContracts(isDebug = false) { for (const contractName of contracts) { console.log(`\n📦 Building contract: ${contractName}`); try { - execSync(`node scripts/build-contract.js ${contractName} ${isDebug ? '--debug' : ''}`, { stdio: 'inherit' }); + const buildScriptPath = path.join('scripts', 'build-contract.js'); + execSync(`node "${buildScriptPath}" ${contractName} ${isDebug ? '--debug' : ''}`, { stdio: 'inherit' }); console.log(`✅ Successfully built: ${contractName} with ${isDebug ? 'debug' : 'release'} version`); } catch (error) { console.error(`❌ Failed to build: ${contractName}`); diff --git a/templates/v4/base-template/scripts/build-contract.js b/templates/v4/base-template/scripts/build-contract.js index 2ba6d92..b7c871b 100644 --- a/templates/v4/base-template/scripts/build-contract.js +++ b/templates/v4/base-template/scripts/build-contract.js @@ -46,7 +46,8 @@ function buildContract(contractName, isDebug = false) { // Step 1: TypeScript type checking (if TypeScript file) - temporarily disabled due to @ckb-ccc/core version conflicts // if (srcFile.endsWith('.ts')) { // console.log(' 🔍 Type checking...'); - // execSync(`./node_modules/.bin/tsc --noEmit --project .`, { stdio: 'pipe' }); + // const tscPath = path.join('node_modules', '.bin', 'tsc'); + // execSync(`"${tscPath}" --noEmit --project .`, { stdio: 'pipe' }); // } // Step 2: Bundle with esbuild @@ -60,28 +61,31 @@ function buildContract(contractName, isDebug = false) { '--loader:.map=json', ]; const releaseParams = ['--minify']; + const esbuildPath = path.join('node_modules', '.bin', 'esbuild'); const esbuildCmd = [ - './node_modules/.bin/esbuild', + `"${esbuildPath}"`, '--platform=neutral', '--bundle', '--external:@ckb-js-std/bindings', '--target=es2022', ...(isDebug ? debugParams : releaseParams), - srcFile, - `--outfile=${outputJsFile}`, + `"${srcFile}"`, + `--outfile="${outputJsFile}"`, ].join(' '); execSync(esbuildCmd, { stdio: 'pipe' }); // Step 3: Compile to bytecode with ckb-debugger console.log(' 🔧 Compiling to bytecode...'); + const ckbJsVmPath = path.join('node_modules', 'ckb-testtool', 'src', 'unittest', 'defaultScript', 'ckb-js-vm'); const debuggerCmd = [ 'ckb-debugger', - `--read-file ${outputJsFile}`, - '--bin node_modules/ckb-testtool/src/unittest/defaultScript/ckb-js-vm', + `--read-file "${outputJsFile}"`, + '--bin', + `"${ckbJsVmPath}"`, '--', '-c', - outputBcFile, + `"${outputBcFile}"`, ].join(' '); execSync(debuggerCmd, { stdio: 'pipe' }); diff --git a/templates/v4/base-template/scripts/deploy.js b/templates/v4/base-template/scripts/deploy.js index 628d4a6..e55d5bd 100644 --- a/templates/v4/base-template/scripts/deploy.js +++ b/templates/v4/base-template/scripts/deploy.js @@ -13,23 +13,34 @@ * - --network: Network to deploy to (devnet, testnet, mainnet) - defaults to devnet * - --privkey: Private key for deployment - defaults to offckb's deployer account * - --type-id: Whether to use upgradable type id - defaults to false + * - --yes, -y: Skip confirmation prompt and deploy immediately - defaults to false * * Usage: * pnpm run deploy * pnpm run deploy --network testnet * pnpm run deploy --network testnet --privkey 0x... * pnpm run deploy --network testnet --type-id + * pnpm run deploy --yes */ import { spawn } from 'child_process'; import fs from 'fs'; +import { fileURLToPath } from 'url'; +import path from 'path'; function parseArgs() { - const args = process.argv.slice(2); + let args = process.argv.slice(2); + + // Skip the first argument if it's "--" (npm/pnpm script separator) + if (args.length > 0 && args[0] === '--') { + args = args.slice(1); + } + const parsed = { network: 'devnet', privkey: null, typeId: false, + yes: false, }; for (let i = 0; i < args.length; i++) { @@ -43,6 +54,8 @@ function parseArgs() { i++; // Skip next argument since we consumed it } else if (arg === '--type-id' || arg === '-t') { parsed.typeId = true; + } else if (arg === '--yes' || arg === '-y') { + parsed.yes = true; } } @@ -59,6 +72,7 @@ function main() { const NETWORK = options.network; const PRIVKEY = options.privkey; const TYPE_ID = options.typeId; + const YES = options.yes; // Validate that dist directory exists if (!fs.existsSync(TARGET)) { @@ -100,12 +114,16 @@ function main() { args.push('--privkey', PRIVKEY); } - // Try to find offckb binary + if (YES) { + args.push('--yes'); + } + + // Use offckb command - should be available in PATH const offckbCmd = 'offckb'; - // For now, use 'offckb' directly - users should have it installed - console.log(`� Deploying contracts...`); - console.log(`�💻 Running: ${offckbCmd} ${args.join(' ')}`); + console.log(`🚀 Deploying contracts...`); + console.log(`💻 Running: ${offckbCmd} ${args.join(' ')}`); + console.log(`🖥️ Platform: ${process.platform}`); console.log(''); // Execute the deploy command @@ -115,6 +133,7 @@ function main() { }); deployProcess.on('close', (code) => { + console.log(`Deploy process exited with code: ${code}`); if (code === 0) { console.log(''); console.log('✅ Successfully deployed all contracts!'); @@ -124,6 +143,7 @@ function main() { console.log('💡 Next steps:'); console.log(' - Check the deployment artifacts in the deployment/ folder'); console.log(' - Run your tests to use the deployed contract scripts'); + process.exit(0); } else { console.error(''); console.error('❌ Deployment failed.'); @@ -134,16 +154,22 @@ function main() { deployProcess.on('error', (error) => { console.error('❌ Error running deploy command:', error.message); + console.error(`💻 Command: ${offckbCmd} ${args.join(' ')}`); console.error(''); - console.error('💡 Make sure offckb is installed:'); - console.error(' npm install -g offckb-cli'); - console.error(' # or'); - console.error(' pnpm add -g offckb-cli'); + console.error('💡 Troubleshooting:'); + console.error(' 1. Make sure offckb is installed:'); + console.error(' npm install -g @offckb/cli'); + console.error(' # or'); + console.error(' pnpm add -g @offckb/cli'); + console.error(' 2. Check if offckb is in your PATH'); + console.error(' 3. Try running the command manually to see the exact error'); process.exit(1); }); } // Run main function if this script is executed directly -if (import.meta.url === `file://${process.argv[1]}`) { +// Use URL comparison for cross-platform compatibility (Windows uses backslashes in process.argv) +const __filename = fileURLToPath(import.meta.url); +if (path.resolve(process.argv[1]) === path.resolve(__filename)) { main(); }