Skip to content

Commit db5ce2a

Browse files
committed
fix(docker) fix project-in-project duplication
1 parent 9d95c6e commit db5ce2a

6 files changed

Lines changed: 259 additions & 40 deletions

File tree

.github/workflows/build.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Publish E2B Templates
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ main, master ]
7+
paths:
8+
- 'sandbox/**/e2b.Dockerfile'
9+
- 'sandbox/**/e2b.toml'
10+
- 'sandbox/**/compile_page.sh'
11+
- 'sandbox/scripts/**'
12+
- 'sandbox/.github/workflows/publish.yml'
13+
14+
concurrency:
15+
group: publish-templates-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
publish:
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: 20
31+
32+
- name: Install E2B CLI
33+
run: npm i -g e2b
34+
35+
- name: Build & Publish All Templates
36+
env:
37+
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
38+
working-directory: sandbox
39+
run: |
40+
node node ./scripts/build-and-publish.mjs --mode build

.github/workflows/publish.yml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: Publish E2B Templates
2+
3+
on:
4+
workflow_dispatch:
5+
push:
6+
branches: [ main, master ]
7+
paths:
8+
- 'sandbox/**/e2b.Dockerfile'
9+
- 'sandbox/**/e2b.toml'
10+
- 'sandbox/**/compile_page.sh'
11+
- 'sandbox/scripts/**'
12+
- 'sandbox/.github/workflows/publish.yml'
13+
14+
concurrency:
15+
group: publish-templates-${{ github.ref }}
16+
cancel-in-progress: true
17+
18+
jobs:
19+
publish:
20+
runs-on: ubuntu-latest
21+
permissions:
22+
contents: read
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@v4
26+
27+
- name: Setup Node.js
28+
uses: actions/setup-node@v4
29+
with:
30+
node-version: 20
31+
32+
- name: Install E2B CLI
33+
run: npm i -g e2b
34+
35+
- name: Build & Publish All Templates
36+
env:
37+
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
38+
working-directory: sandbox
39+
run: |
40+
node node ./scripts/build-and-publish.mjs --mode publish

README.md

Lines changed: 102 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,128 @@
1-
# Sandbox templates
1+
# Code0 Sandbox Templates (standalone)
22

3-
This repo contains E2B sandbox templates used by the app to spin up ephemeral environments for each project.
3+
Standalone E2B sandbox templates used by the Code0 app to spin up ephemeral environments per project.
44

5-
## Structure
6-
- `nextjs/`
7-
- `e2b.Dockerfile` — Docker build for the template image
8-
- `e2b.toml` — Template metadata (team, name/ID, start command)
9-
- `compile_page.sh` — Start script executed inside the sandbox (path: `/compile_page.sh`)
5+
Once published, the app can create sandboxes in E2B Cloud (no local Docker required at runtime).
106

11-
## Requirements
12-
- E2B account + API key (E2B_API_KEY)
13-
- Docker Desktop (only needed to build/publish templates)
14-
- Node.js (to run the E2B CLI via npx or global install)
7+
## Templates
8+
- `nextjs-shadcn` — Next.js 15 + shadcn/ui baseline.
9+
- `nextjs-radixui` — Next.js 15 + Radix UI baseline.
1510

16-
Once a template is published, the app can create sandboxes from E2B Cloud without Docker running locally.
11+
Each template folder contains:
12+
- `e2b.Dockerfile` — how the template image is built.
13+
- `e2b.toml` — template metadata (team, name/ID, CPU/RAM, start command).
14+
- `compile_page.sh` — start script executed inside the sandbox at `/compile_page.sh`.
1715

18-
## Configure env (root .env)
19-
Set one of (ID is preferred):
16+
## Prerequisites
17+
- E2B account + API key (`E2B_API_KEY`).
18+
- E2B CLI (use `npx e2b@latest` or install globally with `npm i -g e2b`).
19+
- Docker Desktop (for building/publishing templates).
20+
- Node.js (to run scripts in this repo).
21+
22+
## Configure (env)
23+
Set your API key before building/publishing:
24+
25+
PowerShell
26+
```
27+
$env:E2B_API_KEY = "<your_e2b_api_key>"
28+
```
29+
30+
In the app that consumes templates, set one of (ID is preferred):
2031
- `E2B_TEMPLATE_ID=<template_id>`
2132
- or `E2B_TEMPLATE_NAME=<template_name>`
2233
- or `E2B_TEMPLATE=<template_name>`
23-
Also set `E2B_API_KEY=<your_key>`.
2434

25-
Sandbox names are derived from each project’s name automatically.
35+
Sandbox names are typically derived from each project’s name.
2636

