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

refactor #341

Merged
merged 1 commit into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 packages/cli/src/commands/up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {

this.logger.debug('expectedServiceUrls: %j', expectedServiceUrls)

const injectLivecycleScript = flags['enable-widget']
const injectWidgetScript = flags['enable-widget']
? editUrl(flags['livecycle-widget-url'], { queryParams: { profile: thumbprint, env: envId } }).toString()
: undefined

Expand All @@ -135,7 +135,7 @@ export default class Up extends MachineCreationDriverCommand<typeof Up> {
userSpecifiedProjectName: flags.project,
composeFiles: this.config.composeFiles,
envId,
injectLivecycleScript,
scriptInjections: injectWidgetScript ? { 'livecycle-widget': { src: injectWidgetScript } } : undefined,
tunnelOpts,
log: this.logger,
dataDir: this.config.dataDir,
Expand Down
10 changes: 8 additions & 2 deletions packages/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ export { Logger } from './src/log'
export { requiredEnv, numberFromEnv } from './src/env'
export { tunnelNameResolver, TunnelNameResolver } from './src/tunnel-name'
export { editUrl } from './src/url'
export * from './src/compose-tunnel-agent'
export * from './src/compose-utils'
export {
ScriptInjection,
parseScriptInjectionLabels,
scriptInjectionsToLabels,
COMPOSE_TUNNEL_AGENT_PORT,
COMPOSE_TUNNEL_AGENT_SERVICE_LABELS,
COMPOSE_TUNNEL_AGENT_SERVICE_NAME,
} from './src/compose-tunnel-agent'
export { MachineStatusCommand, DockerMachineStatusCommandRecipe } from './src/machine-status-command'
export { ProcessOutputBuffers, orderedOutput, OrderedOutput } from './src/process-output-buffers'
3 changes: 1 addition & 2 deletions packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,9 @@
},
"scripts": {
"test": "yarn jest",
"start": "node dist/main.js",
"dev": "tsx watch ./main.ts",
"lint": "eslint . --ext .ts,.tsx --cache",
"build": "tsc -b",
"clean": "shx rm -rf dist tsconfig.tsbuildinfo",
"prepack": "yarn build",
"bump-to": "yarn version --no-commit-hooks --no-git-tag-version --new-version"
}
Expand Down
74 changes: 0 additions & 74 deletions packages/common/src/compose-tunnel-agent.test.ts

This file was deleted.

51 changes: 0 additions & 51 deletions packages/common/src/compose-tunnel-agent.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/common/src/compose-tunnel-agent/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export { COMPOSE_TUNNEL_AGENT_SERVICE_LABELS } from './labels'
export { ScriptInjection, parseScriptInjectionLabels, scriptInjectionsToLabels } from './script-injection'

export const COMPOSE_TUNNEL_AGENT_SERVICE_NAME = 'preevy_proxy'
export const COMPOSE_TUNNEL_AGENT_PORT = 3000
8 changes: 8 additions & 0 deletions packages/common/src/compose-tunnel-agent/labels.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const COMPOSE_TUNNEL_AGENT_SERVICE_LABELS = {
PROFILE_THUMBPRINT: 'preevy.profile_thumbprint',
PRIVATE_MODE: 'preevy.private_mode',
ENV_ID: 'preevy.env_id',
ACCESS: 'preevy.access',
EXPOSE: 'preevy.expose',
INJECT_SCRIPT_PREFIX: 'preevy.inject_script',
} as const
100 changes: 100 additions & 0 deletions packages/common/src/compose-tunnel-agent/script-injection.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { describe, test, expect, it } from '@jest/globals'
import { ScriptInjection, parseScriptInjectionLabels, scriptInjectionsToLabels } from './script-injection'

describe('script injection labels', () => {
describe('parseScriptInjectionLabels', () => {
test('should parse correctly a single label group', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.defer': 'true',
'preevy.inject_script.widget.async': 'false',
'preevy.inject_script.widget.path_regex': 't.*t',
}

const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(errors).toHaveLength(0)
expect(scripts).toHaveLength(1)
expect(scripts[0]).toMatchObject({
src: 'https://my-script',
defer: true,
async: false,
pathRegex: expect.any(RegExp),
})
expect(scripts[0].pathRegex?.source).toBe('t.*t')
})

test('should ignore scripts with invalid regex', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.path_regex': '[',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(scripts).toHaveLength(0)
expect(errors).toHaveLength(1)
})

test('should drop scripts without src', () => {
const labels = {
'preevy.inject_script.widget.defer': 'true',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(scripts).toHaveLength(0)
expect(errors).toHaveLength(1)
})

test('should support multiple scripts', () => {
const labels = {
'preevy.inject_script.widget.src': 'https://my-script',
'preevy.inject_script.widget.defer': '1',
'preevy.inject_script.widget2.src': 'https://my-script2',
'preevy.inject_script.widget2.defer': 'false',
'preevy.inject_script.widget3.src': 'https://my-script3',
'preevy.inject_script.widget3.defer': '0',
}
const [scripts, errors] = parseScriptInjectionLabels(labels)
expect(errors).toHaveLength(0)
expect(scripts).toHaveLength(3)
expect(scripts).toContainEqual(
{
src: 'https://my-script',
defer: true,
},
)
expect(scripts).toContainEqual(
{
src: 'https://my-script2',
defer: false,
},
)
expect(scripts).toContainEqual(
{
src: 'https://my-script3',
defer: false,
},
)
})
})

describe('scriptInjectionsToLabels', () => {
const injections: Record<string, ScriptInjection> = {
script1: {
src: 'https://my-script',
defer: true,
async: false,
pathRegex: /^aaa/,
},
script2: {
src: 'https://my-script2',
},
}

it('should convert to labels', () => {
expect(scriptInjectionsToLabels(injections)).toMatchObject({
'preevy.inject_script.script1.src': 'https://my-script',
'preevy.inject_script.script1.defer': 'true',
'preevy.inject_script.script1.path_regex': '^aaa',
'preevy.inject_script.script2.src': 'https://my-script2',
})
})
})
})
76 changes: 76 additions & 0 deletions packages/common/src/compose-tunnel-agent/script-injection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { groupBy, mapKeys, partition } from 'lodash'
import { inspect } from 'util'
import { COMPOSE_TUNNEL_AGENT_SERVICE_LABELS } from './labels'

