Repository: bacalhau-project/bacalhau (language: python)

Issue:
Move `bacalhau logs` to `bacalhau job logs`
Remove the legacy command from the CLI and direct users to use the new command via a helpful error message. e.g.
```
This command has moved! Please use `job logs` to view job logs.
```


Discussion / hints:

Fix patch:
diff --git a/cmd/cli/cancel/cancel.go b/cmd/cli/cancel/cancel.go
index 4bfb158af2..a4a7cbb9a3 100644
--- a/cmd/cli/cancel/cancel.go
+++ b/cmd/cli/cancel/cancel.go
@@ -8,7 +8,7 @@ func NewCmd() *cobra.Command {
 	cancelCmd := &cobra.Command{
 		Use:        "cancel [id]",
 		Short:      "DEPRECATED: Cancel a previously submitted job",
-		Deprecated: "This command has moved! Please us `job stop` to cancel jobs.",
+		Deprecated: "This command has moved! Please use `job stop` to cancel jobs.",
 		Args:       cobra.ExactArgs(1),
 		RunE: func(cmd *cobra.Command, cmdArgs []string) error {
 			return nil
diff --git a/cmd/cli/describe/describe.go b/cmd/cli/describe/describe.go
index ec6fd37254..7e2f68d00f 100644
--- a/cmd/cli/describe/describe.go
+++ b/cmd/cli/describe/describe.go
@@ -1,154 +1,14 @@
 package describe
 
 import (
-	"encoding/json"
-	"fmt"
-
 	"github.com/spf13/cobra"
-	"k8s.io/kubectl/pkg/util/i18n"
-	"sigs.k8s.io/yaml"
-
-	"github.com/bacalhau-project/bacalhau/pkg/publicapi/apimodels/legacymodels"
-	"github.com/bacalhau-project/bacalhau/pkg/publicapi/client"
-
-	"github.com/bacalhau-project/bacalhau/cmd/util"
-	"github.com/bacalhau-project/bacalhau/cmd/util/hook"
-	"github.com/bacalhau-project/bacalhau/pkg/bacerrors"
-	"github.com/bacalhau-project/bacalhau/pkg/util/templates"
 )
 
-var (
-	//nolint:lll // Documentation
-	describeLong = templates.LongDesc(i18n.T(`
-		Full description of a job, in yaml format. Use 'bacalhau list' to get a list of all ids. Short form and long form of the job id are accepted.
-`))
-	//nolint:lll // Documentation
-	describeExample = templates.Examples(i18n.T(`
-		# Describe a job with the full ID
-		bacalhau describe j-e3f8c209-d683-4a41-b840-f09b88d087b9
-
-		# Describe a job with the a shortened ID
-		bacalhau describe j-47805f5c
-
-		# Describe a job and include all server and local events
-		bacalhau describe --include-events j-b6ad164a
-`))
-)
-
-type DescribeOptions struct {
-	Filename      string // Filename for job (can be .json or .yaml)
-	IncludeEvents bool   // Include events in the description
-	OutputSpec    bool   // Print Just the jobspec to stdout
-	JSON          bool   // Print description as JSON
-}
-
-func NewDescribeOptions() *DescribeOptions {
-	return &DescribeOptions{
-		IncludeEvents: false,
-		OutputSpec:    false,
-		JSON:          false,
-	}
-}
-
 func NewCmd() *cobra.Command {
-	OD := NewDescribeOptions()
-
-	describeCmd := &cobra.Command{
-		Use:      "describe [id]",
-		Short:    "Describe a job on the network",
-		Long:     describeLong,
-		Example:  describeExample,
-		Args:     cobra.ExactArgs(1),
-		PreRunE:  hook.RemoteCmdPreRunHooks,
-		PostRunE: hook.RemoteCmdPostRunHooks,
-		RunE: func(cmd *cobra.Command, cmdArgs []string) error {
-			// initialize a new or open an existing repo merging any config file(s) it contains into cfg.
-			cfg, err := util.SetupRepoConfig(cmd)
-			if err != nil {
-				return fmt.Errorf("failed to setup repo: %w", err)
-			}
-			// create an api client
-			api, err := util.GetAPIClient(cfg)
-			if err != nil {
-				return fmt.Errorf("failed to create api client: %w", err)
-			}
-			return describe(cmd, cmdArgs, api, OD)
-		},
+	return &cobra.Command{
+		Use:        "describe [id]",
+		Short:      "DEPRECATED: Describe a job on the network",
+		Deprecated: "This command has moved! Please use `job describe` to describe jobs.",
+		RunE:       func(cmd *cobra.Command, cmdArgs []string) error { return nil },
 	}
-
-	describeCmd.PersistentFlags().BoolVar(
-		&OD.OutputSpec, "spec", OD.OutputSpec,
-		`Output Jobspec to stdout`,
-	)
-	describeCmd.PersistentFlags().BoolVar(
-		&OD.IncludeEvents, "include-events", OD.IncludeEvents,
-		`Include events in the description (could be noisy)`,
-	)
-	describeCmd.PersistentFlags().BoolVar(
-		&OD.JSON, "json", OD.JSON,
-		`Output description as JSON (if not included will be outputted as YAML by default)`,
-	)
-
-	return describeCmd
-}
-
-func describe(cmd *cobra.Command, cmdArgs []string, api *client.APIClient, OD *DescribeOptions) error {
-	ctx := cmd.Context()
-
-	if err := cmd.ParseFlags(cmdArgs[1:]); err != nil {
-		return fmt.Errorf("failed to parse flags: %w", err)
-	}
-
-	var err error
-	inputJobID := cmdArgs[0]
-	if inputJobID == "" {
-		var byteResult []byte
-		byteResult, err = util.ReadFromStdinIfAvailable(cmd)
-		// If there's no input and no stdin, then cmdArgs is nil and byteResult is nil.
-		if err != nil {
-			return fmt.Errorf("unknown error reading from file: %w", err)
-		}
-		inputJobID = string(byteResult)
-	}
-
-	j, foundJob, err := api.Get(ctx, inputJobID)
-	if err != nil {
-		if errResp, ok := err.(*bacerrors.ErrorResponse); ok {
-			return errResp
-		}
-		return fmt.Errorf("unknown error trying to get job (ID: %s): %w", inputJobID, err)
-	}
-
-	if !foundJob {
-		return fmt.Errorf("job not found: %w", err)
-	}
-
-	jobDesc := j
-
-	if OD.IncludeEvents {
-		jobEvents, err := api.GetEvents(ctx, j.Job.Metadata.ID, legacymodels.EventFilterOptions{})
-		if err != nil {
-			return fmt.Errorf("failure retrieving job events '%s': %w", j.Job.Metadata.ID, err)
-		}
-		jobDesc.History = jobEvents
-	}
-
-	b, err := json.Marshal(jobDesc)
-	if err != nil {
-		return fmt.Errorf("failure marshaling job description '%s': %w", j.Job.Metadata.ID, err)
-	}
-
-	if !OD.JSON {
-		// Convert Json to Yaml
-		y, err := yaml.JSONToYAML(b)
-		if err != nil {
-			return fmt.Errorf("able to marshal to YAML but not JSON whatttt '%s': %w", j.Job.Metadata.ID, err)
-		}
-		cmd.Print(string(y))
-	} else {
-		// Print as Json
-		cmd.Print(string(b))
-	}
-
-	return nil
 }
diff --git a/cmd/cli/id/id.go b/cmd/cli/id/id.go
index 4082c99d5a..af560aa3f0 100644
--- a/cmd/cli/id/id.go
+++ b/cmd/cli/id/id.go
@@ -1,94 +1,14 @@
 package id
 
 import (
-	"fmt"
-
-	"github.com/jedib0t/go-pretty/v6/table"
 	"github.com/spf13/cobra"
-	"github.com/spf13/viper"
-
-	"github.com/bacalhau-project/bacalhau/cmd/util"
-	"github.com/bacalhau-project/bacalhau/cmd/util/flags/cliflags"
-	"github.com/bacalhau-project/bacalhau/cmd/util/flags/configflags"
-	"github.com/bacalhau-project/bacalhau/cmd/util/output"
-	"github.com/bacalhau-project/bacalhau/pkg/config"
-	"github.com/bacalhau-project/bacalhau/pkg/config/types"
-	bac_libp2p "github.com/bacalhau-project/bacalhau/pkg/libp2p"
-	"github.com/bacalhau-project/bacalhau/pkg/util/closer"
 )
 
-type IDInfo struct {
-	ID       string `json:"ID"`
-	ClientID string `json:"ClientID"`
-}
-
 func NewCmd() *cobra.Command {
-	outputOpts := output.OutputOptions{
-		Format: output.JSONFormat,
-	}
-
-	idFlags := map[string][]configflags.Definition{
-		"libp2p": configflags.Libp2pFlags,
+	return &cobra.Command{
+		Use:        "id",
+		Short:      "DEPRECATED: Show bacalhau node id info",
+		Deprecated: "This command has moved! Please use `agent node` to inspect bacalhau nodes.",
+		RunE:       func(cmd *cobra.Command, _ []string) error { return nil },
 	}
-
-	idCmd := &cobra.Command{
-		Use:   "id",
-		Short: "Show bacalhau node id info",
-		PreRunE: func(cmd *cobra.Command, _ []string) error {
-			return configflags.BindFlags(cmd, viper.GetViper(), idFlags)
-		},
-		RunE: func(cmd *cobra.Command, _ []string) error {
-			// initialize a new or open an existing repo merging any config file(s) it contains into cfg.
-			cfg, err := util.SetupRepoConfig(cmd)
-			if err != nil {
-				return fmt.Errorf("failed to setup repo: %w", err)
-			}
-			return id(cmd, cfg, outputOpts)
-		},
-	}
-
-	// TODO(forrest): [ux] these are flags without a corresponding value in the config
-	// in the future we can bind all flags to a config value.
-	idCmd.Flags().AddFlagSet(cliflags.OutputFormatFlags(&outputOpts))
-
-	if err := configflags.RegisterFlags(idCmd, idFlags); err != nil {
-		util.Fatal(idCmd, err, 1)
-	}
-
-	return idCmd
-}
-
-var idColumns = []output.TableColumn[IDInfo]{
-	{
-		ColumnConfig: table.ColumnConfig{Name: "id"},
-		Value:        func(i IDInfo) string { return i.ID },
-	},
-	{
-		ColumnConfig: table.ColumnConfig{Name: "client id"},
-		Value:        func(i IDInfo) string { return i.ClientID },
-	},
-}
-
-func id(cmd *cobra.Command, cfg types.BacalhauConfig, outputOpts output.OutputOptions) error {
-	privKey, err := config.GetLibp2pPrivKey(cfg.User.Libp2pKeyPath)
-	if err != nil {
-		return err
-	}
-
-	libp2pHost, err := bac_libp2p.NewHost(cfg.Node.Libp2p.SwarmPort, privKey)
-	if err != nil {
-		return err
-	}
-	defer closer.CloseWithLogOnError("libp2pHost", libp2pHost)
-
-	clientID, err := config.GetClientID(cfg.User.KeyPath)
-	if err != nil {
-		return err
-	}
-	info := IDInfo{
-		ID:       libp2pHost.ID().String(),
-		ClientID: clientID,
-	}
-
-	return output.OutputOne(cmd, idColumns, outputOpts, info)
 }
diff --git a/cmd/cli/list/list.go b/cmd/cli/list/list.go
index 541153cad9..11cfeb1bae 100644
--- a/cmd/cli/list/list.go
+++ b/cmd/cli/list/list.go
@@ -1,215 +1,14 @@
 package list
 
 import (
-	"errors"
-	"fmt"
-	"time"
-
-	"github.com/jedib0t/go-pretty/v6/table"
-	"github.com/jedib0t/go-pretty/v6/text"
 	"github.com/spf13/cobra"
-	"k8s.io/kubectl/pkg/util/i18n"
-
-	"github.com/bacalhau-project/bacalhau/pkg/publicapi/client"
-	"github.com/bacalhau-project/bacalhau/pkg/util/idgen"
-
-	"github.com/bacalhau-project/bacalhau/cmd/util/flags/cliflags"
-	"github.com/bacalhau-project/bacalhau/cmd/util/hook"
-	"github.com/bacalhau-project/bacalhau/pkg/lib/math"
-
-	"github.com/bacalhau-project/bacalhau/cmd/util"
-	"github.com/bacalhau-project/bacalhau/cmd/util/output"
-	legacy_job "github.com/bacalhau-project/bacalhau/pkg/legacyjob"
-	"github.com/bacalhau-project/bacalhau/pkg/model"
-	"github.com/bacalhau-project/bacalhau/pkg/util/templates"
 )
 
-var (
-	listLong = templates.LongDesc(i18n.T(`
-		List jobs on the network.
-`))
-
-	listExample = templates.Examples(i18n.T(`
-		# List jobs on the network
-		bacalhau list
-
-		# List jobs and output as json
-		bacalhau list --output json`))
-
-	// The tags that will be excluded by default, if the user does not pass any
-	// others to the list command.
-	DefaultExcludedTags = []string{
-		"canary",
-	}
-)
-
-type ListOptions struct {
-	IDFilter    string               // Filter by Job List to IDs matching substring.
-	IncludeTags []string             // Only return jobs with these annotations
-	ExcludeTags []string             // Only return jobs without these annotations
-	MaxJobs     int                  // Print the first NUM jobs instead of the first 10.
-	OutputOpts  output.OutputOptions // The output format for the list of jobs (json or text)
-	SortReverse bool                 // Reverse order of table - for time sorting, this will be newest first.
-	SortBy      ColumnEnum           // Sort by field, defaults to creation time, with newest first [Allowed "id", "created_at"].
-	ReturnAll   bool                 // Return all jobs, not just those that belong to the user
-}
-
-func NewListOptions() *ListOptions {
-	return &ListOptions{
-		IDFilter:    "",
-		IncludeTags: model.IncludeAny,
-		ExcludeTags: DefaultExcludedTags,
-		MaxJobs:     10,
-		OutputOpts:  output.OutputOptions{Format: output.TableFormat},
-		SortReverse: true,
-		SortBy:      ColumnCreatedAt,
-		ReturnAll:   false,
-	}
-}
-
 func NewCmd() *cobra.Command {
-	OL := NewListOptions()
-
-	listCmd := &cobra.Command{
-		Use:      "list",
-		Short:    "List jobs on the network",
-		Long:     listLong,
-		Example:  listExample,
-		PreRunE:  hook.RemoteCmdPreRunHooks,
-		PostRunE: hook.RemoteCmdPostRunHooks,
-		RunE: func(cmd *cobra.Command, _ []string) error {
-			// initialize a new or open an existing repo merging any config file(s) it contains into cfg.
-			cfg, err := util.SetupRepoConfig(cmd)
-			if err != nil {
-				return fmt.Errorf("failed to setup repo: %w", err)
-			}
-			// create an api client
-			api, err := util.GetAPIClient(cfg)
-			if err != nil {
-				return fmt.Errorf("failed to create api client: %w", err)
-			}
-			return list(cmd, api, OL)
-		},
-	}
-
-	listCmd.PersistentFlags().StringVar(&OL.IDFilter, "id-filter", OL.IDFilter, `filter by Job List to IDs matching substring.`)
-	listCmd.PersistentFlags().StringSliceVar(&OL.IncludeTags, "include-tag", OL.IncludeTags,
-		`Only return jobs that have the passed tag in their annotations`)
-	listCmd.PersistentFlags().StringSliceVar(&OL.ExcludeTags, "exclude-tag", OL.ExcludeTags,
-		`Only return jobs that do not have the passed tag in their annotations`)
-	listCmd.PersistentFlags().IntVarP(
-		&OL.MaxJobs, "number", "n", OL.MaxJobs,
-		`print the first NUM jobs instead of the first 10.`,
-	)
-	listCmd.PersistentFlags().BoolVar(&OL.SortReverse, "reverse", OL.SortReverse,
-		//nolint:lll // Documentation
-		`reverse order of table - for time sorting, this will be newest first. Use '--reverse=false' to sort oldest first (single quotes are required).`)
-
-	listCmd.PersistentFlags().Var(&OL.SortBy, "sort-by",
-		`sort by field, defaults to creation time, with newest first [Allowed "id", "created_at"].`)
-	listCmd.PersistentFlags().Lookup("sort-by").DefValue = string(ColumnCreatedAt)
-	if OL.SortBy == "" {
-		OL.SortBy = ColumnCreatedAt
-	}
-	listCmd.PersistentFlags().BoolVar(
-		&OL.ReturnAll, "all", OL.ReturnAll,
-		//nolint:lll // Documentation
-		`Fetch all jobs from the network (default is to filter those belonging to the user). This option may take a long time to return, please use with caution.`,
-	)
-	listCmd.PersistentFlags().AddFlagSet(cliflags.OutputFormatFlags(&OL.OutputOpts))
-
-	return listCmd
-}
-
-// From: https://stackoverflow.com/questions/50824554/permitted-flag-values-for-cobra
-type ColumnEnum string
-
-const (
-	ColumnID        ColumnEnum = "id"
-	ColumnCreatedAt ColumnEnum = "created_at"
-)
-
-func (c *ColumnEnum) String() string {
-	return string(*c)
-}
-
-// Type is only used in help text
-func (c *ColumnEnum) Type() string {
-	return "Column"
-}
-
-// Set must have pointer receiver so it doesn't change the value of a copy
-func (c *ColumnEnum) Set(v string) error {
-	switch v {
-	case string(ColumnID), string(ColumnCreatedAt):
-		*c = ColumnEnum(v)
-		return nil
-	default:
-		return errors.New(`must be one of "id", or "created_at"`)
+	return &cobra.Command{
+		Use:        "list",
+		Short:      "DEPRECATED: List jobs on the network",
+		Deprecated: "This command has moved! Please use `job list` to list jobs.",
+		RunE:       func(cmd *cobra.Command, _ []string) error { return nil },
 	}
 }
-
-const (
-	maxDescWidth = 40
-	maxDescLines = 10
-)
-
-var listColumns = []output.TableColumn[*model.JobWithInfo]{
-	{
-		ColumnConfig: table.ColumnConfig{Name: "created", WidthMax: 8, WidthMaxEnforcer: shortenTime},
-		Value:        func(j *model.JobWithInfo) string { return j.Job.Metadata.CreatedAt.Format(time.DateTime) },
-	},
-	{
-		ColumnConfig: table.ColumnConfig{
-			Name:             "id",
-			WidthMax:         idgen.ShortIDLengthWithPrefix,
-			WidthMaxEnforcer: func(col string, maxLen int) string { return idgen.ShortUUID(col) }},
-		Value: func(jwi *model.JobWithInfo) string { return jwi.Job.ID() },
-	},
-	{
-		ColumnConfig: table.ColumnConfig{Name: "job", WidthMax: maxDescWidth, WidthMaxEnforcer: text.WrapText},
-		Value: func(j *model.JobWithInfo) string {
-			finalStr := fmt.Sprintf("%v", j.Job.Spec.EngineSpec)
-			return finalStr[:math.Min(len(finalStr), maxDescLines*maxDescWidth)]
-		},
-	},
-	{
-		ColumnConfig: table.ColumnConfig{Name: "state", WidthMax: 20, WidthMaxEnforcer: text.WrapText},
-		Value:        func(jwi *model.JobWithInfo) string { return legacy_job.ComputeStateSummary(jwi.State) },
-	},
-	{
-		ColumnConfig: table.ColumnConfig{Name: "published"},
-		Value:        legacy_job.ComputeResultsSummary,
-	},
-}
-
-func list(cmd *cobra.Command, api *client.APIClient, OL *ListOptions) error {
-	ctx := cmd.Context()
-	jobs, err := api.List(
-		ctx,
-		OL.IDFilter,
-		OL.IncludeTags,
-		OL.ExcludeTags,
-		OL.MaxJobs,
-		OL.ReturnAll,
-		OL.SortBy.String(),
-		OL.SortReverse,
-	)
-	if err != nil {
-		return err
-	}
-
-	return output.Output(cmd, listColumns, OL.OutputOpts, jobs)
-}
-
-func shortenTime(formattedTime string, maxLen int) string {
-	if len(formattedTime) > maxLen {
-		t, err := time.Parse(time.DateTime, formattedTime)
-		if err != nil {
-			panic(err)
-		}
-		formattedTime = t.Format(time.TimeOnly)
-	}
-
-	return formattedTime
-}
diff --git a/cmd/cli/logs/logs.go b/cmd/cli/logs/logs.go
index 8afa22578e..688211611e 100644
--- a/cmd/cli/logs/logs.go
+++ b/cmd/cli/logs/logs.go
@@ -2,31 +2,13 @@ package logs
 
 import (
 	"github.com/spf13/cobra"
-	"k8s.io/kubectl/pkg/util/i18n"
-
-	"github.com/bacalhau-project/bacalhau/cmd/cli/job"
-
-	"github.com/bacalhau-project/bacalhau/pkg/util/templates"
-)
-
-var (
-	logsShortDesc = templates.LongDesc(i18n.T(`
-		Follow logs from a currently executing job
-`))
-
-	//nolint:lll // Documentation
-	logsExample = templates.Examples(i18n.T(`
-		# Follow logs for a previously submitted job
-		bacalhau logs j-51225160-807e-48b8-88c9-28311c7899e1
-
-		# Follow output with a short ID
-		bacalhau logs j-ebd9bf2f
-`))
 )
 
 func NewCmd() *cobra.Command {
-	cmd := job.NewLogCmd()
-	cmd.Short = logsShortDesc
-	cmd.Example = logsExample
-	return cmd
+	return &cobra.Command{
+		Use:        "logs [id]",
+		Short:      "DEPRECATED: Follow logs from a currently executing job",
+		Deprecated: "This command has moved! Please use `job logs` to follow job logs.",
+		RunE:       func(cmd *cobra.Command, _ []string) error { return nil },
+	}
 }


Test patch:
diff --git a/cmd/cli/describe/describe_test.go b/cmd/cli/describe/describe_test.go
deleted file mode 100644
index 2e133e88fa..0000000000
--- a/cmd/cli/describe/describe_test.go
+++ /dev/null
@@ -1,262 +0,0 @@
-//go:build unit || !integration
-
-package describe_test
-
-import (
-	"context"
-	"fmt"
-	"strings"
-	"testing"
-
-	"github.com/bacalhau-project/bacalhau/pkg/util/idgen"
-	"github.com/google/uuid"
-	"github.com/stretchr/testify/suite"
-
-	cmdtesting "github.com/bacalhau-project/bacalhau/cmd/testing"
-	"github.com/bacalhau-project/bacalhau/pkg/bacerrors"
-	legacy_job "github.com/bacalhau-project/bacalhau/pkg/legacyjob"
-	"github.com/bacalhau-project/bacalhau/pkg/model"
-	testutils "github.com/bacalhau-project/bacalhau/pkg/test/utils"
-)
-
-// Define the suite, and absorb the built-in basic suite
-// functionality from testify - including a T() method which
-// returns the current testing context
-type DescribeSuite struct {
-	cmdtesting.BaseSuite
-}
-
-func (s *DescribeSuite) TestDescribeJob() {
-	tests := []struct {
-		numberOfAcceptNodes int
-		numberOfRejectNodes int
-		jobState            string
-	}{
-		{numberOfAcceptNodes: 1, numberOfRejectNodes: 0, jobState: model.JobEventResultsPublished.String()}, // Run and accept
-		{numberOfAcceptNodes: 2, numberOfRejectNodes: 0, jobState: model.JobEventResultsPublished.String()}, // Run and accept
-		{numberOfAcceptNodes: 1, numberOfRejectNodes: 1, jobState: model.JobEventResultsPublished.String()}, // Run and accept
-	}
-
-	numOfJobsTests := []struct {
-		numOfJobs int
-	}{
-		{numOfJobs: 1},
-		{numOfJobs: 21}, // one more than the default list length
-	}
-
-	for _, tc := range tests {
-		for _, n := range numOfJobsTests {
-			func() {
-				var submittedJob *model.Job
-				ctx := context.Background()
-
-				for i := 0; i < tc.numberOfAcceptNodes; i++ {
-					for k := 0; k < n.numOfJobs; k++ {
-						j := testutils.MakeJobWithOpts(s.T(),
-							legacy_job.WithEngineSpec(
-								model.NewEngineBuilder().
-									WithType(strings.ToLower(model.EngineNoop.String())).
-									WithParam("Entrypoint-Unique-Array", uuid.NewString()).
-									Build(),
-							),
-						)
-						job, err := s.Client.Submit(ctx, &j)
-						s.Require().NoError(err)
-						submittedJob = job // Default to the last job submitted, should be fine?
-					}
-				}
-				returnedJobDescription := &model.JobWithInfo{}
-
-				// No job id (should error)
-				_, _, err := s.ExecuteTestCobraCommand("describe")
-				s.Require().Error(err, "Submitting a describe request with no id should error.")
-
-				// Job Id at the end
-				_, out, err := s.ExecuteTestCobraCommand("describe", submittedJob.Metadata.ID)
-				s.Require().NoError(err, "Error in describing job: %+v", err)
-
-				err = model.YAMLUnmarshalWithMax([]byte(out), returnedJobDescription)
-				s.Require().NoError(err, "Error in unmarshalling description: %+v", err)
-
-				s.Require().Equal(submittedJob.Metadata.ID, returnedJobDescription.Job.Metadata.ID, "IDs do not match.")
-
-				submittedJobEngineSpec, err := submittedJob.Spec.EngineSpec.Serialize()
-				s.Require().NoError(err)
-				returnedJobEngineSpec, err := returnedJobDescription.Job.Spec.EngineSpec.Serialize()
-				s.Require().NoError(err)
-				s.Require().Equal(
-					submittedJobEngineSpec,
-					returnedJobEngineSpec,
-					fmt.Sprintf("Submitted job entrypoints not the same as the description. expected: %+v, received: %+v",
-						submittedJob.Spec.EngineSpec, returnedJobDescription.Job.Spec.EngineSpec))
-
-				// Job Id in the middle
-				_, out, err = s.ExecuteTestCobraCommand("describe",
-					"--api-host", s.Host,
-					submittedJob.Metadata.ID,
-					"--api-port", fmt.Sprint(s.Port),
-				)
-
-				s.Require().NoError(err, "Error in describing job: %+v", err)
-				err = model.YAMLUnmarshalWithMax([]byte(out), returnedJobDescription)
-				s.Require().NoError(err, "Error in unmarshalling description: %+v", err)
-				s.Require().Equal(submittedJob.Metadata.ID, returnedJobDescription.Job.Metadata.ID, "IDs do not match.")
-
-				returnedJobEngineSpec, err = returnedJobDescription.Job.Spec.EngineSpec.Serialize()
-				s.Require().NoError(err)
-				s.Require().Equal(
-					submittedJobEngineSpec,
-					returnedJobEngineSpec,
-					fmt.Sprintf("Submitted job entrypoints not the same as the description. %d - %d - %s - %d", tc.numberOfAcceptNodes, tc.numberOfRejectNodes, tc.jobState, n.numOfJobs))
-
-				// Short job id
-				_, out, err = s.ExecuteTestCobraCommand("describe",
-					"--api-host", s.Host,
-					idgen.ShortUUID(submittedJob.Metadata.ID),
-					"--api-port", fmt.Sprint(s.Port),
-				)
-
-				s.Require().NoError(err, "Error in describing job: %+v", err)
-				err = model.YAMLUnmarshalWithMax([]byte(out), returnedJobDescription)
-				s.Require().NoError(err, "Error in unmarshalling description: %+v", err)
-				s.Require().Equal(submittedJob.Metadata.ID, returnedJobDescription.Job.Metadata.ID, "IDs do not match.")
-
-				returnedJobEngineSpec, err = returnedJobDescription.Job.Spec.EngineSpec.Serialize()
-				s.Require().NoError(err)
-				s.Require().Equal(
-					submittedJobEngineSpec,
-					returnedJobEngineSpec,
-					fmt.Sprintf("Submitted job entrypoints not the same as the description. %d - %d - %s - %d", tc.numberOfAcceptNodes, tc.numberOfRejectNodes, tc.jobState, n.numOfJobs))
-
-			}()
-		}
-	}
-
-}
-
-func (s *DescribeSuite) TestDescribeJobIncludeEvents() {
-	tests := []struct {
-		includeEvents bool
-	}{
-		{includeEvents: false},
-		{includeEvents: true},
-	}
-
-	for _, tc := range tests {
-		func() {
-			var submittedJob *model.Job
-			ctx := context.Background()
-
-			j := testutils.MakeNoopJob(s.T())
-			job, err := s.Client.Submit(ctx, j)
-			s.Require().NoError(err)
-			submittedJob = job // Default to the last job submitted, should be fine?
-
-			var returnedJob = &model.Job{}
-
-			var args []string
-
-			args = append(args, "describe", submittedJob.Metadata.ID)
-			if tc.includeEvents {
-				args = append(args, "--include-events")
-			}
-
-			// Job Id at the end
-			_, out, err := s.ExecuteTestCobraCommand(args...)
-			s.Require().NoError(err, "Error in describing job: %+v", err)
-
-			err = model.YAMLUnmarshalWithMax([]byte(out), &returnedJob)
-			s.Require().NoError(err, "Error in unmarshalling description: %+v", err)
-
-			// TODO: #600 When we figure out how to add events to a noop job, uncomment the below
-			// require.True(s.T(), eventsWereIncluded == tc.includeEvents,
-			// 	fmt.Sprintf("Events include: %v\nExpected: %v", eventsWereIncluded, tc.includeEvents))
-
-			// require.True(s.T(), localEventsWereIncluded == tc.includeEvents,
-			// 	fmt.Sprintf("Events included: %v\nExpected: %v", localEventsWereIncluded, tc.includeEvents))
-
-		}()
-	}
-
-}
-
-func (s *DescribeSuite) TestDescribeJobEdgeCases() {
-	tests := []struct {
-		describeIDEdgecase string
-		errorMessage       string
-	}{
-		{describeIDEdgecase: "", errorMessage: ""},
-		{describeIDEdgecase: "BAD_JOB_ID", errorMessage: "No job ID found."},
-	}
-
-	numOfJobsTests := []struct {
-		numOfJobs int
-	}{
-		{numOfJobs: 1}, // just enough that describe could get screwed up
-	}
-
-	for _, tc := range tests {
-		for _, n := range numOfJobsTests {
-			func() {
-
-				var submittedJob *model.Job
-				ctx := context.Background()
-
-				for i := 0; i < n.numOfJobs; i++ {
-					j := testutils.MakeJobWithOpts(s.T(),
-						legacy_job.WithEngineSpec(
-							model.NewEngineBuilder().
-								WithType(strings.ToLower(model.EngineNoop.String())).
-								WithParam("Entrypoint-Unique-Array", uuid.NewString()).
-								Build(),
-						),
-					)
-					jj, err := s.Client.Submit(ctx, &j)
-					s.Require().Nil(err)
-					submittedJob = jj // Default to the last job submitted, should be fine?
-				}
-
-				var returnedJobDescription = &model.JobWithInfo{}
-				var err error
-				var out string
-				var jobID string
-
-				// If describeID is empty, should return use submitted ID. Otherwise, use describeID
-				if tc.describeIDEdgecase == "" {
-					jobID = submittedJob.Metadata.ID
-				} else {
-					jobID = tc.describeIDEdgecase
-				}
-
-				_, out, err = s.ExecuteTestCobraCommand("describe", jobID)
-				if tc.describeIDEdgecase == "" {
-					s.Require().NoError(err, "Error in describing job: %+v", err)
-
-					err = model.YAMLUnmarshalWithMax([]byte(out), &returnedJobDescription)
-					s.Require().NoError(err, "Error in unmarshalling description: %+v", err)
-					s.Require().Equal(submittedJob.Metadata.ID, returnedJobDescription.Job.Metadata.ID, "IDs do not match.")
-
-					submittedJobEngineSpec, err := submittedJob.Spec.EngineSpec.Serialize()
-					s.Require().NoError(err)
-					returnedJobEngineSpec, err := returnedJobDescription.Job.Spec.EngineSpec.Serialize()
-					s.Require().NoError(err)
-					s.Require().Equal(
-						submittedJobEngineSpec,
-						returnedJobEngineSpec,
-						fmt.Sprintf("Submitted job entrypoints not the same as the description. Edgecase: %s", tc.describeIDEdgecase))
-				} else {
-					e := bacerrors.NewJobNotFound(tc.describeIDEdgecase)
-					s.Require().Contains(string(out), e.GetMessage(), "Job not found error string not found.", err)
-				}
-
-			}()
-		}
-	}
-
-}
-
-// In order for 'go test' to run this suite, we need to create
-// a normal test function and pass our suite to suite.Run
-func TestDescribeSuite(t *testing.T) {
-	suite.Run(t, new(DescribeSuite))
-}
diff --git a/cmd/cli/list/list_test.go b/cmd/cli/list/list_test.go
deleted file mode 100644
index 898d95e196..0000000000
--- a/cmd/cli/list/list_test.go
+++ /dev/null
@@ -1,347 +0,0 @@
-//go:build unit || !integration
-
-package list_test
-
-import (
-	"context"
-	"fmt"
-	"reflect"
-	"sort"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/bacalhau-project/bacalhau/pkg/lib/marshaller"
-	"github.com/bacalhau-project/bacalhau/pkg/publicapi/apimodels/legacymodels"
-	"github.com/bacalhau-project/bacalhau/pkg/util/idgen"
-	"github.com/stretchr/testify/require"
-	"github.com/stretchr/testify/suite"
-
-	"github.com/bacalhau-project/bacalhau/cmd/cli/list"
-	cmdtesting "github.com/bacalhau-project/bacalhau/cmd/testing"
-	legacy_job "github.com/bacalhau-project/bacalhau/pkg/legacyjob"
-	"github.com/bacalhau-project/bacalhau/pkg/model"
-	"github.com/bacalhau-project/bacalhau/pkg/system"
-	testutils "github.com/bacalhau-project/bacalhau/pkg/test/utils"
-)
-
-// Define the suite, and absorb the built-in basic suite
-// functionality from testify - including a T() method which
-// returns the current testing context
-type ListSuite struct {
-	cmdtesting.BaseSuite
-}
-
-// In order for 'go test' to run this suite, we need to create
-// a normal test function and pass our suite to suite.Run
-func TestListSuite(t *testing.T) {
-	suite.Run(t, new(ListSuite))
-}
-
-func (suite *ListSuite) setupRun() {
-	// have to create a fresh node for each test case to avoid jobs of different runs to be mixed up
-	suite.TearDownTest()
-	// Clear the repo that was created by the previous run so a fresh one is created
-	// TODO: find a better solution to set the repo path for tests in pkg/setup/setup.go:49 instead of env vars to avoid such hacks
-	suite.T().Setenv("BACALHAU_DIR", "")
-	suite.SetupTest()
-}
-
-func (suite *ListSuite) TestList_NumberOfJobs() {
-	tests := []struct {
-		numberOfJobs       int
-		numberOfJobsOutput int
-	}{
-		{numberOfJobs: 0, numberOfJobsOutput: 0},   // Test for zero
-		{numberOfJobs: 5, numberOfJobsOutput: 5},   // Test for 5 (less than default of 10)
-		{numberOfJobs: 20, numberOfJobsOutput: 10}, // Test for 20 (more than max of 10)
-		{numberOfJobs: 20, numberOfJobsOutput: 15}, // The default is 10 so test for non-default
-	}
-
-	for _, tc := range tests {
-		suite.Run(fmt.Sprintf("%d jobs %d output", tc.numberOfJobs, tc.numberOfJobsOutput), func() {
-			ctx := context.Background()
-
-			for i := 0; i < tc.numberOfJobs; i++ {
-				j := testutils.MakeNoopJob(suite.T())
-				_, err := suite.Client.Submit(ctx, j)
-				require.NoError(suite.T(), err)
-			}
-
-			_, out, err := suite.ExecuteTestCobraCommand("list",
-				"--hide-header",
-				"--number", fmt.Sprintf("%d", tc.numberOfJobsOutput),
-				"--reverse", "false",
-			)
-			require.NoError(suite.T(), err)
-			require.Equal(suite.T(), tc.numberOfJobsOutput, strings.Count(out, "\n"), out)
-		})
-	}
-}
-
-func (suite *ListSuite) TestList_IdFilter() {
-	ctx := context.Background()
-
-	// submit 10 jobs
-	var jobIds []string
-	var jobLongIds []string
-	for i := 0; i < 10; i++ {
-		var err error
-		j := testutils.MakeNoopJob(suite.T())
-		j, err = suite.Client.Submit(ctx, j)
-		jobIds = append(jobIds, idgen.ShortUUID(j.Metadata.ID))
-		jobLongIds = append(jobLongIds, j.Metadata.ID)
-		require.NoError(suite.T(), err)
-	}
-	_, out, err := suite.ExecuteTestCobraCommand("list",
-		"--hide-header",
-		"--id-filter", jobIds[0],
-		"--wide",
-	)
-	require.NoError(suite.T(), err)
-	require.Equal(suite.T(), "\n", out[len(out)-1:], "Expected output to end with a newline: %q", out)
-
-	// parse list output
-	lines := strings.Split(strings.TrimRight(out, "\n"), "\n")
-	require.Equal(suite.T(), 1, len(lines), "We didn't get only one result: %q", lines)
-	require.Contains(suite.T(), lines[0], jobIds[0], "The returned job id was not what we asked for")
-
-	//// Test --output json
-
-	// _, out, err = ExecuteTestCobraCommand(suite.T(), suite.rootCmd, "list",
-	_, out, err = suite.ExecuteTestCobraCommand("list",
-		"--hide-header",
-		"--id-filter", jobLongIds[0],
-		"--output", "json",
-	)
-	require.NoError(suite.T(), err)
-
-	// parse response
-	response := legacymodels.ListResponse{}
-	err = marshaller.JSONUnmarshalWithMax([]byte(out), &response.Jobs)
-
-	var firstItem model.Job
-	for _, v := range response.Jobs {
-		firstItem = v.Job
-		break
-	}
-
-	require.NoError(suite.T(), err)
-
-	require.Contains(suite.T(), firstItem.Metadata.ID, jobLongIds[0], "The filtered job id was not found in the response")
-	require.Equal(suite.T(), 1, len(response.Jobs), "The list of jobs is not strictly filtered to the requested job id")
-}
-
-func (suite *ListSuite) TestList_AnnotationFilter() {
-	type testCase struct {
-		Name                                              string
-		JobLabels, ListLabels                             []string
-		AppearByDefault, AppearOnInclude, AppearOnExclude bool
-	}
-
-	testCases := []testCase{
-		{"empty filters have no effect", []string{}, []string{}, true, true, true},
-		{"include filters unlabelled jobs", []string{}, []string{"test"}, true, false, true},
-		{"exclude filters labelled jobs", []string{"test"}, []string{"test"}, true, true, false},
-		{"filters match job labels", []string{"jobb"}, []string{"test"}, true, false, true},
-		{"multiple annotations match any", []string{"test", "jobb"}, []string{"test"}, true, true, false},
-		{"multiple filters match any", []string{"t1"}, []string{"t1", "t2"}, true, true, false},
-	}
-
-	for _, tag := range list.DefaultExcludedTags {
-		testCases = append(testCases, testCase{
-			fmt.Sprintf("%s filtered by default", tag),
-			[]string{tag},
-			[]string{tag},
-			false,
-			false,
-			false,
-		})
-		testCases = append(testCases, testCase{
-			fmt.Sprintf("%s excluded with other tags", tag),
-			[]string{tag},
-			[]string{"test"},
-			false,
-			false,
-			true,
-		})
-	}
-
-	for _, tc := range testCases {
-		suite.Run(tc.Name, func() {
-			ctx := context.Background()
-			suite.setupRun()
-
-			testJob := testutils.MakeJobWithOpts(suite.T(),
-				legacy_job.WithAnnotations(tc.JobLabels...),
-			)
-			j, err := suite.Client.Submit(ctx, &testJob)
-			require.NoError(suite.T(), err)
-
-			checkList := func(shouldAppear bool, flags ...string) {
-				args := []string{"list",
-					"--hide-header",
-					"--output", "json",
-				}
-				args = append(args, flags...)
-				_, out, err := suite.ExecuteTestCobraCommand(args...)
-				require.NoError(suite.T(), err)
-
-				response := legacymodels.ListResponse{}
-				_ = marshaller.JSONUnmarshalWithMax([]byte(out), &response.Jobs)
-				if shouldAppear {
-					require.NotEmpty(suite.T(), response.Jobs)
-					require.Equal(suite.T(), j.Metadata.ID, response.Jobs[0].Job.Metadata.ID)
-				} else {
-					require.Empty(suite.T(), response.Jobs)
-				}
-			}
-
-			// default list
-			suite.Run("default", func() {
-				checkList(tc.AppearByDefault)
-			})
-
-			// list with label included
-			suite.Run("label_included", func() {
-				var flags []string
-				for _, label := range tc.ListLabels {
-					flags = append(flags, "--include-tag", label)
-				}
-				checkList(tc.AppearOnInclude, flags...)
-			})
-
-			// list with label excluded
-			suite.Run("label_excluded", func() {
-				var flags []string
-				for _, label := range tc.ListLabels {
-					flags = append(flags, "--exclude-tag", label)
-				}
-				checkList(tc.AppearOnExclude, flags...)
-			})
-		})
-	}
-}
-
-func (suite *ListSuite) TestList_SortFlags() {
-	var badSortFlag = "BADSORTFLAG"
-	var createdAtSortFlag = "created_at"
-
-	combinationOfJobSizes := []struct {
-		numberOfJobs       int
-		numberOfJobsOutput int
-	}{
-		// {numberOfJobs: 0, numberOfJobsOutput: 0},   // Test for zero
-		{numberOfJobs: 5, numberOfJobsOutput: 5}, // Test for 5 (less than default of 10)
-		// {numberOfJobs: 20, numberOfJobsOutput: 10}, // Test for 20 (more than max of 10)
-		// {numberOfJobs: 20, numberOfJobsOutput: 15}, // The default is 10 so test for non-default
-	}
-
-	sortFlagsToTest := []struct {
-		sortFlag    string
-		reverseFlag bool
-		badSortFlag bool
-	}{
-		{sortFlag: createdAtSortFlag, reverseFlag: false},
-		{sortFlag: createdAtSortFlag, reverseFlag: true},
-		{sortFlag: badSortFlag, reverseFlag: false, badSortFlag: true},
-		{sortFlag: badSortFlag, reverseFlag: true, badSortFlag: true},
-		{sortFlag: "", reverseFlag: false, badSortFlag: true},
-		{sortFlag: "", reverseFlag: true, badSortFlag: true},
-	}
-
-	for _, tc := range combinationOfJobSizes {
-		for _, sortFlags := range sortFlagsToTest {
-			suite.Run(fmt.Sprintf("%+v/%+v", tc, sortFlags), func() {
-				ctx := context.Background()
-				suite.setupRun()
-
-				var jobIDs []string
-				for i := 0; i < tc.numberOfJobs; i++ {
-					var err error
-					j := testutils.MakeNoopJob(suite.T())
-					j, err = suite.Client.Submit(ctx, j)
-					require.NoError(suite.T(), err)
-					jobIDs = append(jobIDs, idgen.ShortUUID(j.Metadata.ID))
-
-					// all the middle jobs can have the same timestamp
-					// but we need the first and last to differ
-					// so we can test sorting on time stamp
-					if (i == 0 || i == tc.numberOfJobs-2) && sortFlags.sortFlag == createdAtSortFlag {
-						time.Sleep(1 * time.Second)
-					} else {
-						time.Sleep(1 * time.Millisecond)
-					}
-				}
-				reverseString := "--reverse=false"
-				if sortFlags.reverseFlag {
-					reverseString = "--reverse"
-				}
-
-				_, out, err := suite.ExecuteTestCobraCommand("list",
-					"--hide-header",
-					"--no-style",
-					"--sort-by", sortFlags.sortFlag,
-					"--number", fmt.Sprintf("%d", tc.numberOfJobsOutput),
-					reverseString,
-				)
-
-				if sortFlags.badSortFlag {
-					require.Error(suite.T(), err, "No error was thrown though it was a bad sort flag: %s", badSortFlag)
-					require.Contains(suite.T(), out, "Error: invalid argument", "'--sort-by' did not reject bad sort flag: %s", badSortFlag)
-				} else {
-					require.NoError(suite.T(), err)
-					require.Equal(suite.T(), tc.numberOfJobsOutput, strings.Count(out, "\n"))
-
-					if tc.numberOfJobsOutput > 0 {
-
-						// jobIDs are already sorted by created ASC
-						if sortFlags.sortFlag == string(list.ColumnID) {
-							sort.Strings(jobIDs)
-						}
-
-						if sortFlags.reverseFlag {
-							jobIDs = system.ReverseList(jobIDs)
-						}
-
-						compareIds := jobIDs[0:tc.numberOfJobsOutput]
-						var seenIds []string
-
-						for _, line := range strings.Split(out, "\n") {
-							parts := strings.Split(line, " ")
-							if len(parts) > 2 {
-								seenIds = append(seenIds, strings.Split(line, " ")[3])
-							}
-						}
-
-						errorMessage := fmt.Sprintf(`
-Table lines do not match
-Number of Jobs: %d
-Number of Max Jobs: %d
-Sort Flag: %s
-Reverse Flag: %t
-
-Out:
-%s
-
-Seen Ids:
-%s
-
-Compare Ids:
-%s
-
-			    		`, tc.numberOfJobs, tc.numberOfJobsOutput, sortFlags.sortFlag, sortFlags.reverseFlag, out, strings.Join(seenIds, " "), strings.Join(compareIds, " "))
-
-						if sortFlags.sortFlag == string(list.ColumnID) {
-							require.True(suite.T(), reflect.DeepEqual(compareIds, seenIds), errorMessage)
-						} else if sortFlags.sortFlag == createdAtSortFlag {
-							// check the first and last are correct
-							// the middles all have the same created time so we ignore those
-							require.Equal(suite.T(), compareIds[0], seenIds[0], errorMessage)
-						}
-					}
-				}
-			})
-		}
-	}
-}
diff --git a/cmd/testing/tls_test.go b/cmd/testing/tls_test.go
index d5f241abc9..b3104d03e5 100644
--- a/cmd/testing/tls_test.go
+++ b/cmd/testing/tls_test.go
@@ -21,17 +21,17 @@ func (s *TLSSuite) TestTLSflagWithSelfSignedCertificate() {
 	// and not providing the client command with the cacert making the connection 'insecure'
 	// in this command we don't provide the --insecure flag or the certificate file (as done in below commands)
 	// meaning we expect an error.
-	_, _, err := s.ExecuteTestCobraCommand("list", "--tls")
+	_, _, err := s.ExecuteTestCobraCommand("job", "list", "--tls")
 	s.Require().Error(err)
 }
 
 func (s *TLSSuite) TestTLSWithInsecureFlag() {
-	_, _, err := s.ExecuteTestCobraCommand("list", "--tls", "--insecure")
+	_, _, err := s.ExecuteTestCobraCommand("job", "list", "--tls", "--insecure")
 
 	s.Require().NoError(err)
 }
 
 func (s *TLSSuite) TestTLSWithCACert() {
-	_, _, err := s.ExecuteTestCobraCommand("list", "--tls", "--cacert", s.TempCACertFilePath)
+	_, _, err := s.ExecuteTestCobraCommand("job", "list", "--tls", "--cacert", s.TempCACertFilePath)
 	s.Require().NoError(err, "failed to execute Cobra Command")
 }
diff --git a/test/secret_auth.sh b/test/secret_auth.sh
index 0f8b9c0f72..56306dbe03 100755
--- a/test/secret_auth.sh
+++ b/test/secret_auth.sh
@@ -25,14 +25,6 @@ testcase_valid_token_is_accepted() {
     assert_equal '[]' $stdout
 }
 
-testcase_token_works_for_v1_api() {
-    setup
-
-    subject "echo insert a secret string here | bacalhau list --output=json"
-    assert_equal 0 $status
-    assert_equal '[]' $stdout
-}
-
 testcase_input_can_be_cancelled() {
     setup