-
Notifications
You must be signed in to change notification settings - Fork 4
configure scope add/list/delete: Add CRUD subcommands for scope management #55
Description
Problem
configure scope is currently a single command with one action: add scopes to a connection. There are no subcommands for listing or removing scopes. This is inconsistent with configure connection, which has list, delete, update, and test subcommands. Users who have added scopes cannot inspect or remove them without using the DevLake API directly.
Additionally, the current scope command auto-detects connection IDs from state files, which can lead to ambiguity when multiple connections exist for the same plugin. Connection ID should be an explicit, mandatory input for standalone scope commands.
Current command tree
configure scope ← RunE = add scopes (only action)
Desired command tree
configure scope ← no RunE, prints help
├── add ← current scope logic (interactive or flags)
├── list ← list scopes on a connection
└── delete ← remove a scope from a connection
Dependencies
Blocked by:
configure connection add: Extract connection creation intoaddsubcommand #54 (connection add) — sets the extract-to-addpattern this issue follows
Blocks:
- Make scope dispatch tool-agnostic: Add
ScopeFunctoConnectionDef#57 (ScopeFunc) — touches the same scope dispatch code; best done after this restructuring lands - Document plugin-specific flag applicability in help text #58 (flag docs) —
Longtext moves toaddsubcommand created here
Parallel with: #56 (project CRUD) — independent files, can be done in parallel
Design decisions
Connection ID is mandatory
A scope is always tied to a specific plugin connection. For standalone scope subcommands:
- Flag mode:
--pluginand--connection-idare required - Interactive mode: show a connection picker (list all connections across plugins, let user choose)
The orchestrators (configureAllPhases, scopeAllConnections) continue to resolve connection IDs internally since they just created the connections.
Plugin-specific flags stay on add
The scope add command retains all current flags. Plugin-specific flags (--repos for GitHub, --enterprise for Copilot) are addressed separately in #58.
Scope of changes
1. Create cmd/configure_scope_add.go
Move runConfigureScopes() from configure_scopes.go into a new add subcommand:
func newScopeAddCmd() *cobra.Command {
var opts ScopeOpts
cmd := &cobra.Command{
Use: "add",
Short: "Add scopes (repos, orgs) to an existing connection",
RunE: func(cmd *cobra.Command, args []string) error {
return runScopeAdd(cmd, args, &opts)
},
}
// Move all current scope flags here
cmd.Flags().StringVar(&opts.Plugin, "plugin", "", ...)
cmd.Flags().IntVar(&opts.ConnectionID, "connection-id", 0, ...)
// ...
return cmd
}2. Create cmd/configure_scope_list.go
// gh devlake configure scope list --plugin github --connection-id 1
// gh devlake configure scope list (interactive: pick a connection)Implementation:
- In flag mode, require
--plugin+--connection-id - In interactive mode, use
pickConnection()(same helper used bydelete/update/testin connection commands) - Call existing
client.ListScopes(plugin, connID)— this API already exists - Render results as a table:
Scope ID | Name | Full Name
3. Create cmd/configure_scope_delete.go
// gh devlake configure scope delete --plugin github --connection-id 1 --scope-id 12345
// gh devlake configure scope delete (interactive: pick connection, then pick scope)Implementation:
- In flag mode, require
--plugin+--connection-id+--scope-id - In interactive mode: pick connection → list scopes → pick scope to delete
- Add new client method:
client.DeleteScope(plugin, connID, scopeID) - DevLake API:
DELETE /plugins/{plugin}/connections/{connId}/scopes/{scopeId} - Confirm before deletion (warn about blueprint impact)
4. Update configure_scopes.go
- Remove
RunEfrom the parent scope command - Remove flag registrations (they move to
add) - Register
add,list,deleteas subcommands
5. Add DeleteScope to internal/devlake/client.go
func (c *Client) DeleteScope(plugin string, connID int, scopeID string) error {
url := fmt.Sprintf("%s/plugins/%s/connections/%d/scopes/%s", c.BaseURL, plugin, connID, scopeID)
req, _ := http.NewRequest(http.MethodDelete, url, nil)
resp, err := c.HTTPClient.Do(req)
// ... error handling ...
}6. Verify orchestrators are unaffected
scopeAllConnections() in helpers.go calls scopeGitHub() and scopeCopilot() directly — it does not invoke the Cobra command. The restructuring should not affect it.
Acceptance criteria
-
gh devlake configure scopeprints help showingadd,list,delete -
gh devlake configure scope add --plugin github --connection-id 1 --org my-org --repos org/repo1works -
gh devlake configure scope addenters interactive mode (pick plugin, resolve connection) -
gh devlake configure scope list --plugin github --connection-id 1shows a table of scopes -
gh devlake configure scope list(interactive) lets user pick a connection, then shows scopes -
gh devlake configure scope delete --plugin github --connection-id 1 --scope-id 12345deletes a scope - Interactive delete picks connection → lists scopes → confirms deletion
-
--connection-idand--pluginare required in flag mode for all subcommands - Orchestrators (
configureAllPhases,scopeAllConnections) continue to work -
go build ./...andgo test ./...pass - README updated
References
cmd/configure_scopes.go— current scope command (to be restructured)cmd/configure_connection_delete.go— pattern for interactive picker + flag mode dualitycmd/configure_connection_list.go— pattern for tabular outputinternal/devlake/client.go—ListScopes()already exists; needDeleteScope()- DevLake API:
DELETE /plugins/{plugin}/connections/{connId}/scopes/{scopeId} cmd/helpers.go—scopeAllConnections()(should be unaffected)