Files
releasekit/internal/gitea/upload.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
}