Skip to content

Commit

Permalink
Add S3 package, cobra commands, doc updates and refactor nexus
Browse files Browse the repository at this point in the history
  • Loading branch information
John Bryan Sazon committed Apr 29, 2018
1 parent 0e327cc commit 8452cf8
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 86 deletions.
119 changes: 59 additions & 60 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,101 +8,90 @@ Automate the beta testing distribution of your Android and iOS application files

Gota is a [Golang](http://golang.org/) powered Over the Air Installation site creation tool.

![](./docs/gota_html.png)
![](./docs/gota_workflow.png)

## Feature Checklist

* [x] Upload and generate site to a Nexus 3 Site Repository
* [ ] Upload and generate site to a Nexus 2 Site Repository (untested)
* [ ] Upload and generate site to an Amazon S3 bucket
* [x] Upload and generate site to an Amazon S3 bucket
* [ ] Upload and generate site to a Nexus 2 Site Repository

## Installation

Get the executable binary for your platform from the [Release Page](https://github.com/bzon/gota/releases/).
Get the executable binary for your platform from the [Release Page](https://github.com/bzon/gota/releases/)

## Commands Guide
If you have Go installed, just run `go get githug.com/bzon/gota`.

Gota command help `gota --help`
## User Guide

To see the required flags, use the --help flag.

```bash
./gota --help  
Go Over the Air installation for Android APK and iOS Ipa files!
gota --help
gota nexus --help
gota s3 --help
```

Usage:
gota [command]
Gota creates a `gotalink.txt` and `ipalink.txt` (if uploading an ipa) that contains the url or direct download link.

Available Commands:
help Help about any command
nexus Upload your apk or ipa file and create an over-the-air static site in a Nexus Site repository
If you are using a CI server, you can have it read these files for quickly getting the url that you can send to your team.

Flags:
--destDir string root directory of the site to create.
-h, --help help for gota
--srcFile string the apk or ipa file.
```
### Upload to S3 Bucket

Nexus command help `gota nexus --help`

```bash
./gota nexus --help  
Upload your apk or ipa file and create an over-the-air static site in a Nexus Site repository

Usage:
gota nexus [flags]

Flags:
-h, --help help for nexus
--nexusHost string nexus host url (including http protocol)
--nexusPassword string nexus password (can be passed as env variable $NEXUS_PASSWORD)
--nexusRepo string nexus site repository id (nexus v3 raw repository not maven!)
--nexusUser string nexus username (can be passed as env variable $NEXUS_USER)

Global Flags:
--destDir string root directory of the site to create.
--srcFile string the apk or ipa file.
# set the aws credentials
export AWS_ACCESS_KEY=xxxxx
export AWS_SECRET_ACCESS_KEY=xxxxx

./gota s3 --bucket example-s3-bucket --srcFile sample.ipa --destDir ios_bucket

2018/04/30 01:12:37 file uploaded: https://example-s3-bucket.s3.amazonaws.com/ios_bucket/1.0.0/4/appicon.png
2018/04/30 01:12:37 file uploaded: https://example-s3-bucket.s3.amazonaws.com/ios_bucket/1.0.0/version.json
2018/04/30 01:12:37 file uploaded: https://example-s3-bucket.s3.amazonaws.com/ios_bucket/1.0.0/4/index.html
2018/04/30 01:12:37 file uploaded: https://example-s3-bucket.s3.amazonaws.com/ios_bucket/1.0.0/4/sample.ipa
2018/04/30 01:12:37 file uploaded: https://example-s3-bucket.s3.amazonaws.com/ios_bucket/1.0.0/4/app.plist
```

### Nexus APK Upload
__NOTE__: Currently, gota assigns a AES256 encrpytion and a public-read ACL to all files that are uploaded.
This may change to be configurable in the future.

Upload an APK file to a Nexus Site Repository
### Upload to Nexus

The repository must be a [Raw Site Repository](https://help.sonatype.com/repomanager3/raw-repositories-and-maven-sites).

```bash
# set the nexus credentials
# this can also be set via command flags
export NEXUS_USER=admin
export NEXUS_PASSWORD=admin123

./gota nexus --nexusHost http://localhost:8081 \
--nexusRepo site \
--nexusUser admin \
--nexusPassword admin123 \
--destDir nexus_android_repo \
--srcFile pkg/resources/DarkSouls.apk \
--srcFile build/outpus/apk/sample.apk \

file uploaded: http://localhost:8081/repository/site/nexus_android_repo/1.0.0/10222333/appicon.png
file uploaded: http://localhost:8081/repository/site/nexus_android_repo/version.json
file uploaded: http://localhost:8081/repository/site/nexus_android_repo/1.0.0/version.json
file uploaded: http://localhost:8081/repository/site/nexus_android_repo/1.0.0/10222333/index.html
file uploaded: http://localhost:8081/repository/site/nexus_android_repo/1.0.0/10222333/DarkSouls.apk
file uploaded: http://localhost:8081/repository/site/nexus_android_repo/1.0.0/10222333/sample.apk
```

Access the index.html file url from your Android device!
__NOTE__: Currently supports only Nexus 3.

### Nexus IPA Upload

Upload an IPA file to a Nexus Site Repository
### Site Directory Layout

```bash
./gota nexus --nexusHost http://localhost:8081 \
--nexusRepo site \
--nexusUser admin \
--nexusPassword admin123 \
--destDir nexus_ios_repo \
--srcFile pkg/resources/DarkSouls.ipa \

file uploaded: http://localhost:8081/repository/site/nexus_ios_repo/1.0.0/4/appicon.png
file uploaded: http://localhost:8081/repository/site/nexus_ios_repo/version.json
file uploaded: http://localhost:8081/repository/site/nexus_ios_repo/1.0.0/4/index.html
file uploaded: http://localhost:8081/repository/site/nexus_ios_repo/1.0.0/4/DarkSouls.ipa
file uploaded: http://localhost:8081/repository/site/nexus_ios_repo/1.0.0/4/app.plist
destDir
\__(ipa CFBundleShortVersion or apk versionName)
\__version.json
\__(ipa CFBundleVersion or apk versionCode)
\__appicon.png
\__(ipa or apk file)
\__app.plist (if ipa file)
\__index.html
```

Access the index.html file url from your iPhone device!

## Development Setup

### Build and Test
Expand All @@ -120,6 +109,16 @@ go get -v ./...
go test -v ./...
```

### S3 Feature Test

Set these environment variables before running `go test` in s3 package.

```bash
AWS_ACCESS_KEY=xxxxx
AWS_SECRET_ACCESS_KEY=xxxxx
GOTEST_AWS_BUCKET=example-bucket
```

### Nexus Feature Test

You must have a Nexus 3 server running in your machine.
Expand Down
9 changes: 0 additions & 9 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,6 @@ var srcFile, destDir string
var rootCmd = &cobra.Command{
Use: "gota",
Short: "Go Over the Air installation for Android APK and iOS Ipa files!",
// Run: func(cmd *cobra.Command, args []string) {
// appInfo, err := ipapk.NewAppParser(srcFile)
// if err != nil {
// log.Fatal(err)
// }
// app.UploadDate = time.Now().Format(time.RFC1123)
// app.AppInfo = appInfo
// app.File = srcFile
// },
}

// Execute adds all child commands to the root command and sets flags appropriately.
Expand Down
72 changes: 72 additions & 0 deletions cmd/s3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright © 2018 NAME HERE <EMAIL ADDRESS>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package cmd

import (
"io/ioutil"
"log"
"os"
"strings"

"github.com/spf13/cobra"

"github.com/bzon/gota/s3"
)

var upload s3.Upload

// s3Cmd represents the s3 command
var s3Cmd = &cobra.Command{
Use: "s3",
Short: "Upload your apk or ipa file and create an over-the-air static site in an S3 Bucket directory",
Long: `Ensure that you have AWS_ACCESS_KEY and AWS_SECRET_ACCESS_KEY set in your environment variable.`,
Run: func(cmd *cobra.Command, args []string) {
if os.Getenv("AWS_ACCESS_KEY") == "" {
log.Fatal("AWS_ACCESS_KEY env variable is not set")
}
if os.Getenv("AWS_SECRET_ACCESS_KEY") == "" {
log.Fatal("AWS_SECRET_ACCESS_KEY env variable is not set")
}
app := NewMobileAppParser()
if err := app.GenerateAssets(); err != nil {
log.Fatal(err)
}
assets, err := s3.UploadAssets(app, upload.Bucket, destDir)
if err != nil {
log.Fatal(err)
}
for _, v := range assets {
log.Println("file uploaded:", v)
// write the index.html file (the ota link) to a file to gotalink.txt
if strings.Contains(v, "index.html") {
if err := ioutil.WriteFile("gotalink.txt", []byte(v), 0644); err != nil {
log.Fatal(err)
}
}
// write the ipa download link to a file ipalink.txt
if strings.Contains(v, ".ipa") {
if err := ioutil.WriteFile("ipalink.txt", []byte(v), 0644); err != nil {
log.Fatal(err)
}
}
}
},
}

func init() {
rootCmd.AddCommand(s3Cmd)
s3Cmd.Flags().StringVar(&upload.Bucket, "bucket", "", "the amazon s3 bucket name")
s3Cmd.MarkFlagRequired("bucket")
}
Binary file modified docs/gota_html.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/gota_workflow.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 12 additions & 12 deletions nexus/nexus_upload.go → nexus/upload.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,17 @@ type Nexus struct {

// NexusComponent contains the fields that will be passed as a parameter for NexusUpload
type NexusComponent struct {
File, Filename, Directory string
SrcFile, DestFilePath string
}

// NexusUpload uploads a file to Nexus returns the uploaded file url
func (n *Nexus) NexusUpload(c NexusComponent) (string, error) {
file, err := os.Open(c.File)
file, err := os.Open(c.SrcFile)
if err != nil {
return "", err
}
defer file.Close()
uri := n.getRepoURL() + "/" + c.Directory + "/" + c.Filename
uri := n.getRepoURL() + "/" + c.DestFilePath
req, err := http.NewRequest("PUT", uri, file)
if err != nil {
return "", err
Expand All @@ -54,13 +54,13 @@ func (n *Nexus) getRepoURL() string {
}

// NexusUploadAssets uploads the generated files by the parser package along with the ipa or apk file
func (n *Nexus) NexusUploadAssets(app *parser.MobileApp, dir string) ([]string, error) {
func (n *Nexus) NexusUploadAssets(app *parser.MobileApp, destBaseDir string) ([]string, error) {
// create the site path names and assume the url before uploaded for templating
buildDir := app.Version + "/" + app.Build
buildDir := destBaseDir + "/" + app.Version + "/" + app.Build
appIconPath := buildDir + "/" + parser.AppIconFile
appSitePath := buildDir + "/" + filepath.Base(app.File)
appIndexHTMLSitePath := buildDir + "/" + parser.IndexHTMLFile
app.DownloadURL = n.getRepoURL() + "/" + dir + "/" + appSitePath
app.DownloadURL = n.getRepoURL() + "/" + appSitePath

// default directory of assets
assetsDir := parser.AndroidAssetsDir
Expand All @@ -70,7 +70,7 @@ func (n *Nexus) NexusUploadAssets(app *parser.MobileApp, dir string) ([]string,
if app.IsIOS() {
assetsDir = parser.IOSAssetsDir
appPlistSitePath = buildDir + "/" + parser.IOSPlistFile
app.PlistURL = htmltemp.URL(n.getRepoURL() + "/" + dir + "/" + appPlistSitePath)
app.PlistURL = htmltemp.URL(n.getRepoURL() + "/" + appPlistSitePath)
}

// create the assets
Expand All @@ -80,13 +80,13 @@ func (n *Nexus) NexusUploadAssets(app *parser.MobileApp, dir string) ([]string,
}

components := []NexusComponent{
{assetsDir + "/" + parser.AppIconFile, appIconPath, dir},
{assetsDir + "/" + parser.VersionJsonFile, app.Version + "/" + parser.VersionJsonFile, dir},
{assetsDir + "/" + parser.IndexHTMLFile, appIndexHTMLSitePath, dir},
{app.File, appSitePath, dir},
{assetsDir + "/" + parser.AppIconFile, appIconPath},
{assetsDir + "/" + parser.VersionJsonFile, destBaseDir + "/" + app.Version + "/" + parser.VersionJsonFile},
{assetsDir + "/" + parser.IndexHTMLFile, appIndexHTMLSitePath},
{app.File, appSitePath},
}
if app.IsIOS() {
components = append(components, NexusComponent{assetsDir + "/" + parser.IOSPlistFile, appPlistSitePath, dir})
components = append(components, NexusComponent{assetsDir + "/" + parser.IOSPlistFile, appPlistSitePath})
}

for _, component := range components {
Expand Down
9 changes: 4 additions & 5 deletions nexus/nexus_upload_test.go → nexus/upload_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,8 @@ var nexus = Nexus{

func TestNexusUpload(t *testing.T) {
var testComponent = NexusComponent{
File: "../resources/index.html",
Filename: "index.html",
Directory: "go_upload_test",
SrcFile: "../resources/index.html",
DestFilePath: "go_upload_test/index.html",
}
uri, err := nexus.NexusUpload(testComponent)
if err != nil {
Expand All @@ -36,8 +35,8 @@ func TestNexusUploadAssets(t *testing.T) {
file string
}
tt := []tc{
{"upload ios assets", "nexus_ios_repo", "../parser/testdata/sample.ipa"},
{"upload android assets", "nexus_android_repo", "../parser/testdata/sample.apk"},
{"upload ios assets", "xx_ios", "../parser/testdata/sample.ipa"},
{"upload android assets", "xx_android", "../parser/testdata/sample.apk"},
}
for _, tc := range tt {
t.Run(tc.name, func(t *testing.T) {
Expand Down
Loading

0 comments on commit 8452cf8

Please sign in to comment.