Skip to content

feat: Implement azdo service-endpoint delete command #64

@tmeckel

Description

@tmeckel

This issue tracks the implementation of the azdo service-endpoint delete command.

Command Description

Delete a service endpoint from the target project, optionally cleaning up the associated Azure AD application (for AzureRM endpoints) and any additional project shares. The command should mirror the capabilities of az devops service-endpoint delete while following the repository's conventions for positional scope parsing, prompting, and output.

azdo Command Signature

azdo service-endpoint delete [ORGANIZATION/]PROJECT/ID [flags]

Arguments:

  • [ORGANIZATION/]PROJECT/ID (required): Project scope following ISSUE-TRIAGE.md. Resolve via util.ParseProjectNameAndOrganization, falling back to the configured default organization when possible. ID (required): UUID of the service endpoint to delete. Validate format before issuing API calls.

Flags

  • --deep: When set, pass deep=true to the REST API so the backing service principal/app registration is also removed (supported for AzureRM endpoints per REST doc).
  • --additional-project: Repeatable flag supplying extra project IDs as [ORGANIZATION/]PROJECT when the endpoint is shared across multiple projects. Combine with the primary project ID from the positional argument to build the projectIds list sent to the API. If omitted, only the positional project will be affected. The names of the additional projects must resolved into their respective GUIDs. An error resolving the GUID for a project returns an error.
  • --yes, -y: Skip the confirmation prompt.

Behavior

  • Acquire IO streams and prompter via ctx.IOStreams()/ctx.Prompter(); start ios.StartProgressIndicator() immediately and stop it before any CLI output.
  • Parse a stable list of project IDs: always include the resolved project GUID (use serviceEndpointClient.GetServiceEndpointDetails or the share references to retrieve the GUID if only the name was supplied) plus any --additional-project-id values. Deduplicate GUIDs to avoid REST errors.
  • Confirm the endpoint exists before deletion by issuing ServiceEndpointClient.GetServiceEndpointDetails (or GetServiceEndpoint) to provide better error messages and to retrieve metadata for confirmation text (e.g., endpoint name/type). If the lookup fails, return the wrapped error without attempting deletion.
  • Unless --yes is supplied, prompt the user: Delete service endpoint <name> (<id>) from project <projectName>? and include deep or additional project warnings when relevant. Declining should return util.ErrCancel.
  • Perform the deletion via ServiceEndpointClient.DeleteServiceEndpoint(ctx, serviceendpoint.DeleteServiceEndpointArgs{ EndpointId: &id, ProjectIds: &[]string{...}, Deep: &deepFlag }) using the vendored Azure DevOps client (azuredevops/v7/serviceendpoint).
  • Treat a non-204 response or returned error as a failure; wrap with context (mention endpoint ID and project).
  • Add zap.L().Debug statements for parsed scope, project ID list, deep flag, and REST call outcomes (excluding secrets).

Error Handling & Edge Cases

  • Validate ID and all --additional-project-id values as UUIDs before calling the API; return descriptive flag errors if parsing fails.
  • If the endpoint is shared with multiple projects and the caller omits additional project IDs, document (in help text) that the endpoint will only be removed from the specified project and remain in others. Consider warning via debug log.
  • Handle the case where the endpoint is already deleted or not found by surfacing a user-facing error from the lookup step.
  • Ensure progress indicator is stopped even on errors or cancellations.

Testing

  • Add table-driven unit tests in internal/cmd/serviceendpoint/delete/delete_test.go using gomock:
    1. Successful delete with single project (asserts prompt, REST call args, output, progress stop).
    2. --yes bypasses prompt.
    3. Deep delete sends deep=true.
    4. Additional project IDs combine with positional project (deduping).
    5. Invalid UUID for ID or additional project ID returns flag error before REST.
    6. Lookup failure (GetServiceEndpoint returns error) surfaces error and skips delete call.
    7. Delete call failure returns wrapped error message.
    8. JSON exporter output structure.
    9. Prompt decline returns util.ErrCancel.
  • Mock out IO streams to assert no extraneous output on errors.

References

Metadata

Metadata

Assignees

Labels

P1Priority 1

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions