Skip to content

Commit 5c90a93

Browse files
committed
ci: add TEMPORARY Windows template build + dev smoke (#19) Scaffolds the default template from a local registry built off this branch, then runs 'npm run build' and a 'npm run dev' smoke (waits for the Blocks server on :3000, then tears down). Confirms a Windows user can build and run a Blocks app end to end with no AWS. Validated locally on macOS before pushing. Temporary — delete with the rest of windows-deploy-check.yml before merge.
1 parent bb74ef1 commit 5c90a93

2 files changed

Lines changed: 150 additions & 0 deletions

File tree

.github/workflows/windows-deploy-check.yml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,33 @@ jobs:
8282
console.log('OK: npx/npm shims spawned on Windows without ENOENT — #19 fixed.');
8383
EOF
8484
node verify-19.mjs
85+
86+
# Broader smoke: a real Windows developer loop with no AWS. Scaffolds the
87+
# `default` template from a local registry (built from this branch's source),
88+
# then `npm run build` + `npm run dev`. Confirms Windows users can build and
89+
# run a Blocks app end to end. NOTE: the default template is a managed app, so
90+
# this exercises the dev/build DX rather than the #19 deploy-spawn path itself
91+
# (the job above is the targeted #19 check).
92+
windows-template-dev:
93+
name: Windows template build + dev
94+
runs-on: windows-latest
95+
timeout-minutes: 30
96+
steps:
97+
- uses: actions/checkout@v5
98+
99+
- uses: actions/setup-node@v5
100+
with:
101+
node-version-file: '.nvmrc'
102+
cache: npm
103+
104+
- name: Install dependencies
105+
run: npm ci
106+
107+
- name: Build publishable packages
108+
run: npm run build:packages
109+
110+
- name: Pack to local registry
111+
run: npm run publish:dry-run
112+
113+
- name: Scaffold + build + dev smoke
114+
run: node scripts/ci/windows-template-smoke.mjs
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// ⚠️ TEMPORARY — delete together with .github/workflows/windows-deploy-check.yml
2+
// once issue #19 is verified/merged.
3+
//
4+
// Cross-platform driver that exercises the real developer loop for a scaffolded
5+
// template, with no AWS: serve the local registry (built by `publish:dry-run`),
6+
// scaffold the `default` template exactly as a customer would, then
7+
// `npm run build` and smoke `npm run dev`. Verifies that a Windows user can
8+
// actually build and run a Blocks app end to end.
9+
//
10+
// Assumes `npm ci`, `npm run build:packages`, and `npm run publish:dry-run`
11+
// have already run (so dist-registry exists). Exits non-zero on any failure.
12+
13+
import { spawn, spawnSync, execSync } from 'node:child_process';
14+
import { mkdtempSync, mkdirSync, writeFileSync, existsSync } from 'node:fs';
15+
import { tmpdir } from 'node:os';
16+
import { join } from 'node:path';
17+
import { setTimeout as sleep } from 'node:timers/promises';
18+
19+
const ROOT = process.cwd();
20+
const isWin = process.platform === 'win32';
21+
const REGISTRY = 'http://localhost:4873/registry/';
22+
const SERVER_URL = 'http://localhost:3000/';
23+
24+
if (!existsSync(join(ROOT, 'dist-registry'))) {
25+
console.error('dist-registry not found — run `npm run publish:dry-run` first.');
26+
process.exit(1);
27+
}
28+
29+
const children = [];
30+
31+
function run(cmd, args, opts = {}) {
32+
console.log(`\n$ ${cmd} ${args.join(' ')} (cwd: ${opts.cwd ?? ROOT})`);
33+
const r = spawnSync(cmd, args, { stdio: 'inherit', shell: isWin, ...opts });
34+
if (r.error) throw r.error;
35+
if (r.status !== 0) throw new Error(`${cmd} ${args.join(' ')} exited with ${r.status}`);
36+
}
37+
38+
async function httpOk(url) {
39+
try {
40+
const res = await fetch(url, { signal: AbortSignal.timeout(2000) });
41+
return res.status > 0;
42+
} catch {
43+
return false;
44+
}
45+
}
46+
47+
async function waitFor(url, label, attempts) {
48+
for (let i = 0; i < attempts; i++) {
49+
if (await httpOk(url)) return true;
50+
await sleep(1000);
51+
}
52+
return false;
53+
}
54+
55+
function killTree(pid) {
56+
if (!pid) return;
57+
try {
58+
if (isWin) execSync(`taskkill /pid ${pid} /T /F`, { stdio: 'ignore' });
59+
else process.kill(-pid, 'SIGKILL');
60+
} catch { /* already gone */ }
61+
}
62+
63+
async function main() {
64+
// 1. Serve the local registry (node.exe + tsx loader — no shim needed).
65+
const registry = spawn(process.execPath, ['--import', 'tsx', 'scripts/publish/serve-local-registry.ts'], {
66+
cwd: ROOT,
67+
stdio: 'inherit',
68+
detached: !isWin,
69+
});
70+
children.push(registry);
71+
72+
if (!(await waitFor(`${REGISTRY}@aws-blocks/blocks`, 'registry', 30))) {
73+
throw new Error('Local registry did not start on :4873');
74+
}
75+
console.log('Local registry is up.');
76+
77+
// 2. Isolated npm config pointing the @aws-blocks scope at the local registry.
78+
const work = mkdtempSync(join(tmpdir(), 'blocks-win-smoke-'));
79+
const userNpmrc = join(work, '.npmrc');
80+
writeFileSync(userNpmrc, `@aws-blocks:registry=${REGISTRY}\n`);
81+
const env = {
82+
...process.env,
83+
NPM_CONFIG_USERCONFIG: userNpmrc,
84+
npm_config_cache: join(work, '.npm-cache'),
85+
};
86+
87+
// 3. Install the CLI from the local registry and scaffold the default template.
88+
run('npm', ['install', '@aws-blocks/create-blocks-app@latest'], { cwd: work, env });
89+
const createBin = join(work, 'node_modules', '.bin', isWin ? 'create-blocks-app.cmd' : 'create-blocks-app');
90+
const appDir = join(work, 'my-app');
91+
run(createBin, [appDir], { cwd: work, env });
92+
93+
// 4. The real developer loop: build the app.
94+
run('npm', ['run', 'build'], { cwd: appDir, env });
95+
96+
// 5. Smoke `npm run dev`: start it, wait for the Blocks server, then tear down.
97+
console.log('\n$ npm run dev (background smoke)');
98+
const dev = spawn('npm', ['run', 'dev'], {
99+
cwd: appDir,
100+
env,
101+
shell: isWin,
102+
detached: !isWin,
103+
stdio: 'inherit',
104+
});
105+
children.push(dev);
106+
107+
const up = await waitFor(SERVER_URL, 'dev server', 120);
108+
killTree(dev.pid);
109+
if (!up) throw new Error(`npm run dev did not serve ${SERVER_URL} within 120s`);
110+
111+
console.log(`\nOK: scaffold + npm run build + npm run dev all work on ${process.platform}.`);
112+
}
113+
114+
main()
115+
.then(() => { for (const c of children) killTree(c.pid); process.exit(0); })
116+
.catch((err) => {
117+
console.error('\nFAIL:', err?.message ?? err);
118+
for (const c of children) killTree(c.pid);
119+
process.exit(1);
120+
});

0 commit comments

Comments
 (0)