Skip to content

Commit d8652c2

Browse files
experimental/air: scaffold AI runtime CLI command package
Add the experimental `air` command group as the Go port surface for the Python `air` CLI. Every subcommand (run, status, list, logs, cancel, register-image) is registered as a stub that returns a not-implemented error; the real implementations land in later milestones. The package lives under experimental/air/cmd (imported as aircmd), matching the layout of the other experimental features (aitools, genie, postgres); cmd/experimental/ keeps only the dispatcher. TEST_PACKAGES in Taskfile.yml gains ./experimental/air/... so the unit tests keep running after the move. Includes unit tests for the command-tree wiring and the not-implemented stubs, plus an acceptance test exercising the stubs end-to-end. Co-authored-by: Isaac
1 parent d66b99e commit d8652c2

15 files changed

Lines changed: 336 additions & 1 deletion

File tree

Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ vars:
44
# Absolute path so tasks with `dir:` (lint-go-tools, lint-go-codegen) can use it.
55
GO_TOOL: go tool -modfile={{.ROOT_DIR}}/tools/go.mod
66
EXE_EXT: '{{if eq OS "windows"}}.exe{{end}}'
7-
TEST_PACKAGES: ./acceptance/internal ./libs/... ./internal/... ./cmd/... ./bundle/... ./experimental/ssh/... .
7+
TEST_PACKAGES: ./acceptance/internal ./libs/... ./internal/... ./cmd/... ./bundle/... ./experimental/air/... ./experimental/ssh/... .
88
ACCEPTANCE_TEST_FILTER: ""
99
# Single brace-expansion glob covering every //go:embed target in the repo,
1010
# computed by grepping `//go:embed` directives. Evaluated lazily by Task so

acceptance/experimental/air/unimplemented/out.test.toml

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
2+
=== run
3+
>>> [CLI] experimental air run
4+
Error: `air run` is not implemented yet
5+
6+
Exit code: 1
7+
8+
=== status
9+
>>> [CLI] experimental air status 123
10+
Error: `air status` is not implemented yet
11+
12+
Exit code: 1
13+
14+
=== list
15+
>>> [CLI] experimental air list
16+
Error: `air list` is not implemented yet
17+
18+
Exit code: 1
19+
20+
=== logs
21+
>>> [CLI] experimental air logs 123
22+
Error: `air logs` is not implemented yet
23+
24+
Exit code: 1
25+
26+
=== cancel
27+
>>> [CLI] experimental air cancel 123
28+
Error: `air cancel` is not implemented yet
29+
30+
Exit code: 1
31+
32+
=== register-image
33+
>>> [CLI] experimental air register-image my-image:latest
34+
Error: `air register-image` is not implemented yet
35+
36+
Exit code: 1
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Each stub must fail with "not implemented"; errcode records the exit code.
2+
3+
title "run"
4+
errcode trace $CLI experimental air run
5+
6+
title "status"
7+
errcode trace $CLI experimental air status 123
8+
9+
title "list"
10+
errcode trace $CLI experimental air list
11+
12+
title "logs"
13+
errcode trace $CLI experimental air logs 123
14+
15+
title "cancel"
16+
errcode trace $CLI experimental air cancel 123
17+
18+
title "register-image"
19+
errcode trace $CLI experimental air register-image my-image:latest
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Local = true
2+
Cloud = false
3+
4+
# Stubs fail locally before any API call, so no server stubs needed.
5+
[EnvMatrix]
6+
DATABRICKS_BUNDLE_ENGINE = []

cmd/experimental/experimental.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package experimental
22

