CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-grunt-exec

Grunt plugin for executing shell commands with comprehensive configuration options

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

index.mddocs/

grunt-exec

grunt-exec is a Grunt plugin that provides comprehensive shell command execution capabilities within Grunt build processes. It offers extensive configuration options for process control, input/output handling, error management, and both synchronous and asynchronous execution modes with cross-platform compatibility.

Package Information

  • Package Name: grunt-exec
  • Package Type: npm
  • Language: JavaScript
  • Installation: npm install grunt-exec --save-dev

Core Imports

After installing, load the plugin in your Gruntfile:

grunt.loadNpmTasks('grunt-exec');

Basic Usage

grunt.initConfig({
  exec: {
    simple_command: 'echo "Hello World"',
    
    advanced_command: {
      command: 'ls -la',
      stdout: true,
      stderr: true,
      cwd: './src'
    },
    
    function_command: {
      cmd: function(arg1, arg2) {
        return 'echo "Arguments: ' + arg1 + ', ' + arg2 + '"';
      }
    }
  }
});

// Run tasks
grunt.registerTask('default', ['exec:simple_command']);

Architecture

grunt-exec is built around the Grunt multitask system:

  • Task Registration: The plugin registers an 'exec' multitask with Grunt
  • Configuration Processing: Each target configuration is processed to handle commands, options, and I/O settings
  • Process Execution: Uses Node.js child_process.spawn/spawnSync for reliable command execution
  • Output Management: Provides sophisticated stdout/stderr handling with buffering and piping options
  • Error Handling: Comprehensive error checking with customizable exit code validation

Capabilities

Shell Command Execution

Core capability for executing shell commands with comprehensive configuration options.

/**
 * Main plugin registration function
 * @param grunt - The Grunt object instance
 */
function(grunt: GruntObject): void;

/**
 * Exec task configuration object
 */
interface ExecTaskConfig {
  /** The shell command to execute (required) */
  command?: string | CommandFunction;
  /** Alias for command */
  cmd?: string | CommandFunction;
  /** Current working directory */
  cwd?: string | CwdFunction;
  /** Control stdin behavior */
  stdin?: boolean | string;
  /** Control stdout behavior */
  stdout?: boolean | string;
  /** Control stderr behavior */
  stderr?: boolean | string;
  /** Shorthand for stdio configuration */
  stdio?: 'inherit' | 'pipe' | 'ignore';
  /** Use synchronous execution */
  sync?: boolean;
  /** Expected exit code(s) */
  exitCode?: number | number[];
  /** Alias for exitCode */
  exitCodes?: number | number[];
  /** Custom callback function */
  callback?: CallbackFunction;
  /** Additional callback arguments */
  callbackArgs?: any[];
  /** Character encoding for output */
  encoding?: string;
  /** Maximum buffer size for output */
  maxBuffer?: number;
  /** Command timeout in milliseconds */
  timeout?: number;
  /** Signal to use when killing process */
  killSignal?: string;
  /** Shell to use for command execution */
  shell?: boolean | string;
  /** Advanced process options */
  options?: ProcessOptions;
}

/**
 * Command function type for dynamic commands
 */
interface CommandFunction {
  (...args: any[]): string;
}

/**
 * Working directory function type
 */
interface CwdFunction {
  (...args: any[]): string;
}

/**
 * Callback function for handling command results
 */
interface CallbackFunction {
  (error: Error | null, stdout: string | Buffer, stderr: string | Buffer, callbackArgs?: any[]): void;
}

/**
 * Advanced process options
 */
interface ProcessOptions {
  /** Current working directory */
  cwd?: string;
  /** Environment variables */
  env?: { [key: string]: string };
  /** Character encoding */
  encoding?: string;
  /** Shell to execute command with */
  shell?: string | boolean;
  /** Timeout in milliseconds */
  timeout?: number;
  /** Maximum buffer size */
  maxBuffer?: number;
  /** Kill signal */
  killSignal?: string;
  /** User identity */
  uid?: number;
  /** Group identity */
  gid?: number;
  /** Stdio configuration */
  stdio?: (string | number)[];
}

Task Configuration Patterns

grunt-exec supports multiple configuration patterns for different use cases.

Simple String Configuration

For basic commands, use a simple string:

exec: {
  simple_task: 'echo "Hello World"'
}

Object Configuration

For advanced options, use an object:

exec: {
  advanced_task: {
    command: 'npm test',
    cwd: './packages/core',
    stdout: true,
    stderr: true,
    exitCodes: [0, 1],
    timeout: 30000
  }
}

Function Commands

For dynamic commands that accept command-line arguments:

exec: {
  dynamic_task: {
    cmd: function(environment, version) {
      return 'deploy --env=' + environment + ' --version=' + version;
    }
  }
}

Run with: grunt exec:dynamic_task:production:1.2.0

Custom Callbacks

For processing command output:

exec: {
  callback_task: {
    cmd: 'git log --oneline -10',
    callback: function(error, stdout, stderr) {
      if (error) {
        grunt.log.error('Git command failed: ' + error.message);
        return;
      }
      
      var commits = stdout.split('\n').filter(Boolean);
      grunt.log.writeln('Found ' + commits.length + ' recent commits');
      commits.forEach(function(commit) {
        grunt.log.writeln('  ' + commit);
      });
    }
  }
}

Input/Output Control

Comprehensive control over process stdin, stdout, and stderr.

Standard Output Configuration

// Enable stdout (default)
stdout: true

// Disable stdout
stdout: false

// Pipe stdout
stdout: 'pipe'

// Inherit from parent process
stdout: 'inherit'

// Ignore stdout
stdout: 'ignore'

Standard Error Configuration

// Enable stderr (default)
stderr: true

