Skip to content

Commit

Permalink
feat(globals; utils): globals manages environment variables; places v…
Browse files Browse the repository at this point in the history
…ersion range validation in utils
  • Loading branch information
rafamel committed May 6, 2019
1 parent f2674d9 commit ba9d3d2
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 54 deletions.
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ export const CONCURRENTLY_PATH = require.resolve(
'concurrently/bin/concurrently'
);
/* Shared between instances: changes might imply a major version release */
export const LOG_ENV_KEY = 'kpo_log';
export const GLOBALS_KEY = 'kpo_globals';
export type TEnvironmental = 'kpo_log';
export type TGlobal = 'version' | 'core' | 'options' | 'processses';
2 changes: 1 addition & 1 deletion src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { rejects } from 'errorish';
import { absolute } from '~/utils/file';
import wrapCore from './wrap';
import guardian from '~/utils/guardian';
import globals from '~/globals';
import { globals } from '~/globals';

export interface ICoreState {
scopes: string[];
Expand Down
8 changes: 4 additions & 4 deletions src/core/options.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ICliOptions, IScopeOptions, TCoreOptions, IOfType } from '~/types';
import { DEFAULT_LOG_LEVEL, LOG_ENV_KEY } from '~/constants';
import { DEFAULT_LOG_LEVEL } from '~/constants';
import { setLevel } from '~/utils/logger';
import globals from '~/globals';
import { globals, environmentals } from '~/globals';
import cache from '~/utils/cache';

/* Shared between instances: changes might imply a major version release */
Expand All @@ -12,7 +12,7 @@ export const state = globals('options', {
directory: null,
env: {},
silent: false,
log: process.env[LOG_ENV_KEY] || DEFAULT_LOG_LEVEL
log: environmentals('kpo_log').get() || DEFAULT_LOG_LEVEL
} as TCoreOptions,
cli: {} as ICliOptions,
scope: {} as IScopeOptions
Expand Down Expand Up @@ -67,7 +67,7 @@ function merge(): void {
// Set logging level
if (options.log) {
setLevel(options.log);
process.env[LOG_ENV_KEY] = options.log;
environmentals('kpo_log').set(options.log);
}
}

Expand Down
63 changes: 63 additions & 0 deletions src/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/* eslint-disable @typescript-eslint/explicit-function-return-type */
import inVersionRange from '~/utils/version-range';
import read from 'read-pkg-up';
import cache from '~/utils/cache';
import errors from '~/utils/errors';
import { GLOBALS_KEY, TGlobal, TEnvironmental } from '~/constants';
import { IOfType } from '~/types';

const locals = {
globals: {} as { [key in TGlobal]: any },
environmentals: {} as IOfType<string>
};

export const pkg = cache(
null,
(): IOfType<any> => {
try {
return read.sync({ cwd: __dirname }).pkg;
} catch (e) {
throw new errors.CustomError(`Package couldn't be retrieved`, null, e);
}
}
);

/**
* Used for state preservation for different kpo instances (installations)
* on the same process. Will only pollute `global` if the process is kpo owned,
* that is, if `process.env[OWNED_ENV_KEY]` is set.
*/
export function globals<T>(key: TGlobal, initial: T) {
const vars = ((global as any)[GLOBALS_KEY] ||
((global as any)[GLOBALS_KEY] = {})) as { [key in TGlobal]: any };

if (!vars.version) vars.version = pkg().version;
else inVersionRange(pkg().version, vars.version);

return {
get(): T {
return vars[key] || (vars[key] = initial);
},
set(value: T): void {
vars[key] = value;
}
};
}

/**
* Used for state preservation for different kpo instances AND children
* processes. Will only pollute `process.env` if the process is kpo owned,
* that is, if `process.env[OWNED_ENV_KEY]` is set.
*/
export function environmentals(key: TEnvironmental) {
const vars = process.env;

return {
get(): string | void {
return vars[key] || undefined;
},
set(value?: string): void {
vars[key] = value || undefined;
}
};
}
4 changes: 0 additions & 4 deletions src/globals/globals.ts

This file was deleted.

17 changes: 0 additions & 17 deletions src/globals/index.ts

This file was deleted.

15 changes: 0 additions & 15 deletions src/globals/pkg.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/utils/ps-manager.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import globals from '~/globals';
import { globals } from '~/globals';
import { IOfType } from '~/types';
import logger from './logger';

Expand Down
18 changes: 7 additions & 11 deletions src/globals/version-range.ts → src/utils/version-range.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { clean, diff } from 'semver';
import pkg from './pkg';
import globals from './globals';

export default function inVersionRange(): void {
if (!globals.version) {
globals.version = clean(pkg().version);
return;
}

const executable = globals.version && clean(globals.version);
const local = pkg().version && clean(pkg().version);
export default function inVersionRange(
local?: string | null,
executable?: string | null
): void {
local = local && clean(local);
executable = executable && clean(executable);

if (!executable || !local) throw Error(`Version could not be parsed`);
if (!local || !executable) throw Error(`Version could not be parsed`);

const release = diff(executable, local);

Expand Down
61 changes: 61 additions & 0 deletions test/utils/version-range.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import inVersionRange from '~/utils/version-range';

describe(`all`, () => {
test(`fails for undefined`, () => {
expect(() => inVersionRange('1.0.1')).toThrowErrorMatchingInlineSnapshot(
`"Version could not be parsed"`
);
expect(() => inVersionRange(undefined, '1.0.1')).toThrowError();
expect(() => inVersionRange()).toThrowError();
});
});
describe(`stable`, () => {
test(`succeeds for equal`, () => {
expect(() => inVersionRange('1.0.1', '1.0.1')).not.toThrow();
});
test(`succeeds for patch`, () => {
expect(() => inVersionRange('1.0.1', '1.0.2')).not.toThrow();
});
test(`succeeds for minor`, () => {
expect(() => inVersionRange('1.1.1', '1.2.1')).not.toThrow();
expect(() => inVersionRange('1.2.9', '1.1.1')).not.toThrow();
});
test(`fails for major`, () => {
expect(() =>
inVersionRange('1.1.1', '2.1.1')
).toThrowErrorMatchingInlineSnapshot(
`"Local kpo version (1.1.1) doesn't match executing version (2.1.1)"`
);
});
});
describe(`unstable`, () => {
test(`succeedsfor equal`, () => {
expect(() => inVersionRange('0.1.1', '0.1.1')).not.toThrow();
});
test(`fails for patch`, () => {
expect(() =>
inVersionRange('0.1.1', '0.1.2')
).toThrowErrorMatchingInlineSnapshot(
`"Local kpo version (0.1.1) doesn't match executing version (0.1.2)"`
);
});
test(`fails for minor`, () => {
expect(() =>
inVersionRange('0.1.1', '0.2.1')
).toThrowErrorMatchingInlineSnapshot(
`"Local kpo version (0.1.1) doesn't match executing version (0.2.1)"`
);
expect(() =>
inVersionRange('0.2.9', '0.1.1')
).toThrowErrorMatchingInlineSnapshot(
`"Local kpo version (0.2.9) doesn't match executing version (0.1.1)"`
);
});
test(`fails for major`, () => {
expect(() =>
inVersionRange('0.1.1', '1.1.1')
).toThrowErrorMatchingInlineSnapshot(
`"Local kpo version (0.1.1) doesn't match executing version (1.1.1)"`
);
});
});

0 comments on commit ba9d3d2

Please sign in to comment.