Skip to content

Commit

Permalink
Add build commands
Browse files Browse the repository at this point in the history
  • Loading branch information
ipmb committed Dec 12, 2020
1 parent 8e5d0bd commit 5d8a035
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 0 deletions.
108 changes: 108 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/codebuild"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
"github.com/aws/aws-sdk-go/service/ecs"
"github.com/aws/aws-sdk-go/service/s3"
"github.com/aws/aws-sdk-go/service/ssm"
"github.com/lincolnloop/apppack/auth"
"github.com/logrusorgru/aurora"
Expand Down Expand Up @@ -67,6 +69,9 @@ type Settings struct {
S3Bucket string `json:"s3_bucket"`
DumpLoadTaskFamily string `json:"dumpload_task_family"`
} `json:"dbutils"`
CodebuildProject struct {
Name string `json:"name"`
} `json:"codebuild_project"`
LogGroup struct {
Name string `json:"name"`
} `json:"log_group"`
Expand Down Expand Up @@ -283,6 +288,109 @@ func (a *App) ConnectToTask(task *ecs.Task, cmd *string) error {
return nil
}

// StartBuild starts a new CodeBuild run
func (a *App) StartBuild() (*codebuild.Build, error) {
codebuildSvc := codebuild.New(a.Session)
err := a.LoadSettings()
if err != nil {
return nil, err
}
build, err := codebuildSvc.StartBuild(&codebuild.StartBuildInput{
ProjectName: &a.Settings.CodebuildProject.Name,
})
return build.Build, err
}

// ListBuilds lists recent CodeBuild runs
func (a *App) ListBuilds() ([]*codebuild.Build, error) {
codebuildSvc := codebuild.New(a.Session)
err := a.LoadSettings()
if err != nil {
return nil, err
}
buildList, err := codebuildSvc.ListBuildsForProject(&codebuild.ListBuildsForProjectInput{
ProjectName: &a.Settings.CodebuildProject.Name,
})
if err != nil {
return nil, err
}
builds, err := codebuildSvc.BatchGetBuilds(&codebuild.BatchGetBuildsInput{
Ids: buildList.Ids,
})
if err != nil {
return nil, err
}
return builds.Builds, nil
}

// GetBuildArtifact retrieves an artifact stored in S3
func (a *App) GetBuildArtifact(build *codebuild.Build, name string) ([]byte, error) {
artifactArn := build.Artifacts.Location
if artifactArn == nil {
return []byte{}, nil
}
s3Path := strings.Join(strings.Split(*artifactArn, ":")[5:], ":")
pathParts := strings.Split(s3Path, "/")
s3Svc := s3.New(a.Session)
obj, err := s3Svc.GetObject(&s3.GetObjectInput{
Bucket: &pathParts[0],
Key: aws.String(strings.Join(append(pathParts[1:], name), "/")),
})
if err != nil {
return []byte{}, err
}
return ioutil.ReadAll(obj.Body)
}

// GetConsoleURL generate a URL which will sign the user in to the AWS console and redirect to the desinationURL
func (a *App) GetConsoleURL(destinationURL string) (*string, error) {
credentials, err := a.Session.Config.Credentials.Get()
if err != nil {
return nil, err
}
sessionJSON, err := json.Marshal(map[string]string{
"sessionId": credentials.AccessKeyID,
"sessionKey": credentials.SecretAccessKey,
"sessionToken": credentials.SessionToken,
})
if err != nil {
return nil, err
}
client := &http.Client{}
signinURL := "https://signin.aws.amazon.com/federation"
req, err := http.NewRequest("GET", signinURL, nil)
if err != nil {
return nil, err
}
q := req.URL.Query()
q.Add("Action", "getSigninToken")
q.Add("SessionDuration", "3600")
q.Add("Session", fmt.Sprintf("%s", sessionJSON))
req.URL.RawQuery = q.Encode()
resp, err := client.Do(req)
signinResp := struct {
SigninToken string `json:"SigninToken"`
}{}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
if err = json.Unmarshal(body, &signinResp); err != nil {
return nil, err
}
req, err = http.NewRequest("GET", signinURL, nil)
if err != nil {
return nil, err
}
q = req.URL.Query()
q.Add("Action", "login")
q.Add("Issuer", "AppPack.io")
q.Add("SigninToken", signinResp.SigninToken)
q.Add("Destination", destinationURL)
req.URL.RawQuery = q.Encode()
return aws.String(req.URL.String()), nil
}

