73 lines
2.5 KiB
Go
73 lines
2.5 KiB
Go
package gitea
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"io"
|
|
"mime/multipart"
|
|
"net/http"
|
|
"net/url"
|
|
"strconv"
|
|
)
|
|
|
|
func (c Client) uploadAsset(ctx context.Context, client *http.Client, token, apiRoot string, releaseID int64, filename string, content io.Reader) (int, error) {
|
|
if content == nil {
|
|
return 0, failure(FailureInvalid, "upload release asset", 0, errors.New("asset content reader is required"))
|
|
}
|
|
uploadURL := apiRoot + "/releases/" + strconv.FormatInt(releaseID, 10) + "/assets"
|
|
parsed, err := url.Parse(uploadURL)
|
|
if err != nil {
|
|
return 0, failure(FailureInvalid, "prepare asset upload", 0, err)
|
|
}
|
|
query := parsed.Query()
|
|
query.Set("name", filename)
|
|
parsed.RawQuery = query.Encode()
|
|
reader, writer := io.Pipe()
|
|
multipartWriter := multipart.NewWriter(writer)
|
|
writeDone := make(chan error, 1)
|
|
go func() {
|
|
part, partErr := multipartWriter.CreateFormFile("attachment", filename)
|
|
if partErr == nil {
|
|
_, partErr = io.Copy(part, content)
|
|
}
|
|
closeErr := multipartWriter.Close()
|
|
if partErr == nil {
|
|
partErr = closeErr
|
|
}
|
|
_ = writer.CloseWithError(partErr)
|
|
writeDone <- partErr
|
|
}()
|
|
|
|
request, err := http.NewRequestWithContext(ctx, http.MethodPost, parsed.String(), reader)
|
|
if err != nil {
|
|
_ = reader.CloseWithError(err)
|
|
<-writeDone
|
|
return 0, failure(FailureInvalid, "upload release asset", 0, err)
|
|
}
|
|
request.Header.Set("Authorization", "token "+token)
|
|
request.Header.Set("Accept", "application/json")
|
|
request.Header.Set("Content-Type", multipartWriter.FormDataContentType())
|
|
response, requestErr := client.Do(request)
|
|
if requestErr != nil {
|
|
_ = reader.CloseWithError(requestErr)
|
|
<-writeDone
|
|
return 0, failure(FailureTransport, "upload release asset", 0, requestErr)
|
|
}
|
|
defer response.Body.Close()
|
|
writeErr := <-writeDone
|
|
if response.StatusCode < 200 || response.StatusCode >= 300 {
|
|
return response.StatusCode, responseFailure("upload release asset", response.StatusCode)
|
|
}
|
|
var uploaded assetResponse
|
|
if err := decodeJSON(response.Body, &uploaded); err != nil {
|
|
return response.StatusCode, failure(FailureMalformed, "decode uploaded asset", response.StatusCode, err)
|
|
}
|
|
if uploaded.ID <= 0 || uploaded.Name != filename {
|
|
return response.StatusCode, failure(FailureMalformed, "verify uploaded asset", response.StatusCode, errors.New("upload response does not identify the selected asset"))
|
|
}
|
|
if writeErr != nil {
|
|
return response.StatusCode, failure(FailureMalformed, "stream uploaded asset", response.StatusCode, writeErr)
|
|
}
|
|
return response.StatusCode, nil
|
|
}
|