diff --git a/.gitignore b/.gitignore
index e8b537fc9ca..083498b1bd2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -67,4 +67,5 @@ paket-files/
# Ignore VS2015 folder
.vs/
+Samples/WebNpmGrunt/node_modules
.fake
diff --git a/Samples/WebNpmGrunt/Gruntfile.js b/Samples/WebNpmGrunt/Gruntfile.js
new file mode 100644
index 00000000000..469894be22d
--- /dev/null
+++ b/Samples/WebNpmGrunt/Gruntfile.js
@@ -0,0 +1,20 @@
+/*global module:false*/
+module.exports = function(grunt) {
+
+ // Project configuration.
+ grunt.initConfig({
+ // Task configuration.
+ jasmine_nodejs : {
+ sample: {
+ specs : ['spec/**/*Spec.js']
+ }
+ }
+ });
+
+ // These plugins provide necessary tasks.
+ grunt.loadNpmTasks('grunt-jasmine-nodejs');
+
+ // Default task.
+ grunt.registerTask('default', ['jasmine_nodejs']);
+
+};
diff --git a/Samples/WebNpmGrunt/build.fsx b/Samples/WebNpmGrunt/build.fsx
new file mode 100644
index 00000000000..aa5cf793845
--- /dev/null
+++ b/Samples/WebNpmGrunt/build.fsx
@@ -0,0 +1,44 @@
+#r @"FakeLib.dll"
+open Fake
+open Fake.NpmHelper
+
+
+Target "Install" (fun _ ->
+ Npm (fun p ->
+ { p with
+ Command = Install Standard
+ })
+ )
+
+Target "Run" (fun _ ->
+ Npm (fun p ->
+ { p with
+ Command = Run "test"
+ })
+ )
+
+Target "RunSilent" (fun _ ->
+ Npm (fun p ->
+ { p with
+ Command = RunSilent "test"
+ })
+ )
+
+Target "RunTest" (fun _ ->
+ Npm (fun p ->
+ { p with
+ Command = RunTest "test"
+ })
+ )
+
+Target "Test" (fun _ ->
+ Npm (fun p ->
+ { p with
+ Command = Test
+ })
+ )
+
+"Install"
+ ==> "Test"
+
+RunTargetOrDefault "Test"
\ No newline at end of file
diff --git a/Samples/WebNpmGrunt/package.json b/Samples/WebNpmGrunt/package.json
new file mode 100644
index 00000000000..09478557dea
--- /dev/null
+++ b/Samples/WebNpmGrunt/package.json
@@ -0,0 +1,14 @@
+{
+ "engines": {
+ "node": ">= 0.10.0"
+ },
+ "devDependencies": {
+ "grunt": "^1.0.1",
+ "grunt-cli": "^1.2.0",
+ "grunt-jasmine-nodejs": "^1.6.0",
+ "jasmine": "^2.5.3"
+ },
+ "scripts": {
+ "test": "grunt jasmine_nodejs"
+ }
+}
diff --git a/Samples/WebNpmGrunt/spec/SampleSpec.js b/Samples/WebNpmGrunt/spec/SampleSpec.js
new file mode 100644
index 00000000000..d76bd20905b
--- /dev/null
+++ b/Samples/WebNpmGrunt/spec/SampleSpec.js
@@ -0,0 +1,19 @@
+(function () {
+ 'use strict';
+
+ describe('Sample Suite', function () {
+ var success;
+
+ beforeAll(function () {
+ success = true;
+ });
+
+ it('should have a successful test', function () {
+ expect(success).toBeTruthy();
+ });
+
+ it('should have a failing test', function () {
+ expect(success).toBeFalsy();
+ });
+ });
+})();
diff --git a/src/app/FakeLib/FakeLib.fsproj b/src/app/FakeLib/FakeLib.fsproj
index 4b291618eb8..3964504c0fe 100644
--- a/src/app/FakeLib/FakeLib.fsproj
+++ b/src/app/FakeLib/FakeLib.fsproj
@@ -60,7 +60,6 @@
-
@@ -95,6 +94,7 @@
+
diff --git a/src/app/FakeLib/NpmHelper.fs b/src/app/FakeLib/NpmHelper.fs
index aeffdee8b5f..5af0b002a5f 100644
--- a/src/app/FakeLib/NpmHelper.fs
+++ b/src/app/FakeLib/NpmHelper.fs
@@ -36,12 +36,19 @@ type InstallArgs =
| Standard
| Forced
-/// The list of supported Npm commands. The `Custom` alternative
-/// can be used for other commands not in the list until they are
-/// implemented
+/// The list of supported Npm commands.
type NpmCommand =
+/// Run `npm install`
| Install of InstallArgs
+/// Run `npm run `
| Run of string
+/// Run `npm run --silent `. Suppresses npm error output. See [npm:8821](https://github.com/npm/npm/issues/8821).
+| RunSilent of string
+/// Run `npm run --silent `. Suppresses npm error output and will raise an FailedTestsException exception after the script execution instead of failing, useful for CI. See [npm:8821](https://github.com/npm/npm/issues/8821).
+| RunTest of string
+/// Run `npm test --silent`. Suppresses npm error output and will raise an FailedTestsException exception after the script execution instead of failing, useful for CI. See [npm:8821](https://github.com/npm/npm/issues/8821).
+| Test
+/// Run `npm `. Can be used for running not implemented commands.
| Custom of string
/// The Npm parameter type
@@ -66,19 +73,36 @@ let private parseInstallArgs = function
| Forced -> " --force"
let private parse = function
- | Install installArgs -> sprintf "install%s" (installArgs |> parseInstallArgs)
+ | Install installArgs -> sprintf "install %s" (installArgs |> parseInstallArgs)
| Run str -> sprintf "run %s" str
+ | RunSilent str -> sprintf "run --silent %s" str
+ | RunTest str -> sprintf "run --silent %s" str
| Custom str -> str
+ | Test -> "test --silent"
+/// Runs the given process and returns the process result.
let run npmParams =
+ let result = ref None
let npmPath = Path.GetFullPath(npmParams.NpmFilePath)
- let arguments = npmParams.Command |> parse
- let ok =
- execProcess (fun info ->
- info.FileName <- npmPath
- info.WorkingDirectory <- npmParams.WorkingDirectory
- info.Arguments <- arguments) npmParams.Timeout
- if not ok then failwith (sprintf "'npm %s' task failed" arguments)
+ let args = npmParams.Command |> parse
+ try
+ let exitCode =
+ ExecProcess (fun info ->
+ info.WorkingDirectory <- npmParams.WorkingDirectory
+ info.FileName <- npmPath
+ info.Arguments <- args) npmParams.Timeout
+ if exitCode <> 0 then result := Some(sprintf "exit code: %d" exitCode)
+ with exn ->
+ let message = ref exn.Message
+ if exn.InnerException <> null then message := !message + Environment.NewLine + exn.InnerException.Message
+ result := Some(!message)
+ match !result with
+ | None -> ()
+ | Some msg ->
+ match npmParams.Command with
+ | RunTest str -> raise (UnitTestCommon.FailedTestsException("Test(s) Failed"))
+ | Test -> raise (UnitTestCommon.FailedTestsException("Test(s) Failed"))
+ | _ -> failwith msg
/// Runs npm with the given modification function. Make sure to have npm installed,
/// you can install npm with nuget or a regular install. To change which `Npm` executable
@@ -103,5 +127,4 @@ let run npmParams =
/// WorkingDirectory = "./src/FAKESimple.Web/"
/// })
/// )
-let Npm setParams =
- defaultNpmParams |> setParams |> run
+let Npm setParams = defaultNpmParams |> setParams |> run