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

Commit

Permalink
Merge pull request #1318 from mitar/support-avatar
Browse files Browse the repository at this point in the history
Added UploadAvatar
  • Loading branch information
svanharmelen authored Jan 4, 2022
2 parents 65e314f + cff4b0b commit 609ee71
Show file tree
Hide file tree
Showing 6 changed files with 264 additions and 69 deletions.
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

0 comments on commit 609ee71

Please sign in to comment.