[CMPT-6969] feat(pipeline): add dr pipeline clone command - #719
Conversation
|
🎫 Jira: |
|
👋 Thanks so much for contributing to the DataRobot community! As a quick heads-up on how our team handles reviews: if you're still iterating on Once everything is finalized and you're ready for feedback, just click "Ready for review" |
456f377 to
cc6277a
Compare
There was a problem hiding this comment.
Pull request overview
Adds a new dr pipeline clone <pipeline-id> [--name] write-style subcommand that calls the pipelines API clone endpoint to duplicate an existing pipeline into a new draft.
Changes:
- Added
internal/pipeline.ClonePipeline()to POST/api/v2/pipelines/{id}/clonewith an optional JSONname. - Added
cmd/pipeline/clonecobra subcommand with--namevalidation, output-format support, and telemetry properties. - Added client + command rendering tests, and updated pipeline command documentation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| internal/pipeline/pipeline.go | Adds the API client method for the clone endpoint. |
| internal/pipeline/clone_test.go | Adds httptest coverage for request/response behavior (default vs overridden name, 404). |
| cmd/pipeline/cmd.go | Registers the new pipeline clone subcommand. |
| cmd/pipeline/clone/cmd.go | Implements the cobra command, flag validation, rendering, and telemetry wiring. |
| cmd/pipeline/clone/cmd_test.go | Adds tests for JSON/human rendering and flag/output-format validation. |
| docs/commands/pipeline.md | Documents the new dr pipeline clone command in the pipeline command table. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| endpoint, err := config.GetEndpointURL("/api/v2/pipelines/" + pipelineID + "/clone") | ||
| if err != nil { | ||
| return nil, err | ||
| } |
There was a problem hiding this comment.
Applied — ClonePipeline now url.PathEscapes the pipeline id before building the endpoint (mirrors internal/workload/workload.go).
| w.Header().Set("Content-Type", "application/json") | ||
| _, _ = w.Write([]byte(`{ | ||
| "id": "p-2", | ||
| "name": "Clone of wf", | ||
| "mode": "draft", | ||
| "taskNames": ["e1"], | ||
| "createdAt": "2026-04-29T10:00:00Z" | ||
| }`)) | ||
| })) | ||
|
|
||
| defer srv.Close() | ||
|
|
||
| installEndpoint(t, srv.URL) | ||
|
|
||
| got, err := ClonePipeline("p-1", "") | ||
| require.NoError(t, err) | ||
| assert.Equal(t, "p-2", got.PipelineID) | ||
| assert.Equal(t, "Clone of wf", got.Name) | ||
| assert.Equal(t, "draft", got.Mode) |
There was a problem hiding this comment.
A clone always returns a fresh draft, so the server sends no version/status (same as POST /pipelines) — the fixture omits them deliberately. I made that explicit: the test now asserts got.Version == 0 / got.Status == "". Adding version:1/status:READY would misrepresent the clone as a locked v1.
| func sample() pipeline.CreateResponse { | ||
| return pipeline.CreateResponse{ | ||
| PipelineID: "p-2", | ||
| Name: "Clone of wf", | ||
| Mode: "draft", | ||
| TaskNames: []string{"e1", "e2"}, | ||
| CreatedAt: time.Date(2026, 4, 30, 10, 0, 0, 0, time.UTC), | ||
| } | ||
| } |
There was a problem hiding this comment.
Same rationale — the clone is a draft, so Version/Status are intentionally zero-valued (documented with a comment on the fixture). Populating them would portray the clone as locked, which it never is.
cc6277a to
a346d69
Compare
Add `dr pipeline clone <pipeline-id> [--name]` mirroring the new
pipelines-api POST /api/v2/pipelines/{id}/clone endpoint. Clones a
pipeline into a new draft (source, description, latest input params,
assigned image). Name defaults to "Clone of <source name>" and is
overridable via --name; the server auto-suffixes on collision.
- internal/pipeline: ClonePipeline (POST .../clone, JSON body with
omitempty name) mirroring LockPipeline.
- cmd/pipeline/clone: cobra command following the write-command pattern
(returns fmt.Errorf on error, renders via RenderCreateResponse); JSON
output stays uncorrupted (no read-command friendly-404 handler), per
datarobot-oss#707.
- Tests: internal httptest coverage (default/override/404) + command
render + flag-validation tests.
- docs/commands/pipeline.md: clone row, plus the fan-out `run task`
node-id error-table update (404/409 causes).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
a346d69 to
5bbee15
Compare
|
/approve-smoke-tests |
|
🔐 Fork PR smoke tests triggered by @sunny2get What happens next:
|
|
🔐 Fork smoke tests started by maintainer ⏳ Security scans passed. Running smoke tests... Commit: |
|
✅ All smoke tests passed! (Fork PR) ✅ Security Scan: success |
Code OwnershipCompute Services
Review requested from the teams above. Labels will be removed automatically upon approval. |
Summary
Adds
dr pipeline clone <pipeline-id> [--name], mirroring the new pipelines-api endpointPOST /api/v2/pipelines/{id}/clone. Clones a pipeline into a new draft, copying its source code, description, latest input params, and assigned image. The name defaults toClone of <source name>and is overridable via--name; the server auto-suffixes on collision so repeated clones never fail.Changes
internal/pipeline:ClonePipeline(pipelineID, name)→POST .../clonewith a JSON body (nameomitempty), mirroringLockPipeline.cmd/pipeline/clone: cobra subcommand following the write-command pattern — returnsfmt.Errorf("clone pipeline: %w", err)and renders viaRenderCreateResponse. No read-command friendly-404 handler, so JSON stdout is never corrupted (consistent with [CFX-7097] Fix 404 error handlers corrupting JSON stdout #707).internal/pipeline/clone_test.go(httptest: default name omits body key,--nameoverride, 404) +cmd/pipeline/clone/cmd_test.go(JSON/human render, invalid-output + blank-name rejection).docs/commands/pipeline.md: clone row.Test
go build ./...,go vet,gofmtclean;go test ./cmd/pipeline/clone/... ./internal/pipeline/...passes.🤖 Generated with Claude Code
Note
Low Risk
Additive CLI and API client for a new write endpoint; no changes to auth or existing pipeline flows beyond registering a subcommand.
Overview
Adds
dr pipeline clone <pipeline-id>so users can duplicate an existing pipeline into a new draft viaPOST /api/v2/pipelines/{id}/clone, copying source, description, latest input, and image as described in the command help.The client sends an optional
--namein JSON (nameomitted when unset so the API can default toClone of <source>); whitespace-only--nameis rejected locally. Success output reusesRenderCreateResponse(same shape as create/lock). The subcommand is registered underdr pipeline, includes auth, output format, and telemetry, and is documented in the pipeline command table.internal/pipeline.ClonePipelinemirrorsLockPipeline’s JSON POST pattern. Tests cover default vs override name, 404 handling, rendering, and flag validation.Reviewed by Cursor Bugbot for commit cc6277a. Configure here.