27-
## Build & publish
28-
Windows PowerShell examples:
37+
## Build & publish (per template)
38+
PowerShell examples:
2939

30-
- Using npx (no install):
40+
Using npx (no global install):
3141
```
3242
$env:E2B_API_KEY = "<your_e2b_api_key>"
33-
cd sandbox\nextjs
43+
cd .\nextjs-shadcn\
44+
npx e2b@latest template build
45+
npx e2b@latest template publish
46+
47+
cd ..\nextjs-radixui\
3448
npx e2b@latest template build
35-
npx e2b@latest templates publish
49+
npx e2b@latest template publish
3650
```
3751

38-
- Or global install:
52+
Or with global CLI:
3953
```
4054
npm i -g e2b
4155
$env:E2B_API_KEY = "<your_e2b_api_key>"
42-
cd sandbox\nextjs
43-
e2b template build
44-
e2b templates publish
56+
cd .\nextjs-shadcn\ ; e2b template build ; e2b template publish
57+
cd ..\nextjs-radixui\ ; e2b template build ; e2b template publish
58+
```
59+
60+
After publishing, the CLI prints the `template_id`. Use that in your app `.env` as `E2B_TEMPLATE_ID`.
61+
62+
## Build & publish all templates (script)
63+
64+
This repo includes a helper script to build/publish every template under this folder:
65+
66+
```
67+
node ./scripts/build-and-publish.mjs # build + publish all
68+
node ./scripts/build-and-publish.mjs --mode build # build only
69+
node ./scripts/build-and-publish.mjs --mode publish # publish only
70+
```
71+
72+
Requirements: E2B CLI available on PATH (use `npx e2b@latest` or global `e2b`). On Windows, the script spawns with shell support.
73+
74+
## Resource configuration
75+
You can set CPU/RAM per template in `e2b.toml`:
76+
77+
```
78+
cpu_count = 8
79+
memory_mb = 8192
80+
```
81+
82+
Or override at build time:
83+
84+
```
85+
e2b template build --cpu-count 8 --memory-mb 8192
4586
```
46-
After publishing, copy the `template_id` from the CLI output and put it in `.env` as `E2B_TEMPLATE_ID`.
4787

4888
## Start command & script path
49-
- `e2b.toml`: `start_cmd = "/compile_page.sh"`
50-
- `e2b.Dockerfile` copies and makes it executable:
89+
- `e2b.toml` sets: `start_cmd = "/compile_page.sh"`
90+
- `e2b.Dockerfile` ensures the script exists and is executable:
5191
- `COPY compile_page.sh /compile_page.sh`
5292
- `RUN chmod +x /compile_page.sh`
53-
Update both if you rename or move the script.
93+
94+
Always use the absolute path (`/compile_page.sh`) and LF line endings inside the image.
95+
96+
## CI/CD (GitHub Actions example)
97+
```
98+
name: Publish E2B Templates
99+
on:
100+
workflow_dispatch:
101+
push:
102+
branches: [ main ]
103+
jobs:
104+
publish:
105+
runs-on: ubuntu-latest
106+
steps:
107+
- uses: actions/checkout@v4
108+
- uses: actions/setup-node@v4
109+
with:
110+
node-version: 20
111+
- name: Install E2B CLI
112+
run: npm i -g e2b
113+
- name: Build & Publish All Templates
114+
env:
115+
E2B_API_KEY: ${{ secrets.E2B_API_KEY }}
116+
run: |
117+
cd sandbox
118+
node ./scripts/build-and-publish.mjs
119+
```
54120

55121
## Troubleshooting
56-
- Docker daemon not running: start Docker Desktop; WSL2 & Linux containers enabled. Test with `docker version` and `docker run hello-world`.
57-
- Script not found / exit 127: ensure `start_cmd` uses the absolute path and the script has LF line endings on Windows.
58-
- Template 404: ensure the template exists in your E2B team and `.env` points to the correct ID/name.
122+
- Docker daemon not running: start Docker Desktop; WSL2 & Linux containers enabled. Verify with `docker version` and `docker run hello-world`.
123+
- Exit 127 / script not found: ensure `start_cmd` is absolute and the script has executable bit and LF line endings.
124+
- Template 404: ensure the template exists in the correct E2B team and you’re using the right `template_id` or name.
125+
- Nested app folder: both Dockerfiles build in `/tmp/app` and copy to `/home/user` to avoid `nextjs-app` nesting.
126+
127+
## Security & license
128+
See `SECURITY.md` and `LICENSE`.

nextjs-radixui/e2b.Dockerfile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ RUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/li
77
COPY compile_page.sh /compile_page.sh
88
RUN chmod +x /compile_page.sh
99

