126 lines
3.8 KiB
JavaScript
126 lines
3.8 KiB
JavaScript
/**
|
|||
|
|
* CI: clone backend repo at pinned ref (see e2e/backend.contract.json).
|
||
|
|
* In CI (CI=true): E2E_BACKEND_REF is required — no fallback to main.
|
||
|
|
*/
|
||
|
|
import { readFileSync, existsSync, rmSync } from 'node:fs'
|
||
|
|
import { dirname, join, resolve } from 'node:path'
|
||
|
|
import { fileURLToPath } from 'node:url'
|
||
|
|
import { spawnSync } from 'node:child_process'
|
||
|
|
|
||
|
|
const scriptDir = dirname(fileURLToPath(import.meta.url))
|
||
|
|
const frontendRoot = join(scriptDir, '..')
|
||
|
|
const contractPath = join(frontendRoot, 'e2e', 'backend.contract.json')
|
||
|
|
|
||
|
|
const isCi = process.env.CI === 'true' || process.env.GITEA_ACTIONS === 'true'
|
||
|
|
|
||
|
|
if (!existsSync(contractPath)) {
|
||
|
|
console.error('Missing e2e/backend.contract.json')
|
||
|
|
process.exit(1)
|
||
|
|
}
|
||
|
|
|
||
|
|
/** @type {{ repositoryUrl: string; checkoutPath: string; localRef?: string }} */
|
||
|
|
const contract = JSON.parse(readFileSync(contractPath, 'utf8'))
|
||
|
|
|
||
|
|
const envRef = process.env.E2E_BACKEND_REF?.trim()
|
||
|
|
let ref = envRef
|
||
|
|
|
||
|
|
if (isCi) {
|
||
|
|
if (!ref) {
|
||
|
|
console.error(
|
||
|
|
'E2E backend ref is required in CI. Set repository variable E2E_BACKEND_REF to a full commit SHA (or immutable tag). Silent fallback to main is disabled.',
|
||
|
|
)
|
||
|
|
process.exit(1)
|
||
|
|
}
|
||
|
|
} else if (!ref) {
|
||
|
|
ref = contract.localRef?.trim()
|
||
|
|
if (!ref) {
|
||
|
|
console.error(
|
||
|
|
'Set E2E_BACKEND_REF to a backend commit SHA/tag, or localRef in e2e/backend.contract.json for clone-based local runs.',
|
||
|
|
)
|
||
|
|
process.exit(1)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const repoUrl = process.env.E2E_BACKEND_REPOSITORY_URL?.trim() || contract.repositoryUrl
|
||
|
|
const checkoutPath = resolve(
|
||
|
|
frontendRoot,
|
||
|
|
process.env.E2E_BACKEND_ROOT?.trim() || contract.checkoutPath,
|
||
|
|
)
|
||
|
|
|
||
|
|
const token = process.env.E2E_BACKEND_CHECKOUT_TOKEN?.trim()
|
||
|
|
let cloneUrl = repoUrl
|
||
|
|
if (token) {
|
||
|
|
const u = new URL(repoUrl.replace(/^git\+/, ''))
|
||
|
|
u.username = token
|
||
|
|
u.password = 'x-oauth-basic'
|
||
|
|
cloneUrl = u.toString()
|
||
|
|
}
|
||
|
|
|
||
|
|
if (existsSync(checkoutPath)) {
|
||
|
|
rmSync(checkoutPath, { recursive: true, force: true })
|
||
|
|
}
|
||
|
|
|
||
|
|
const git = 'git'
|
||
|
|
const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' }
|
||
|
|
const gitOpts = { stdio: 'inherit', env: gitEnv, shell: process.platform === 'win32' }
|
||
|
|
|
||
|
|
const isFullSha = /^[0-9a-f]{40}$/i.test(ref)
|
||
|
|
|
||
|
|
console.log(`Cloning backend ref=${ref} into ${checkoutPath}`)
|
||
|
|
|
||
|
|
let clone
|
||
|
|
if (isFullSha) {
|
||
|
|
clone = spawnSync(git, ['clone', '--depth', '1', '--no-checkout', cloneUrl, checkoutPath], gitOpts)
|
||
|
|
if (clone.status !== 0) {
|
||
|
|
console.error('Backend clone failed (init).')
|
||
|
|
process.exit(clone.status ?? 1)
|
||
|
|
}
|
||
|
|
const fetch = spawnSync(
|
||
|
|
git,
|
||
|
|
['fetch', '--depth', '1', 'origin', ref],
|
||
|
|
{ ...gitOpts, cwd: checkoutPath },
|
||
|
|
)
|
||
|
|
if (fetch.status !== 0) {
|
||
|
|
console.error(`Backend fetch failed for SHA ${ref}.`)
|
||
|
|
process.exit(fetch.status ?? 1)
|
||
|
|
}
|
||
|
|
const co = spawnSync(git, ['checkout', 'FETCH_HEAD'], { ...gitOpts, cwd: checkoutPath })
|
||
|
|
if (co.status !== 0) {
|
||
|
|
console.error('Backend checkout failed.')
|
||
|
|
process.exit(co.status ?? 1)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
clone = spawnSync(
|
||
|
|
git,
|
||
|
|
['clone', '--depth', '1', '--branch', ref, cloneUrl, checkoutPath],
|
||
|
|
gitOpts,
|
||
|
|
)
|
||
|
|
if (clone.status !== 0) {
|
||
|
|
console.error(
|
||
|
|
'Backend clone failed. For private repos set secret E2E_BACKEND_CHECKOUT_TOKEN (repo read).',
|
||
|
|
)
|
||
|
|
process.exit(clone.status ?? 1)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
const head = spawnSync(git, ['rev-parse', 'HEAD'], {
|
||
|
|
cwd: checkoutPath,
|
||
|
|
encoding: 'utf8',
|
||
|
|
shell: process.platform === 'win32',
|
||
|
|
})
|
||
|
|
const checkedOutSha = head.stdout?.trim()
|
||
|
|
if (checkedOutSha) {
|
||
|
|
console.log(`Backend checkout commit: ${checkedOutSha}`)
|
||
|
|
if (isFullSha && checkedOutSha.toLowerCase() !== ref.toLowerCase()) {
|
||
|
|
console.error(
|
||
|
|
`E2E_BACKEND_REF (${ref}) does not match cloned HEAD (${checkedOutSha}).`,
|
||
|
|
)
|
||
|
|
process.exit(1)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
console.error('Could not read cloned backend commit (git rev-parse HEAD failed).')
|
||
|
|
process.exit(1)
|
||
|
|
}
|
||
|
|
|
||
|
|
process.env.E2E_BACKEND_ROOT = checkoutPath
|