Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix(internals, migrate): split isCi into isInteractive (#15008)
Co-authored-by: Alberto Schiabel <jkomyno@users.noreply.github.com>
- Loading branch information
Showing
14 changed files
with
155 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,68 +1,51 @@ | ||
import { isCi } from '../isCi' | ||
|
||
// This allows us to override the return value of `is-ci`. The getter method | ||
// is required because the package exports a value, not a function, and we want | ||
// to be able to control it in tests. | ||
const mockValue = jest.fn().mockReturnValue(false) | ||
jest.mock('is-ci', () => ({ | ||
get isCi() { | ||
return mockValue() | ||
}, | ||
})) | ||
const originalEnv = { ...process.env } | ||
const originalStdinisTTY = process.stdin.isTTY | ||
|
||
const temporarilySet = (object: any, prop: string, value: unknown) => { | ||
const original = object[prop] | ||
describe('isCi', () => { | ||
beforeEach(() => { | ||
setValueOnProcess(object, prop, value) | ||
process.env = originalEnv | ||
process.stdin.isTTY = originalStdinisTTY | ||
}) | ||
afterEach(() => { | ||
setValueOnProcess(object, prop, original) | ||
afterAll(() => { | ||
process.env = originalEnv | ||
process.stdin.isTTY = originalStdinisTTY | ||
}) | ||
} | ||
|
||
// If you set undefined in process.env it stringifies it, so we | ||
// need special handling for that case of "unsetting" the process.env. | ||
const setValueOnProcess = (object: any, prop: string, value: unknown) => { | ||
if (object === process.env && value === undefined) { | ||
delete object[prop] | ||
} else { | ||
object[prop] = value | ||
} | ||
} | ||
|
||
describe('isCi', () => { | ||
describe('when outside a TTY environment', () => { | ||
temporarilySet(process.stdin, 'isTTY', false) | ||
describe('in non TTY environment', () => { | ||
beforeEach(() => { | ||
delete process.env.BUILDKITE | ||
delete process.env.GITHUB_ACTIONS | ||
delete process.env.CI | ||
process.stdin.isTTY = false | ||
}) | ||
|
||
test('returns false', () => { | ||
expect(isCi()).toBe(true) | ||
test('with undefined env vars, isCi should be false', () => { | ||
expect(isCi()).toBe(false) | ||
}) | ||
}) | ||
|
||
describe('when in TTY environment', () => { | ||
temporarilySet(process.stdin, 'isTTY', true) | ||
describe('in TTY environment', () => { | ||
beforeEach(() => { | ||
delete process.env.BUILDKITE | ||
delete process.env.GITHUB_ACTIONS | ||
delete process.env.CI | ||
process.stdin.isTTY = true | ||
}) | ||
|
||
test('when isCiLib tells us so', () => { | ||
mockValue.mockReturnValueOnce(true) | ||
test('with CI env var, isCi should be true', () => { | ||
process.env.CI = 'true' | ||
expect(isCi()).toBe(true) | ||
}) | ||
|
||
describe('with GitHub Actions env var', () => { | ||
temporarilySet(process.env, 'GITHUB_ACTIONS', 'true') | ||
|
||
test('returns true', () => { | ||
expect(isCi()).toBe(true) | ||
}) | ||
test('with GitHub Actions env var, isCi should be true', () => { | ||
process.env.GITHUB_ACTIONS = 'true' | ||
expect(isCi()).toBe(true) | ||
}) | ||
|
||
describe('outside a CI environment, with TTY', () => { | ||
temporarilySet(process.stdin, 'isTTY', true) | ||
temporarilySet(process.env, 'GITHUB_ACTIONS', undefined) | ||
|
||
test('returns false', () => { | ||
mockValue.mockReturnValueOnce(false) | ||
expect(isCi()).toBe(false) | ||
}) | ||
test('with undefined env vars, isCi should be false', () => { | ||
expect(isCi()).toBe(false) | ||
}) | ||
}) | ||
}) |
36 changes: 36 additions & 0 deletions
36
packages/internals/src/utils/__tests__/isInteractive.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { isInteractive } from '../isInteractive' | ||
|
||
const originalEnv = { ...process.env } | ||
|
||
describe('isInteractive', () => { | ||
beforeEach(() => { | ||
process.env = { ...originalEnv } | ||
}) | ||
afterAll(() => { | ||
process.env = { ...originalEnv } | ||
}) | ||
|
||
describe('in non TTY environment', () => { | ||
const mockedValue = { isTTY: false } as NodeJS.ReadStream | ||
test('isInteractive should be false', () => { | ||
expect(isInteractive({ stream: mockedValue })).toBe(false) | ||
}) | ||
|
||
test('isInteractive should be false if TERM = dumb', () => { | ||
process.env.TERM = 'dumb' | ||
expect(isInteractive({ stream: mockedValue })).toBe(false) | ||
}) | ||
}) | ||
|
||
describe('in TTY environment', () => { | ||
const mockedValue = { isTTY: true } as NodeJS.ReadStream | ||
test('isInteractive should be true', () => { | ||
expect(isInteractive({ stream: mockedValue })).toBe(true) | ||
}) | ||
|
||
test('isInteractive should be false if TERM = dumb', () => { | ||
process.env.TERM = 'dumb' | ||
expect(isInteractive({ stream: mockedValue })).toBe(false) | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import prompt from 'prompts' | ||
import { isCi } from './isCi' | ||
import { isInteractive } from './isInteractive' | ||
|
||
// If not TTY or in CI we want to throw an error and not prompt. | ||
// Because: | ||
// Prompting when non interactive is not possible. | ||
// Prompting in CI would hang forever / until a timeout occurs. | ||
export const canPrompt = (): boolean => { | ||
// Note: We use prompts.inject() for testing prompts in our CI | ||
return Boolean((prompt as any)._injected?.length) === true || (isInteractive() && !isCi()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,52 @@ | ||
import { isCi as isCiLib } from 'is-ci' | ||
|
||
// Returns true if the current environment is a CI environment. | ||
export const isCi = (): boolean => { | ||
return !process.stdin.isTTY || isCiLib || Boolean(process.env.GITHUB_ACTIONS) | ||
const env = process.env | ||
|
||
// From https://github.com/watson/ci-info/blob/44e98cebcdf4403f162195fbcf90b1f69fc6e047/index.js#L54-L61 | ||
// Evaluating at runtime makes it possible to change the values in our tests | ||
// This list is probably not exhaustive though `process.env.CI` should be enough | ||
// but since we were using this utility in the past, we want to keep the same behavior | ||
return !!( | ||
env.CI || // Travis CI, CircleCI, Cirrus CI, Gitlab CI, Appveyor, CodeShip, dsari | ||
env.CONTINUOUS_INTEGRATION || // Travis CI, Cirrus CI | ||
env.BUILD_NUMBER || // Jenkins, TeamCity | ||
env.RUN_ID || // TaskCluster, dsari | ||
// From `env` from https://github.com/watson/ci-info/blob/44e98cebcdf4403f162195fbcf90b1f69fc6e047/vendors.json | ||
env.APPVEYOR || | ||
env.SYSTEM_TEAMFOUNDATIONCOLLECTIONURI || | ||
env.AC_APPCIRCLE || | ||
env.bamboo_planKey || | ||
env.BITBUCKET_COMMIT || | ||
env.BITRISE_IO || | ||
env.BUILDKITE || | ||
env.CIRCLECI || | ||
env.CIRRUS_CI || | ||
env.CODEBUILD_BUILD_ARN || | ||
env.CF_BUILD_ID || | ||
env.CI_NAME || | ||
env.DRONE || | ||
env.DSARI || | ||
env.EAS_BUILD || | ||
env.GITHUB_ACTIONS || | ||
env.GITLAB_CI || | ||
env.GOCD || | ||
env.LAYERCI || | ||
env.HUDSON || | ||
env.JENKINS || | ||
env.MAGNUM || | ||
env.NETLIFY || | ||
env.NEVERCODE || | ||
env.RENDER || | ||
env.SAILCI || | ||
env.SEMAPHORE || | ||
env.SCREWDRIVER || | ||
env.SHIPPABLE || | ||
env.TDDIUM || | ||
env.STRIDER || | ||
env.TEAMCITY_VERSION || | ||
env.TRAVIS || | ||
env.NOW_BUILDER || | ||
env.APPCENTER_BUILD_ID || | ||
false | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
// Same logic as https://github.com/sindresorhus/is-interactive/blob/dc8037ae1a61d828cfb42761c345404055b1e036/index.js | ||
// But defaults to check `stdin` for our prompts | ||
// It checks that the stream is TTY, not a dumb terminal | ||
export const isInteractive = ({ stream = process.stdin } = {}): boolean => { | ||
return Boolean(stream && stream.isTTY && process.env.TERM !== 'dumb') | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.