internal/gitlabnet/git/client.go (84 lines of code) (raw):

// Package git provides functionality for interacting with Git repositories. package git import ( "context" "io" "net/http" "gitlab.com/gitlab-org/gitlab-shell/v14/client" "gitlab.com/gitlab-org/labkit/log" ) var httpClient = &http.Client{ Transport: client.NewTransport(client.DefaultTransport()), } const ( repoUnavailableErrMsg = "Remote repository is unavailable" sshUploadPackPath = "/ssh-upload-pack" sshReceivePackPath = "/ssh-receive-pack" ) // Client represents a client for interacting with Git repositories. type Client struct { URL string Headers map[string]string } // InfoRefs retrieves information about the Git repository references. func (c *Client) InfoRefs(ctx context.Context, service string) (*http.Response, error) { request, err := http.NewRequestWithContext(ctx, http.MethodGet, c.URL+"/info/refs?service="+service, nil) if err != nil { return nil, err } return c.do(request) } // ReceivePack sends a Git push request to the server. func (c *Client) ReceivePack(ctx context.Context, body io.Reader) (*http.Response, error) { request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL+"/git-receive-pack", body) if err != nil { return nil, err } request.Header.Add("Content-Type", "application/x-git-receive-pack-request") request.Header.Add("Accept", "application/x-git-receive-pack-result") return c.do(request) } // UploadPack sends a Git fetch request to the server. func (c *Client) UploadPack(ctx context.Context, body io.Reader) (*http.Response, error) { request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL+"/git-upload-pack", body) if err != nil { return nil, err } request.Header.Add("Content-Type", "application/x-git-upload-pack-request") request.Header.Add("Accept", "application/x-git-upload-pack-result") return c.do(request) } // SSHUploadPack sends a SSH Git fetch request to the server. func (c *Client) SSHUploadPack(ctx context.Context, body io.Reader) (*http.Response, error) { request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL+sshUploadPackPath, body) if err != nil { return nil, err } return c.do(request) } // SSHReceivePack sends a SSH Git push request to the server. func (c *Client) SSHReceivePack(ctx context.Context, body io.Reader) (*http.Response, error) { request, err := http.NewRequestWithContext(ctx, http.MethodPost, c.URL+sshReceivePackPath, body) if err != nil { return nil, err } return c.do(request) } func (c *Client) do(request *http.Request) (*http.Response, error) { for k, v := range c.Headers { request.Header.Add(k, v) } response, err := httpClient.Do(request) if err != nil { return nil, &client.APIError{Msg: repoUnavailableErrMsg} } if response.StatusCode >= 400 { defer func() { if err := response.Body.Close(); err != nil { log.WithError(err).Error("Unable to close response body") } }() body, err := io.ReadAll(response.Body) if err != nil { return nil, &client.APIError{Msg: repoUnavailableErrMsg} } if len(body) > 0 { return nil, &client.APIError{Msg: string(body)} } return nil, &client.APIError{Msg: repoUnavailableErrMsg} } return response, nil }