github.com/rainforestapp/rainforest-cli@v2.12.0+incompatible/mobile_upload.go (about)

     1  package main
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"path/filepath"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/rainforestapp/rainforest-cli/rainforest"
    11  	"github.com/urfave/cli"
    12  )
    13  
    14  // mobileUploadAPI is part of the API connected to mobile uploads
    15  type mobileUploadAPI interface {
    16  	GetPresignedPOST(fileExt string, siteID int, environmentID int, appSlot int) (*rainforest.RFPresignedPostData, error)
    17  	UploadToS3(postData *rainforest.RFPresignedPostData, filePath string) error
    18  	UpdateURL(siteID int, environmentID int, appSlot int, newURL string) error
    19  }
    20  
    21  // uploadMobileApp takes a path to a mobile app file and uploads it to S3 then sets
    22  // the site-id specified's URL to the magic url
    23  func uploadMobileApp(api mobileUploadAPI, filePath string, siteID int, environmentID int, appSlot int) error {
    24  
    25  	presignedPostData, err := api.GetPresignedPOST(filepath.Ext(filePath), siteID, environmentID, appSlot)
    26  	if err != nil {
    27  		return err
    28  	}
    29  
    30  	err = api.UploadToS3(presignedPostData, filePath)
    31  	if err != nil {
    32  		return err
    33  	}
    34  
    35  	err = api.UpdateURL(siteID, environmentID, appSlot, presignedPostData.RainforestURL)
    36  	if err != nil {
    37  		return err
    38  	}
    39  
    40  	return nil
    41  }
    42  
    43  func isAllowedExtension(extension string) bool {
    44  	switch extension {
    45  	case ".apk", ".ipa", ".zip", ".gz", ".tar.gz":
    46  		return true
    47  	}
    48  	return false
    49  }
    50  
    51  const allowedExtensionsPretty = ".apk, .ipa, .zip, .gz, .tar.gz"
    52  
    53  // mobileAppUpload is a wrapper around uploadMobileApp to function with mobile-upload cli command
    54  func mobileAppUpload(c cliContext, api mobileUploadAPI) error {
    55  	// Get the filepath from the arg
    56  	filePath := c.Args().First()
    57  	if filePath == "" {
    58  		return cli.NewExitError("Mobile app file path not specified", 1)
    59  	}
    60  
    61  	// verify extension
    62  	fileExt := strings.ToLower(filepath.Ext(filePath))
    63  	if !isAllowedExtension(fileExt) {
    64  		return cli.NewExitError(fmt.Sprintf("Invalid file extension. - %v. Allowed Extensions: %v", fileExt, allowedExtensionsPretty), 1)
    65  	}
    66  
    67  	siteIDString := c.String("site-id")
    68  	if siteIDString == "" {
    69  		return cli.NewExitError("site-id flag required", 1)
    70  	}
    71  	siteID, err := strconv.Atoi(siteIDString)
    72  	if err != nil {
    73  		return cli.NewExitError("site-id must be an integer", 1)
    74  	}
    75  
    76  	envIDstring := c.String("environment-id")
    77  	if envIDstring == "" {
    78  		return cli.NewExitError("environment-id flag required", 1)
    79  	}
    80  	environmentID, err := strconv.Atoi(envIDstring)
    81  	if err != nil {
    82  		return cli.NewExitError("environment-id must be an integer", 1)
    83  	}
    84  
    85  	appSlot := 1 // Default to 1, optional param
    86  	appSlotString := c.String("app-slot")
    87  	if appSlotString != "" {
    88  		appSlot, err = strconv.Atoi(appSlotString)
    89  		if err != nil || appSlot < 1 || appSlot > 100 {
    90  			return cli.NewExitError("app-slot must be an integer (1 to 100)", 1)
    91  		}
    92  	}
    93  
    94  	// Open app and return early with an error if we fail
    95  	f, err := os.Open(filePath)
    96  	if err != nil {
    97  		return cli.NewExitError(err.Error(), 1)
    98  	}
    99  	defer f.Close()
   100  
   101  	err = uploadMobileApp(api, filePath, siteID, environmentID, appSlot)
   102  	if err != nil {
   103  		return cli.NewExitError(err.Error(), 1)
   104  	}
   105  
   106  	return nil
   107  }