-
Notifications
You must be signed in to change notification settings - Fork 3.4k
feat: exit with code 112 when api errors prevent cloud orchestrated runs (record mode, parallel run mode) #32635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
5ac2316
17c1002
79be6fe
d401df8
d61e91d
9affeaa
3e891c9
2d5528b
25724e9
c321884
12a8a1e
e903179
b405587
afed8c5
eb8b28b
ba640a1
edcf651
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[31mWe encountered an unexpected error communicating with our servers.[39m | ||
[31m[39m | ||
[31m[95mError: fail whale[39m[31m[39m | ||
[31m[39m | ||
[31mBecause you passed the [95m--parallel[39m[31m flag, this run cannot proceed since it requires a valid response from our servers.[39m | ||
[31m[39m | ||
[31mThe --group flag you passed was: [33mfoo[39m[31m[39m | ||
[31mThe --ciBuildId flag you passed was: [33minvalid[39m[31m[39m |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[31mWe encountered an unexpected error communicating with our servers.[39m | ||
[31m[39m | ||
[31m[95mError: fail whale[39m[31m[39m | ||
[31m[39m | ||
[31mBecause you passed the [95m--record[39m[31m flag, this run cannot proceed since it requires a valid response from our servers.[39m | ||
[31m[39m | ||
[31mThe --group flag you passed was: [33mfoo[39m[31m[39m | ||
[31mThe --ciBuildId flag you passed was: [33minvalid[39m[31m[39m |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,7 +16,8 @@ import argsUtils from './util/args' | |
import { telemetry } from '@packages/telemetry' | ||
import { getCtx, hasCtx } from '@packages/data-context' | ||
import { warning as errorsWarning } from './errors' | ||
|
||
import type { CypressError } from '@packages/errors' | ||
import { toNumber } from 'lodash' | ||
const debug = Debug('cypress:server:cypress') | ||
|
||
type Mode = 'exit' | 'info' | 'interactive' | 'pkg' | 'record' | 'results' | 'run' | 'smokeTest' | 'version' | 'returnPkg' | 'exitWithCode' | ||
|
@@ -42,6 +43,8 @@ const exit = async (code = 0) => { | |
debug('telemetry shutdown errored with: ', err) | ||
}) | ||
|
||
debug('process.exit', code) | ||
|
||
return process.exit(code) | ||
} | ||
|
||
|
@@ -66,18 +69,31 @@ const exit0 = () => { | |
return exit(0) | ||
} | ||
|
||
const exitErr = (err: any) => { | ||
function isCypressError (err: unknown): err is CypressError { | ||
return (err as CypressError).isCypressErr | ||
} | ||
|
||
async function exitErr (err: unknown, posixExitCodes?: boolean) { | ||
// log errors to the console | ||
// and potentially raygun | ||
// and exit with 1 | ||
debug('exiting with err', err) | ||
|
||
return require('./errors').logException(err) | ||
.then(() => { | ||
debug('calling exit 1') | ||
await require('./errors').logException(err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. any reason we can just import errors at the top of the file since we are starting to move away from CJS? |
||
|
||
return exit(1) | ||
}) | ||
if (isCypressError(err)) { | ||
if ( | ||
posixExitCodes && ( | ||
err.type === 'CLOUD_CANNOT_PROCEED_IN_PARALLEL_NETWORK' || | ||
err.type === 'CLOUD_CANNOT_PROCEED_IN_SERIAL_NETWORK' | ||
)) { | ||
return exit(112) | ||
} | ||
} | ||
|
||
debug('calling exit 1') | ||
|
||
return exit(1) | ||
} | ||
|
||
export = { | ||
|
@@ -151,7 +167,7 @@ export = { | |
debug('could not parse CLI arguments: %o', argv) | ||
|
||
// note - this is promise-returned call | ||
return exitErr(argumentsError) | ||
return exitErr(argumentsError, Boolean(options?.posixExitCodes)) | ||
} | ||
|
||
debug('from argv %o got options %o', argv, options) | ||
|
@@ -206,80 +222,79 @@ export = { | |
}) | ||
}, | ||
|
||
startInMode (mode: Mode, options: any) { | ||
async startInMode (mode: Mode, options: any) { | ||
debug('starting in mode %s with options %o', mode, options) | ||
|
||
switch (mode) { | ||
case 'version': | ||
return require('./modes/pkg')(options) | ||
.get('version') | ||
.then((version: any) => { | ||
return console.log(version) // eslint-disable-line no-console | ||
}).then(exit0) | ||
.catch(exitErr) | ||
|
||
case 'info': | ||
return require('./modes/info')(options) | ||
.then(exit0) | ||
.catch(exitErr) | ||
|
||
case 'smokeTest': | ||
return this.runElectron(mode, options) | ||
.then((pong: any) => { | ||
if (mode === 'interactive') { | ||
return this.runElectron(mode, options) | ||
} | ||
|
||
try { | ||
switch (mode) { | ||
case 'version': { | ||
const version = await require('./modes/pkg')(options).get('version') | ||
|
||
// eslint-disable-next-line no-console | ||
console.log(version) | ||
break | ||
} | ||
case 'info': { | ||
await require('./modes/info')(options) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we just hoist this import or await import it? If not I'll likely get to this in the launcher refactor |
||
break | ||
} | ||
case 'smokeTest': { | ||
const pong = await this.runElectron(mode, options) | ||
|
||
if (!this.isCurrentlyRunningElectron()) { | ||
return pong | ||
return exit(pong) | ||
} else if (pong !== options.ping) { | ||
return exit(1) | ||
} | ||
|
||
if (pong === options.ping) { | ||
return 0 | ||
} | ||
break | ||
} | ||
case 'returnPkg': { | ||
const pkg = await require('./modes/pkg')(options) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we just |
||
|
||
// eslint-disable-next-line no-console | ||
console.log(JSON.stringify(pkg)) | ||
break | ||
} | ||
case 'exitWithCode': { | ||
return exit(toNumber(options.exitWithCode)) | ||
break | ||
} | ||
case 'run': { | ||
const results = await this.runElectron(mode, options) | ||
|
||
return 1 | ||
}).then(exit) | ||
.catch(exitErr) | ||
|
||
case 'returnPkg': | ||
return require('./modes/pkg')(options) | ||
.then((pkg: any) => { | ||
return console.log(JSON.stringify(pkg)) // eslint-disable-line no-console | ||
}).then(exit0) | ||
.catch(exitErr) | ||
|
||
case 'exitWithCode': | ||
return require('./modes/exit')(options) | ||
.then(exit) | ||
.catch(exitErr) | ||
|
||
case 'run': | ||
// run headlessly and exit | ||
// with num of totalFailed | ||
return this.runElectron(mode, options) | ||
.then((results: any) => { | ||
if (results.runs) { | ||
const isCanceled = results.runs.filter((run) => run.skippedSpec).length | ||
|
||
if (isCanceled) { | ||
// eslint-disable-next-line no-console | ||
console.log(require('chalk').magenta('\n Exiting with non-zero exit code because the run was canceled.')) | ||
|
||
return 1 | ||
return exit(1) | ||
} | ||
} | ||
|
||
debug('results.totalFailed, posix?', results.totalFailed, options.posixExitCodes) | ||
|
||
if (options.posixExitCodes) { | ||
return results.totalFailed ? 1 : 0 | ||
return exit(results.totalFailed ? 1 : 0) | ||
} | ||
|
||
return results.totalFailed | ||
}) | ||
.then(exit) | ||
.catch(exitErr) | ||
|
||
case 'interactive': | ||
return this.runElectron(mode, options) | ||
|
||
default: | ||
throw new Error(`Cannot start. Invalid mode: '${mode}'`) | ||
return exit(results.totalFailed ?? 0) | ||
} | ||
default: { | ||
throw new Error(`Cannot start. Invalid mode: '${mode}'`) | ||
} | ||
} | ||
} catch (err) { | ||
return exitErr(err, options.posixExitCodes) | ||
} | ||
debug('end of startInMode, exit 0') | ||
|
||
return exit(0) | ||
}, | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is so much easier to diff now