Files
gold_land_user/scripts/ci-checkout-backend.mjs
T
safavimohadeseh78andCursor e3f0457dc9
Frontend CI / unit (test, type-check, build) (push) Successful in 1m11s
Frontend CI / browser E2E (frontend + pinned backend) (push) Failing after 2m48s
feat: complete server-backed six-lesson app and trial tooling
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-12 14:40:37 +03:30

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