import type { Deploy, GitDeploy, GitRef, ShellDeploy } from '@/config' import type { DeployFunction, Job, JobBase } from '@/jobs' import path from 'path' import { exists, normalizeURL, sleep } from '@/lib/utils' import { type Runner } 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(runner: Runner, deploy: Deploy & { url: string; ref: GitRef }) { const repoDir = getDeployDirectory(deploy) if (await exists(repoDir)) { await runner.command(`git -C "${repoDir}" pull`, { silent: true, }) } else { await runner.command(`mkdir -p "${repoDir}"`, { silent: true, }) await runner.command(`git clone "${normalizeURL(deploy.url)}" "${repoDir}"`, { silent: true, }) } if (deploy.ref.type !== 'default') { await runner.command(`git -C "${repoDir}" checkout "${deploy.ref.value}"`, { silent: true, }) } } export async function shellRunner(runner: Runner, deploy: ShellDeploy) { await cloneOrUpdateRepo(runner, deploy) const repoDir = getDeployDirectory(deploy) const { path, env } = deploy.options await runner.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') ) } export function createDeployJob(deploy: Deploy, submitter: any): [JobBase, DeployFunction] { return [ { name: deploy.name, submitter, }, async runner => { debug('[Runner]', `Deploying "${deploy.name}"`) await sleep(1000) // TODO: Add other deploy types if (deploy.type === 'shell') { await shellRunner(runner, deploy) } else { throw new Error(`deploy type "${deploy.type}" not yet implemented`) } debug('[Runner]', 'Finished deploy') }, ] }