2025-08-01 16:08:22 -07:00
#!/usr/bin/env node
/ * *
* Release Workflow Script for @ soulcraft / brainy - models - package
*
* This script provides a comprehensive workflow for releasing a new version :
* 1. Updates the version ( major , minor , or patch )
* 2. Automatically updates the CHANGELOG . md with commit messages since the last release
* 3. Creates a GitHub release
* 4. Deploys to NPM
*
* Usage :
* node scripts / release - workflow . js [ patch | minor | major ]
*
* If no version type is specified , it defaults to "patch"
* /
/* global process, console */
import { execSync } from 'child_process'
import fs from 'fs'
import path from 'path'
import { fileURLToPath } from 'url'
import readline from 'readline'
// Get the directory of the current module
const _ _filename = fileURLToPath ( import . meta . url )
const _ _dirname = path . dirname ( _ _filename )
// Path to the brainy-models-package directory
const packageDir = path . join ( _ _dirname , '..' )
const rootDir = path . join ( _ _dirname , '..' , '..' )
// Get the version type from command line arguments
const args = process . argv . slice ( 2 )
const versionType = args [ 0 ] || 'patch'
// Validate version type
if ( ! [ 'patch' , 'minor' , 'major' ] . includes ( versionType ) ) {
// eslint-disable-next-line no-console
console . error ( 'Error: Version type must be one of: patch, minor, major' )
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
}
// Function to execute a command and log its output
function executeStep ( command , description , cwd = packageDir ) {
// eslint-disable-next-line no-console
console . log ( ` \n 🚀 ${ description } ... \n ` )
try {
execSync ( command , { stdio : 'inherit' , cwd } )
// eslint-disable-next-line no-console
console . log ( ` ✅ ${ description } completed successfully! \n ` )
return true
} catch ( error ) {
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . error (
` ❌ Error during ${ description . toLowerCase ( ) } : ${ error . message } `
)
2025-08-01 16:08:22 -07:00
return false
}
}
// Main workflow
async function runReleaseWorkflow ( ) {
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . log (
` \n === Starting @soulcraft/brainy-models-package Release Workflow ( ${ versionType } ) === \n `
)
2025-08-01 16:08:22 -07:00
// Step 1: Build the project
if ( ! executeStep ( 'npm run build' , 'Building brainy-models-package' ) ) {
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
}
// Step 2: Run tests to ensure everything is working
if ( ! executeStep ( 'npm test' , 'Running tests' ) ) {
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . warn (
'⚠️ Tests failed. This might indicate issues with the release.'
)
2025-08-01 16:08:22 -07:00
// Ask the user if they want to continue despite test failures
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . log (
'\n⚠️ Do you want to continue with the release process despite test failures? (y/N)'
)
2025-08-01 16:08:22 -07:00
const rl = readline . createInterface ( {
input : process . stdin ,
output : process . stdout
} )
2025-08-01 17:33:13 -07:00
const response = await new Promise ( ( resolve ) => {
rl . question ( '' , ( answer ) => {
2025-08-01 16:08:22 -07:00
rl . close ( )
resolve ( answer . toLowerCase ( ) )
} )
} )
2025-08-01 17:33:13 -07:00
2025-08-01 16:08:22 -07:00
if ( response !== 'y' && response !== 'yes' ) {
// eslint-disable-next-line no-console
console . error ( 'Release process aborted due to test failures.' )
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
}
2025-08-01 17:33:13 -07:00
2025-08-01 16:08:22 -07:00
// eslint-disable-next-line no-console
console . log ( 'Continuing with release process despite test failures...' )
}
// Step 3: Update version and generate changelog
2025-08-01 17:33:13 -07:00
if (
! executeStep (
` npm run release: ${ versionType } ` ,
` Updating version ( ${ versionType } ) and generating changelog `
)
) {
2025-08-01 16:08:22 -07:00
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
}
// Step 4: Create GitHub release
2025-08-01 17:33:13 -07:00
if ( ! executeStep ( 'npm run _github-release' , 'Creating GitHub release' ) ) {
2025-08-01 16:08:22 -07:00
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . log (
'Warning: GitHub release creation failed, but continuing with deployment...'
)
2025-08-01 16:08:22 -07:00
}
// Step 5: Publish to NPM
if ( ! executeStep ( 'npm publish' , 'Publishing to NPM' ) ) {
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
}
// Get the new version from package.json
const packageJsonPath = path . join ( packageDir , 'package.json' )
const packageJson = JSON . parse ( fs . readFileSync ( packageJsonPath , 'utf8' ) )
const newVersion = packageJson . version
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . log (
` \n 🎉 @soulcraft/brainy-models-package v ${ newVersion } release completed successfully! 🎉 \n `
)
2025-08-01 16:08:22 -07:00
// eslint-disable-next-line no-console
console . log ( 'Summary of actions:' )
// eslint-disable-next-line no-console
console . log ( ` - Package built and tested ` )
// eslint-disable-next-line no-console
console . log ( ` - Version bumped to v ${ newVersion } ( ${ versionType } ) ` )
// eslint-disable-next-line no-console
console . log ( ` - CHANGELOG.md updated with recent commits ` )
// eslint-disable-next-line no-console
console . log ( ` - GitHub release created with auto-generated notes ` )
// eslint-disable-next-line no-console
console . log ( ` - Package published to NPM as @soulcraft/brainy-models-package ` )
// eslint-disable-next-line no-console
2025-08-01 17:33:13 -07:00
console . log (
'\nThank you for using the brainy-models-package release workflow!\n'
)
2025-08-01 16:08:22 -07:00
}
// Run the workflow
2025-08-01 17:33:13 -07:00
runReleaseWorkflow ( ) . catch ( ( error ) => {
2025-08-01 16:08:22 -07:00
// eslint-disable-next-line no-console
console . error ( 'Unexpected error during release workflow:' , error )
// eslint-disable-next-line no-process-exit
process . exit ( 1 )
} )