|
|
|
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')
|
|
|
|
},
|
|
|
|
]
|
|
|
|
}
|