import type { Deploy, GitDeploy, GitRef, ShellDeploy } from '@/config' import type { Job, Worker } from '@/jobs' import path from 'path' import { exists, normalizeURL, sleep } from '@/lib/utils' import { runCommand } from '@/runners' import { debug } from '@/logger' const toSafePath = (target: string) => { return '.' + path.posix.normalize('/' + target) } function getDeployDirectory(deploy: GitDeploy): string { const { url, ref } = deploy const repoSlug = url .replace(/(^\w+:|^)\/\//, '') // strip protocol .replace(/[^a-zA-Z]+/g, '-') // only keep letters, other symbols become dashes .replace(/^\-|\-$/g, '') // remove leading or trailing dashes const slug = ref.type === 'default' ? `${deploy.name}_${repoSlug}` : `${deploy.name}_${repoSlug}@${ref.value}` return `${import.meta.env.CLONE_PATH ?? `${import.meta.env.DATA_PATH}/clone`}/${slug}` } async function cloneOrUpdateRepo(deploy: Deploy & { url: string; ref: GitRef }) { const repoDir = getDeployDirectory(deploy) if (await exists(repoDir)) { await runCommand(`git -C "${repoDir}" pull`) } else { await runCommand(`mkdir -p "${repoDir}"`) await runCommand(`git clone "${normalizeURL(deploy.url)}" "${repoDir}"`) } if (deploy.ref.type !== 'default') { await runCommand(`git -C "${repoDir}" checkout "${deploy.ref.value}"`) } } export async function shellRunner(deploy: ShellDeploy) { const { path, env } = deploy.options const repoDir = getDeployDirectory(deploy) await cloneOrUpdateRepo(deploy) const script = [ // mode to correct directory `cd ${repoDir}`, // append env variables Object.entries(env ?? {}) .map(([key, value]) => `export ${key}="${value.replace(/"/g, '\\"')}"`) .join('\n'), // launch program toSafePath(path ?? './deploy.sh'), ].join('\n\n') await runCommand(script) } export function createDeployJob(deploy: Deploy, submitter: any): Job & Worker { return { name: deploy.name, submitter, submittedAt: new Date(), async work() { debug('[Runner]', `Deploying "${deploy.name}"`) await sleep(1000) // TODO: Add other deploy types if (deploy.type === 'shell') await shellRunner(deploy) else { throw new Error(`deploy type "${deploy.type}" not yet implemented`) } debug('[Runner]', 'Finished deploy') }, } }