scripts/publish-schema-types.ts
Rama main · réplica de lectura del repositorio original.
import { execFileSync } from 'node:child_process'
import process from 'node:process'
type GitRunner = (args: string[]) => string
export interface PublishSchemaTypesOptions {
branch: string
expectedBranchSha: string
remote: string
}
function runGit(args: string[]): string {
return execFileSync('git', args, {
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
}).trim()
}
function isValidRefName(value: string): boolean {
return value.length > 0
&& value.length <= 255
&& !value.startsWith('.')
&& !value.endsWith('.')
&& !value.endsWith('/')
&& !value.endsWith('.lock')
&& !value.includes('..')
&& !value.includes('//')
&& !value.includes('@{')
&& !/[\x00-\x20\x7F~^:?*[\\]/.test(value)
&& !value.split('/').some(part => part.startsWith('.') || part.endsWith('.lock'))
}
function validateOptions(options: PublishSchemaTypesOptions): void {
if (!isValidRefName(options.branch))
throw new Error(`Invalid schema/types branch: ${options.branch}`)
if (!/^[0-9a-f]{40,64}$/i.test(options.expectedBranchSha))
throw new Error('Expected schema/types branch SHA must be a full hexadecimal object ID')
if (!options.remote || /[\r\n]/.test(options.remote) || options.remote.startsWith('-'))
throw new Error('Schema/types remote must be non-empty, contain no line breaks, and not start with "-"')
}
function readRemoteBranchSha(remote: string, branch: string, run: GitRunner): string {
const ref = `refs/heads/${branch}`
const output = run(['ls-remote', '--heads', remote, ref])
const [line, ...extraLines] = output.split('\n').filter(Boolean)
const match = line?.match(/^([0-9a-f]{40,64})\trefs\/heads\/(.+)$/i)
if (!match || extraLines.length > 0 || match[2] !== branch)
throw new Error(`Could not resolve remote branch ${ref}`)
return match[1]
}
export function publishSchemaTypes(
options: PublishSchemaTypesOptions,
run: GitRunner = runGit,
): 'published' | 'retry' {
validateOptions(options)
const remoteSha = readRemoteBranchSha(options.remote, options.branch, run)
if (remoteSha !== options.expectedBranchSha)
return 'retry'
try {
run([
'push',
'--atomic',
options.remote,
`HEAD:refs/heads/${options.branch}`,
])
return 'published'
}
catch (error) {
try {
const remoteShaAfterFailure = readRemoteBranchSha(options.remote, options.branch, run)
const localHead = run(['rev-parse', 'HEAD'])
if (remoteShaAfterFailure === localHead)
return 'published'
if (remoteShaAfterFailure !== options.expectedBranchSha)
return 'retry'
}
catch {
// Preserve the original push failure when remote state cannot be verified.
}
throw error
}
}
if (import.meta.main) {
const branch = process.argv[2] ?? ''
const expectedBranchSha = process.argv[3] ?? ''
const remote = process.env.SCHEMA_TYPES_REMOTE_URL ?? ''
if (!branch || !expectedBranchSha || !remote) {
console.error('Usage: SCHEMA_TYPES_REMOTE_URL=<remote> bun scripts/publish-schema-types.ts <branch> <expected-branch-sha>')
process.exit(1)
}
console.log(publishSchemaTypes({ branch, expectedBranchSha, remote }))
}