Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cmd/pipeline/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ import (
"github.com/datarobot/cli/cmd/pipeline/del"
"github.com/datarobot/cli/cmd/pipeline/get"
"github.com/datarobot/cli/cmd/pipeline/graph"
"github.com/datarobot/cli/cmd/pipeline/input"
"github.com/datarobot/cli/cmd/pipeline/list"
"github.com/datarobot/cli/cmd/pipeline/lock"
"github.com/datarobot/cli/cmd/pipeline/run"
"github.com/datarobot/cli/cmd/pipeline/schedule"
"github.com/datarobot/cli/cmd/pipeline/update"
"github.com/datarobot/cli/cmd/pipeline/version"
"github.com/datarobot/cli/internal/features"
Expand Down Expand Up @@ -53,6 +55,8 @@ input payloads, runs, and recurring schedules.`,
version.Cmd(),
graph.Cmd(),
run.Cmd(),
input.Cmd(),
schedule.Cmd(),
)

return cmd
Expand Down
20 changes: 11 additions & 9 deletions cmd/pipeline/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,17 @@ func TestCmd_HasExpectedSubcommands(t *testing.T) {
cmd := Cmd()

want := map[string]bool{
"create": false,
"get": false,
"list": false,
"update": false,
"delete": false,
"lock": false,
"version": false,
"graph": false,
"run": false,
"create": false,
"get": false,
"list": false,
"update": false,
"delete": false,
"lock": false,
"version": false,
"graph": false,
"run": false,
"input": false,
"schedule": false,
}

for _, sub := range cmd.Commands() {
Expand Down
51 changes: 51 additions & 0 deletions cmd/pipeline/input/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Copyright 2026 DataRobot, Inc. and its affiliates.
//
// 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 input

import (
"github.com/datarobot/cli/cmd/pipeline/input/create"
"github.com/datarobot/cli/cmd/pipeline/input/del"
"github.com/datarobot/cli/cmd/pipeline/input/get"
"github.com/datarobot/cli/cmd/pipeline/input/list"
"github.com/datarobot/cli/cmd/pipeline/input/update"
"github.com/spf13/cobra"
)

// Cmd returns the parent command for `dr pipeline input`. It groups the
// CRUD verbs that operate on pipeline input sets.
func Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "input",
Short: "Manage pipeline input sets",
Long: `Manage input payloads bound to a pipeline.

Inputs come in two scopes:
- draft : mutable; bound to the current draft of a pipeline
- locked : immutable; bound to a specific frozen version

When --version is supplied, the locked scope is selected automatically.
Pass --scope=draft to be explicit.`,
}

cmd.AddCommand(
create.Cmd(),
list.Cmd(),
get.Cmd(),
update.Cmd(),
del.Cmd(),
)

return cmd
}
41 changes: 41 additions & 0 deletions cmd/pipeline/input/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright 2026 DataRobot, Inc. and its affiliates.
//
// 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 input

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestCmd_RegistersAllVerbs(t *testing.T) {
cmd := Cmd()

want := map[string]bool{
"create": false,
"list": false,
"get": false,
"update": false,
"delete": false,
}

for _, sub := range cmd.Commands() {
want[sub.Name()] = true
}

for verb, present := range want {
assert.Truef(t, present, "missing subcommand: %s", verb)
}
}
95 changes: 95 additions & 0 deletions cmd/pipeline/input/create/cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Copyright 2026 DataRobot, Inc. and its affiliates.
//
// 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 create

import (
"errors"

"github.com/datarobot/cli/cmd/pipeline/scopeflag"
"github.com/datarobot/cli/internal/auth"
"github.com/datarobot/cli/internal/pipeline"
"github.com/datarobot/cli/internal/telemetry"
"github.com/spf13/cobra"
)

func Cmd() *cobra.Command {
var (
flags scopeflag.Flags
fromFile string
outputFormat pipeline.OutputFormat
)

cmd := &cobra.Command{
Use: "create [<payload-file>]",
Short: "Create a pipeline input set",
Long: `Create an input payload for a pipeline.

The payload must be a JSON object. The path to the JSON file can be
supplied either as a positional argument or via --from-file=<path>.
Exactly one of the two must be provided.

Scope is selected from the --scope/--version flags:
- no flags -> draft
- --version=N -> locked, version N (scope auto-set)
- --scope=draft -> draft
- --scope=locked --version=N -> locked, version N

Example:
dr pipeline input create --pipeline <id> ./payload.json
dr pipeline input create --pipeline <id> --from-file=./payload.json
dr pipeline input create --pipeline <id> --version=2 ./payload.json --output-format json`,
Args: cobra.MaximumNArgs(1),
PreRunE: auth.EnsureAuthenticatedE,
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
if flags.PipelineID == "" {
return errors.New("--pipeline is required")
}

scope, version, err := flags.Resolve(cmd)
if err != nil {
return err
}

payload, err := pipeline.ResolvePayload(args, fromFile)
if err != nil {
return err
}

result, err := pipeline.CreateInput(flags.PipelineID, scope, version, payload)
if err != nil {
return err
}

return pipeline.RenderInput(outputFormat, *result)
},
}

flags.Bind(cmd)
_ = cmd.MarkFlagRequired("pipeline")
cmd.Flags().StringVar(&fromFile, "from-file", "", "Path to the JSON payload file, e.g. --from-file=./payload.json (alternative to the positional argument)")
pipeline.AddOutputFlag(cmd, &outputFormat)

telemetry.TrackWith(cmd, func(_ *cobra.Command, _ []string) map[string]any {
return map[string]any{
"pipeline_id": flags.PipelineID,
"scope": flags.Scope,
"version": flags.Version,
"output_format": string(outputFormat),
}
})

return cmd
}
67 changes: 67 additions & 0 deletions cmd/pipeline/input/create/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2026 DataRobot, Inc. and its affiliates.
//
// 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 create

import (
"io"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func runCmd(t *testing.T, args ...string) error {
t.Helper()

cmd := Cmd()
cmd.SetArgs(args)
cmd.SetOut(io.Discard)
cmd.SetErr(io.Discard)
cmd.PreRunE = nil

return cmd.Execute()
}

func TestCmd_RejectsInvalidOutput(t *testing.T) {
err := runCmd(t, "--pipeline", "p", "--output-format", "yaml", "p.json")
require.Error(t, err)
assert.Contains(t, err.Error(), "invalid output format")
}

func TestCmd_RejectsMissingPipeline(t *testing.T) {
err := runCmd(t, "p.json")
require.Error(t, err)
assert.Contains(t, err.Error(), "pipeline")
}

func TestCmd_RejectsBadScopeCombo(t *testing.T) {
err := runCmd(t, "--pipeline", "p", "--scope", "draft", "--version", "2", "p.json")
require.Error(t, err)
assert.Contains(t, err.Error(), "draft cannot be combined")
}

func TestCmd_RejectsMissingPayload(t *testing.T) {
err := runCmd(t, "--pipeline", "p")
require.Error(t, err)
assert.Contains(t, err.Error(), "required")
}

func TestCmd_HasExpectedFlags(t *testing.T) {
cmd := Cmd()

for _, name := range []string{"pipeline", "scope", "version", "from-file", "output-format"} {
assert.NotNilf(t, cmd.Flags().Lookup(name), "expected --%s flag", name)
}
}
Loading