// Init will pull in app settings from DyanmoDB and provide helper
func Init(name string) (*App, error) {
sess, err := auth.AwsSession(name)
Expand Down
123 changes: 123 additions & 0 deletions cmd/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/*
Copyright © 2020 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 (
"fmt"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/codebuild"
"github.com/dustin/go-humanize"
"github.com/lincolnloop/apppack/app"
"github.com/logrusorgru/aurora"
"github.com/spf13/cobra"
)

const indentStr = " "

func indent(text, indent string) string {
if len(text) == 0 {
return indent
}
if text[len(text)-1:] == "\n" {
result := ""
for _, j := range strings.Split(text[:len(text)-1], "\n") {
result += indent + j + "\n"
}
return result
}
result := ""
for _, j := range strings.Split(strings.TrimRight(text, "\n"), "\n") {
result += indent + j + "\n"
}
return result[:len(result)-1]
}

func printBuild(build *codebuild.Build, commitLog []byte) error {
icon := map[string]aurora.Value{
"IN_PROGRESS": aurora.Faint(aurora.Blue("ℹ")),
"SUCCEEDED": aurora.Green("✔"),
"FAILED": aurora.Red("✖"),
}
fmt.Print(aurora.Faint("==="), aurora.White(fmt.Sprintf("%d", *build.BuildNumber)))
if build.BuildStatus == aws.String("IN_PROGRESS") {
fmt.Print(" in progress")
}
fmt.Print(" ", aurora.Blue(*build.SourceVersion), icon[*build.BuildStatus])
fmt.Println()
if build.EndTime != nil {
fmt.Println(aurora.Faint(fmt.Sprintf("%s%s ~ %s", indentStr, build.EndTime.Local().Format("Jan 02, 2006 15:04:05 MST"), humanize.Time(*build.EndTime))))
} else {
fmt.Println(aurora.Faint(fmt.Sprintf("%sstarted %s ~ %s", indentStr, build.StartTime.Local().Format("Jan 02, 2006 15:04:05 MST"), humanize.Time(*build.EndTime))))
}
fmt.Println(indent(fmt.Sprintf("%s", commitLog), indentStr))
return nil
}

// buildCmd represents the build command
var buildCmd = &cobra.Command{
Use: "build",
Short: "Work with AppPack builds",
Long: `Use to view, list, and trigger code builds.`,
}

// buildStartCmd represents the start command
var buildStartCmd = &cobra.Command{
Use: "start",
Short: "Start a new build from the latest commit on the branch defined in AppPack",
Long: `Start a new build from the latest commit on the branch defined in AppPack`,
Run: func(cmd *cobra.Command, args []string) {
Spinner.Start()
a, err := app.Init(AppName)
checkErr(err)
build, err := a.StartBuild()
checkErr(err)
Spinner.Stop()
printSuccess("Build started")
err = printBuild(build, []byte{})
checkErr(err)
},
}

// buildListCmd represents the list command
var buildListCmd = &cobra.Command{
Use: "list",
Short: "List recent builds",
Long: `List recent builds`,
Run: func(cmd *cobra.Command, args []string) {
Spinner.Start()
a, err := app.Init(AppName)
checkErr(err)
builds, err := a.ListBuilds()
checkErr(err)
Spinner.Stop()
for _, build := range builds {
commitLog, _ := a.GetBuildArtifact(build, "commit.txt")
err = printBuild(build, commitLog)
checkErr(err)
}
},
}

func init() {
rootCmd.AddCommand(buildCmd)
buildCmd.PersistentFlags().StringVarP(&AppName, "app-name", "a", "", "App name (required)")
buildCmd.MarkPersistentFlagRequired("app-name")

buildCmd.AddCommand(buildStartCmd)
buildCmd.AddCommand(buildListCmd)
}
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/TylerBrock/saw v0.2.2
github.com/aws/aws-sdk-go v1.35.35
github.com/briandowns/spinner v1.12.0
github.com/dustin/go-humanize v1.0.0
github.com/google/uuid v1.1.2
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/pkg/browser v0.0.0-20201112035734-206646e67786
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
Expand Down

0 comments on commit 5d8a035

Please sign in to comment.