mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-11-13 08:51:28 +00:00
fix(devcontainer): resolve workspace volume ID before startup
This commit is contained in:
parent
e3fe9f9ab7
commit
ca821e623e
4 changed files with 25 additions and 13 deletions
|
|
@ -24,6 +24,8 @@ Keep the host folder and selected configuration path stable: moving either can c
|
|||
|
||||
The default workspace is `gitnexus-source-${devcontainerId}:/workspace`. The host `initializeCommand` runs `initialize-volumes.cjs`, starts a disposable helper with volume mounts only, and streams a tar archive through [Docker's copy API](https://docs.docker.com/reference/cli/docker/container/cp/). The helper uses the Dockerfile's digest-pinned base image. It is removed afterward; volumes and host files remain.
|
||||
|
||||
The workspace volume is declared in `mounts`, with `workspaceMount` set to an empty string to disable the automatic host mount. This lets the Dev Containers CLI substitute `${devcontainerId}` before starting Docker; affected CLI versions leave it literal when the volume is declared in `workspaceMount`. Default and generated profiles retain their existing volume names, so this placement does not trigger another source import.
|
||||
|
||||
The import preserves `.git`, branches, local commits, the index, stashes, uncommitted and ignored files, checkout-local indexes, and nested worktrees. Generated `node_modules`, `.venv`, `.husky/_`, `.gitnexus/parse-cache`, `.gitnexus/parse-cache.json`, and `.gitnexus/parsedfile-cache` paths are excluded at every depth, including under `.worktrees` and `.claude/worktrees`. GitNexus graph databases, embeddings, metadata, and runners are kept; parser caches regenerate on the next analysis. Git metadata is preserved except for source-volume completion markers. Reinstall dependencies inside each worktree as needed, and recreate Python environments with the evaluation project's `uv run` commands. Host files are left intact. Existing dependency, index-store, AI configuration, history, and session volume names stay unchanged.
|
||||
|
||||
During archive transfers, `[volumes]` reports elapsed time, entries queued, excluded paths, symlinks, and MiB streamed to Docker every five seconds, followed by a completion or failure line. Streamed bytes measure data sent to Docker, not bytes committed to disk; there is no percentage because the total is not pre-scanned. Helper startup, the second copy into the source volume, Git normalization, snapshot finalization, and cleanup also report activity every five seconds. Output from the Linux helper is shown as it arrives.
|
||||
|
|
|
|||
|
|
@ -41,8 +41,9 @@
|
|||
"updateRemoteUserUID": true,
|
||||
// Reap orphaned subprocesses from CLI workers and test runs.
|
||||
"init": true,
|
||||
// Keep the host folder/config path stable so existing volume IDs are reused.
|
||||
"workspaceMount": "source=gitnexus-source-${devcontainerId},target=/workspace,type=volume",
|
||||
// Disable the automatic workspace mount. Declare it in mounts below so the
|
||||
// Dev Containers CLI substitutes devcontainerId before passing it to Docker.
|
||||
"workspaceMount": "",
|
||||
"workspaceFolder": "/workspace",
|
||||
|
||||
// Existing writable config, session, dependency and cache volumes retain
|
||||
|
|
@ -50,6 +51,7 @@
|
|||
// Snapshot credentials seed missing files only; container logins persist.
|
||||
// Session volumes overlay config volumes so resetting config preserves history.
|
||||
"mounts": [
|
||||
"source=gitnexus-source-${devcontainerId},target=/workspace,type=volume",
|
||||
"source=claude-config-${devcontainerId},target=/home/node/.claude,type=volume",
|
||||
"source=codex-config-${devcontainerId},target=/home/node/.codex,type=volume",
|
||||
"source=cursor-config-${devcontainerId},target=/home/node/.cursor,type=volume",
|
||||
|
|
|
|||
|
|
@ -69,8 +69,8 @@ function profile(
|
|||
);
|
||||
result = replaceOnce(
|
||||
result,
|
||||
/"workspaceMount": "[^"\n]+"/,
|
||||
'"workspaceMount": "source=gitnexus-workspace-${devcontainerId},target=/workspace,type=volume"',
|
||||
/"source=gitnexus-source-\$\{devcontainerId\},target=\/workspace,type=volume"/,
|
||||
'"source=gitnexus-workspace-${devcontainerId},target=/workspace,type=volume"',
|
||||
);
|
||||
result = replaceOnce(
|
||||
result,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const parse = (text) => {
|
|||
return result.config;
|
||||
};
|
||||
|
||||
test('every runtime profile has only volume mounts and no 9p capability or hook', () => {
|
||||
test('runtime profiles use the substituted mounts list and disable the automatic workspace mount', () => {
|
||||
for (const text of [
|
||||
source,
|
||||
...[
|
||||
|
|
@ -23,10 +23,18 @@ test('every runtime profile has only volume mounts and no 9p capability or hook'
|
|||
{ native: true },
|
||||
{ ui: true, playwright: '1.63.0' },
|
||||
{ native: true, image: 'example/toolchain' },
|
||||
{ native: true, ui: true, playwright: '1.63.0' },
|
||||
{ ui: true, image: 'example/toolchain' },
|
||||
{ native: true, ui: true, image: 'example/toolchain' },
|
||||
].map((options) => profile(source, options)),
|
||||
]) {
|
||||
const config = parse(text);
|
||||
for (const mount of [config.workspaceMount, ...config.mounts]) {
|
||||
assert.equal(config.workspaceMount, '');
|
||||
assert.equal(
|
||||
config.mounts.filter((mount) => mount.split(',').includes('target=/workspace')).length,
|
||||
1,
|
||||
);
|
||||
for (const mount of config.mounts) {
|
||||
assert.match(mount, /(?:^|,)type=volume(?:,|$)/);
|
||||
assert.doesNotMatch(mount, /localEnv|type=bind|workspace-host/);
|
||||
}
|
||||
|
|
@ -44,9 +52,9 @@ test('default, UI and prebuilt profiles seed local work into a source volume', (
|
|||
profile(source, { image: 'example/toolchain' }),
|
||||
]) {
|
||||
const c = parse(text);
|
||||
assert.equal(
|
||||
c.workspaceMount,
|
||||
'source=gitnexus-source-${devcontainerId},target=/workspace,type=volume',
|
||||
assert.deepEqual(
|
||||
c.mounts.filter((mount) => mount.split(',').includes('target=/workspace')),
|
||||
['source=gitnexus-source-${devcontainerId},target=/workspace,type=volume'],
|
||||
);
|
||||
assert.equal(c.workspaceFolder, '/workspace');
|
||||
assert.equal(
|
||||
|
|
@ -66,11 +74,11 @@ test('native/UI profile inherits hooks, storage and defaults while changing work
|
|||
const c = parse(
|
||||
profile(source, { native: true, ui: true, playwright: '1.63.0', ref: 'feature/test' }),
|
||||
);
|
||||
assert.match(c.workspaceMount, /type=volume/);
|
||||
assert.equal(c.workspaceMount, '');
|
||||
assert.match(c.onCreateCommand, /bootstrap-native/);
|
||||
assert.equal(
|
||||
c.workspaceMount,
|
||||
'source=gitnexus-workspace-${devcontainerId},target=/workspace,type=volume',
|
||||
assert.deepEqual(
|
||||
c.mounts.filter((mount) => mount.split(',').includes('target=/workspace')),
|
||||
['source=gitnexus-workspace-${devcontainerId},target=/workspace,type=volume'],
|
||||
);
|
||||
assert.equal(
|
||||
c.mounts.some((m) => m.includes('target=/workspace-host,')),
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue