mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
build(orcad): a dark test template opt-in, marked so packaging refuses it (#31097)
build-orcad-template.mjs takes --dark-test-template to let ORCA_LAYOUT_OWNER=main through for test servers; the template and out/orcad carry the switch marker, and packaging refuses a marked template. The e2e template steps build a switch-on server when the workflow runs with layout_owner=main. Co-authored-by: E2E Test <e2e@test.local>
This commit is contained in:
@@ -38,7 +38,7 @@ on:
|
||||
required: false
|
||||
type: string
|
||||
default: ''
|
||||
# Why only the app builds read it: the orcad template build refuses a dark switch.
|
||||
# Why: the app, orcad and its test template (--dark-test-template) build with it; releases refuse it.
|
||||
layout_owner:
|
||||
description: Set to main to build with ORCA_LAYOUT_OWNER=main and record save-divergence reports
|
||||
required: false
|
||||
@@ -471,13 +471,18 @@ jobs:
|
||||
slot="$(node config/scripts/build-orcad-prebuilds.mjs --print-slot)"
|
||||
pnpm build:orcad-prebuilds
|
||||
pnpm build:orcad-prebuilds --require-slots "$slot"
|
||||
# The headless oracle's orcad host must hold the same layout owner as the Electron host.
|
||||
# The headless oracle's orcad host must hold the same layout owner as the Electron host,
|
||||
# and so must the template `orca serve` materializes its server from.
|
||||
if [ -n "$LAYOUT_OWNER" ]; then
|
||||
ORCA_LAYOUT_OWNER="$LAYOUT_OWNER" pnpm build:orcad
|
||||
export ORCA_LAYOUT_OWNER="$LAYOUT_OWNER"
|
||||
pnpm build:orcad
|
||||
node config/scripts/build-orcad-template.mjs --targets "$slot" --dark-test-template
|
||||
test -f out/orcad/ORCA_LAYOUT_OWNER_MAIN
|
||||
test -f out/orcad-template/ORCA_LAYOUT_OWNER_MAIN
|
||||
else
|
||||
pnpm build:orcad
|
||||
node config/scripts/build-orcad-template.mjs --targets "$slot"
|
||||
fi
|
||||
node config/scripts/build-orcad-template.mjs --targets "$slot"
|
||||
- name: Switch serve hosts on one profile
|
||||
if: inputs.test_files == '' || contains(inputs.test_files, 'tests/e2e/orcad-serve-mode-switch.spec.ts')
|
||||
env:
|
||||
@@ -557,11 +562,19 @@ jobs:
|
||||
name: e2e-build-out${{ inputs.artifact_suffix }}
|
||||
path: out/
|
||||
# Built to a path the app does not look at by default, so the relay-era phase has no template.
|
||||
# The switch-on leg deploys a switch-on server, so both sides of the host run one layout owner.
|
||||
- name: Build the linux-x64-glibc orcad template
|
||||
env:
|
||||
LAYOUT_OWNER: ${{ inputs.layout_owner }}
|
||||
run: |
|
||||
pnpm build:orcad-prebuilds
|
||||
pnpm build:orcad-prebuilds --require-slots linux-x64-glibc
|
||||
node config/scripts/build-orcad-template.mjs --targets linux-x64-glibc
|
||||
if [ -n "$LAYOUT_OWNER" ]; then
|
||||
ORCA_LAYOUT_OWNER="$LAYOUT_OWNER" node config/scripts/build-orcad-template.mjs --targets linux-x64-glibc --dark-test-template
|
||||
test -f out/orcad-template/ORCA_LAYOUT_OWNER_MAIN
|
||||
else
|
||||
node config/scripts/build-orcad-template.mjs --targets linux-x64-glibc
|
||||
fi
|
||||
mv out/orcad-template "$RUNNER_TEMP/orcad-convert-template"
|
||||
# The Windows CLI matrix collects here too and skips: it needs a Windows host descriptor.
|
||||
- name: Run managed SSH specs on a Docker host
|
||||
|
||||
@@ -2,8 +2,9 @@ const { existsSync } = require('node:fs')
|
||||
const { join } = require('node:path')
|
||||
|
||||
// Dark build switches: a build compiles a switch's path in only when its variable is 'main'. Such a
|
||||
// main build leaves the switch's marker in out/main and in the phone page bundle (out/mobile-web),
|
||||
// and packaging refuses either; packaging and the orcad template also refuse the variable itself.
|
||||
// main build leaves the switch's marker in out/main, the phone page bundle (out/mobile-web), out/orcad
|
||||
// and a --dark-test-template orcad template; packaging refuses any of them, and packaging and a
|
||||
// release orcad template also refuse the variable itself.
|
||||
const DARK_BUILD_SWITCHES = [
|
||||
// src/shared/layout-owner-switch.ts
|
||||
{ variable: 'ORCA_LAYOUT_OWNER', off: 'window' },
|
||||
|
||||
@@ -406,9 +406,11 @@ module.exports = {
|
||||
beforePack: (
|
||||
context,
|
||||
mobileWebBundleDir = MOBILE_WEB_BUNDLE_DIR,
|
||||
ensureWaylandClipboard = ensureBundledWaylandClipboard
|
||||
ensureWaylandClipboard = ensureBundledWaylandClipboard,
|
||||
orcadTemplateDir = join(__dirname, '..', orcadTemplateExtraResource.from)
|
||||
) => {
|
||||
assertNotDarkBuild([join(__dirname, '..', 'out', 'main'), mobileWebBundleDir])
|
||||
// The template is the server every SSH host gets, so a dark test template must never ship.
|
||||
assertNotDarkBuild([join(__dirname, '..', 'out', 'main'), mobileWebBundleDir, orcadTemplateDir])
|
||||
assertPackagedNativeVariantsInstalled(context.electronPlatformName, context.arch)
|
||||
assertBundledRipgrepInstalled()
|
||||
assertProcessHostOutputBuilt()
|
||||
|
||||
@@ -38,7 +38,7 @@ import {
|
||||
import { runProcessSync } from '@orca/process-host'
|
||||
import { verifyPackagedOrcadTemplate } from './verify-packaged-orcad-template.cjs'
|
||||
import { readOrcadMobileWebAssetFilenames } from './orcad-mobile-web-bundle.mjs'
|
||||
import { assertNotDarkBuild } from '../dark-build-switches.cjs'
|
||||
import { assertNotDarkBuild, darkBuildMarkers } from '../dark-build-switches.cjs'
|
||||
|
||||
const root = resolve(import.meta.dirname, '../..')
|
||||
const outputDir = join(root, 'out', 'orcad-template')
|
||||
@@ -175,13 +175,23 @@ function stageCompatTarget(compat, basePackageDir) {
|
||||
return { files }
|
||||
}
|
||||
|
||||
/**
|
||||
* `--dark-test-template` lets a dark switch through for test servers only; the template then
|
||||
* carries the switch's marker, which packaging refuses.
|
||||
*/
|
||||
export function assertTemplateBuildAllowed(argv = process.argv, env = process.env) {
|
||||
if (!argv.includes('--dark-test-template')) {
|
||||
// The template is what releases ship as the server; a dark build must never become one.
|
||||
assertNotDarkBuild([], env)
|
||||
}
|
||||
}
|
||||
|
||||
function sameBytes(left, right) {
|
||||
return sha256(left) === sha256(right)
|
||||
}
|
||||
|
||||
async function main() {
|
||||
// The template is what releases ship as the server; a dark build must never become one.
|
||||
assertNotDarkBuild([])
|
||||
assertTemplateBuildAllowed()
|
||||
const templateTargets = requestedTemplateTargets()
|
||||
rmSync(buildDir, { recursive: true, force: true })
|
||||
const packages = Object.fromEntries(
|
||||
@@ -224,6 +234,10 @@ async function main() {
|
||||
`${JSON.stringify({ schemaVersion: 3, commonSha256, targets }, null, 2)}\n`
|
||||
)
|
||||
verifyPackagedOrcadTemplate(join(root, 'out'), templateTargets)
|
||||
// Outside the manifest, so deploys never copy it; it marks the whole template as test-only.
|
||||
for (const marker of darkBuildMarkers()) {
|
||||
writeFileSync(join(outputDir, marker.fileName), marker.text)
|
||||
}
|
||||
rmSync(buildDir, { recursive: true, force: true })
|
||||
process.stdout.write(`[build-orcad-template] ok — ${Object.keys(targets).length} targets\n`)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { ORCAD_TEMPLATE_TARGETS } from '../../src/shared/node-runtime-pin.ts'
|
||||
import { requestedTemplateTargets } from './build-orcad-template.mjs'
|
||||
import { assertTemplateBuildAllowed, requestedTemplateTargets } from './build-orcad-template.mjs'
|
||||
|
||||
describe('requestedTemplateTargets', () => {
|
||||
it('builds every target unless a subset is named', () => {
|
||||
@@ -29,3 +29,21 @@ describe('requestedTemplateTargets', () => {
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('assertTemplateBuildAllowed', () => {
|
||||
const argv = ['node', 'build-orcad-template.mjs']
|
||||
const dark = { ORCA_LAYOUT_OWNER: 'main' }
|
||||
|
||||
it('refuses a dark switch for a release template', () => {
|
||||
expect(() => assertTemplateBuildAllowed(argv, dark)).toThrow('ORCA_LAYOUT_OWNER=main')
|
||||
})
|
||||
|
||||
it('lets a dark switch through only for an explicit test template', () => {
|
||||
expect(() => assertTemplateBuildAllowed([...argv, '--dark-test-template'], dark)).not.toThrow()
|
||||
})
|
||||
|
||||
it('allows a plain template either way', () => {
|
||||
expect(() => assertTemplateBuildAllowed(argv, {})).not.toThrow()
|
||||
expect(() => assertTemplateBuildAllowed([...argv, '--dark-test-template'], {})).not.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -60,6 +60,8 @@ import { runProcessSync } from '@orca/process-host'
|
||||
import { describeProcessFailure } from './process-failure-message.mjs'
|
||||
import { resolveBuildSourceCommit } from './build-source-commit.mjs'
|
||||
|
||||
const { darkBuildMarkers } = createRequire(import.meta.url)('../dark-build-switches.cjs')
|
||||
|
||||
const ROOT = join(import.meta.dirname, '..', '..')
|
||||
const OUT_DIR = process.env.ORCAD_OUT_DIR
|
||||
? resolve(process.env.ORCAD_OUT_DIR)
|
||||
@@ -159,6 +161,10 @@ function stageNodePty(target) {
|
||||
rmSync(OUT_DIR, { recursive: true, force: true })
|
||||
mkdirSync(OUT_DIR, { recursive: true })
|
||||
writeFileSync(join(OUT_DIR, ORCAD_SERVER_TARGET_FILENAME), `${BUILD_TARGET}\n`)
|
||||
// Outside the artifact list, so the version hash and every deploy ignore it.
|
||||
for (const marker of darkBuildMarkers()) {
|
||||
writeFileSync(join(OUT_DIR, marker.fileName), marker.text)
|
||||
}
|
||||
writeFileSync(
|
||||
join(OUT_DIR, ORCAD_NODE_RUNTIME_MARKER_FILENAME),
|
||||
`${runtimeAsset.executableSha256}\n`
|
||||
|
||||
@@ -616,6 +616,24 @@ describe('arch-aware packaging guard', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('refuses to package an orcad template marked by a dark test build', async () => {
|
||||
const templateDir = join(scratch, 'orcad-template')
|
||||
await mkdir(templateDir, { recursive: true })
|
||||
await writeFile(join(templateDir, 'ORCA_LAYOUT_OWNER_MAIN'), 'dark\n')
|
||||
try {
|
||||
expect(() =>
|
||||
electronBuilderConfig.beforePack(
|
||||
{ electronPlatformName: process.platform, arch: HOST_ARCH },
|
||||
bundleDir,
|
||||
() => undefined,
|
||||
templateDir
|
||||
)
|
||||
).toThrow(`${templateDir} holds an ORCA_LAYOUT_OWNER=main build`)
|
||||
} finally {
|
||||
await rm(templateDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
it('requires the other architecture natives to be installed', () => {
|
||||
const otherSherpaInstalled = existsSync(
|
||||
join(REPO_ROOT, 'node_modules', otherSherpa, 'package.json')
|
||||
|
||||
Reference in New Issue
Block a user