// Disable stderr
stderr: false

// Pipe stderr for processing
stderr: 'pipe'

// Inherit from parent process
stderr: 'inherit'

Standard Input Configuration

// Enable stdin interaction (experimental)
stdin: true

// Disable stdin (default)
stdin: false

// Inherit stdin from parent
stdin: 'inherit'

Stdio Shorthand

// Inherit all stdio from parent
stdio: 'inherit'

// Pipe all stdio
stdio: 'pipe'

// Ignore all stdio
stdio: 'ignore'

Process Control Options

Advanced options for controlling command execution behavior.

Working Directory

// Static working directory
cwd: '/path/to/directory'

// Dynamic working directory
cwd: function(arg1, arg2) {
  return './environments/' + arg1;
}

Exit Code Validation

// Single expected exit code (default: 0)
exitCode: 0

// Multiple allowed exit codes
exitCodes: [0, 1, 2]

// Allow any exit code
exitCodes: []

Timeout Configuration

// 30 second timeout
timeout: 30000

// No timeout (default)
timeout: 0

Process Termination

// Custom kill signal
killSignal: 'SIGKILL'

// Default termination signal
killSignal: 'SIGTERM'

Synchronous vs Asynchronous Execution

Control execution mode based on your needs.

Asynchronous Execution (Default)

exec: {
  async_task: {
    cmd: 'long-running-command',
    sync: false  // or omit (default)
  }
}

Synchronous Execution

exec: {
  sync_task: {
    cmd: 'quick-command',
    sync: true
  }
}

Output Processing and Buffering

Control how command output is handled and processed.

Encoding Options

// UTF-8 encoding (default)
encoding: 'utf8'

// Binary encoding
encoding: 'binary'

// Buffer objects (no string conversion)
encoding: 'buffer'

Buffer Size Limits

// Custom buffer size (200KB default)
maxBuffer: 1024 * 1024  // 1MB

// Unlimited buffering
maxBuffer: 0

Output Processing Example

exec: {
  process_output: {
    cmd: 'npm ls --json',
    encoding: 'utf8',
    callback: function(error, stdout, stderr) {
      if (error) {
        grunt.fail.warn('Command failed: ' + error.message);
        return;
      }
      
      try {
        var packageInfo = JSON.parse(stdout);
        grunt.log.writeln('Package: ' + packageInfo.name);
        grunt.log.writeln('Version: ' + packageInfo.version);
      } catch (e) {
        grunt.log.error('Failed to parse JSON output');
      }
    }
  }
}

Error Handling and Debugging

Comprehensive error handling with detailed logging options.

Verbose Logging

Enable verbose logging for debugging:

grunt exec:my_task --verbose

Verbose mode provides detailed information about:

  • Command parsing and arguments
  • Process configuration
  • Buffer settings
  • Execution environment
  • Process ID and exit codes

Error Scenarios

grunt-exec handles various error conditions:

exec: {
  error_handling: {
    cmd: 'potentially-failing-command',
    exitCodes: [0, 1],  // Allow exit code 1
    callback: function(error, stdout, stderr) {
      if (error) {
        if (error.code === 'ENOENT') {
          grunt.log.error('Command not found');
        } else if (error.message.includes('timeout')) {
          grunt.log.error('Command timed out');
        } else {
          grunt.log.error('Command failed: ' + error.message);
        }
        return;
      }
      
      // Process successful output
      grunt.log.ok('Command completed successfully');
    }
  }
}

Shell Configuration

Control shell behavior and compatibility across platforms.

Shell Options

// Use default shell (recommended for cross-platform)
shell: true

// Use specific shell
shell: '/bin/bash'

// Disable shell (direct command execution)
shell: false

Platform Considerations

grunt-exec handles platform differences automatically:

exec: {
  cross_platform: {
    cmd: process.platform === 'win32' 
      ? 'dir /b' 
      : 'ls -1',
    shell: true
  }
}

Environment Variables

Pass custom environment variables to commands.

exec: {
  with_env: {
    cmd: 'echo $NODE_ENV',
    options: {
      env: {
        NODE_ENV: 'production',
        API_KEY: process.env.API_KEY
      }
    }
  }
}

Common Use Cases

Build Automation

exec: {
  build: {
    cmd: 'npm run build',
    cwd: './client'
  },
  
  test: {
    cmd: 'npm test',
    exitCodes: [0, 1]  // Allow test failures
  },
  
  deploy: {
    cmd: function(env) {
      return 'docker build -t myapp:' + env + ' .';
    }
  }
}

Git Operations

exec: {
  git_status: 'git status --porcelain',
  
  git_commit: {
    cmd: function(message) {
      return 'git commit -m "' + message + '"';
    }
  },
  
  git_push: {
    cmd: 'git push origin main',
    callback: function(error, stdout, stderr) {
      if (error) {
        grunt.fail.warn('Push failed: ' + stderr);
      } else {
        grunt.log.ok('Push successful');
      }
    }
  }
}

File Operations

exec: {
  cleanup: {
    cmd: process.platform === 'win32' ? 'del /q *.log' : 'rm -f *.log',
    stdout: false,
    stderr: false
  },
  
  backup: {
    cmd: 'tar -czf backup.tar.gz ./src',
    timeout: 60000  // 1 minute timeout
  }
}

Development Server Management

exec: {
  dev_server: {
    cmd: 'npm run dev',
    stdio: 'inherit',  // Show server output
    timeout: 0         // No timeout for long-running server
  },
  
  stop_server: {
    cmd: process.platform === 'win32' 
      ? 'taskkill /f /im node.exe' 
      : 'pkill -f "npm run dev"',
    exitCodes: [0, 1]  // Allow if no process found
  }
}

docs

index.md

tile.json