Functions/Invoke-WhiskeyNpmCommand.ps1
function Invoke-WhiskeyNpmCommand { <# .SYNOPSIS Runs `npm` with given command and argument. .DESCRIPTION The `Invoke-WhiskeyNpmCommand` function runs `npm` commands with given arguments in a Node.js project. The function will first call `Install-WhiskeyNodeJs` and `Get-WhiskeyNPMPath` to download and install the desired versions of Node.js and npm listed in the project's `package.json` `engines` field. Then `npm` will be invoked with the given `NpmCommand` and `Argument` in the `ApplicationRoot` directory. If `npm` returns a non-zero exit code this function will write an error indicating that the npm command failed. You must specify the `npm` command you would like to run with the `NpmCommand` parameter. Optionally, you may specify arguments for the `npm command` with the `Argument` parameter. The `ApplicationRoot` parameter must contain the path to the directory where the Node.js module's `package.json` can be found. .EXAMPLE Invoke-WhiskeyNpmCommand -NpmCommand 'install' -ApplicationRoot 'src\app' -RegistryUri 'http://registry.npmjs.org' -ForDeveloper Runs the `npm install' command without any arguments in the 'src\app' directory as a developer. .EXAMPLE Invoke-WhiskeyNpmCommand -NpmCommand 'run' -Argument 'test --silent' -ApplicationRoot 'src\app' -RegistryUri 'http://registry.npmjs.org' Executes `npm run test --silent` in the 'src\app' directory. #> [CmdletBinding()] param( [Parameter(Mandatory=$true,ParameterSetName='InvokeNpm')] [string] # The NPM command to execute. $NpmCommand, [Parameter(ParameterSetName='InvokeNpm')] [string[]] # An array of arguments to be given to the NPM command being executed. $Argument, [Parameter(ParameterSetName='InitializeOnly')] [switch] $InitializeOnly, [Parameter(Mandatory=$true)] [string] # The root directory of the target Node.js application. This directory will contain the application's `package.json` config file and will be where NPM will be executed from. $ApplicationRoot, [Parameter(Mandatory=$true)] # The URI to the registry from which NPM packages should be downloaded. $RegistryUri, [switch] # NPM commands are being run on a developer computer. $ForDeveloper ) Set-StrictMode -Version 'Latest' Use-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState $startedAt = Get-Date function Write-Timing { param( $Message ) $now = Get-Date Write-Debug -Message ('[{0}] [{1}] {2}' -f $now,($now - $startedAt),$Message) } $activity = ('Invoke npm command ''{0}''' -f $NpmCommand) Write-Progress -Activity $activity -Status 'Validating package.json and starting installation of Node.js version required for this package (if required)' Write-Timing -Message 'Installing Node.js' $nodePath = Install-WhiskeyNodeJs -RegistryUri $RegistryUri -ApplicationRoot $ApplicationRoot -ForDeveloper:$ForDeveloper Write-Timing -Message ('COMPLETE') if (-not $nodePath) { Write-Error -Message 'Node.js version required for this package failed to install. Please see previous errors for details.' $Global:LASTEXITCODE = 1 return } $nodeRoot = $nodePath | Split-Path $npmGlobalPath = Join-Path -Path $nodeRoot -ChildPath 'node_modules\npm\bin\npm-cli.js' -Resolve if (-not $npmGlobalPath) { Write-Error -Message 'NPM didn''t get installed by NVM when installing Node. Please use NVM to uninstall this version of Node.' $Global:LASTEXITCODE = 2 return } Write-Progress -Activity $activity -Status 'Getting path to the version of NPM required for this package' Write-Timing -Message 'Resolving path to NPM.' $npmPath = Get-WhiskeyNPMPath -NodePath $nodePath -ApplicationRoot $ApplicationRoot Write-Timing -Message ('COMPLETE') if (-not $npmPath) { Write-Error -Message ('Could not locate version of NPM that is required for this package. Please see previous errors for details.') $Global:LASTEXITCODE = 3 return } if ($InitializeOnly) { $Global:LASTEXITCODE = 0 Write-Timing -Message 'Initialization complete.' return } $originalPath = $env:PATH Push-Location -Path $ApplicationRoot try { Set-Item -Path 'env:PATH' -Value ('{0};{1}' -f $nodeRoot,$env:Path) $defaultArguments = @('--scripts-prepend-node-path=auto') if (-not $ForDeveloper) { $defaultArguments += '--no-color' } $npmCommandString = ('npm {0} {1} {2}' -f $NpmCommand,($Argument -join ' '),($defaultArguments -join ' ')) Write-Progress -Activity $activity -Status ('Executing ''{0}''' -f $npmCommandString) Invoke-Command -NoNewScope -ScriptBlock { & $nodePath $npmPath $NpmCommand $Argument $defaultArguments } if ($LASTEXITCODE -ne 0) { Write-Error -Message ('NPM command ''{0}'' failed with exit code {1}.' -f $npmCommandString,$LASTEXITCODE) } } finally { Set-Item -Path 'env:PATH' -Value $originalPath Pop-Location } } |