Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into script-injection-updates
Browse files Browse the repository at this point in the history
  • Loading branch information
Yshayy committed Oct 2, 2023
2 parents a517d70 + 116a7fc commit 6d0fad0
Show file tree
Hide file tree
Showing 39 changed files with 835 additions and 364 deletions.
5 changes: 3 additions & 2 deletions packages/cli/src/commands/proxy/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ export default class Connect extends ProfileCommand<typeof Connect> {

const inspector = commands.proxy.inspectRunningComposeApp(composeProject)
const networks = await inspector.getComposeNetworks()

const model = commands.proxy.initProxyComposeModel({
const projectDirectory = await inspector.getWorkingDirectory()
const model = await commands.proxy.initProxyComposeModel({
version: this.config.version,
envId,
debug: this.flags.debug,
Expand All @@ -102,6 +102,7 @@ export default class Connect extends ProfileCommand<typeof Connect> {
privateMode: flags['private-env'],
injectLivecycleScript: flags['disable-widget'] ? undefined : flags['livecycle-widget-url'],
tunnelingKeyThumbprint: await jwkThumbprint(tunnelingKey),
projectDirectory,
})

const composeTmpDir = await model.write({ tunnelingKey, knownServerPublicKey: tunnelServerPublicKey })
Expand Down
9 changes: 4 additions & 5 deletions packages/cli/src/commands/proxy/disconnect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,10 @@ export default class Disconnect extends ProfileCommand<typeof Disconnect> {
async run(): Promise<unknown> {
const { args } = await this.parse(Disconnect)
const inspector = commands.proxy.inspectRunningComposeApp(args['compose-project'])
const agentContainerId = await inspector.getPreevyAgentContainer()

if (agentContainerId) {
await execPromiseStdout(`docker rm -f ${agentContainerId}`)
this.log(`Removed ${agentContainerId}, disconnected ${args['compose-project']} tunnel`)
const agentContainer = await inspector.getPreevyAgentContainer()
if (agentContainer) {
await execPromiseStdout(`docker rm -f ${agentContainer.id}`)
this.log(`Removed ${agentContainer.id}, disconnected ${args['compose-project']} tunnel`)
}
return undefined
}
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/tunnel-server-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const connectToTunnelServerSsh = async ({ tunnelOpts, log, tunnelingKey,
log,
tunnelOpts,
clientPrivateKey: tunnelingKey,
username: process.env.USER || 'preview',
username: process.env.USER || 'preevy',
confirmHostFingerprint: async (...args) => {
spinner?.stop()
return await confirmHostFingerprint(...args)
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/ssh/base-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export const baseSshClient = async (
ssh.on('ready', () => resolve(result))
ssh.on('error', err => {
reject(err)
ssh.end()
})
ssh.connect({
debug: msg => log.debug(msg),
Expand Down
14 changes: 5 additions & 9 deletions packages/compose-tunnel-agent/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,11 +95,6 @@ const main = async () => {
log: sshLog,
})

sshClient.ssh.on('error', async err => {
log.error('ssh client error: %j', inspect(err))
await sshClient.end()
})

sshClient.ssh.on('close', () => {
if (!endRequested) {
log.error('ssh client closed unexpectedly')
Expand Down Expand Up @@ -147,17 +142,18 @@ const SHUTDOWN_TIMEOUT = 5000

void main().then(
({ end }) => {
['SIGTERM', 'SIGINT'].forEach(signal => {
process.once(signal, async () => {
log.info(`shutting down on ${signal}`)
['SIGTERM', 'SIGINT', 'uncaughtException'].forEach(signal => {
process.once(signal, async (...args) => {
const argsStr = args ? args.map(arg => inspect(arg)).join(', ') : undefined
log.warn(`shutting down on ${[signal, argsStr].filter(Boolean).join(': ')}`)
const endResult = await Promise.race([
end().then(() => true),
new Promise<void>(resolve => { setTimeout(resolve, SHUTDOWN_TIMEOUT) }),
])
if (!endResult) {
log.error(`timed out while waiting ${SHUTDOWN_TIMEOUT}ms for server to close, exiting`)
}
process.exit(0)
process.exit(1)
})
})
},
Expand Down
68 changes: 0 additions & 68 deletions packages/compose-tunnel-agent/src/docker/services.test.ts

This file was deleted.

5 changes: 5 additions & 0 deletions packages/compose-tunnel-agent/src/ssh/tunnel-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ export const sshClient = async ({
connectionConfig,
})

ssh.on('error', err => {
log.error('ssh client error: %j', inspect(err))
// baseSshClient calls end
})

const currentForwards = new Map<string, Forward>()

ssh.on('unix connection', ({ socketPath: forwardRequestId }, accept, reject) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/child-process.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ProcessOutputBuffers, orderedOutput } from '@preevy/common'
import childProcess, { ChildProcess } from 'child_process'
import childProcess, { ChildProcess, ExecOptions } from 'child_process'
import { Readable, Writable } from 'stream'
import { promisify } from 'util'

Expand Down Expand Up @@ -69,7 +69,7 @@ export const spawnPromise = async (

export const execPromise = promisify(childProcess.exec)

export const execPromiseStdout = async (command: string) => (await execPromise(command)).stdout.trim()
export const execPromiseStdout = async (command: string, opts?: Pick<ExecOptions, 'cwd'>) => (await execPromise(command, { cwd: opts?.cwd })).stdout.trim()

export type PartialStdioStringOption = 'inherit' | 'ignore'
export type PartialStdioOptions = PartialStdioStringOption
Expand Down
34 changes: 24 additions & 10 deletions packages/core/src/commands/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { widgetScriptInjector } from '../compose/script-injection'
import { ComposeModel } from '../compose'
import { TunnelOpts } from '../ssh'
import { EnvId } from '../env-id'
import { EnvMetadata, detectGitMetadata } from '../env-metadata'

export const agentServiceName = COMPOSE_TUNNEL_AGENT_SERVICE_NAME

Expand All @@ -31,29 +32,41 @@ export function inspectRunningComposeApp(projectName: string) {
const getNetworkName = (labels: string) => labels.split(',').map(l => l.split('=')).find(l => l[0] === 'com.docker.compose.network')?.[1]
return Object.fromEntries(composeNetworks.map(x => ([getNetworkName(x.Labels), { name: x.Name }])))
}

function parseJSONContainer(s: string) {
const ctr = JSON.parse(s) as {Names: string; ID: string; Labels: string }
return { names: ctr.Names, id: ctr.ID, labels: Object.fromEntries(ctr.Labels.split(',').map(l => l.split('='))) as Record<string, string> }
}

const getPreevyAgentContainer = async () => {
const agentContainerId = await dockerCmd(`ps --filter ${projectFilter} --filter label=com.docker.compose.service=${agentServiceName} -q`)
if (!agentContainerId) {
const agentContainer = await dockerCmd(`ps --filter ${projectFilter} --filter label=com.docker.compose.service=${agentServiceName} --format json`)
if (!agentContainer) {
return null
}
return agentContainerId
return parseJSONContainer(agentContainer)
}

const getEnvId = async () => {
const agentContainerId = await getPreevyAgentContainer()
if (agentContainerId) {
return await dockerCmd(`inspect ${agentContainerId} --format '{{ index .Config.Labels "preevy.env_id"}}'`)
}
return null
const agentContainer = await getPreevyAgentContainer()
return agentContainer?.labels['preevy.env_id']
}

const listAllContainers = async () => ((await dockerCmd(`ps -a --filter ${projectFilter} --format json`)).split('\n') ?? [])
.map(parseJSONContainer)

const getWorkingDirectory = async () => {
const containers = await listAllContainers()
return containers.find(x => x.labels['com.docker.compose.service'] !== agentServiceName)?.labels['com.docker.compose.project.working_dir']
}
return {
getComposeNetworks,
getPreevyAgentContainer,
getEnvId,
getWorkingDirectory,
}
}

export function initProxyComposeModel(opts: {
export async function initProxyComposeModel(opts: {
envId: EnvId
projectName: string
tunnelOpts: TunnelOpts
Expand All @@ -72,11 +85,12 @@ export function initProxyComposeModel(opts: {
}

const privateMode = Boolean(opts.privateMode)
const envMetadata = {
const envMetadata:EnvMetadata = {
id: opts.envId,
lastDeployTime: new Date(),
version: opts.version,
profileThumbprint: opts.tunnelingKeyThumbprint,
git: opts.projectDirectory ? await detectGitMetadata(opts.projectDirectory) : undefined,
}

let newComposeModel = addComposeTunnelAgentService({
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/env-id.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { detectCiProvider } from './ci-providers'
import { gitBranchName } from './git'
import { gitContext } from './git'
import { ComposeModel } from './compose'
import { Logger } from './log'

Expand Down Expand Up @@ -45,7 +45,7 @@ const findAmbientEnvIdSuffix = async () => {
return { value: envIdFromBranch(branch), basedOn: 'CI branch' }
}
}
const branch = await gitBranchName()
const branch = await gitContext().branchName()
if (branch) {
return { value: envIdFromBranch(branch), basedOn: 'local git branch' }
}
Expand Down
18 changes: 10 additions & 8 deletions packages/core/src/env-metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as git from './git'
import { gitContext } from './git'
import { detectCiProvider } from './ci-providers'

export type GitAuthor = { name: string; email: string }
Expand Down Expand Up @@ -31,31 +31,33 @@ export type EnvMetadata = {
profileThumbprint?: string
}

const detectGitMetadata = async (): Promise<EnvGitMetadata | undefined> => {
export const detectGitMetadata = async (workingDir: string): Promise<EnvGitMetadata | undefined> => {
const git = gitContext(workingDir)
const ciProvider = detectCiProvider()
const branch = await git.gitBranchName()
const branch = await git.branchName()
if (!branch) {
return undefined
}
const commit = ciProvider?.gitCommit() ?? await git.gitCommit() as string
const commit = ciProvider?.gitCommit() ?? await git.commit() as string

return {
ciProvider: ciProvider?.id,
branch: ciProvider?.branchName() ?? branch,
commit,
author: await git.gitAuthor(commit) as GitAuthor,
author: await git.author(commit) as GitAuthor,
pullRequestNumber: ciProvider?.pullRequestNumber(),
repoUrl: ciProvider?.repoUrl() || await git.gitRemoteTrackingBranchUrl(),
repoUrl: ciProvider?.repoUrl() || await git.remoteTrackingBranchUrl(),
}
}

export const envMetadata = async ({
envId,
version,
profileThumbprint,
}: { envId: string; version: string; profileThumbprint?: string }): Promise<Omit<EnvMetadata, 'driver'>> => ({
workingDir = process.cwd(),
}: { envId: string; version: string; profileThumbprint?: string; workingDir?: string }): Promise<Omit<EnvMetadata, 'driver'>> => ({
id: envId,
git: await detectGitMetadata(),
git: await detectGitMetadata(workingDir),
lastDeployTime: new Date(),
version,
profileThumbprint,
Expand Down
44 changes: 27 additions & 17 deletions packages/core/src/git.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,34 @@
import { execPromiseStdout } from './child-process'

export const gitBranchName = async () => await execPromiseStdout('git rev-parse --abbrev-ref HEAD')
.catch(() => undefined)
export function gitContext(cwd: string = process.cwd()) {
const execGit = async (command: string) => await execPromiseStdout(`git ${command}`, { cwd })
const branchName = async () => await execGit('rev-parse --abbrev-ref HEAD')
.catch(() => undefined)

export const gitCommit = async () => await execPromiseStdout('git rev-parse HEAD')
.catch(() => undefined)
const head = async () => await execGit('rev-parse HEAD')
.catch(() => undefined)

export const gitAuthor = async (commit?: string) => {
const [email, name] = await Promise.all([
`git log -1 ${commit} --pretty=format:'%ae'`,
`git log -1 ${commit} --pretty=format:'%an'`,
].map(cmd => execPromiseStdout(cmd).catch(() => undefined)))
return email === undefined || name === undefined ? undefined : { name, email }
}
const author = async (commit?: string) => {
const [email, name] = await Promise.all([
`log -1 ${commit} --pretty=format:'%ae'`,
`log -1 ${commit} --pretty=format:'%an'`,
].map(cmd => execGit(cmd).catch(() => undefined)))
return email === undefined || name === undefined ? undefined : { name, email }
}

const remoteTrackingBranchUrl = async (localBranch?: string) => {
const b = localBranch ?? (await execGit('rev-parse --abbrev-ref HEAD'))
const trackingRemote = await execGit(`config branch.${b}.remote || true`)
if (!trackingRemote) {
return undefined
}
return await execGit(`config remote.${trackingRemote}.url`)
}

export const gitRemoteTrackingBranchUrl = async (localBranch?: string) => {
const b = localBranch ?? (await execPromiseStdout('git rev-parse --abbrev-ref HEAD'))
const trackingRemote = await execPromiseStdout(`git config branch.${b}.remote || true`)
if (!trackingRemote) {
return undefined
return {
branchName,
commit: head,
author,
remoteTrackingBranchUrl,
}
return await execPromiseStdout(`git config remote.${trackingRemote}.url`)
}
2 changes: 1 addition & 1 deletion packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ export { ciProviders, detectCiProvider } from './ci-providers'
export { paginationIterator } from './pagination'
export { ensureDefined, extractDefined, HasRequired } from './nulls'
export { pSeries } from './p-series'
export * as git from './git'
export { gitContext } from './git'
export * as config from './config'
export { login, getTokensFromLocalFs as getLivecycleTokensFromLocalFs, TokenExpiredError } from './login'
4 changes: 2 additions & 2 deletions packages/plugin-github-pr-link/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { defaults } from 'lodash'
import fs from 'fs'
import { Config as OclifConfig } from '@oclif/core'
import { Logger, detectCiProvider, git } from '@preevy/core'
import { Logger, detectCiProvider, gitContext } from '@preevy/core'
import { tryParseRepo, tryParseUrlToRepo } from './repo'
import { ParsedFlags, flagsDef, prefixedFlagsDef } from './flags'
import { defaultCommentTemplate } from './lib/github-comment'
Expand Down Expand Up @@ -47,7 +47,7 @@ const ambientGithubConfig = async ({ log }: { log: Logger }): Promise<Partial<Gi

log.debug('ambientGithubConfig, ciProvider: %j', ciProvider?.name)

const repoUrlStr = ciProvider?.repoUrl() ?? await git.gitRemoteTrackingBranchUrl().catch(() => undefined)
const repoUrlStr = ciProvider?.repoUrl() ?? await gitContext().remoteTrackingBranchUrl().catch(() => undefined)

log.debug('ambientGithubConfig, repoUrlStr: %j', repoUrlStr)

Expand Down
Loading

0 comments on commit 6d0fad0

Please sign in to comment.