10-
# Install dependencies and customize sandbox
11-
WORKDIR /home/user/nextjs-app
10+
# Install dependencies and customize sandbox in a temp directory
11+
WORKDIR /tmp/app
1212

1313
# Create a fresh Next.js app (non-interactive)
1414
RUN npx --yes create-next-app@15.3.3 . --yes
@@ -42,5 +42,7 @@ RUN npm i --save \
4242
@radix-ui/react-toggle-group \
4343
@radix-ui/react-tooltip
4444

45-
# Move the Next.js app to the home directory and remove the temp directory
46-
RUN mv /home/user/nextjs-app/* /home/user/ && rm -rf /home/user/nextjs-app
45+
# Copy everything (including dotfiles) to /home/user and remove temp dir to avoid nesting
46+
RUN mkdir -p /home/user \
47+
&& cp -a /tmp/app/. /home/user/ \
48+
&& rm -rf /tmp/app

nextjs-shadcn/e2b.Dockerfile

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ RUN apt-get update && apt-get install -y curl && apt-get clean && rm -rf /var/li
77
COPY compile_page.sh /compile_page.sh
88
RUN chmod +x /compile_page.sh
99

10-
# Install dependencies and customize sandbox
11-
WORKDIR /home/user/nextjs-app
10+
# Install dependencies and customize sandbox in a temp directory
11+
WORKDIR /tmp/app
1212

1313
RUN npx --yes create-next-app@15.3.3 . --yes
1414

1515
RUN npx --yes shadcn@2.6.3 init --yes -b neutral --force
1616
RUN npx --yes shadcn@2.6.3 add --all --yes
1717

18-
# Move the Nextjs app to the home directory and remove the nextjs-app directory
19-
RUN mv /home/user/nextjs-app/* /home/user/ && rm -rf /home/user/nextjs-app
18+
# Copy everything (including dotfiles) to /home/user and remove temp dir to avoid nesting
19+
RUN mkdir -p /home/user \
20+
&& cp -a /tmp/app/. /home/user/ \
21+
&& rm -rf /tmp/app

scripts/build-and-publish.mjs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#!/usr/bin/env node
2+
import { readdirSync, statSync } from 'node:fs';
3+
import { join } from 'node:path';
4+
import { spawn } from 'node:child_process';
5+
6+
function run(cmd, args, cwd) {
7+
return new Promise((resolve, reject) => {
8+
const child = spawn(cmd, args, { cwd, stdio: 'inherit', shell: process.platform === 'win32' });
9+
child.on('close', (code) => {
10+
if (code === 0) resolve();
11+
else reject(new Error(`${cmd} ${args.join(' ')} exited with ${code}`));
12+
});
13+
});
14+
}
15+
16+
function findTemplates(root) {
17+
const entries = readdirSync(root, { withFileTypes: true });
18+
return entries
19+
.filter((e) => e.isDirectory())
20+
.map((e) => join(root, e.name))
21+
.filter((p) => {
22+
try {
23+
const dockerfile = statSync(join(p, 'e2b.Dockerfile'));
24+
const toml = statSync(join(p, 'e2b.toml'));
25+
return dockerfile.isFile() && toml.isFile();
26+
} catch {
27+
return false;
28+
}
29+
});
30+
}
31+
32+
async function main() {
33+
const args = process.argv.slice(2);
34+
const modeIdx = args.indexOf('--mode');
35+
const mode = modeIdx >= 0 ? (args[modeIdx + 1] || '').toLowerCase() : '';
36+
37+
const root = join(process.cwd());
38+
const sandboxDir = join(root, 'sandbox');
39+
const templates = findTemplates(sandboxDir);
40+
if (templates.length === 0) {
41+
console.error('No templates found in sandbox/*');
42+
process.exit(1);
43+
}
44+
45+
console.log(`Found ${templates.length} template(s):`);
46+
for (const t of templates) console.log('-', t);
47+
48+
for (const t of templates) {
49+
if (!mode || mode === 'build' || mode === 'all') {
50+
console.log(`\n=== Building: ${t} ===`);
51+
await run('e2b', ['template', 'build'], t);
52+
}
53+
if (!mode || mode === 'publish' || mode === 'all' || mode === '') {
54+
console.log(`\n=== Publishing: ${t} ===`);
55+
await run('e2b', ['template', 'publish'], t);
56+
}
57+
}
58+
59+
console.log('\nDone.');
60+
}
61+
62+
main().catch((err) => {
63+
console.error(err);
64+
process.exit(1);
65+
});

0 commit comments

Comments
 (0)