33
import (
4+
aircmd "github.com/databricks/cli/experimental/air/cmd"
45
aitoolscmd "github.com/databricks/cli/experimental/aitools/cmd"
56
geniecmd "github.com/databricks/cli/experimental/genie/cmd"
67
postgrescmd "github.com/databricks/cli/experimental/postgres/cmd"
@@ -22,6 +23,7 @@ These commands provide early access to new features that are still under
2223
development. They may change or be removed in future versions without notice.`,
2324
}
2425

26+
cmd.AddCommand(aircmd.New())
2527
cmd.AddCommand(aitoolscmd.NewAitoolsCmd())
2628
cmd.AddCommand(geniecmd.NewGenieCmd())
2729
cmd.AddCommand(postgrescmd.New())

experimental/air/cmd/air.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package aircmd
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/spf13/cobra"
7+
)
8+
9+
// New returns the root command for the experimental AI runtime CLI.
10+
//
11+
// Milestone 0: scaffolds the command group with every subcommand registered as a
12+
// stub (not yet implemented), pending the port from the Python `air` CLI.
13+
func New() *cobra.Command {
14+
cmd := &cobra.Command{
15+
Use: "air",
16+
Short: "Run and manage AI runtime training workloads",
17+
Long: `Run and manage AI runtime training workloads on Databricks serverless GPU compute.
18+
19+
This command set is the Go port of the standalone Python "air" CLI. It is
20+
experimental and may change in future versions.`,
21+
}
22+
23+
cmd.AddCommand(newRunCommand())
24+
cmd.AddCommand(newStatusCommand())
25+
cmd.AddCommand(newListCommand())
26+
cmd.AddCommand(newLogsCommand())
27+
cmd.AddCommand(newCancelCommand())
28+
cmd.AddCommand(newRegisterImageCommand())
29+
30+
return cmd
31+
}
32+
33+
// notImplemented returns the placeholder error used by milestone-0 stubs.
34+
func notImplemented(name string) error {
35+
return fmt.Errorf("`air %s` is not implemented yet", name)
36+
}

experimental/air/cmd/air_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package aircmd
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
// TestNewRegistersAllSubcommands asserts the `ai` command wires up every
10+
// expected subcommand, so none is accidentally dropped from New.
11+
func TestNewRegistersAllSubcommands(t *testing.T) {
12+
registered := make(map[string]bool)
13+
for _, c := range New().Commands() {
14+
registered[c.Name()] = true
15+
}
16+
17+
want := []string{"run", "status", "list", "logs", "cancel", "register-image"}
18+
for _, name := range want {
19+
assert.True(t, registered[name], "subcommand %q is not registered", name)
20+
}
21+
assert.Len(t, registered, len(want), "unexpected number of subcommands")
22+
}

experimental/air/cmd/cancel.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package aircmd
2+
3+
import (
4+
"github.com/spf13/cobra"
5+
)
6+
7+
func newCancelCommand() *cobra.Command {
8+
var (
9+
all bool
10+
yes bool
11+
)
12+
13+
cmd := &cobra.Command{
14+
Use: "cancel [RUN_ID...]",
15+
Args: cobra.ArbitraryArgs,
16+
Short: "Cancel one or more runs",
17+
Long: `Cancel one or more runs by ID, or cancel all of your active runs with --all.`,
18+
RunE: func(cmd *cobra.Command, args []string) error {
19+
return notImplemented("cancel")
20+
},
21+
}
22+
23+
cmd.Flags().BoolVar(&all, "all", false, "Cancel all of your active runs")
24+
cmd.Flags().BoolVarP(&yes, "yes", "y", false, "Skip the confirmation prompt")
25+
26+
return cmd
27+
}

experimental/air/cmd/list.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package aircmd
2+
3+
import (
4+
"github.com/databricks/cli/cmd/root"
5+
"github.com/spf13/cobra"
6+
)
7+
8+
func newListCommand() *cobra.Command {
9+
var (
10+
limit int
11+
active bool
12+
allUsers bool
13+
filters []string
14+
)
15+
16+
cmd := &cobra.Command{
17+
Use: "list",
18+
Args: root.NoArgs,
19+
Short: "List recent runs",
20+
RunE: func(cmd *cobra.Command, args []string) error {
21+
return notImplemented("list")
22+
},
23+
}
24+
25+
cmd.Flags().IntVar(&limit, "limit", 20, "Maximum number of runs to show")
26+
cmd.Flags().BoolVar(&active, "active", false, "Show only active runs")
27+
cmd.Flags().BoolVar(&allUsers, "all-users", false, "Show runs from all users")
28+
cmd.Flags().StringArrayVar(&filters, "filter", nil, "Filter runs, e.g. experiment=foo* (repeatable)")
29+
30+
return cmd
31+
}

0 commit comments

Comments
 (0)