@hanzo/runtime 0.0.0-dev

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/Git.ts ADDED
@@ -0,0 +1,303 @@
1
+ /*
2
+ * Copyright 2025 Daytona Platforms Inc.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+
6
+ import { ToolboxApi, ListBranchResponse, GitStatus } from '@daytonaio/api-client'
7
+ import { prefixRelativePath } from './utils/Path'
8
+
9
+ /**
10
+ * Response from the git commit.
11
+ *
12
+ * @interface
13
+ * @property {string} sha - The SHA of the commit
14
+ */
15
+ export interface GitCommitResponse {
16
+ sha: string
17
+ }
18
+
19
+ /**
20
+ * Provides Git operations within a Sandbox.
21
+ *
22
+ * @class
23
+ */
24
+ export class Git {
25
+ constructor(
26
+ private readonly sandboxId: string,
27
+ private readonly toolboxApi: ToolboxApi,
28
+ private readonly getRootDir: () => Promise<string>,
29
+ ) {}
30
+
31
+ /**
32
+ * Stages the specified files for the next commit, similar to
33
+ * running 'git add' on the command line.
34
+ *
35
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
36
+ * root directory.
37
+ * @param {string[]} files - List of file paths or directories to stage, relative to the repository root
38
+ * @returns {Promise<void>}
39
+ *
40
+ * @example
41
+ * // Stage a single file
42
+ * await git.add('workspace/repo', ['file.txt']);
43
+ *
44
+ * @example
45
+ * // Stage whole repository
46
+ * await git.add('workspace/repo', ['.']);
47
+ */
48
+ public async add(path: string, files: string[]): Promise<void> {
49
+ await this.toolboxApi.gitAddFiles(this.sandboxId, {
50
+ path: prefixRelativePath(await this.getRootDir(), path),
51
+ files,
52
+ })
53
+ }
54
+
55
+ /**
56
+ * List branches in the repository.
57
+ *
58
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
59
+ * root directory.
60
+ * @returns {Promise<ListBranchResponse>} List of branches in the repository
61
+ *
62
+ * @example
63
+ * const response = await git.branches('workspace/repo');
64
+ * console.log(`Branches: ${response.branches}`);
65
+ */
66
+ public async branches(path: string): Promise<ListBranchResponse> {
67
+ const response = await this.toolboxApi.gitListBranches(
68
+ this.sandboxId,
69
+ prefixRelativePath(await this.getRootDir(), path),
70
+ )
71
+ return response.data
72
+ }
73
+
74
+ /**
75
+ * Create branche in the repository.
76
+ *
77
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
78
+ * root directory.
79
+ * @param {string} name - Name of the new branch to create
80
+ * @returns {Promise<void>}
81
+ *
82
+ * @example
83
+ * await git.createBranch('workspace/repo', 'new-feature');
84
+ */
85
+ public async createBranch(path: string, name: string): Promise<void> {
86
+ await this.toolboxApi.gitCreateBranch(this.sandboxId, {
87
+ path: prefixRelativePath(await this.getRootDir(), path),
88
+ name,
89
+ })
90
+ return
91
+ }
92
+
93
+ /**
94
+ * Delete branche in the repository.
95
+ *
96
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
97
+ * root directory.
98
+ * @param {string} name - Name of the branch to delete
99
+ * @returns {Promise<void>}
100
+ *
101
+ * @example
102
+ * await git.deleteBranch('workspace/repo', 'new-feature');
103
+ */
104
+ public async deleteBranch(path: string, name: string): Promise<void> {
105
+ await this.toolboxApi.gitDeleteBranch(this.sandboxId, {
106
+ path: prefixRelativePath(await this.getRootDir(), path),
107
+ name,
108
+ })
109
+ return
110
+ }
111
+
112
+ /**
113
+ * Checkout branche in the repository.
114
+ *
115
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
116
+ * root directory.
117
+ * @param {string} branch - Name of the branch to checkout
118
+ * @returns {Promise<void>}
119
+ *
120
+ * @example
121
+ * await git.checkoutBranch('workspace/repo', 'new-feature');
122
+ */
123
+ public async checkoutBranch(path: string, branch: string): Promise<void> {
124
+ await this.toolboxApi.gitCheckoutBranch(this.sandboxId, {
125
+ path: prefixRelativePath(await this.getRootDir(), path),
126
+ branch,
127
+ })
128
+ return
129
+ }
130
+
131
+ /**
132
+ * Clones a Git repository into the specified path. It supports
133
+ * cloning specific branches or commits, and can authenticate with the remote
134
+ * repository if credentials are provided.
135
+ *
136
+ * @param {string} url - Repository URL to clone from
137
+ * @param {string} path - Path where the repository should be cloned. Relative paths are resolved based on the user's
138
+ * root directory.
139
+ * @param {string} [branch] - Specific branch to clone. If not specified, clones the default branch
140
+ * @param {string} [commitId] - Specific commit to clone. If specified, the repository will be left in a detached HEAD state at this commit
141
+ * @param {string} [username] - Git username for authentication
142
+ * @param {string} [password] - Git password or token for authentication
143
+ * @returns {Promise<void>}
144
+ *
145
+ * @example
146
+ * // Clone the default branch
147
+ * await git.clone(
148
+ * 'https://github.com/user/repo.git',
149
+ * 'workspace/repo'
150
+ * );
151
+ *
152
+ * @example
153
+ * // Clone a specific branch with authentication
154
+ * await git.clone(
155
+ * 'https://github.com/user/private-repo.git',
156
+ * 'workspace/private',
157
+ * branch='develop',
158
+ * username='user',
159
+ * password='token'
160
+ * );
161
+ *
162
+ * @example
163
+ * // Clone a specific commit
164
+ * await git.clone(
165
+ * 'https://github.com/user/repo.git',
166
+ * 'workspace/repo-old',
167
+ * commitId='abc123'
168
+ * );
169
+ */
170
+ public async clone(
171
+ url: string,
172
+ path: string,
173
+ branch?: string,
174
+ commitId?: string,
175
+ username?: string,
176
+ password?: string,
177
+ ): Promise<void> {
178
+ await this.toolboxApi.gitCloneRepository(this.sandboxId, {
179
+ url: url,
180
+ branch: branch,
181
+ path: prefixRelativePath(await this.getRootDir(), path),
182
+ username,
183
+ password,
184
+ commit_id: commitId,
185
+ })
186
+ }
187
+
188
+ /**
189
+ * Commits staged changes.
190
+ *
191
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
192
+ * root directory.
193
+ * @param {string} message - Commit message describing the changes
194
+ * @param {string} author - Name of the commit author
195
+ * @param {string} email - Email address of the commit author
196
+ * @returns {Promise<void>}
197
+ *
198
+ * @example
199
+ * // Stage and commit changes
200
+ * await git.add('workspace/repo', ['README.md']);
201
+ * await git.commit(
202
+ * 'workspace/repo',
203
+ * 'Update documentation',
204
+ * 'John Doe',
205
+ * 'john@example.com'
206
+ * );
207
+ */
208
+ public async commit(path: string, message: string, author: string, email: string): Promise<GitCommitResponse> {
209
+ const response = await this.toolboxApi.gitCommitChanges(this.sandboxId, {
210
+ path: prefixRelativePath(await this.getRootDir(), path),
211
+ message,
212
+ author,
213
+ email,
214
+ })
215
+ return {
216
+ sha: response.data.hash,
217
+ }
218
+ }
219
+
220
+ /**
221
+ * Push local changes to the remote repository.
222
+ *
223
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
224
+ * root directory.
225
+ * @param {string} [username] - Git username for authentication
226
+ * @param {string} [password] - Git password or token for authentication
227
+ * @returns {Promise<void>}
228
+ *
229
+ * @example
230
+ * // Push to a public repository
231
+ * await git.push('workspace/repo');
232
+ *
233
+ * @example
234
+ * // Push to a private repository
235
+ * await git.push(
236
+ * 'workspace/repo',
237
+ * 'user',
238
+ * 'token'
239
+ * );
240
+ */
241
+ public async push(path: string, username?: string, password?: string): Promise<void> {
242
+ await this.toolboxApi.gitPushChanges(this.sandboxId, {
243
+ path: prefixRelativePath(await this.getRootDir(), path),
244
+ username,
245
+ password,
246
+ })
247
+ }
248
+
249
+ /**
250
+ * Pulls changes from the remote repository.
251
+ *
252
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
253
+ * root directory.
254
+ * @param {string} [username] - Git username for authentication
255
+ * @param {string} [password] - Git password or token for authentication
256
+ * @returns {Promise<void>}
257
+ *
258
+ * @example
259
+ * // Pull from a public repository
260
+ * await git.pull('workspace/repo');
261
+ *
262
+ * @example
263
+ * // Pull from a private repository
264
+ * await git.pull(
265
+ * 'workspace/repo',
266
+ * 'user',
267
+ * 'token'
268
+ * );
269
+ */
270
+ public async pull(path: string, username?: string, password?: string): Promise<void> {
271
+ await this.toolboxApi.gitPullChanges(this.sandboxId, {
272
+ path: prefixRelativePath(await this.getRootDir(), path),
273
+ username,
274
+ password,
275
+ })
276
+ }
277
+
278
+ /**
279
+ * Gets the current status of the Git repository.
280
+ *
281
+ * @param {string} path - Path to the Git repository root. Relative paths are resolved based on the user's
282
+ * root directory.
283
+ * @returns {Promise<GitStatus>} Current repository status including:
284
+ * - currentBranch: Name of the current branch
285
+ * - ahead: Number of commits ahead of the remote branch
286
+ * - behind: Number of commits behind the remote branch
287
+ * - branchPublished: Whether the branch has been published to the remote repository
288
+ * - fileStatus: List of file statuses
289
+ *
290
+ * @example
291
+ * const status = await sandbox.git.status('workspace/repo');
292
+ * console.log(`Current branch: ${status.currentBranch}`);
293
+ * console.log(`Commits ahead: ${status.ahead}`);
294
+ * console.log(`Commits behind: ${status.behind}`);
295
+ */
296
+ public async status(path: string): Promise<GitStatus> {
297
+ const response = await this.toolboxApi.gitGetStatus(
298
+ this.sandboxId,
299
+ prefixRelativePath(await this.getRootDir(), path),
300
+ )
301
+ return response.data
302
+ }
303
+ }