Skip to content

Commit

Permalink
use k6provider
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Chacin <[email protected]>
  • Loading branch information
pablochacin committed Jan 28, 2025
1 parent c8d2c26 commit 67010f3
Show file tree
Hide file tree
Showing 12 changed files with 151 additions and 172 deletions.
9 changes: 1 addition & 8 deletions cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,6 @@ func New(levelVar *slog.LevelVar) *cobra.Command {

flags := root.PersistentFlags()

flags.StringVar(
&state.extensionCatalogURL,
"extension-catalog-url",
state.extensionCatalogURL,
"URL of the k6 extension catalog to be used",
)
flags.StringVar(
&state.buildServiceURL,
"build-service-url",
Expand All @@ -67,13 +61,12 @@ func New(levelVar *slog.LevelVar) *cobra.Command {
flags.BoolVarP(&state.quiet, "quiet", "q", false, "disable progress updates")
flags.BoolVar(&state.nocolor, "no-color", false, "disable colored output")
flags.BoolVar(&state.usage, "usage", false, "print launcher usage")
flags.BoolVar(&state.autoCleanup, "auto-cleanup", true, "remove binary after execution")

root.InitDefaultHelpFlag()
root.Flags().Lookup("help").Usage = "help for k6"
root.Flags().BoolVar(&state.version, "version", false, "version for k6")

root.MarkFlagsMutuallyExclusive("extension-catalog-url", "build-service-url")

return root
}

Expand Down
8 changes: 1 addition & 7 deletions cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"io"
"log/slog"
"os"
"strings"
"testing"

"github.com/grafana/k6exec/cmd"
Expand All @@ -25,18 +24,13 @@ func TestNew(t *testing.T) { //nolint:paralleltest

flags := c.PersistentFlags()

require.NotNil(t, flags.Lookup("extension-catalog-url"))
require.NotNil(t, flags.Lookup("build-service-url"))
require.NotNil(t, flags.Lookup("verbose"))
require.NotNil(t, flags.Lookup("quiet"))
require.NotNil(t, flags.Lookup("no-color"))

out := captureStdout(t, func() { require.NoError(t, c.Execute()) })

require.True(t, strings.Contains(out, " k6"))
}

//nolint:forbidigo
//nolint:forbidigo,unused
func captureStdout(t *testing.T, fn func()) string {
t.Helper()

Expand Down
6 changes: 0 additions & 6 deletions cmd/help.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ The build service URL can be specified in the `K6_BUILD_SERVICE_URL` environment

There is no default URL for the build service, otherwise k6exec will automatically provide k6 with the native builder.

#### Native Builder

To use the native builder, you only need to install the [Go language toolkit](https://go.dev/doc/install).

The native builder uses a k6 extension catalog to resolve extension URLs and versions. The extension catalog URL has a default value. A different extension catalog URL can be specified in the `K6_EXTENSION_CATALOG_URL` environment variable or by using the `--extension-catalog-url` flag.

### Dependencies

Dependencies can come from three sources: k6 test script, manifest file, `K6_DEPENDENCIES` environment variable. Instead of these three sources, a k6 archive can also be specified, which can contain all three sources.
Expand Down
4 changes: 2 additions & 2 deletions cmd/k6exec/main_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ func Test_newCmd(t *testing.T) { //nolint:paralleltest

lvar := new(slog.LevelVar)

// TODO: add more assertions and more test cases
cmd := newCmd([]string{"run", abs}, lvar)

require.NoError(t, cmd.Execute())
require.Equal(t, "k6exec", cmd.Name())
}

func Test_initLogging(t *testing.T) { //nolint:paralleltest
Expand Down
53 changes: 21 additions & 32 deletions cmd/state.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cmd
import (
"context"
"log/slog"
"net/url"
"os"
"os/exec"

Expand All @@ -13,18 +12,16 @@ import (

type state struct {
k6exec.Options
buildServiceURL string
extensionCatalogURL string
verbose bool
quiet bool
nocolor bool
version bool
usage bool
levelVar *slog.LevelVar

cmd *exec.Cmd

cleanup func() error
buildServiceURL string
verbose bool
quiet bool
nocolor bool
version bool
usage bool
levelVar *slog.LevelVar
cmd *exec.Cmd
autoCleanup bool
cleanup func() error
}

//nolint:forbidigo
Expand All @@ -33,34 +30,18 @@ func newState(levelVar *slog.LevelVar) *state {

s.levelVar = levelVar

// FIXME: Remove this as the k6provider library does it
if value, found := os.LookupEnv("K6_BUILD_SERVICE_URL"); found {
s.buildServiceURL = value
}

if value, found := os.LookupEnv("K6_EXTENSION_CATALOG_URL"); found {
s.extensionCatalogURL = value
}

return s
}

func (s *state) persistentPreRunE(_ *cobra.Command, _ []string) error {
// TODO: is this check necessary?
if len(s.buildServiceURL) > 0 {
val, err := url.Parse(s.buildServiceURL)
if err != nil {
return err
}

s.Options.BuildServiceURL = val
}

if len(s.extensionCatalogURL) > 0 {
val, err := url.Parse(s.extensionCatalogURL)
if err != nil {
return err
}

s.Options.ExtensionCatalogURL = val
s.Options.BuildServiceURL = s.buildServiceURL
}

if s.verbose && s.levelVar != nil {
Expand Down Expand Up @@ -115,13 +96,18 @@ func (s *state) preRunE(sub *cobra.Command, args []string) error {

s.cmd = cmd
s.cleanup = cleanup
// don't cleanup the binary
if !s.autoCleanup {
s.cleanup = func() error { return nil }
}

return nil
}

func (s *state) runE(_ *cobra.Command, _ []string) error {
var err error

// FIXME: I think this code is not setting the error to the cleanup function (pablochacin)
defer func() {
e := s.cleanup()
if err == nil {
Expand All @@ -138,6 +124,9 @@ func (s *state) helpFunc(cmd *cobra.Command, args []string) {
err := s.preRunE(cmd, append(args, "-h"))
if err != nil {
cmd.PrintErr(err)
// FIXME: added this return because in case of error provisioning the binary,
// it doesn't make sense to continue (pablochacin)
return
}

err = s.runE(cmd, args)
Expand Down
65 changes: 34 additions & 31 deletions cmd/state_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,19 @@ import (
"path/filepath"
"testing"

"github.com/grafana/k6build/pkg/testutils"
"github.com/grafana/k6exec"
"github.com/stretchr/testify/require"
)

func Test_newState(t *testing.T) {
lvar := new(slog.LevelVar)
t.Parallel()

t.Setenv("K6_BUILD_SERVICE_URL", "")
t.Setenv("K6_EXTENSION_CATALOG_URL", "")
lvar := new(slog.LevelVar)

st := newState(lvar)

require.Same(t, lvar, st.levelVar)
require.Empty(t, st.buildServiceURL)
require.Empty(t, st.extensionCatalogURL)

t.Setenv("K6_BUILD_SERVICE_URL", "foo")
t.Setenv("K6_EXTENSION_CATALOG_URL", "bar")

st = newState(lvar)

require.Equal(t, "foo", st.buildServiceURL)
require.Equal(t, "bar", st.extensionCatalogURL)
}

func Test_persistentPreRunE(t *testing.T) {
Expand All @@ -38,26 +28,15 @@ func Test_persistentPreRunE(t *testing.T) {
st := &state{levelVar: new(slog.LevelVar)}

require.NoError(t, st.persistentPreRunE(nil, nil))
require.Nil(t, st.BuildServiceURL)
require.Nil(t, st.ExtensionCatalogURL)
require.Empty(t, st.BuildServiceURL)
require.Equal(t, slog.LevelInfo, st.levelVar.Level())

st.buildServiceURL = "http://example.com"
st.extensionCatalogURL = "http://example.net"

require.NoError(t, st.persistentPreRunE(nil, nil))
require.Equal(t, "http://example.com", st.BuildServiceURL.String())
require.Equal(t, "http://example.net", st.ExtensionCatalogURL.String())

st.buildServiceURL = "http://example.com/%"
require.Error(t, st.persistentPreRunE(nil, nil))
require.Equal(t, "http://example.com", st.BuildServiceURL)

st.buildServiceURL = "http://example.com"
st.extensionCatalogURL = "http://example.net/%"
require.Error(t, st.persistentPreRunE(nil, nil))

st.buildServiceURL = "http://example.com"
st.extensionCatalogURL = "http://example.net"
st.verbose = true

require.NoError(t, st.persistentPreRunE(nil, nil))
Expand All @@ -70,9 +49,16 @@ func Test_persistentPreRunE(t *testing.T) {
func Test_preRunE(t *testing.T) {
t.Parallel()

env, err := testutils.NewTestEnv(testutils.TestEnvConfig{
WorkDir: t.TempDir(),
})
require.NoError(t, err)

t.Cleanup(env.Cleanup)

st := &state{
levelVar: new(slog.LevelVar),
Options: k6exec.Options{CacheDir: t.TempDir()},
Options: k6exec.Options{CacheDir: t.TempDir(), BuildServiceURL: env.BuildServiceURL()},
}

sub := newSubcommand("version", st)
Expand Down Expand Up @@ -117,12 +103,21 @@ func Test_preRunE(t *testing.T) {
func Test_runE(t *testing.T) {
t.Parallel()

env, err := testutils.NewTestEnv(testutils.TestEnvConfig{
WorkDir: t.TempDir(),
CatalogURL: "../testdata/minimal-catalog.json",
})
require.NoError(t, err)

t.Cleanup(env.Cleanup)

st := &state{
levelVar: new(slog.LevelVar),
Options: k6exec.Options{CacheDir: t.TempDir()},
levelVar: new(slog.LevelVar),
Options: k6exec.Options{CacheDir: t.TempDir(), BuildServiceURL: env.BuildServiceURL()},
autoCleanup: true,
}

err := st.preRunE(newSubcommand("version", st), nil)
err = st.preRunE(newSubcommand("version", st), nil)

require.NoError(t, err)

Expand All @@ -136,9 +131,17 @@ func Test_runE(t *testing.T) {
}

func Test_helpFunc(t *testing.T) { //nolint:paralleltest
env, err := testutils.NewTestEnv(testutils.TestEnvConfig{
WorkDir: t.TempDir(),
CatalogURL: "../testdata/minimal-catalog.json",
})
require.NoError(t, err)

t.Cleanup(env.Cleanup)

st := &state{
levelVar: new(slog.LevelVar),
Options: k6exec.Options{CacheDir: t.TempDir()},
Options: k6exec.Options{CacheDir: t.TempDir(), BuildServiceURL: env.BuildServiceURL()},
}

out := captureStderr(t, func() { st.helpFunc(newSubcommand("version", st), nil) })
Expand Down
28 changes: 4 additions & 24 deletions command.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,47 +4,27 @@ import (
"context"
"os"
"os/exec"
"path/filepath"

"github.com/grafana/k6provision"
)

// Command returns the exec.Cmd struct to execute k6 with the given arguments.
// If the given subcommand has a script argument, it analyzes the dependencies
// in the script and provisions a k6 executable based on them.
// In Options, you can also specify environment variable and manifest file as dependency sources.
// If no errors occur, the provisioned k6 executable will be placed in a temporary directory.
// The second return value is a cleanup function that is used to delete this temporary directory.
// TODO: as the cache is now handled by the k6provider library, consider removing the cleanup function
func Command(ctx context.Context, args []string, opts *Options) (*exec.Cmd, func() error, error) {
deps, err := analyze(args, opts)
if err != nil {
return nil, nil, err
}

dir, err := os.MkdirTemp("", "k6exec-*") //nolint:forbidigo
exe, err := provision(ctx, deps, opts)
if err != nil {
return nil, nil, err
}

exe := filepath.Join(dir, k6provision.ExeName)

if err := provision(ctx, deps, exe, opts); err != nil {
return nil, nil, err
}

cmd := exec.CommandContext(ctx, exe, args...) //nolint:gosec

return cmd, func() error { return os.RemoveAll(dir) }, nil //nolint:forbidigo
// FIXME: maybe we should just cleanup the binary and not all the CacheDir (pablochacin)
return cmd, func() error { return os.RemoveAll(opts.CacheDir) }, nil //nolint:forbidigo
}

/*
sum := sha256.Sum256([]byte(deps.String()))
dir := filepath.Join(os.TempDir(), "k6exec-"+hex.EncodeToString(sum[:]))
if err := os.MkdirAll(dir, 0o700); err != nil { //nolint:forbidigo
return nil, nil, err
}
exe := filepath.Join(dir, k6provision.ExeName)
*/
Loading

0 comments on commit 67010f3

Please sign in to comment.