Repository: bokeh/bokeh

Issue:
[BUG] BokehJS build does not abort on compilation error
If I introduce an intentional typo into a source file and attempt to build, the error is printed, but the build continues after and returns a 0 (success) return code:
```
(dev) ❯ node make
[15:02:32] Starting 'styles:compile'...
[15:02:33] Finished 'styles:compile' after 348 ms
[15:02:33] Starting 'scripts:compile'...
[15:02:40] There were 7 TypeScript errors:
src/lib/index.ts:4:1 - error TS2304: Cannot find name 'expojrt'.

4 expojrt * as protocol           from "./protocol"
  ~~~~~~~
src/lib/index.ts:4:11 - error TS2304: Cannot find name 'as'.

4 expojrt * as protocol           from "./protocol"
            ~~
src/lib/index.ts:4:14 - error TS1005: ';' expected.

4 expojrt * as protocol           from "./protocol"
               ~~~~~~~~
src/lib/index.ts:4:14 - error TS2304: Cannot find name 'protocol'.

4 expojrt * as protocol           from "./protocol"
               ~~~~~~~~
src/lib/index.ts:4:33 - error TS1005: ';' expected.

4 expojrt * as protocol           from "./protocol"
                                  ~~~~
src/lib/index.ts:4:33 - error TS2304: Cannot find name 'from'.

4 expojrt * as protocol           from "./protocol"
                                  ~~~~
src/lib/index.ts:4:38 - error TS1005: ';' expected.

4 expojrt * as protocol           from "./protocol"
                                       ~~~~~~~~~~~~

[15:02:40] Finished 'scripts:compile' after 7.56 s
[15:02:40] Starting 'scripts:bundle'...
[15:02:43] Finished 'scripts:bundle' after 2.14 s
[15:02:43] Starting 'scripts:bundle-legacy'...
[15:02:45] Finished 'scripts:bundle-legacy' after 1.98 s
[15:02:45] Finished 'scripts:build'
[15:02:45] Finished 'scripts'
[15:02:45] Finished 'styles:build'
[15:02:45] Finished 'styles'
[15:02:45] Starting 'compiler:ts'...
[15:02:46] Finished 'compiler:ts' after 1.05 s
[15:02:46] Starting 'compiler:build'...
[15:02:48] Finished 'compiler:build' after 2.76 s
[15:02:48] Finished 'build'
[15:02:48] Starting 'install'...
[15:02:50] setup.py: DONE!
[15:02:50] Finished 'install' after 1.18 s
[15:02:50] Finished 'default'

~/work/bokeh/bokehjs bryanv/release_automation* 23s
(dev) ❯ echo $?
0
```
Same result for `node make build`. This is  an issue for  automation scripts, since build failures need to be reliably detectable. 

cc @mattpap 


Discussion:
OK I guess there is `--emit-error` but why is this not the default?
`--emit-error` was a primitive hack to get build fail in CI and is scheduled to be removed. The build should work without it and fail when needed. Note that the goal is not just fail when a single task fails, but to perform as much meaningful operations as possible before failing. The problem is that some tasks, like `scripts:compile` don't participate in this process correctly.

Resolving patch:
diff --git a/_setup_support.py b/_setup_support.py
--- a/_setup_support.py
+++ b/_setup_support.py
@@ -235,7 +235,7 @@ def build_js():
     sys.stdout.flush()
     os.chdir('bokehjs')
 
-    cmd = ["node", "make", 'build', '--emit-error']
+    cmd = ["node", "make", "build"]
 
     t0 = time.time()
     try:


Test patch:
diff --git a/bokehjs/make/tasks/test.ts b/bokehjs/make/tasks/test.ts
--- a/bokehjs/make/tasks/test.ts
+++ b/bokehjs/make/tasks/test.ts
@@ -7,7 +7,7 @@ import assert from "assert"
 
 import which from "which"
 
-import {task, task2, log, success, BuildError} from "../task"
+import {task, task2, success, BuildError} from "../task"
 import {Linker} from "@compiler/linker"
 import {default_prelude} from "@compiler/prelude"
 import {compile_typescript} from "@compiler/compiler"
@@ -41,7 +41,7 @@ async function is_available(port: number): Promise<boolean> {
       if (!failure)
         resolve(available)
       else
-        reject(new Error("timeout when searching for unused port"))
+        reject(new BuildError("net", "timeout when searching for unused port"))
     })
 
     socket.connect(port, host)
@@ -100,10 +100,7 @@ function mocha(files: string[]): Promise<void> {
 }
 
 task("test:codebase:compile", async () => {
-  const success = compile_typescript("./test/codebase/tsconfig.json", {log})
-
-  if (argv.emitError && !success)
-    process.exit(1)
+  compile_typescript("./test/codebase/tsconfig.json")
 })
 
 task("test:size", ["test:codebase:compile"], async () => {
@@ -297,10 +294,7 @@ const start = task2("test:start", [start_headless, start_server], async (devtool
 })
 
 function compile(name: string) {
-  const success = compile_typescript(`./test/${name}/tsconfig.json`, {log})
-
-  if (argv.emitError && !success)
-    process.exit(1)
+  compile_typescript(`./test/${name}/tsconfig.json`)
 }
 
 function bundle(name: string): void {