Skip to content

feat: Implement azdo security group list command #74

@tmeckel

Description

@tmeckel

This issue tracks the implementation of the azdo security group list command.

Command Description

List all security groups within a given project or organization.

azdo Command Signature

This command should support the following parameters:

  • A positional argument in the format ORGANIZATION or ORGANIZATION/PROJECT. The organization is always required. If a project is included, the list is scoped to that project; otherwise, it is scoped to the organization.
  • --filter: An expression to filter the returned groups by name. (Optional)
  • --json: If specified, the command will output the results in JSON format.

Technical constraints

  • To list groups the "Groups List" method of the Azure DevOps REST API must be used: https://learn.microsoft.com/en-us/rest/api/azure/devops/graph/groups/list?view=azure-devops-rest-7.2&tabs=HTTP

  • The "Groups List" method must be called as long as the returned ContinuationToken is nil or len()==0

    func getGroupsWithContinuationToken(clients *client.AggregatedClient, projectDescriptor string, continuationToken string) (*[]graph.GraphGroup, string, error) {
      args := graph.ListGroupsArgs{}
      if projectDescriptor != "" {
        args.ScopeDescriptor = &projectDescriptor
      }
      if continuationToken != "" {
        args.ContinuationToken = &continuationToken
      }
    
      response, err := clients.GraphClient.ListGroups(clients.Ctx, args)
      if err != nil {
        return nil, "", err
      }
    
      if response.ContinuationToken != nil && len(*response.ContinuationToken) > 1 {
        return nil, "", fmt.Errorf("Expected at most 1 continuation token, but found %d", len(*response.ContinuationToken))
      }
    
      var newToken string
      if response.ContinuationToken != nil && len(*response.ContinuationToken) > 0 {
        newToken = (*response.ContinuationToken)[0]
      }
    
      return response.GraphGroups, newToken, nil
    }
  • To get the descriptor of a Project given by it's ID (UUID):

        func getProjectDescriptor(clients *client.AggregatedClient, projectID string) (string, error) {
      if projectID == "" {
        return "", nil
      }
    
      projectUUID, err := uuid.Parse(projectID)
      if err != nil {
        return "", err
      }
    
      descriptor, err := clients.GraphClient.GetDescriptor(clients.Ctx, graph.GetDescriptorArgs{StorageKey: &projectUUID})
      if err != nil {
        return "", err
      }
    
      return *descriptor.Value, nil
    }

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions