Repository navigation
feat(cli): show the project ID in sandbox, snapshot and template lists #2106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| '@e2b/cli': patch | ||
| --- | ||
|
|
||
| `e2b sandbox list`, `e2b sandbox snapshot list` and `e2b template list` show the `prj_` ID of the project they list, as a `Project ID` column and as `projectId` (`projectID` for templates) in `--format json`. With `E2B_API_KEY`, where the key decides the project, it is left out. |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,7 +1,7 @@ | ||||||
| import * as commander from '@commander-js/extra-typings' | ||||||
| import { NotFoundError, Sandbox, SnapshotInfo } from 'e2b' | ||||||
|
|
||||||
| import { ensureAuth } from 'src/api' | ||||||
| import { ensureAuth, projectIdOf } from 'src/api' | ||||||
| import { Format, parseFormat } from 'src/options' | ||||||
| import { integer, zodParser } from 'src/validation' | ||||||
| import { asBold } from 'src/utils/format' | ||||||
|
|
@@ -67,6 +67,7 @@ const listSnapshotsCommand = new commander.Command('list') | |||||
| .action(async (sandboxID, options) => { | ||||||
| try { | ||||||
| const auth = await ensureAuth() | ||||||
| const projectId = projectIdOf(auth) | ||||||
| const limit = | ||||||
| options.limit === 0 ? undefined : (options.limit ?? DEFAULT_LIMIT) | ||||||
|
|
||||||
|
|
@@ -93,14 +94,22 @@ const listSnapshotsCommand = new commander.Command('list') | |||||
| paginator.hasNext || (limit ? allSnapshots.length > limit : false) | ||||||
|
|
||||||
| if (options.format === Format.PRETTY) { | ||||||
| renderSnapshotTable(snapshots) | ||||||
| renderSnapshotTable(snapshots, projectId) | ||||||
| if (hasMore) { | ||||||
| console.log( | ||||||
| `Showing first ${limit} snapshots. Use --limit to change.` | ||||||
| ) | ||||||
| } | ||||||
| } else { | ||||||
| console.log(JSON.stringify(snapshots, null, 2)) | ||||||
| console.log( | ||||||
| JSON.stringify( | ||||||
| snapshots.map((snapshot) => | ||||||
| projectId ? { ...snapshot, projectId } : snapshot | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. T-12 — same issue as in
Suggested change
|
||||||
| ), | ||||||
| null, | ||||||
| 2 | ||||||
| ) | ||||||
| ) | ||||||
| } | ||||||
| } catch (err: any) { | ||||||
| console.error(err) | ||||||
|
|
@@ -153,7 +162,7 @@ export const snapshotCommand = new commander.Command('snapshot') | |||||
| .addCommand(listSnapshotsCommand) | ||||||
| .addCommand(deleteSnapshotCommand) | ||||||
|
|
||||||
| function renderSnapshotTable(snapshots: SnapshotInfo[]) { | ||||||
| function renderSnapshotTable(snapshots: SnapshotInfo[], projectId?: string) { | ||||||
| if (!snapshots?.length) { | ||||||
| console.log('No snapshots found') | ||||||
| return | ||||||
|
|
@@ -165,6 +174,8 @@ function renderSnapshotTable(snapshots: SnapshotInfo[]) { | |||||
| header: 'Names', | ||||||
| value: (snapshot) => snapshot.names.map(stripControlChars).join(', '), | ||||||
| }, | ||||||
| // Omitted with E2B_API_KEY, where the CLI doesn't know the key's project. | ||||||
| ...(projectId ? [{ header: 'Project ID', value: () => projectId }] : []), | ||||||
| ]) | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -218,3 +218,22 @@ export async function pickProject( | |
| default: entries.find(({ project }) => project.id === selectedId), | ||
| }) | ||
| } | ||
|
|
||
| const TYPEID_ALPHABET = '0123456789abcdefghjkmnpqrstvwxyz' | ||
|
|
||
| /** | ||
| * The `prj_` public ID of a project UUID: the TypeID encoding workspace-api | ||
| * uses for `public_id`, computed locally so lists don't need `/v1/me`. | ||
| * Anything that isn't a UUID is returned as is. | ||
| */ | ||
| export function publicProjectId(id: string): string { | ||
| const hex = id.replace(/-/g, '') | ||
| if (!/^[0-9a-f]{32}$/i.test(hex)) return id | ||
|
Comment on lines
+225
to
+231
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. T-52 — the backend is the source of truth, and client code must not copy backend business rules ("a duplicated rule drifts from the server's the moment the API changes"). This re-implements workspace-api's The fallback makes this worse. Any Compliant form: take |
||
|
|
||
| const value = BigInt(`0x${hex}`) | ||
| let suffix = '' | ||
| for (let i = 25; i >= 0; i--) { | ||
| suffix += TYPEID_ALPHABET[Number((value >> BigInt(5 * i)) & 31n)] | ||
| } | ||
| return `prj_${suffix}` | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
T-12 — abbreviations keep their casing in identifiers:
ID, notId. This PR adds the same new JSON key in three places and spells it two ways —projectIdhere and insandbox snapshot list, butprojectIDintemplate list. Sojq '.[].projectID'works on one list and silently returnsnullon the other two. Use the T-12 spelling, whichtemplate listalready uses, everywhere. It's a new key, so it doesn't matter that the neighbouringsandboxIdpredates the rule: