Skip to content

feat(configure): add project add/list/delete CRUD subcommands#74

Merged
ewega merged 4 commits intomainfrom
copilot/add-crud-subcommands-project
Mar 2, 2026
Merged

feat(configure): add project add/list/delete CRUD subcommands#74
ewega merged 4 commits intomainfrom
copilot/add-crud-subcommands-project

Conversation

Copy link
Contributor

Copilot AI commented Mar 2, 2026

  • Add ListProjects() and DeleteProject() to internal/devlake/client.go
  • Add ProjectListResponse to internal/devlake/types.go
  • Create cmd/configure_project_add.go (delegates to existing runConfigureProjects)
  • Create cmd/configure_project_list.go (table + JSON output)
  • Create cmd/configure_project_delete.go (flag mode + interactive picker + confirmation)
    • Move projectDeleteName to locally-scoped var inside newProjectDeleteCmd() (opts pattern)
    • Remove unreachable if name == "" guard (dead code)
  • Update cmd/configure_projects.go (remove RunE/flags, register add/list/delete subcommands)
  • Update cmd/configure_full.go and cmd/configure_scopes.go help text references
  • Update README.md command reference table and usage example
  • Add tests for new project subcommands (configure_project_test.go)
  • Update docs/configure-project.md to document all three subcommands (add/list/delete)
  • Update .github/skills/devlake-dev-architecture/SKILL.md command tree
  • Update AGENTS.md with command tree showing project add/list/delete
  • go build ./..., go test ./..., and go vet ./... all pass
Original prompt

This section details on the original issue you should resolve

<issue_title>configure project add/list/delete: Add CRUD subcommands for project management</issue_title>
<issue_description>## Problem

configure project is currently a single command that creates a project. There are no subcommands for listing existing projects or deleting them. This is inconsistent with the CRUD pattern established by configure connection (which has add, list, update, delete, test) and the restructuring planned for configure scope in #55.

Users who want to inspect what projects exist, or remove a stale project, must use the DevLake API directly (or the Config UI).

Current command tree

configure project            ← RunE = create project (only action)

Desired command tree

configure project            ← no RunE, prints help
  ├── add                    ← current project creation logic
  ├── list                   ← list projects
  └── delete                 ← delete a project by name

Dependencies

Blocked by:

Blocks: nothing directly

Parallel with: #55 (scope CRUD) — independent files, can be done in parallel

Scope of changes

1. Create cmd/configure_project_add.go

Move the current runConfigureProjects() from configure_projects.go into a new add subcommand:

func newProjectAddCmd() *cobra.Command {
    var opts ProjectOpts
    cmd := &cobra.Command{
        Use:   "add",
        Short: "Create a DevLake project and start data collection",
        RunE: func(cmd *cobra.Command, args []string) error {
            return runProjectAdd(cmd, args, &opts)
        },
    }
    // Move all current project flags here
    cmd.Flags().StringVar(&opts.ProjectName, "project-name", "", ...)
    cmd.Flags().StringVar(&opts.Cron, "cron", "0 0 * * *", ...)
    // ...
    return cmd
}

2. Create cmd/configure_project_list.go

// gh devlake configure project list

Implementation:

  • Call new client method client.ListProjects()GET /projects
  • Render results as a table: Name | Description | Blueprint ID | Blueprint Status
  • No flags needed — lists all projects

3. Create cmd/configure_project_delete.go

// gh devlake configure project delete --name my-project
// gh devlake configure project delete   (interactive: pick from list)

Implementation:

  • In flag mode, require --name
  • In interactive mode: list projects → pick one → confirm deletion
  • Call new client method client.DeleteProject(name)DELETE /projects/{name}
  • Confirm before deletion (warn about losing blueprint and sync schedule)

4. Update configure_projects.go

  • Remove RunE from the parent project command
  • Remove flag registrations (they move to add)
  • Register add, list, delete as subcommands

5. Add client methods to internal/devlake/client.go

// ListProjects returns all DevLake projects.
func (c *Client) ListProjects() ([]Project, error) {
    result, err := doGet[struct{ Projects []Project }](c, "/projects")
    if err != nil {
        return nil, err
    }
    return result.Projects, nil
}

// DeleteProject deletes a project by name.
func (c *Client) DeleteProject(name string) error {
    url := fmt.Sprintf("%s/projects/%s", c.BaseURL, name)
    req, _ := http.NewRequest(http.MethodDelete, url, nil)
    resp, err := c.HTTPClient.Do(req)
    // ... error handling ...
}

Note: The exact response shape of GET /projects should be verified against the DevLake API. The upstream code is at backend/server/api/project/project.go in the apache/incubator-devlake repo.

6. Verify orchestrators are unaffected

collectAndFinalizeProject() in helpers.go calls finalizeProject() directly — it does not invoke the Cobra command. The restructuring should not affect orchestrators.

Acceptance criteria

  • gh devlake configure project prints help showing add, list, delete
  • gh devlake configure project add creates a project (same as current behavior)
  • gh devlake configure project add --project-name my-team works in flag mode
  • gh devlake configure project list shows a table of all projects
  • gh devlake configure project delete --name my-project deletes a project
  • Interactive delete lists projects → user picks one → confirms → deletes
  • Orchestrators (configureAllPhases, collectAndFinalizeProject) continue to work
  • go build ./... and go test ./... pass
  • README updated

