Skip to content

Commit 39cc2d4

Browse files
committed
feat(packaging): bundle vendored runtime readmes
1 parent 33fa3b3 commit 39cc2d4

4 files changed

Lines changed: 251 additions & 16 deletions

File tree

packages/code-server/scripts/build-artifacts.mjs

Lines changed: 94 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ const packageId = "code-server"
1919
const platform = normalizePlatform(process.env.BUILD_ARTIFACTS_PLATFORM || process.platform)
2020
const arch = normalizeArch(process.env.ARCH || process.arch)
2121

22-
main().catch((error) => {
23-
console.error(error instanceof Error ? error.stack || error.message : String(error))
24-
process.exitCode = 1
25-
})
22+
if (isMainModule()) {
23+
main().catch((error) => {
24+
console.error(error instanceof Error ? error.stack || error.message : String(error))
25+
process.exitCode = 1
26+
})
27+
}
2628

2729
async function main() {
2830
process.chdir(root)
@@ -31,15 +33,17 @@ async function main() {
3133
const version = await resolveVersion()
3234

3335
await run("git", ["submodule", "update", "--init", "--recursive"], { cwd: root })
36+
const sourceRevision = (await readGitOutput(["rev-parse", "HEAD"], codeServerRoot)).trim()
3437

3538
await rm(artifactsDir, { recursive: true, force: true })
3639
await mkdir(artifactsDir, { recursive: true })
3740

3841
await runBuildPipeline(version)
3942
await slimRelease()
43+
await writePackagedReadme(releaseDir, { version, sourceRevision, targetPlatform: platform, targetArch: arch })
4044

4145
const artifacts = await collectArtifacts(version)
42-
await writeMetadata(version, artifacts)
46+
await writeMetadata(version, sourceRevision, artifacts)
4347
}
4448

4549
async function runBuildPipeline(version) {
@@ -195,8 +199,77 @@ async function collectArtifacts(version) {
195199
]
196200
}
197201

198-
async function writeMetadata(version, artifacts) {
199-
const revision = await readGitOutput(["rev-parse", "HEAD"], codeServerRoot)
202+
export async function writePackagedReadme(releaseRoot, details) {
203+
const readmePath = path.join(releaseRoot, "README.md")
204+
const upstreamReadmePath = path.join(releaseRoot, "README.upstream.md")
205+
206+
if ((await exists(readmePath)) && !(await exists(upstreamReadmePath))) {
207+
await writeFile(upstreamReadmePath, await readFile(readmePath, "utf8"))
208+
}
209+
210+
await writeFile(readmePath, renderPackagedReadme(details))
211+
}
212+
213+
export function renderPackagedReadme({ version, sourceRevision, targetPlatform = platform, targetArch = arch }) {
214+
const usageBlock =
215+
targetPlatform === "windows"
216+
? [
217+
"```powershell",
218+
".\\bin\\code-server.cmd --help",
219+
".\\bin\\code-server.cmd --bind-addr 0.0.0.0:8080 .",
220+
"```",
221+
"",
222+
"Direct Node entrypoint:",
223+
"",
224+
"```powershell",
225+
"node .\\out\\node\\entry.js --help",
226+
"```",
227+
].join("\n")
228+
: [
229+
"```bash",
230+
"./bin/code-server --help",
231+
"./bin/code-server --bind-addr 0.0.0.0:8080 .",
232+
"```",
233+
"",
234+
"Direct Node entrypoint:",
235+
"",
236+
"```bash",
237+
"node ./out/node/entry.js --help",
238+
"```",
239+
].join("\n")
240+
241+
return [
242+
"# code-server",
243+
"",
244+
"This archive is the HagiCode vendored slim build of code-server. Extract it and run it directly.",
245+
"",
246+
"## Usage",
247+
"",
248+
"1. Extract the archive and change into the extracted directory.",
249+
"2. Start code-server with the wrapper below.",
250+
"",
251+
usageBlock,
252+
"",
253+
"## Dependencies",
254+
"",
255+
"- Node.js 22 must be available on PATH. This archive does not bundle a Node runtime.",
256+
"- A modern web browser is required to use the UI after the server starts.",
257+
"",
258+
"## Version",
259+
"",
260+
`- Package: \`${packageId}\``,
261+
`- Packaged version: \`${version}\``,
262+
`- Target: \`${targetPlatform}/${targetArch}\``,
263+
`- Source revision: \`${sourceRevision}\``,
264+
"",
265+
"## Notes",
266+
"",
267+
"- The original upstream README is preserved as `README.upstream.md` when it exists in the release tree.",
268+
"",
269+
].join("\n")
270+
}
271+
272+
async function writeMetadata(version, sourceRevision, artifacts) {
200273
const metadataFileName = "metadata.json"
201274
await writeFile(
202275
path.join(artifactsDir, metadataFileName),
@@ -207,7 +280,7 @@ async function writeMetadata(version, artifacts) {
207280
version,
208281
platform,
209282
arch,
210-
sourceRevision: revision.trim(),
283+
sourceRevision,
211284
extra: {
212285
slimArtifact: true,
213286
bundledNodeRuntime: false,
@@ -282,6 +355,15 @@ function normalizeArch(value) {
282355
}
283356
}
284357

358+
async function exists(targetPath) {
359+
try {
360+
await access(targetPath)
361+
return true
362+
} catch {
363+
return false
364+
}
365+
}
366+
285367
function toPosixPath(value) {
286368
return value.replaceAll("\\", "/")
287369
}
@@ -375,3 +457,7 @@ async function calculateSha256(filePath) {
375457
const contents = await readFile(filePath)
376458
return createHash("sha256").update(contents).digest("hex")
377459
}
460+
461+
function isMainModule() {
462+
return process.argv[1] != null && path.resolve(process.argv[1]) === __filename
463+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import test from "node:test"
2+
import assert from "node:assert/strict"
3+
import { mkdtemp, readFile, writeFile } from "node:fs/promises"
4+
import os from "node:os"
5+
import path from "node:path"
6+
7+
import { renderPackagedReadme, writePackagedReadme } from "./build-artifacts.mjs"
8+
9+
test("renderPackagedReadme emits code-server usage, dependency, and version details", () => {
10+
const readme = renderPackagedReadme({
11+
version: "4.99.0",
12+
sourceRevision: "abc123",
13+
targetPlatform: "windows",
14+
targetArch: "amd64",
15+
})
16+
17+
assert.match(readme, /\.\\bin\\code-server\.cmd --help/)
18+
assert.match(readme, /Node\.js 22 must be available on PATH/)
19+
assert.match(readme, /Packaged version: `4\.99\.0`/)
20+
assert.match(readme, /Source revision: `abc123`/)
21+
})
22+
23+
test("writePackagedReadme preserves the upstream README before overwriting it", async () => {
24+
const releaseRoot = await mkdtemp(path.join(os.tmpdir(), "code-server-readme-"))
25+
await writeFile(path.join(releaseRoot, "README.md"), "upstream docs\n")
26+
27+
await writePackagedReadme(releaseRoot, {
28+
version: "4.99.0",
29+
sourceRevision: "abc123",
30+
targetPlatform: "linux",
31+
targetArch: "amd64",
32+
})
33+
34+
assert.equal(await readFile(path.join(releaseRoot, "README.upstream.md"), "utf8"), "upstream docs\n")
35+
const packagedReadme = await readFile(path.join(releaseRoot, "README.md"), "utf8")
36+
assert.match(packagedReadme, /# code-server/)
37+
assert.match(packagedReadme, /\.\/bin\/code-server --help/)
38+
})

packages/omniroute/scripts/build-artifacts.mjs

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ async function main() {
3636
const version = process.env.VERSION || upstreamVersion
3737

3838
await run("git", ["submodule", "update", "--init", "--recursive"], { cwd: root })
39+
const sourceRevision = (await readGitOutput(["rev-parse", "HEAD"], upstreamRoot)).trim()
3940
await rm(artifactsDir, { recursive: true, force: true })
4041
await rm(releaseWorkspace, { recursive: true, force: true })
4142
await mkdir(artifactsDir, { recursive: true })
@@ -61,12 +62,12 @@ async function main() {
6162
env: withBuildEnv(process.env, version),
6263
})
6364

64-
const releaseRoot = await stageReleaseTree(version)
65+
const releaseRoot = await stageReleaseTree({ version, upstreamVersion, sourceRevision })
6566
const artifacts = await createArchive(version, releaseRoot)
66-
await writeMetadata(version, upstreamVersion, artifacts)
67+
await writeMetadata(version, upstreamVersion, sourceRevision, artifacts)
6768
}
6869

69-
async function stageReleaseTree(version) {
70+
async function stageReleaseTree({ version, upstreamVersion, sourceRevision }) {
7071
const releaseRoot = path.join(releaseWorkspace, `${packageId}-${version}-${platform}-${arch}`)
7172
await rm(releaseRoot, { recursive: true, force: true })
7273
await mkdir(releaseRoot, { recursive: true })
@@ -98,6 +99,7 @@ async function stageReleaseTree(version) {
9899
await access(path.join(releaseRoot, "app", "server.js"))
99100
await assertPackagedEntrypoints(releaseRoot, binEntries)
100101
await writePlatformWrappers(releaseRoot, binEntries, platform)
102+
await writePackagedReadme(releaseRoot, { version, upstreamVersion, sourceRevision, targetPlatform: platform, targetArch: arch })
101103

102104
return releaseRoot
103105
}
@@ -141,12 +143,11 @@ async function createArchive(version, releaseRoot) {
141143
]
142144
}
143145

144-
async function writeMetadata(version, upstreamVersion, artifacts) {
145-
const revision = (await readGitOutput(["rev-parse", "HEAD"], upstreamRoot)).trim()
146+
async function writeMetadata(version, upstreamVersion, sourceRevision, artifacts) {
146147
const metadataFileName = "metadata.json"
147148
await writeFile(
148149
path.join(artifactsDir, metadataFileName),
149-
`${JSON.stringify(createMetadataPayload({ version, upstreamVersion, sourceRevision: revision, artifacts }), null, 2)}\n`,
150+
`${JSON.stringify(createMetadataPayload({ version, upstreamVersion, sourceRevision, artifacts }), null, 2)}\n`,
150151
)
151152
}
152153

@@ -182,6 +183,82 @@ export function createMetadataPayload({ version, upstreamVersion, sourceRevision
182183
}
183184
}
184185

186+
export async function writePackagedReadme(releaseRoot, details) {
187+
const readmePath = path.join(releaseRoot, "README.md")
188+
const upstreamReadmePath = path.join(releaseRoot, "README.upstream.md")
189+
190+
if ((await exists(readmePath)) && !(await exists(upstreamReadmePath))) {
191+
await writeFile(upstreamReadmePath, await readFile(readmePath, "utf8"))
192+
}
193+
194+
await writeFile(readmePath, renderPackagedReadme(details))
195+
}
196+
197+
export function renderPackagedReadme({ version, upstreamVersion, sourceRevision, targetPlatform = platform, targetArch = arch }) {
198+
const usageBlock =
199+
targetPlatform === "windows"
200+
? [
201+
"```powershell",
202+
".\\omniroute.cmd --help",
203+
".\\omniroute.cmd",
204+
".\\omniroute-reset-password.cmd",
205+
"```",
206+
"",
207+
"Direct Node entrypoint:",
208+
"",
209+
"```powershell",
210+
"node .\\bin\\omniroute.mjs --help",
211+
"```",
212+
].join("\n")
213+
: [
214+
"```bash",
215+
"./omniroute.sh --help",
216+
"./omniroute.sh",
217+
"./omniroute-reset-password.sh",
218+
"```",
219+
"",
220+
"Direct Node entrypoint:",
221+
"",
222+
"```bash",
223+
"node ./bin/omniroute.mjs --help",
224+
"```",
225+
].join("\n")
226+
227+
return [
228+
"# omniroute",
229+
"",
230+
"This archive is the HagiCode vendored standalone OmniRoute bundle. Extract it and run it directly.",
231+
"",
232+
"## Usage",
233+
"",
234+
"1. Extract the archive and change into the extracted directory.",
235+
"2. If you need provider credentials or other runtime settings, start from `.env.example`.",
236+
"3. Start OmniRoute with the wrapper below.",
237+
"",
238+
usageBlock,
239+
"",
240+
"## Dependencies",
241+
"",
242+
"- Run this vendored build with Node.js 22. The archive includes `.node-version` with `22`.",
243+
"- No Node runtime is bundled. The wrapper scripts call `node` from PATH.",
244+
"- Provider credentials, network access, and any route-specific configuration remain external dependencies.",
245+
"",
246+
"## Version",
247+
"",
248+
`- Package: \`${packageId}\``,
249+
`- Packaged version: \`${version}\``,
250+
`- Upstream version: \`${upstreamVersion}\``,
251+
`- Target: \`${targetPlatform}/${targetArch}\``,
252+
`- Source revision: \`${sourceRevision}\``,
253+
"",
254+
"## Notes",
255+
"",
256+
"- Packaged CLI entrypoint: `bin/omniroute.mjs`",
257+
"- The original upstream README is preserved as `README.upstream.md` when it exists in the release tree.",
258+
"",
259+
].join("\n")
260+
}
261+
185262
async function readUpstreamVersion() {
186263
const packageJson = JSON.parse(await readFile(path.join(upstreamRoot, "package.json"), "utf8"))
187264
return packageJson.version

packages/omniroute/scripts/build-artifacts.test.mjs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import test from "node:test"
22
import assert from "node:assert/strict"
3-
import { access, mkdtemp, readFile, stat } from "node:fs/promises"
3+
import { access, mkdtemp, readFile, stat, writeFile } from "node:fs/promises"
44
import os from "node:os"
55
import path from "node:path"
66

7-
import { createMetadataPayload, patchPrepublishScriptSource, patchResponsesWsProxySource, writePlatformWrappers } from "./build-artifacts.mjs"
7+
import { createMetadataPayload, patchPrepublishScriptSource, patchResponsesWsProxySource, renderPackagedReadme, writePackagedReadme, writePlatformWrappers } from "./build-artifacts.mjs"
88
import { buildBlobKey } from "../../../scripts/publication.mjs"
99
import { WINDOWS_WRAPPER_EXTENSIONS, getManifestBinEntries, getNativeSmokeWrapperFile, getWrapperDefinitions } from "./wrappers.mjs"
1010

@@ -203,3 +203,37 @@ export function createResponsesWsProxy({
203203
assert.equal(patched.includes('const module = requireFn("wreq-js");'), true)
204204
assert.equal(patched.includes('wsFactory = loadDefaultWsFactory(),'), true)
205205
})
206+
207+
208+
test("renderPackagedReadme emits OmniRoute usage, dependency, and version details", () => {
209+
const readme = renderPackagedReadme({
210+
version: "2026.0505.0001",
211+
upstreamVersion: "3.7.9",
212+
sourceRevision: "abc123",
213+
targetPlatform: "windows",
214+
targetArch: "amd64",
215+
})
216+
217+
assert.match(readme, /\.\\omniroute\.cmd --help/)
218+
assert.match(readme, /\.node-version/)
219+
assert.match(readme, /Upstream version: `3\.7\.9`/)
220+
assert.match(readme, /Packaged CLI entrypoint: `bin\/omniroute\.mjs`/)
221+
})
222+
223+
test("writePackagedReadme preserves the upstream OmniRoute README before overwriting it", async () => {
224+
const releaseRoot = await mkdtemp(path.join(os.tmpdir(), "omniroute-readme-"))
225+
await writeFile(path.join(releaseRoot, "README.md"), "upstream docs\n")
226+
227+
await writePackagedReadme(releaseRoot, {
228+
version: "2026.0505.0001",
229+
upstreamVersion: "3.7.9",
230+
sourceRevision: "abc123",
231+
targetPlatform: "linux",
232+
targetArch: "amd64",
233+
})
234+
235+
assert.equal(await readFile(path.join(releaseRoot, "README.upstream.md"), "utf8"), "upstream docs\n")
236+
const packagedReadme = await readFile(path.join(releaseRoot, "README.md"), "utf8")
237+
assert.match(packagedReadme, /# omniroute/)
238+
assert.match(packagedReadme, /\.\/omniroute\.sh --help/)
239+
})

0 commit comments

Comments
 (0)