From e0f9abcac361f8255eb7609c01b0e5d15d23ef6a Mon Sep 17 00:00:00 2001 From: Vedran Date: Thu, 26 Dec 2024 15:01:34 +0100 Subject: [PATCH] =?UTF-8?q?=E2=89=88feat:=20git=20checkout=20command?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Vedran --- pkg/agent/toolbox/git/checkout.go | 28 +++ pkg/agent/toolbox/git/types.go | 5 + pkg/agent/toolbox/toolbox.go | 1 + pkg/api/controllers/workspace/toolbox/git.go | 17 ++ pkg/api/docs/docs.go | 58 ++++++ pkg/api/docs/swagger.json | 58 ++++++ pkg/api/docs/swagger.yaml | 39 ++++ pkg/api/server.go | 1 + pkg/apiclient/README.md | 2 + pkg/apiclient/api/openapi.yaml | 45 +++++ pkg/apiclient/api_workspace_toolbox.go | 122 ++++++++++++ pkg/apiclient/docs/GitCheckoutRequest.md | 72 ++++++++ pkg/apiclient/docs/WorkspaceToolboxAPI.md | 74 ++++++++ pkg/apiclient/model_git_checkout_request.go | 184 +++++++++++++++++++ pkg/git/checkout.go | 40 ++++ 15 files changed, 746 insertions(+) create mode 100644 pkg/agent/toolbox/git/checkout.go create mode 100644 pkg/apiclient/docs/GitCheckoutRequest.md create mode 100644 pkg/apiclient/model_git_checkout_request.go create mode 100644 pkg/git/checkout.go diff --git a/pkg/agent/toolbox/git/checkout.go b/pkg/agent/toolbox/git/checkout.go new file mode 100644 index 0000000000..25115f3627 --- /dev/null +++ b/pkg/agent/toolbox/git/checkout.go @@ -0,0 +1,28 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package git + +import ( + "github.com/daytonaio/daytona/pkg/git" + "github.com/gin-gonic/gin" +) + +func CheckoutBranch(c *gin.Context) { + var req GitCheckoutRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.AbortWithError(400, err) + return + } + + gitService := git.Service{ + ProjectDir: req.Path, + } + + if err := gitService.Checkout(req.Branch); err != nil { + c.AbortWithError(400, err) + return + } + + c.Status(200) +} diff --git a/pkg/agent/toolbox/git/types.go b/pkg/agent/toolbox/git/types.go index 8974f5102c..1dc7bf4a0c 100644 --- a/pkg/agent/toolbox/git/types.go +++ b/pkg/agent/toolbox/git/types.go @@ -43,3 +43,8 @@ type GitRepoRequest struct { Username *string `json:"username,omitempty" validate:"optional"` Password *string `json:"password,omitempty" validate:"optional"` } // @name GitRepoRequest + +type GitCheckoutRequest struct { + Path string `json:"path" validate:"required"` + Branch string `json:"branch" validate:"required"` +} // @name GitCheckoutRequest diff --git a/pkg/agent/toolbox/toolbox.go b/pkg/agent/toolbox/toolbox.go index eea5034254..ee7cd9fc2d 100644 --- a/pkg/agent/toolbox/toolbox.go +++ b/pkg/agent/toolbox/toolbox.go @@ -76,6 +76,7 @@ func (s *Server) Start() error { gitController.POST("/add", git.AddFiles) gitController.POST("/branches", git.CreateBranch) + gitController.POST("/checkout", git.CheckoutBranch) gitController.POST("/clone", git.CloneRepository) gitController.POST("/commit", git.CommitChanges) gitController.POST("/pull", git.PullChanges) diff --git a/pkg/api/controllers/workspace/toolbox/git.go b/pkg/api/controllers/workspace/toolbox/git.go index ac25efb75a..9f009b69eb 100644 --- a/pkg/api/controllers/workspace/toolbox/git.go +++ b/pkg/api/controllers/workspace/toolbox/git.go @@ -157,3 +157,20 @@ func GitPushChanges(ctx *gin.Context) { func GitStatus(ctx *gin.Context) { forwardRequestToToolbox(ctx) } + +// GitCheckoutBranch godoc +// +// @Tags workspace toolbox +// @Summary Checkout branch +// @Description Checkout branch or commit in git repository inside workspace project +// @Produce json +// @Param workspaceId path string true "Workspace ID or Name" +// @Param projectId path string true "Project ID" +// @Param params body GitCheckoutRequest true "GitCheckoutRequest" +// @Success 200 +// @Router /workspace/{workspaceId}/{projectId}/toolbox/git/checkout [post] +// +// @id GitCheckoutBranch +func GitCheckoutBranch(ctx *gin.Context) { + forwardRequestToToolbox(ctx) +} diff --git a/pkg/api/docs/docs.go b/pkg/api/docs/docs.go index 44d631a92e..e2853a6b5c 100644 --- a/pkg/api/docs/docs.go +++ b/pkg/api/docs/docs.go @@ -2539,6 +2539,49 @@ const docTemplate = `{ } } }, + "/workspace/{workspaceId}/{projectId}/toolbox/git/checkout": { + "post": { + "description": "Checkout branch or commit in git repository inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Checkout branch", + "operationId": "GitCheckoutBranch", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project ID", + "name": "projectId", + "in": "path", + "required": true + }, + { + "description": "GitCheckoutRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCheckoutRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/workspace/{workspaceId}/{projectId}/toolbox/git/clone": { "post": { "description": "Clone git repository inside workspace project", @@ -3812,6 +3855,21 @@ const docTemplate = `{ } } }, + "GitCheckoutRequest": { + "type": "object", + "required": [ + "branch", + "path" + ], + "properties": { + "branch": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, "GitCloneRequest": { "type": "object", "required": [ diff --git a/pkg/api/docs/swagger.json b/pkg/api/docs/swagger.json index 6e51e598a5..328d0eb6fb 100644 --- a/pkg/api/docs/swagger.json +++ b/pkg/api/docs/swagger.json @@ -2536,6 +2536,49 @@ } } }, + "/workspace/{workspaceId}/{projectId}/toolbox/git/checkout": { + "post": { + "description": "Checkout branch or commit in git repository inside workspace project", + "produces": [ + "application/json" + ], + "tags": [ + "workspace toolbox" + ], + "summary": "Checkout branch", + "operationId": "GitCheckoutBranch", + "parameters": [ + { + "type": "string", + "description": "Workspace ID or Name", + "name": "workspaceId", + "in": "path", + "required": true + }, + { + "type": "string", + "description": "Project ID", + "name": "projectId", + "in": "path", + "required": true + }, + { + "description": "GitCheckoutRequest", + "name": "params", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/GitCheckoutRequest" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + } + } + }, "/workspace/{workspaceId}/{projectId}/toolbox/git/clone": { "post": { "description": "Clone git repository inside workspace project", @@ -3809,6 +3852,21 @@ } } }, + "GitCheckoutRequest": { + "type": "object", + "required": [ + "branch", + "path" + ], + "properties": { + "branch": { + "type": "string" + }, + "path": { + "type": "string" + } + } + }, "GitCloneRequest": { "type": "object", "required": [ diff --git a/pkg/api/docs/swagger.yaml b/pkg/api/docs/swagger.yaml index 60cb3e0d7d..4cf3601011 100644 --- a/pkg/api/docs/swagger.yaml +++ b/pkg/api/docs/swagger.yaml @@ -395,6 +395,16 @@ definitions: - name - path type: object + GitCheckoutRequest: + properties: + branch: + type: string + path: + type: string + required: + - branch + - path + type: object GitCloneRequest: properties: branch: @@ -2910,6 +2920,35 @@ paths: summary: Create branch tags: - workspace toolbox + /workspace/{workspaceId}/{projectId}/toolbox/git/checkout: + post: + description: Checkout branch or commit in git repository inside workspace project + operationId: GitCheckoutBranch + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + type: string + - description: Project ID + in: path + name: projectId + required: true + type: string + - description: GitCheckoutRequest + in: body + name: params + required: true + schema: + $ref: '#/definitions/GitCheckoutRequest' + produces: + - application/json + responses: + "200": + description: OK + summary: Checkout branch + tags: + - workspace toolbox /workspace/{workspaceId}/{projectId}/toolbox/git/clone: post: description: Clone git repository inside workspace project diff --git a/pkg/api/server.go b/pkg/api/server.go index 12e704c175..e16bc9dcbb 100644 --- a/pkg/api/server.go +++ b/pkg/api/server.go @@ -182,6 +182,7 @@ func (a *ApiServer) Start() error { gitController.POST("/add", toolbox.GitAddFiles) gitController.POST("/branches", toolbox.GitCreateBranch) + gitController.POST("/checkout", toolbox.GitCheckoutBranch) gitController.POST("/clone", toolbox.GitCloneRepository) gitController.POST("/commit", toolbox.GitCommitChanges) gitController.POST("/pull", toolbox.GitPushChanges) diff --git a/pkg/apiclient/README.md b/pkg/apiclient/README.md index 89c62c7984..f441fb2528 100644 --- a/pkg/apiclient/README.md +++ b/pkg/apiclient/README.md @@ -155,6 +155,7 @@ Class | Method | HTTP request | Description *WorkspaceToolboxAPI* | [**GetProjectDir**](docs/WorkspaceToolboxAPI.md#getprojectdir) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/project-dir | Get project dir *WorkspaceToolboxAPI* | [**GitAddFiles**](docs/WorkspaceToolboxAPI.md#gitaddfiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/add | Add files *WorkspaceToolboxAPI* | [**GitBranchList**](docs/WorkspaceToolboxAPI.md#gitbranchlist) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Get branch list +*WorkspaceToolboxAPI* | [**GitCheckoutBranch**](docs/WorkspaceToolboxAPI.md#gitcheckoutbranch) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/checkout | Checkout branch *WorkspaceToolboxAPI* | [**GitCloneRepository**](docs/WorkspaceToolboxAPI.md#gitclonerepository) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/clone | Clone git repository *WorkspaceToolboxAPI* | [**GitCommitChanges**](docs/WorkspaceToolboxAPI.md#gitcommitchanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/commit | Commit changes *WorkspaceToolboxAPI* | [**GitCommitHistory**](docs/WorkspaceToolboxAPI.md#gitcommithistory) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/history | Get commit history @@ -203,6 +204,7 @@ Class | Method | HTTP request | Description - [GitAddRequest](docs/GitAddRequest.md) - [GitBranch](docs/GitBranch.md) - [GitBranchRequest](docs/GitBranchRequest.md) + - [GitCheckoutRequest](docs/GitCheckoutRequest.md) - [GitCloneRequest](docs/GitCloneRequest.md) - [GitCommitInfo](docs/GitCommitInfo.md) - [GitCommitRequest](docs/GitCommitRequest.md) diff --git a/pkg/apiclient/api/openapi.yaml b/pkg/apiclient/api/openapi.yaml index 3f72addbd7..2a9eb01ac5 100644 --- a/pkg/apiclient/api/openapi.yaml +++ b/pkg/apiclient/api/openapi.yaml @@ -1845,6 +1845,38 @@ paths: tags: - workspace toolbox x-codegen-request-body-name: params + /workspace/{workspaceId}/{projectId}/toolbox/git/checkout: + post: + description: Checkout branch or commit in git repository inside workspace project + operationId: GitCheckoutBranch + parameters: + - description: Workspace ID or Name + in: path + name: workspaceId + required: true + schema: + type: string + - description: Project ID + in: path + name: projectId + required: true + schema: + type: string + requestBody: + content: + '*/*': + schema: + $ref: '#/components/schemas/GitCheckoutRequest' + description: GitCheckoutRequest + required: true + responses: + "200": + content: {} + description: OK + summary: Checkout branch + tags: + - workspace toolbox + x-codegen-request-body-name: params /workspace/{workspaceId}/{projectId}/toolbox/git/clone: post: description: Clone git repository inside workspace project @@ -3015,6 +3047,19 @@ components: - name - path type: object + GitCheckoutRequest: + example: + path: path + branch: branch + properties: + branch: + type: string + path: + type: string + required: + - branch + - path + type: object GitCloneRequest: example: path: path diff --git a/pkg/apiclient/api_workspace_toolbox.go b/pkg/apiclient/api_workspace_toolbox.go index 57d884dbe7..c9a72a391f 100644 --- a/pkg/apiclient/api_workspace_toolbox.go +++ b/pkg/apiclient/api_workspace_toolbox.go @@ -1902,6 +1902,128 @@ func (a *WorkspaceToolboxAPIService) GitBranchListExecute(r ApiGitBranchListRequ return localVarReturnValue, localVarHTTPResponse, nil } +type ApiGitCheckoutBranchRequest struct { + ctx context.Context + ApiService *WorkspaceToolboxAPIService + workspaceId string + projectId string + params *GitCheckoutRequest +} + +// GitCheckoutRequest +func (r ApiGitCheckoutBranchRequest) Params(params GitCheckoutRequest) ApiGitCheckoutBranchRequest { + r.params = ¶ms + return r +} + +func (r ApiGitCheckoutBranchRequest) Execute() (*http.Response, error) { + return r.ApiService.GitCheckoutBranchExecute(r) +} + +/* +GitCheckoutBranch Checkout branch + +Checkout branch or commit in git repository inside workspace project + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param workspaceId Workspace ID or Name + @param projectId Project ID + @return ApiGitCheckoutBranchRequest +*/ +func (a *WorkspaceToolboxAPIService) GitCheckoutBranch(ctx context.Context, workspaceId string, projectId string) ApiGitCheckoutBranchRequest { + return ApiGitCheckoutBranchRequest{ + ApiService: a, + ctx: ctx, + workspaceId: workspaceId, + projectId: projectId, + } +} + +// Execute executes the request +func (a *WorkspaceToolboxAPIService) GitCheckoutBranchExecute(r ApiGitCheckoutBranchRequest) (*http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "WorkspaceToolboxAPIService.GitCheckoutBranch") + if err != nil { + return nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/workspace/{workspaceId}/{projectId}/toolbox/git/checkout" + localVarPath = strings.Replace(localVarPath, "{"+"workspaceId"+"}", url.PathEscape(parameterValueToString(r.workspaceId, "workspaceId")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"projectId"+"}", url.PathEscape(parameterValueToString(r.projectId, "projectId")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.params == nil { + return nil, reportError("params is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.params + if r.ctx != nil { + // API Key Authentication + if auth, ok := r.ctx.Value(ContextAPIKeys).(map[string]APIKey); ok { + if apiKey, ok := auth["Bearer"]; ok { + var key string + if apiKey.Prefix != "" { + key = apiKey.Prefix + " " + apiKey.Key + } else { + key = apiKey.Key + } + localVarHeaderParams["Authorization"] = key + } + } + } + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + return localVarHTTPResponse, newErr + } + + return localVarHTTPResponse, nil +} + type ApiGitCloneRepositoryRequest struct { ctx context.Context ApiService *WorkspaceToolboxAPIService diff --git a/pkg/apiclient/docs/GitCheckoutRequest.md b/pkg/apiclient/docs/GitCheckoutRequest.md new file mode 100644 index 0000000000..9559eb22ec --- /dev/null +++ b/pkg/apiclient/docs/GitCheckoutRequest.md @@ -0,0 +1,72 @@ +# GitCheckoutRequest + +## Properties + +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**Branch** | **string** | | +**Path** | **string** | | + +## Methods + +### NewGitCheckoutRequest + +`func NewGitCheckoutRequest(branch string, path string, ) *GitCheckoutRequest` + +NewGitCheckoutRequest instantiates a new GitCheckoutRequest object +This constructor will assign default values to properties that have it defined, +and makes sure properties required by API are set, but the set of arguments +will change when the set of required properties is changed + +### NewGitCheckoutRequestWithDefaults + +`func NewGitCheckoutRequestWithDefaults() *GitCheckoutRequest` + +NewGitCheckoutRequestWithDefaults instantiates a new GitCheckoutRequest object +This constructor will only assign default values to properties that have it defined, +but it doesn't guarantee that properties required by API are set + +### GetBranch + +`func (o *GitCheckoutRequest) GetBranch() string` + +GetBranch returns the Branch field if non-nil, zero value otherwise. + +### GetBranchOk + +`func (o *GitCheckoutRequest) GetBranchOk() (*string, bool)` + +GetBranchOk returns a tuple with the Branch field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetBranch + +`func (o *GitCheckoutRequest) SetBranch(v string)` + +SetBranch sets Branch field to given value. + + +### GetPath + +`func (o *GitCheckoutRequest) GetPath() string` + +GetPath returns the Path field if non-nil, zero value otherwise. + +### GetPathOk + +`func (o *GitCheckoutRequest) GetPathOk() (*string, bool)` + +GetPathOk returns a tuple with the Path field if it's non-nil, zero value otherwise +and a boolean to check if the value has been set. + +### SetPath + +`func (o *GitCheckoutRequest) SetPath(v string)` + +SetPath sets Path field to given value. + + + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/pkg/apiclient/docs/WorkspaceToolboxAPI.md b/pkg/apiclient/docs/WorkspaceToolboxAPI.md index 3f5a11ddc6..96e6cc0c47 100644 --- a/pkg/apiclient/docs/WorkspaceToolboxAPI.md +++ b/pkg/apiclient/docs/WorkspaceToolboxAPI.md @@ -18,6 +18,7 @@ Method | HTTP request | Description [**GetProjectDir**](WorkspaceToolboxAPI.md#GetProjectDir) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/project-dir | Get project dir [**GitAddFiles**](WorkspaceToolboxAPI.md#GitAddFiles) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/add | Add files [**GitBranchList**](WorkspaceToolboxAPI.md#GitBranchList) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/branches | Get branch list +[**GitCheckoutBranch**](WorkspaceToolboxAPI.md#GitCheckoutBranch) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/checkout | Checkout branch [**GitCloneRepository**](WorkspaceToolboxAPI.md#GitCloneRepository) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/clone | Clone git repository [**GitCommitChanges**](WorkspaceToolboxAPI.md#GitCommitChanges) | **Post** /workspace/{workspaceId}/{projectId}/toolbox/git/commit | Commit changes [**GitCommitHistory**](WorkspaceToolboxAPI.md#GitCommitHistory) | **Get** /workspace/{workspaceId}/{projectId}/toolbox/git/history | Get commit history @@ -1088,6 +1089,79 @@ Name | Type | Description | Notes [[Back to README]](../README.md) +## GitCheckoutBranch + +> GitCheckoutBranch(ctx, workspaceId, projectId).Params(params).Execute() + +Checkout branch + + + +### Example + +```go +package main + +import ( + "context" + "fmt" + "os" + openapiclient "github.com/GIT_USER_ID/GIT_REPO_ID/apiclient" +) + +func main() { + workspaceId := "workspaceId_example" // string | Workspace ID or Name + projectId := "projectId_example" // string | Project ID + params := *openapiclient.NewGitCheckoutRequest("Branch_example", "Path_example") // GitCheckoutRequest | GitCheckoutRequest + + configuration := openapiclient.NewConfiguration() + apiClient := openapiclient.NewAPIClient(configuration) + r, err := apiClient.WorkspaceToolboxAPI.GitCheckoutBranch(context.Background(), workspaceId, projectId).Params(params).Execute() + if err != nil { + fmt.Fprintf(os.Stderr, "Error when calling `WorkspaceToolboxAPI.GitCheckoutBranch``: %v\n", err) + fmt.Fprintf(os.Stderr, "Full HTTP response: %v\n", r) + } +} +``` + +### Path Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- +**ctx** | **context.Context** | context for authentication, logging, cancellation, deadlines, tracing, etc. +**workspaceId** | **string** | Workspace ID or Name | +**projectId** | **string** | Project ID | + +### Other Parameters + +Other parameters are passed through a pointer to a apiGitCheckoutBranchRequest struct via the builder pattern + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + + + **params** | [**GitCheckoutRequest**](GitCheckoutRequest.md) | GitCheckoutRequest | + +### Return type + + (empty response body) + +### Authorization + +[Bearer](../README.md#Bearer) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) +[[Back to Model list]](../README.md#documentation-for-models) +[[Back to README]](../README.md) + + ## GitCloneRepository > GitCloneRepository(ctx, workspaceId, projectId).Params(params).Execute() diff --git a/pkg/apiclient/model_git_checkout_request.go b/pkg/apiclient/model_git_checkout_request.go new file mode 100644 index 0000000000..2569e69c94 --- /dev/null +++ b/pkg/apiclient/model_git_checkout_request.go @@ -0,0 +1,184 @@ +/* +Daytona Server API + +Daytona Server API + +API version: v0.0.0-dev +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package apiclient + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the GitCheckoutRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &GitCheckoutRequest{} + +// GitCheckoutRequest struct for GitCheckoutRequest +type GitCheckoutRequest struct { + Branch string `json:"branch"` + Path string `json:"path"` +} + +type _GitCheckoutRequest GitCheckoutRequest + +// NewGitCheckoutRequest instantiates a new GitCheckoutRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewGitCheckoutRequest(branch string, path string) *GitCheckoutRequest { + this := GitCheckoutRequest{} + this.Branch = branch + this.Path = path + return &this +} + +// NewGitCheckoutRequestWithDefaults instantiates a new GitCheckoutRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewGitCheckoutRequestWithDefaults() *GitCheckoutRequest { + this := GitCheckoutRequest{} + return &this +} + +// GetBranch returns the Branch field value +func (o *GitCheckoutRequest) GetBranch() string { + if o == nil { + var ret string + return ret + } + + return o.Branch +} + +// GetBranchOk returns a tuple with the Branch field value +// and a boolean to check if the value has been set. +func (o *GitCheckoutRequest) GetBranchOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Branch, true +} + +// SetBranch sets field value +func (o *GitCheckoutRequest) SetBranch(v string) { + o.Branch = v +} + +// GetPath returns the Path field value +func (o *GitCheckoutRequest) GetPath() string { + if o == nil { + var ret string + return ret + } + + return o.Path +} + +// GetPathOk returns a tuple with the Path field value +// and a boolean to check if the value has been set. +func (o *GitCheckoutRequest) GetPathOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Path, true +} + +// SetPath sets field value +func (o *GitCheckoutRequest) SetPath(v string) { + o.Path = v +} + +func (o GitCheckoutRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o GitCheckoutRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["branch"] = o.Branch + toSerialize["path"] = o.Path + return toSerialize, nil +} + +func (o *GitCheckoutRequest) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "branch", + "path", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if _, exists := allProperties[requiredProperty]; !exists { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varGitCheckoutRequest := _GitCheckoutRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varGitCheckoutRequest) + + if err != nil { + return err + } + + *o = GitCheckoutRequest(varGitCheckoutRequest) + + return err +} + +type NullableGitCheckoutRequest struct { + value *GitCheckoutRequest + isSet bool +} + +func (v NullableGitCheckoutRequest) Get() *GitCheckoutRequest { + return v.value +} + +func (v *NullableGitCheckoutRequest) Set(val *GitCheckoutRequest) { + v.value = val + v.isSet = true +} + +func (v NullableGitCheckoutRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableGitCheckoutRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableGitCheckoutRequest(val *GitCheckoutRequest) *NullableGitCheckoutRequest { + return &NullableGitCheckoutRequest{value: val, isSet: true} +} + +func (v NullableGitCheckoutRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableGitCheckoutRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/pkg/git/checkout.go b/pkg/git/checkout.go new file mode 100644 index 0000000000..3c3ce32365 --- /dev/null +++ b/pkg/git/checkout.go @@ -0,0 +1,40 @@ +// Copyright 2024 Daytona Platforms Inc. +// SPDX-License-Identifier: Apache-2.0 + +package git + +import ( + "fmt" + + "github.com/go-git/go-git/v5" + "github.com/go-git/go-git/v5/plumbing" +) + +func (s *Service) Checkout(branch string) error { + r, err := git.PlainOpen(s.ProjectDir) + if err != nil { + return fmt.Errorf("failed to open repository: %w", err) + } + + w, err := r.Worktree() + if err != nil { + return fmt.Errorf("failed to get worktree: %w", err) + } + + // Try to checkout as a branch first + err = w.Checkout(&git.CheckoutOptions{ + Branch: plumbing.NewBranchReferenceName(branch), + }) + + if err != nil { + // If branch checkout fails, try as a commit hash + err = w.Checkout(&git.CheckoutOptions{ + Hash: plumbing.NewHash(branch), + }) + if err != nil { + return fmt.Errorf("failed to checkout branch or commit '%s': %w", branch, err) + } + } + + return nil +}