Skip to content
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

Feat/973 provide configuration via env vars #988

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7cb0b63
fear(util): add extractFromEnv
pafik13 Dec 14, 2024
c22cd7b
chore(config): increase size limits
pafik13 Dec 14, 2024
3589408
test(core): clean up env var some tests
pafik13 Dec 14, 2024
3dbeb88
test(util): cover extractFromEnv
pafik13 Dec 14, 2024
ffae30f
Merge branch 'main' into feat/973-provide-configuration-via-env-vars
antongolub Dec 15, 2024
d4ea3b2
Merge branch 'main' into feat/973-provide-configuration-via-env-vars
antongolub Dec 15, 2024
808e065
feat(util): remove extractFromEnv and snakeToCamel, add camelToSnake
pafik13 Dec 16, 2024
2f5d75e
feat(core): implement getZxDefaults
pafik13 Dec 16, 2024
d53cc00
test: add tests for getZxDefaults and camelToSnake
pafik13 Dec 16, 2024
b156882
Merge branch 'feat/973-provide-configuration-via-env-vars' of github.…
pafik13 Dec 16, 2024
46c201e
Merge branch 'main' into feat/973-provide-configuration-via-env-vars
pafik13 Dec 16, 2024
c8c0597
chore: up size limit
pafik13 Dec 16, 2024
3e8a4d4
feat(util): add snakeToCamel
pafik13 Dec 16, 2024
6baa606
refactor(core): remove extra param from getZxDefaults
pafik13 Dec 16, 2024
8fb923a
test(util): cover snakeToCamel
pafik13 Dec 16, 2024
655b771
test(core): actualize getZxDefaults
pafik13 Dec 16, 2024
0b86a0b
feat(core): extend types in getZxDefaults and use it as allowed list
pafik13 Dec 16, 2024
15e2770
test(core): update suites
pafik13 Dec 16, 2024
a4bd346
chore(core): swap getZxDefaults definition and usage for better git b…
pafik13 Dec 16, 2024
fdfb0b6
chore(core): remove one tab for defaults
pafik13 Dec 16, 2024
a6ab3b4
Merge branch 'main' into feat/973-provide-configuration-via-env-vars
antongolub Dec 17, 2024
c05c487
chore: update .size-limit.json
antongolub Dec 17, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .size-limit.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@
{
"name": "zx/core",
"path": ["build/core.cjs", "build/util.cjs", "build/vendor-core.cjs"],
"limit": "73 kB",
"limit": "74 kB",
"brotli": false,
"gzip": false
},
{
"name": "zx/index",
"path": "build/*.{js,cjs}",
"limit": "800 kB",
"limit": "801 kB",
"brotli": false,
"gzip": false
},
Expand Down
79 changes: 57 additions & 22 deletions src/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ import {
proxyOverride,
quote,
quotePowerShell,
camelToSnake,
} from './util.js'

const CWD = Symbol('processCwd')
Expand Down Expand Up @@ -81,7 +82,7 @@ export interface Options {
verbose: boolean
sync: boolean
env: NodeJS.ProcessEnv
shell: string | boolean
shell: string | true
nothrow: boolean
prefix: string
postfix: string
Expand All @@ -97,29 +98,63 @@ export interface Options {
killSignal?: NodeJS.Signals
halt?: boolean
}
// prettier-ignore
export const defaults: Options = {
[CWD]: process.cwd(),
[SYNC]: false,
verbose: false,
env: process.env,
sync: false,
shell: true,
stdio: 'pipe',
nothrow: false,
quiet: false,
prefix: '',
postfix: '',
detached: false,
preferLocal: false,
spawn,
spawnSync,
log,
kill,
killSignal: SIGTERM,
timeoutSignal: SIGTERM,

export function getZxDefaults(
defs: Options,
extra: Partial<Options> = {
cwd: '',
halt: false,
preferLocal: '',
input: '',
},
prefix: string = 'ZX_',
env = process.env
) {
const process = (opts: Partial<Options>) => {
const o: Record<string, string | boolean> = {}
for (const [dk, dv] of Object.entries(opts)) {
const ek = prefix + camelToSnake(dk)
const ev = env[ek]
if (typeof ev !== 'undefined') {
const v = { true: true, false: false }[ev.toLowerCase()] ?? ev
if (typeof v === typeof dv) {
o[dk] = v
}
}
}
return o
}
const subset1 = process(defs)
const subset2 = process(extra)

return Object.assign(defs, subset1, subset2)
}

// prettier-ignore
export const defaults: Options = getZxDefaults(
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep the original formatting here for git blame

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// prettier-ignore
export const defaults: Options = getZxDefaults({
  // ... to keep git blame
})

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I restored formatting, but it didn't help (:

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prettier-ignore should go above the export const defaults declaration

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was there and extended only to the closest expression - the function call...
JSON declaration was out of scope)
Now, JSON isn't formatted

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was hard, but I did it.
Thank you)

[CWD]: process.cwd(),
[SYNC]: false,
verbose: false,
env: process.env,
sync: false,
shell: true,
stdio: 'pipe',
nothrow: false,
quiet: false,
prefix: '',
postfix: '',
detached: false,
preferLocal: false,
spawn,
spawnSync,
log,
kill,
killSignal: SIGTERM,
timeoutSignal: SIGTERM,
},
)

