Skip to content

Commit

Permalink
Fix file size upload param (#204)
Browse files Browse the repository at this point in the history
* Fix file size upload param

* Fix vendor

* Fix?

* Query file size only once

* Revert unintentional change
  • Loading branch information
ofalvai authored Jul 23, 2024
1 parent 60e219b commit d3b1275
Show file tree
Hide file tree
Showing 20 changed files with 729 additions and 67 deletions.
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/bitrise-io/go-utils/v2 v2.0.0-alpha.22
github.com/bitrise-io/go-xcode v1.0.18
github.com/bitrise-io/go-xcode/v2 v2.0.0-alpha.44
github.com/docker/go-units v0.5.0
github.com/google/go-cmp v0.6.0
github.com/gorilla/mux v1.8.0
github.com/hashicorp/go-retryablehttp v0.7.7
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa h1:RDBNVkRviHZtvDvId8XSGPu3rmpmSe+wKRcEWNgsfWU=
github.com/fullsailor/pkcs7 v0.0.0-20190404230743-d7302db945fa/go.mod h1:KnogPXtdwXqoenmZCw6S+25EAm2MkxbG0deNDu4cbSA=
github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
Expand Down
11 changes: 10 additions & 1 deletion report/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"io"
"net/http"
"net/http/httputil"
"os"

"github.com/bitrise-io/go-utils/retry"
"github.com/bitrise-io/go-utils/v2/log"
Expand Down Expand Up @@ -79,7 +80,15 @@ func (t *TestReportClient) CreateReport(params CreateReportParameters) (CreateRe

// UploadAsset ...
func (t *TestReportClient) UploadAsset(url, path, contentType string) error {
return uploaders.UploadArtifact(url, path, contentType)
fileInfo, err := os.Stat(path)
if err != nil {
return err
}
artifact := uploaders.ArtifactArgs {
Path: path,
FileSize: fileInfo.Size(),
}
return uploaders.UploadArtifact(url, artifact, contentType)
}

// FinishReport ...
Expand Down
10 changes: 7 additions & 3 deletions uploaders/aabuploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ func DeployAAB(item deployment.DeployableItem, artifacts []string, buildURL, tok
info := androidartifact.ParseArtifactPath(pth)

aabInfoMap := map[string]interface{}{
"file_size_bytes": fmt.Sprintf("%f", fileSize),
"file_size_bytes": fmt.Sprintf("%d", fileSize),
"app_info": appInfo,
"module": info.Module,
"product_flavour": info.ProductFlavour,
Expand All @@ -83,12 +83,16 @@ func DeployAAB(item deployment.DeployableItem, artifacts []string, buildURL, tok
// ---

const AABContentType = "application/octet-stream aab"
uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "android-apk", AABContentType)
artifact := ArtifactArgs {
Path: pth,
FileSize: fileSize,
}
uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "android-apk", AABContentType)
if err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to create apk artifact: %s %w", pth, err)
}

if err := UploadArtifact(uploadURL, pth, AABContentType); err != nil {
if err := UploadArtifact(uploadURL, artifact, AABContentType); err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to upload apk artifact, error: %s", err)
}

Expand Down
10 changes: 7 additions & 3 deletions uploaders/apkuploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func DeployAPK(item deployment.DeployableItem, artifacts []string, buildURL, tok
info := androidartifact.ParseArtifactPath(pth)

apkInfoMap := map[string]interface{}{
"file_size_bytes": fmt.Sprintf("%f", fileSize),
"file_size_bytes": fmt.Sprintf("%d", fileSize),
"app_info": appInfo,
"module": info.Module,
"product_flavour": info.ProductFlavour,
Expand All @@ -67,12 +67,16 @@ func DeployAPK(item deployment.DeployableItem, artifacts []string, buildURL, tok
// ---

const APKContentType = "application/vnd.android.package-archive"
uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "android-apk", APKContentType)
artifact := ArtifactArgs {
Path: pth,
FileSize: fileSize,
}
uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "android-apk", APKContentType)
if err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to create apk artifact: %s %w", pth, err)
}

if err := UploadArtifact(uploadURL, pth, APKContentType); err != nil {
if err := UploadArtifact(uploadURL, artifact, APKContentType); err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to upload apk artifact, error: %s", err)
}

Expand Down
44 changes: 16 additions & 28 deletions uploaders/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,37 @@ import (
"time"

"github.com/bitrise-steplib/steps-deploy-to-bitrise-io/deployment"

"github.com/docker/go-units"

"github.com/bitrise-io/go-utils/log"
"github.com/bitrise-io/go-utils/retry"
"github.com/bitrise-io/go-utils/urlutil"
)

// ArtifactURLs ...
type ArtifactURLs struct {
PublicInstallPageURL string
PermanentDownloadURL string
DetailsPageURL string
}

// AppDeploymentMetaData ...
type AppDeploymentMetaData struct {
ArtifactInfo map[string]interface{}
NotifyUserGroups string
NotifyEmails string
IsEnablePublicPage bool
}

func createArtifact(buildURL, token, artifactPth, artifactType, contentType string) (string, string, error) {
type ArtifactArgs struct {
Path string
FileSize int64 // bytes
}

func createArtifact(buildURL, token string, artifact ArtifactArgs, artifactType, contentType string) (string, string, error) {
// create form data
artifactName := filepath.Base(artifactPth)
fileSize, err := fileSizeInBytes(artifactPth)
if err != nil {
return "", "", fmt.Errorf("failed to get file size, error: %s", err)
}
artifactName := filepath.Base(artifact.Path)

megaBytes := fileSize / 1024.0 / 1024.0
roundedMegaBytes := int(roundPlus(megaBytes, 2))

if roundedMegaBytes < 1 {
log.Printf("file size: %dB", int(fileSize))
} else {
log.Printf("file size: %dMB", roundedMegaBytes)
}
log.Printf("file size: %s", units.BytesSize(float64(artifact.FileSize)))

if strings.TrimSpace(token) == "" {
return "", "", fmt.Errorf("provided API token is empty")
Expand All @@ -62,7 +56,7 @@ func createArtifact(buildURL, token, artifactPth, artifactType, contentType stri
"title": {artifactName},
"filename": {artifactName},
"artifact_type": {artifactType},
"file_size_bytes": {fmt.Sprintf("%d", int(fileSize))},
"file_size_bytes": {fmt.Sprintf("%d", artifact.FileSize)},
"content_type": {contentType},
}
// ---
Expand Down Expand Up @@ -137,14 +131,13 @@ func createArtifact(buildURL, token, artifactPth, artifactType, contentType stri
return artifactResponse.UploadURL, fmt.Sprintf("%d", artifactResponse.ID), nil
}

// UploadArtifact ...
func UploadArtifact(uploadURL, artifactPth, contentType string) error {
func UploadArtifact(uploadURL string, artifact ArtifactArgs, contentType string) error {
netClient := &http.Client{
Timeout: 10 * time.Minute,
}

return retry.Times(3).Wait(5).Try(func(attempt uint) error {
file, err := os.Open(artifactPth)
file, err := os.Open(artifact.Path)
if err != nil {
return fmt.Errorf("failed to open artifact, error: %s", err)
}
Expand All @@ -154,14 +147,9 @@ func UploadArtifact(uploadURL, artifactPth, contentType string) error {
}
}()

fileInfo, err := file.Stat()
if err != nil {
return fmt.Errorf("failed to get file info for %s, error: %s", artifactPth, err)
}

// Initializes request body to nil to send a Content-Length of 0: https://github.com/golang/go/issues/20257#issuecomment-299509391
var reqBody io.Reader
if fileInfo.Size() > 0 {
if artifact.FileSize > 0 {
reqBody = io.NopCloser(file)
}

Expand All @@ -174,8 +162,8 @@ func UploadArtifact(uploadURL, artifactPth, contentType string) error {
request.Header.Add("Content-Type", contentType)
}

request.Header.Add("X-Upload-Content-Length", strconv.FormatInt(fileInfo.Size(), 10)) // header used by Google Cloud Storage signed URLs
request.ContentLength = fileInfo.Size()
request.Header.Add("X-Upload-Content-Length", strconv.FormatInt(artifact.FileSize, 10)) // header used by Google Cloud Storage signed URLs
request.ContentLength = artifact.FileSize

ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
defer cancel()
Expand Down
14 changes: 11 additions & 3 deletions uploaders/common_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
package uploaders

import (
"os"
"io"
"image"
"image/png"
"io"
"math/rand"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"strconv"
"testing"

"github.com/stretchr/testify/require"
)

func Test_uploadArtifact(t *testing.T) {
Expand Down Expand Up @@ -90,7 +92,13 @@ func Test_uploadArtifact(t *testing.T) {
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := UploadArtifact(tt.uploadURL, tt.artifactPth, tt.contentType); (err != nil) != tt.wantErr {
fileInfo, err := os.Stat(tt.artifactPth)
require.NoError(t, err)
artifact := ArtifactArgs {
Path: tt.artifactPth,
FileSize: fileInfo.Size(),
}
if err := UploadArtifact(tt.uploadURL, artifact, tt.contentType); (err != nil) != tt.wantErr {
t.Errorf("UploadArtifact() error = %v, wantErr %v", err, tt.wantErr)
}
})
Expand Down
15 changes: 11 additions & 4 deletions uploaders/fileuploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,20 @@ import (

// DeployFile ...
func DeployFile(item deployment.DeployableItem, buildURL, token string) (ArtifactURLs, error) {
pth := item.Path
uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "file", "")
fileSize, err := fileSizeInBytes(item.Path)
if err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to create file artifact: %s %w", pth, err)
return ArtifactURLs{}, fmt.Errorf("get file size: %s", err)
}
artifact := ArtifactArgs {
Path: item.Path,
FileSize: fileSize,
}
uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "file", "")
if err != nil {
return ArtifactURLs{}, fmt.Errorf("create file artifact: %s %w", artifact.Path, err)
}

if err := UploadArtifact(uploadURL, pth, ""); err != nil {
if err := UploadArtifact(uploadURL, artifact, ""); err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to upload file artifact, error: %s", err)
}

Expand Down
10 changes: 7 additions & 3 deletions uploaders/ipauploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,24 @@ func DeployIPA(item deployment.DeployableItem, buildURL, token, notifyUserGroups
}

ipaInfoMap := map[string]interface{}{
"file_size_bytes": fmt.Sprintf("%f", fileSize),
"file_size_bytes": fmt.Sprintf("%d", fileSize),
"app_info": appInfo,
"provisioning_info": provisioningInfo,
}

logger.Printf("ipa infos: %v", appInfo)

const IPAContentType = "application/octet-stream ipa"
uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "ios-ipa", IPAContentType)
artifact := ArtifactArgs {
Path: pth,
FileSize: fileSize,
}
uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "ios-ipa", IPAContentType)
if err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to create ipa artifact from %s: %w", pth, err)
}

if err := UploadArtifact(uploadURL, pth, IPAContentType); err != nil {
if err := UploadArtifact(uploadURL, artifact, IPAContentType); err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to upload ipa (%s): %w", pth, err)
}

Expand Down
23 changes: 4 additions & 19 deletions uploaders/utils.go
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
package uploaders

import (
"fmt"
"math"

"github.com/bitrise-io/go-utils/pathutil"
"os"
)

func round(f float64) float64 {
return math.Floor(f + .5)
}

func roundPlus(f float64, places int) float64 {
shift := math.Pow(10, float64(places))
return round(f*shift) / shift
}

func fileSizeInBytes(pth string) (float64, error) {
info, exist, err := pathutil.PathCheckAndInfos(pth)
func fileSizeInBytes(pth string) (int64, error) {
finfo, err := os.Stat(pth)
if err != nil {
return 0, err
}
if !exist {
return 0, fmt.Errorf("file not exist at: %s", pth)
}
return float64(info.Size()), nil
return finfo.Size(), nil
}
10 changes: 7 additions & 3 deletions uploaders/xcarchiveuploader.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,23 @@ func DeployXcarchive(item deployment.DeployableItem, buildURL, token string) (Ar
}

xcarchiveInfoMap := map[string]interface{}{
"file_size_bytes": fmt.Sprintf("%f", fileSize),
"file_size_bytes": fmt.Sprintf("%d", fileSize),
"app_info": appInfo,
"scheme": scheme,
}

logger.Printf("xcarchive infos: %v", appInfo)

uploadURL, artifactID, err := createArtifact(buildURL, token, pth, "ios-xcarchive", "")
artifact := ArtifactArgs {
Path: pth,
FileSize: fileSize,
}
uploadURL, artifactID, err := createArtifact(buildURL, token, artifact, "ios-xcarchive", "")
if err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to create xcarchive artifact from %s %w", pth, err)
}

if err := UploadArtifact(uploadURL, pth, ""); err != nil {
if err := UploadArtifact(uploadURL, artifact, ""); err != nil {
return ArtifactURLs{}, fmt.Errorf("failed to upload xcarchive (%s): %w", pth, err)
}

Expand Down
Loading

0 comments on commit d3b1275

Please sign in to comment.