Skip to content
This repository has been archived by the owner on Dec 10, 2024. It is now read-only.

Added UploadAvatar #1318

Merged
merged 3 commits into from
Jan 4, 2022
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
88 changes: 83 additions & 5 deletions gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@
package gitlab

import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math/rand"
"mime/multipart"
"net/http"
"net/url"
"sort"
Expand Down Expand Up @@ -520,11 +522,11 @@ func (c *Client) setBaseURL(urlStr string) error {
return nil
}

// NewRequest creates an API request. An optional relative URL path can be
// provided in path, in which case it is resolved relative to the base URL
// of the Client.
// Paths should always be specified without a preceding slash. If specified,
// the value pointed to by body is JSON encoded and included as request body.
// NewRequest creates a new API request. The method expects a relative URL
// path that will be resolved relative to the base URL of the Client.
// Relative URL paths should always be specified without a preceding slash.
// If specified, the value pointed to by body is JSON encoded and included
// as the request body.
func (c *Client) NewRequest(method, path string, opt interface{}, options []RequestOptionFunc) (*retryablehttp.Request, error) {
u := *c.baseURL
unescaped, err := url.PathUnescape(path)
Expand Down Expand Up @@ -585,6 +587,82 @@ func (c *Client) NewRequest(method, path string, opt interface{}, options []Requ
return req, nil
}

// UploadRequest creates an API request for uploading a file. The method
// expects a relative URL path that will be resolved relative to the base
// URL of the Client. Relative URL paths should always be specified without
// a preceding slash. If specified, the value pointed to by body is JSON
// encoded and included as the request body.
func (c *Client) UploadRequest(method, path string, content io.Reader, filename string, uploadType UploadType, opt interface{}, options []RequestOptionFunc) (*retryablehttp.Request, error) {
u := *c.baseURL
unescaped, err := url.PathUnescape(path)
if err != nil {
return nil, err
}

// Set the encoded path data
u.RawPath = c.baseURL.Path + path
u.Path = c.baseURL.Path + unescaped

// Create a request specific headers map.
reqHeaders := make(http.Header)
reqHeaders.Set("Accept", "application/json")

if c.UserAgent != "" {
reqHeaders.Set("User-Agent", c.UserAgent)
}

b := new(bytes.Buffer)
w := multipart.NewWriter(b)

fw, err := w.CreateFormFile(string(uploadType), filename)
if err != nil {
return nil, err
}

if _, err := io.Copy(fw, content); err != nil {
return nil, err
}

if opt != nil {
fields, err := query.Values(opt)
if err != nil {
return nil, err
}
for name := range fields {
if err = w.WriteField(name, fmt.Sprintf("%v", fields.Get(name))); err != nil {
return nil, err
}
}
}

if err = w.Close(); err != nil {
return nil, err
}

reqHeaders.Set("Content-Type", w.FormDataContentType())

req, err := retryablehttp.NewRequest(method, u.String(), b)
if err != nil {
return nil, err
}

for _, fn := range options {
if fn == nil {
continue
}
if err := fn(req); err != nil {
return nil, err
}
}

// Set the request specific headers.
for k, v := range reqHeaders {
req.Header[k] = v
}

return req, nil
}

// Response is a GitLab API response. This wraps the standard http.Response
// returned from GitLab and provides convenient access to things like
// pagination links.
Expand Down
17 changes: 13 additions & 4 deletions project_import_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package gitlab
import (
"bytes"
"fmt"
"io"
"net/http"
"time"
)
Expand Down Expand Up @@ -162,18 +163,26 @@ func (s *ProjectImportExportService) ExportDownload(pid interface{}, options ...
// https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file
type ImportFileOptions struct {
Namespace *string `url:"namespace,omitempty" json:"namespace,omitempty"`
File *string `url:"file,omitempty" json:"file,omitempty"`
Name *string `url:"name,omitempty" json:"name,omitempty"`
Path *string `url:"path,omitempty" json:"path,omitempty"`
Overwrite *bool `url:"overwrite,omitempty" json:"overwrite,omitempty"`
OverrideParams *CreateProjectOptions `url:"override_params,omitempty" json:"override_params,omitempty"`
}

// ImportFile import a file.
// Import a project from an archive file.
//
// GitLab API docs:
// https://docs.gitlab.com/ce/api/project_import_export.html#import-a-file
func (s *ProjectImportExportService) ImportFile(opt *ImportFileOptions, options ...RequestOptionFunc) (*ImportStatus, *Response, error) {
req, err := s.client.NewRequest(http.MethodPost, "projects/import", opt, options)
func (s *ProjectImportExportService) ImportFromFile(archive io.Reader, opt *ImportFileOptions, options ...RequestOptionFunc) (*ImportStatus, *Response, error) {
req, err := s.client.UploadRequest(
http.MethodPost,
"projects/import",
archive,
"archive.tar.gz",
UploadFile,
opt,
options,
)
if err != nil {
return nil, nil, err
}
Expand Down
21 changes: 4 additions & 17 deletions project_import_export_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gitlab

import (
"bytes"
"fmt"
"net/http"
"testing"
Expand Down Expand Up @@ -159,32 +160,18 @@ func TestProjectImportExportService_ImportFile(t *testing.T) {
ImportStatus: "scheduled",
}

es, resp, err := client.ProjectImportExport.ImportFile(nil, nil)
file := bytes.NewBufferString("dummy")
es, resp, err := client.ProjectImportExport.ImportFromFile(file, nil, nil)
require.NoError(t, err)
require.NotNil(t, resp)
require.Equal(t, want, es)

es, resp, err = client.ProjectImportExport.ImportFile(nil, errorOption)
es, resp, err = client.ProjectImportExport.ImportFromFile(file, nil, errorOption)
require.EqualError(t, err, "RequestOptionFunc returns an error")
require.Nil(t, resp)
require.Nil(t, es)
}

func TestProjectImportExportService_ImportFile_NotFound(t *testing.T) {
mux, server, client := setup(t)
defer teardown(server)

mux.HandleFunc("/api/v4/projects/import", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, http.MethodPost)
w.WriteHeader(http.StatusNotFound)
})

es, resp, err := client.ProjectImportExport.ImportFile(nil, nil)
require.Error(t, err)
require.Nil(t, es)
require.Equal(t, http.StatusNotFound, resp.StatusCode)
}

func TestProjectImportExportService_ImportStatus(t *testing.T) {
mux, server, client := setup(t)
defer teardown(server)
Expand Down
Loading