// prettier-ignore
export interface Shell<
S = false,
Expand Down
7 changes: 7 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -462,3 +462,10 @@ export const proxyOverride = <T extends object>(
)
},
}) as T

// https://stackoverflow.com/questions/7888238/javascript-split-string-on-uppercase-characters
export const camelToSnake = (str: string) =>
str
.split(/(?=[A-Z])/)
.map((s) => s.toUpperCase())
.join('_')
40 changes: 39 additions & 1 deletion test/core.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,46 @@ import { basename } from 'node:path'
import { WriteStream } from 'node:fs'
import { Readable, Transform, Writable } from 'node:stream'
import { Socket } from 'node:net'
import { ProcessPromise, ProcessOutput } from '../build/index.js'
import { ProcessPromise, ProcessOutput, getZxDefaults } from '../build/index.js'
import '../build/globals.js'

describe('core', () => {
describe('getZxDefaults', () => {
test('verbose rewrite', async () => {
const defaults = getZxDefaults({ verbose: false }, {}, 'ZX_', {
ZX_VERBOSE: 'true',
})
assert.equal(defaults.verbose, true)
})
test('verbose ignore', async () => {
const defaults = getZxDefaults({ verbose: false }, {}, 'ZX_', {
ZX_VERBOSE: 'true123',
})
assert.equal(defaults.verbose, false)
})
test('input in extra', async () => {
const defaults = getZxDefaults({}, { input: '' }, 'ZX_', {
ZX_INPUT: 'input',
})
assert.equal(defaults.input, 'input')
})
test('preferLocal rewrite boolean', async () => {
const defaults = getZxDefaults({ preferLocal: false }, {}, 'ZX_', {
ZX_PREFER_LOCAL: 'true',
})
assert.equal(defaults.preferLocal, true)
})
test('preferLocal rewrite string', async () => {
const defaults = getZxDefaults(
{ preferLocal: false },
{ preferLocal: '' },
'ZX_',
{ ZX_PREFER_LOCAL: 'true123' }
)
assert.equal(defaults.preferLocal, 'true123')
})
})

describe('$', () => {
test('is a regular function', async () => {
const _$ = $.bind(null)
Expand All @@ -42,12 +78,14 @@ describe('core', () => {
process.env.ZX_TEST_FOO = 'foo'
const foo = await $`echo $ZX_TEST_FOO`
assert.equal(foo.stdout, 'foo\n')
delete process.env.ZX_TEST_FOO
})

test('env vars are safe to pass', async () => {
process.env.ZX_TEST_BAR = 'hi; exit 1'
const bar = await $`echo $ZX_TEST_BAR`
assert.equal(bar.stdout, 'hi; exit 1\n')
delete process.env.ZX_TEST_BAR
})

test('arguments are quoted', async () => {
Expand Down
7 changes: 7 additions & 0 deletions test/util.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
tempdir,
tempfile,
preferLocalBin,
camelToSnake,
} from '../build/util.js'

describe('util', () => {
Expand Down Expand Up @@ -191,3 +192,9 @@ test('preferLocalBin()', () => {
`${process.cwd()}/node_modules/.bin:${process.cwd()}:${env.PATH}`
)
})
test('camelToSnake()', () => {
assert.equal(camelToSnake('verbose'), 'VERBOSE')
assert.equal(camelToSnake('nothrow'), 'NOTHROW')
assert.equal(camelToSnake('preferLocal'), 'PREFER_LOCAL')
assert.equal(camelToSnake('someMoreBigStr'), 'SOME_MORE_BIG_STR')
})