export type ScriptInjection = {
pathRegex?: RegExp
src: string
defer?: boolean
async?: boolean
}

const parseBooleanLabelValue = (s:string) => s === 'true' || s === '1'

const parseScriptInjection = (o: Record<string, string>): ScriptInjection | Error => {
// eslint-disable-next-line camelcase
const { src, defer, async, path_regex } = o
try {
if (!src) {
throw new Error('missing src')
}
return {
// eslint-disable-next-line camelcase
...path_regex && { pathRegex: new RegExp(path_regex) },
...defer && { defer: parseBooleanLabelValue(defer) },
...async && { async: parseBooleanLabelValue(async) },
src,
}
} catch (e) {
return new Error(`error parsing script injection ${inspect(o)}: ${e}`, { cause: e })
}
}

const scriptInjectionToLabels = (
id: string,
{ src, async, defer, pathRegex }: ScriptInjection,
): Record<string, string> => mapKeys<Record<string, string>>({
src,
...async && { async: 'true' },
...defer && { defer: 'true' },
...pathRegex && { path_regex: pathRegex.source },
}, (_value, key) => [COMPOSE_TUNNEL_AGENT_SERVICE_LABELS.INJECT_SCRIPT_PREFIX, id, key].join('.'))

export const scriptInjectionsToLabels = (
injections: Record<string, ScriptInjection>
) => Object.fromEntries(
Object.entries(injections).flatMap(([id, injection]) => Object.entries(scriptInjectionToLabels(id, injection)))
)

const groupedLabelsRe = /^(?<prefix>[^\s]+)\.(?<id>[^.\s]+)\.(?<key>[^.\s]+)$/
type ParsedGroupedLabelKey = { prefix: string; id: string; key: string }
const parseGroupedLabelKey = (key: string) => {
const match = groupedLabelsRe.exec(key)
return match && match.groups as ParsedGroupedLabelKey
}

const parseLabelsWithPrefixAndId = (
labels: Record<string, string>,
prefix: string,
): Record<string, string>[] => {
const split: [ParsedGroupedLabelKey | null, string][] = Object.entries(labels)
.map(([k, v]) => [parseGroupedLabelKey(k), v])
const filteredForPrefix = split.filter(([k]) => k?.prefix === prefix) as [ParsedGroupedLabelKey, string][]
const grouped = groupBy(filteredForPrefix, ([{ id }]) => id)
return Object.values(grouped).map(group => Object.fromEntries(group.map(([{ key }, value]) => [key, value])))
}

export const parseScriptInjectionLabels = (
labels: Record<string, string>,
): [ScriptInjection[], Error[]] => {
const stringifiedInjections = parseLabelsWithPrefixAndId(
labels,
COMPOSE_TUNNEL_AGENT_SERVICE_LABELS.INJECT_SCRIPT_PREFIX,
)
const injectionOrErrors = stringifiedInjections.map(parseScriptInjection)
return partition(injectionOrErrors, x => !(x instanceof Error)) as [ScriptInjection[], Error[]]
}
23 changes: 0 additions & 23 deletions packages/common/src/compose-utils.ts

This file was deleted.

Loading
Loading