Skip to content

Commit

Permalink
[testing] Add av command to simplify cross-repo tool maintenance
Browse files Browse the repository at this point in the history
  • Loading branch information
marun committed Dec 23, 2024
1 parent 934d00b commit 766bb37
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# TODO(marun) Document usage of direnv

# contains manually-installed tooling
PATH_add bin
# contains avalanchego and xsvm binaries
PATH_add build
# contains tool wrappers
PATH_add tools
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,5 @@ tests/upgrade/upgrade.test
vendor

**/testdata

.tool-downloads
3 changes: 2 additions & 1 deletion scripts/ginkgo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
set -euo pipefail

# Run the ginkgo version from go.mod
go run github.com/onsi/ginkgo/v2/ginkgo "${@}"
AVALANCHE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd )
${AVALANCHE_PATH}/scripts/av.sh tool ginkgo "$@"
172 changes: 172 additions & 0 deletions tests/av/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
// Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.

package main

import (
"errors"
"fmt"
"os"
"os/exec"
"path/filepath"

"github.com/spf13/cobra"
"go.uber.org/zap"

"github.com/ava-labs/avalanchego/tests"
"github.com/ava-labs/avalanchego/utils/logging"
"github.com/ava-labs/avalanchego/utils/perms"
)

const (
cmdName = "av"
kubectlVersion = "v1.30.2"
)

func main() {
var rawLogFormat string
rootCmd := &cobra.Command{
Use: cmdName,
Short: cmdName + " commands",
}
rootCmd.PersistentFlags().StringVar(&rawLogFormat, "log-format", logging.AutoString, logging.FormatDescription)

toolCmd := &cobra.Command{
Use: "tool",
Short: "configured cli tools",
RunE: func(*cobra.Command, []string) error {
return fmt.Errorf("please specify a valid tool name")

Check failure on line 38 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

string-format: no format directive, use errors.New instead (revive)

Check failure on line 38 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

fmt.Errorf can be replaced with errors.New (perfsprint)
},
}
rootCmd.AddCommand(toolCmd)

ginkgoCmd := &cobra.Command{
Use: "ginkgo",
Short: "cli for building and running e2e tests",
RunE: func(c *cobra.Command, args []string) error {
cmdArgs := []string{
"run",
"github.com/onsi/ginkgo/v2/ginkgo",
}
cmdArgs = append(cmdArgs, args...)
cmd := exec.Command("go", cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
// TODO(marun) Suppress the duplicated 'exit status X'
// caused by passing through the exit code from the
// `go run` subcommand
return cmd.Run()
},
}
toolCmd.AddCommand(ginkgoCmd)

tmpnetctlCmd := &cobra.Command{
Use: "tmpnetctl",
Short: "cli for managing temporary networks",
RunE: func(c *cobra.Command, args []string) error {
cmdArgs := []string{
"run",
"github.com/ava-labs/avalanchego/tests/fixture/tmpnet/cmd",
}
cmdArgs = append(cmdArgs, args...)
cmd := exec.Command("go", cmdArgs...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
// TODO(marun) Suppress the duplicated 'exit status X'
// caused by passing through the exit code from the
// `go run` subcommand
return cmd.Run()
},
}
toolCmd.AddCommand(tmpnetctlCmd)

kubectlCmd := &cobra.Command{
Use: "kubectl",
Short: "cli for interacting with a kubernetes cluster",
RunE: func(c *cobra.Command, args []string) error {
log, err := tests.LoggerForFormat("", rawLogFormat)
if err != nil {
return err
}

downloadDir, err := filepath.Abs(".tool-downloads")
if err != nil {
return err
}

// Ensure the download directory exists
if info, err := os.Stat(downloadDir); errors.Is(err, os.ErrNotExist) {
log.Info("creating tool download directory",
zap.String("dir", downloadDir),
)
if err := os.MkdirAll(downloadDir, perms.ReadWriteExecute); err != nil {
return err
}
} else if err != nil {
return err
} else if !info.IsDir() {
return fmt.Errorf("download path is not a directory: %s", downloadDir)
}

var (
kubectlPath = downloadDir + "/kubectl-" + kubectlVersion
// TODO(marun) Make these dynamic
kubeOS = "linux"
kubeArch = "arm64"
)

if _, err := os.Stat(downloadDir); errors.Is(err, os.ErrNotExist) {
// TODO(marun) Maybe use a library to download the binary?
curlArgs := []string{
"curl -L -o " + kubectlPath + " https://dl.k8s.io/release/" + kubectlVersion + "/bin/" + kubeOS + "/" + kubeArch + "/kubectl",
}
log.Info("downloading kubectl with curl",
zap.Strings("curlArgs", curlArgs),
)
// Run in a subshell to ensure -L redirects work
curl := exec.Command("bash", append([]string{"-x", "-c"}, curlArgs...)...)

Check failure on line 133 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

G204: Subprocess launched with a potential tainted input or cmd arguments (gosec)
curl.Stdin = os.Stdin
curl.Stdout = os.Stdout
curl.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
err = curl.Run()
if err != nil {
return err
}

if err := os.Chmod(kubectlPath, perms.ReadWriteExecute); err != nil {
return err
}

log.Info("running kubectl for the first time",
zap.String("path", kubectlPath),
)
}

kubectl := exec.Command(kubectlPath, args...)
kubectl.Stdin = os.Stdin
kubectl.Stdout = os.Stdout
kubectl.Stderr = os.Stderr
c.SilenceUsage = true
c.SilenceErrors = true
return kubectl.Run()
},
}
toolCmd.AddCommand(kubectlCmd)

if err := rootCmd.Execute(); err != nil {
var exitCode int = 1

Check failure on line 165 in tests/av/cmd/main.go

View workflow job for this annotation

GitHub Actions / Lint

ST1023: should omit type int from declaration; it will be inferred from the right-hand side (stylecheck)
if exitError, ok := err.(*exec.ExitError); ok {
exitCode = exitError.ExitCode()
}
os.Exit(exitCode)
}
os.Exit(0)
}
17 changes: 17 additions & 0 deletions tools/av
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash

set -euo pipefail

AVALANCHE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd )
cd ${AVALANCHE_PATH}

# Set the CGO flags to use the portable version of BLST
#
# We use "export" here instead of just setting a bash variable because we need
# to pass this flag to all child processes spawned by the shell.
export CGO_CFLAGS="-O2 -D__BLST_PORTABLE__"
# While CGO_ENABLED doesn't need to be explicitly set, it produces a much more
# clear error due to the default value change in go1.20.
export CGO_ENABLED=1

go run ./tests/av/cmd "${@}"
6 changes: 6 additions & 0 deletions tools/ginkgo
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool ginkgo "$@"
6 changes: 6 additions & 0 deletions tools/kubectl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool kubectl "$@"
6 changes: 6 additions & 0 deletions tools/tmpnetctl
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -euo pipefail

TOOLS_DIR="$( dirname "${BASH_SOURCE[0]}" )"
${TOOLS_DIR}/av tool tmpnetctl "$@"

0 comments on commit 766bb37

Please sign in to comment.