Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/git-clone-depth-option.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@upstash/box": patch
---

adds depth option to git.clone for shallow clones
3 changes: 3 additions & 0 deletions packages/python-sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ All notable changes to `upstash-box` (Python) are documented here.

## Unreleased

- `git.clone(depth=...)` — shallow clone support (`git clone --depth N`).
`depth=1` fetches only the latest commit; omitting it keeps the current
full-clone behavior. Mirrors `depth` in `@upstash/box` `git.clone`.
- Add Claude Opus 5 model constants for Claude Code, OpenRouter, Vercel AI
Gateway, OpenCode/Zen, and Cursor, mirroring `@upstash/box`.
- `schedule.update(id, ...)` — partial schedule updates (PATCH). Omitted
Expand Down
1 change: 1 addition & 0 deletions packages/python-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ await box.files.download(folder="output/")

```python
await box.git.clone(repo="https://github.com/user/repo", branch="main")
await box.git.clone(repo="https://github.com/user/repo", depth=1) # shallow clone
diff = await box.git.diff()
await box.git.commit(message="feat: add feature")
await box.git.push(branch="main")
Expand Down
11 changes: 11 additions & 0 deletions packages/python-sdk/tests/_async/test_box_git.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ async def test_clone_includes_git_token():
assert body["repo"] == "https://github.com/u/r"
assert body["branch"] == "main"
assert body["github_token"] == "ght"
assert "depth" not in body
await box.aclose()


@respx.mock
async def test_clone_with_depth():
box = await make_async_box(respx.mock)
route = respx.post(f"{BASE}/git/clone").mock(return_value=httpx.Response(200, json={}))
await box.git.clone(repo="https://github.com/u/r", depth=1)
body = last_json_body(route)
assert body["depth"] == 1
await box.aclose()


Expand Down
10 changes: 7 additions & 3 deletions packages/python-sdk/upstash_box/_async/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,10 @@ class AsyncGitNamespace:
def __init__(self, box: "AsyncBox") -> None:
self._box = box

async def clone(self, *, repo: str, branch: Optional[str] = None) -> None:
await self._box._git_clone(repo, branch)
async def clone(
self, *, repo: str, branch: Optional[str] = None, depth: Optional[int] = None
) -> None:
await self._box._git_clone(repo, branch, depth)

async def diff(self) -> str:
return await self._box._git_diff()
Expand Down Expand Up @@ -1522,9 +1524,11 @@ async def _schedule_delete(self, id: str) -> None:

# ==================== Git ====================

async def _git_clone(self, repo, branch) -> None:
async def _git_clone(self, repo, branch, depth) -> None:
folder = self._get_folder()
body: Dict[str, Any] = {"repo": repo, "branch": branch, "github_token": self._git_token}
if depth is not None:
body["depth"] = depth
if folder:
body["folder"] = folder
await self._request("POST", f"/v2/box/{self.id}/git/clone", body=body)
Expand Down
10 changes: 7 additions & 3 deletions packages/python-sdk/upstash_box/_sync/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,8 +314,10 @@ class GitNamespace:
def __init__(self, box: "Box") -> None:
self._box = box

def clone(self, *, repo: str, branch: Optional[str] = None) -> None:
self._box._git_clone(repo, branch)
def clone(
self, *, repo: str, branch: Optional[str] = None, depth: Optional[int] = None
) -> None:
self._box._git_clone(repo, branch, depth)

def diff(self) -> str:
return self._box._git_diff()
Expand Down Expand Up @@ -1507,9 +1509,11 @@ def _schedule_delete(self, id: str) -> None:

# ==================== Git ====================

def _git_clone(self, repo, branch) -> None:
def _git_clone(self, repo, branch, depth) -> None:
folder = self._get_folder()
body: Dict[str, Any] = {"repo": repo, "branch": branch, "github_token": self._git_token}
if depth is not None:
body["depth"] = depth
if folder:
body["folder"] = folder
self._request("POST", f"/v2/box/{self.id}/git/clone", body=body)
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ await box.files.download({ folder: "output/" });

```ts
await box.git.clone({ repo: "https://github.com/user/repo", branch: "main" });
await box.git.clone({ repo: "https://github.com/user/repo", depth: 1 }); // shallow clone
const diff = await box.git.diff();
const status = await box.git.status();
await box.git.commit({
Expand Down
20 changes: 20 additions & 0 deletions packages/sdk/src/__tests__/box-git.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,26 @@ describe("Box git operations", () => {
const body = JSON.parse(fetchMock.mock.calls[1]![1]?.body as string);
expect(body.branch).toBe("dev");
});

it("clones a repo with depth", async () => {
const { box, fetchMock } = await createTestBox();
fetchMock.mockResolvedValueOnce(mockResponse({}));

await box.git.clone({ repo: "owner/repo", depth: 1 });

const body = JSON.parse(fetchMock.mock.calls[1]![1]?.body as string);
expect(body.depth).toBe(1);
});

it("omits depth when not provided", async () => {
const { box, fetchMock } = await createTestBox();
fetchMock.mockResolvedValueOnce(mockResponse({}));

await box.git.clone({ repo: "owner/repo" });

const body = JSON.parse(fetchMock.mock.calls[1]![1]?.body as string);
expect(body).not.toHaveProperty("depth");
});
});

describe("git.diff", () => {
Expand Down
1 change: 1 addition & 0 deletions packages/sdk/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2670,6 +2670,7 @@ export class Box<TProvider = unknown> {
body: {
repo: options.repo,
branch: options.branch,
depth: options.depth,
github_token: this._gitToken,
...(folder ? { folder } : {}),
},
Expand Down
2 changes: 2 additions & 0 deletions packages/sdk/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -902,6 +902,8 @@ export interface FileEntry {
export interface GitCloneOptions {
repo: string;
branch?: string;
/** History depth (git clone --depth N); depth: 1 = shallow clone. Omit for a full clone. */
depth?: number;
}

export interface GitExecOptions {
Expand Down
2 changes: 2 additions & 0 deletions skills/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ await box.cd("/workspace/home/other") // absolute path

```ts
await box.git.clone({ repo: "github.com/org/repo", branch: "main" })
// large repo? depth: 1 fetches only the latest commit
await box.git.clone({ repo: "github.com/org/repo", depth: 1 })
await box.cd("repo") // cd into cloned repo

const status = await box.git.status()
Expand Down
Loading