2026-10-12 14:40:37 +03:30
/**
* 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 )
}
2026-10-22 13:01:49 +03:30
/** @type {{ repositoryUrl: string; checkoutPath: string; localRef?: string; pinnedRef?: string }} */
2026-10-12 14:40:37 +03:30
const contract = JSON . parse ( readFileSync ( contractPath , 'utf8' ))
const envRef = process . env . E2E_BACKEND_REF ? . trim ()
let ref = envRef
2026-10-22 13:01:49 +03:30
if ( isCi && ! ref ) {
ref = contract . pinnedRef ? . trim ()
if ( ! /^[0-9a-f]{40}$/i . test ( ref ?? '' )) {
2026-10-12 14:40:37 +03:30
console . error (
2026-10-22 13:01:49 +03:30
'E2E backend ref is required in CI. Set E2E_BACKEND_REF or pinnedRef in e2e/backend.contract.json to a full commit SHA. Silent fallback to main is disabled.' ,
2026-10-12 14:40:37 +03:30
)
process . exit ( 1 )
}
2026-10-22 13:01:49 +03:30
console . log ( 'E2E_BACKEND_REF unset; using committed pinnedRef' )
} else if ( ! isCi && ! ref ) {
2026-10-12 14:40:37 +03:30
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