References

  • cmd/configure_projects.go — current project command (to be restructured)
  • cmd/helpers.gocollectAndFinalizeProject(), finalizeProject() (should be unaffected)
  • internal/devlake/client.goCreateProject(), GetProject() exist; need ListProjects(), DeleteProject()
  • DevLake API: GET /projects, `DELETE /...

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Co-authored-by: ewega <26189114+ewega@users.noreply.github.com>
Copilot AI changed the title [WIP] Add CRUD subcommands for project management feat(configure): add project add/list/delete CRUD subcommands Mar 2, 2026
Copilot finished work on behalf of ewega March 2, 2026 11:23
@ewega ewega requested a review from Copilot March 2, 2026 11:29
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR restructures configure project from a single command into a parent with three subcommands (add, list, delete), matching the CRUD pattern established by configure connection. The core creation logic is unchanged — it is simply moved to the new add subcommand.

Changes:

  • Added list and delete subcommands (configure_project_list.go, configure_project_delete.go) plus add wrapper (configure_project_add.go)
  • Stripped the RunE and flags from the parent configure_projects.go; added ListProjects() and DeleteProject() to the DevLake client
  • Updated all command reference strings (configure_scopes.go, configure_full.go, README.md) to use configure project add

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/devlake/types.go Adds ProjectListResponse struct for GET /projects
internal/devlake/client.go Adds ListProjects() (via doGet) and DeleteProject() (raw HTTP, matching DeleteConnection)
cmd/configure_projects.go Parent command stripped of RunE and flags; registers three subcommands
cmd/configure_project_add.go Thin add subcommand wrapping the existing runConfigureProjects logic
cmd/configure_project_list.go list subcommand rendering a tabwriter table; supports --json
cmd/configure_project_delete.go delete subcommand with interactive project picker and confirmation prompt
cmd/configure_project_test.go Structural tests for subcommand registration, NoRunE, and flag presence
cmd/configure_scopes.go Help text reference updated to configure project add
cmd/configure_full.go Long description example updated to configure project add
README.md Command reference table expanded with add, list, delete entries

Comment on lines +12 to +29
var projectDeleteName string

func newProjectDeleteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "delete",
Short: "Delete a DevLake project",
Long: `Deletes a DevLake project by name.

If --name is not specified, prompts interactively.

⚠️ Deleting a project also removes its blueprint and sync schedule.

Examples:
gh devlake configure project delete
gh devlake configure project delete --name my-project`,
RunE: runProjectDelete,
}
cmd.Flags().StringVar(&projectDeleteName, "name", "", "Name of the project to delete")
Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The projectDeleteName package-level variable is inconsistent with the opts struct pattern used by the sibling newProjectAddCmd() in configure_project_add.go, which declares var opts ProjectOpts locally inside the constructor. Using a package-level variable for flag state means the flag value persists between test runs and could cause subtle issues in test suites that call newProjectDeleteCmd() multiple times. The --name flag should be bound to a locally-scoped variable (e.g. declared inside newProjectDeleteCmd()), consistent with the opts pattern established in configure_project_add.go and configure_scopes.go (line 36).

Copilot generated this review using guidance from repository custom instructions.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in cea4de5projectDeleteName is now declared locally inside newProjectDeleteCmd() and passed to runProjectDelete as a parameter, consistent with the opts pattern used by the sibling commands.

Comment on lines +71 to +74
if name == "" {
return fmt.Errorf("--name is required (or omit for interactive mode)")
}

Copy link

Copilot AI Mar 2, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if name == "" guard at lines 71-73 is unreachable dead code. By the time execution reaches it, name is guaranteed to be non-empty: if --name was provided, it was copied from the non-empty projectDeleteName at line 43; if the interactive path was taken, the code already returned early at line 66 when chosen == "", so name was assigned from chosen (which is non-empty). This guard can never trigger and should be removed.

Suggested change
if name == "" {
return fmt.Errorf("--name is required (or omit for interactive mode)")
}

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in cea4de5 — the dead if name == "" guard is gone.

@ewega
Copy link
Contributor

ewega commented Mar 2, 2026

@copilot Three documentation gaps to fix:

  1. Update docs/configure-project.md: Restructure it to document the three new subcommands (add, list, delete) instead of treating configure project as a single command. Update the Usage section, examples, and "What It Does" descriptions. Follow the same pattern as docs/configure-connection.md which already documents CRUD subcommands.

  2. Update .github/skills/devlake-dev-architecture/SKILL.md: In the command tree, change:

    │   └── project                   # Create project + blueprint + trigger sync
    

    to:

    │   └── project                   # Manage DevLake projects
    │       ├── add                   # Create project + blueprint + trigger sync
    │       ├── list                  # List all projects
    │       └── delete               # Delete a project
    
  3. Update AGENTS.md: Same command tree fix — update the project entry under configure to show add/list/delete subcommands.

…docs

Co-authored-by: ewega <26189114+ewega@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Mar 2, 2026

@copilot Three documentation gaps to fix:

  1. Update docs/configure-project.md: Restructure it to document the three new subcommands (add, list, delete) instead of treating `configure proj...

All three done in cea4de5:

  1. docs/configure-project.md — restructured with separate sections for add, list, and delete, following the configure-connection.md pattern.
  2. .github/skills/devlake-dev-architecture/SKILL.md — command tree updated to show add/list/delete under project.
  3. AGENTS.md — added a full command tree section (it previously had none) showing project add/list/delete alongside the connection CRUD entries.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 13 changed files in this pull request and generated no new comments.

@ewega ewega marked this pull request as ready for review March 2, 2026 12:45
@ewega ewega merged commit 01cdcf2 into main Mar 2, 2026
3 checks passed
@ewega ewega deleted the copilot/add-crud-subcommands-project branch March 2, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

configure project add/list/delete: Add CRUD subcommands for project management

3 participants