github.com/argoproj/argo-cd/v2@v2.10.9/applicationset/services/pull_request/azure_devops.go (about)

     1  package pull_request
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/microsoft/azure-devops-go-api/azuredevops"
     9  	core "github.com/microsoft/azure-devops-go-api/azuredevops/core"
    10  	git "github.com/microsoft/azure-devops-go-api/azuredevops/git"
    11  )
    12  
    13  const AZURE_DEVOPS_DEFAULT_URL = "https://dev.azure.com"
    14  
    15  type AzureDevOpsClientFactory interface {
    16  	// Returns an Azure Devops Client interface.
    17  	GetClient(ctx context.Context) (git.Client, error)
    18  }
    19  
    20  type devopsFactoryImpl struct {
    21  	connection *azuredevops.Connection
    22  }
    23  
    24  func (factory *devopsFactoryImpl) GetClient(ctx context.Context) (git.Client, error) {
    25  	gitClient, err := git.NewClient(ctx, factory.connection)
    26  	if err != nil {
    27  		return nil, fmt.Errorf("failed to get new Azure DevOps git client for pull request generator: %w", err)
    28  	}
    29  	return gitClient, nil
    30  }
    31  
    32  type AzureDevOpsService struct {
    33  	clientFactory AzureDevOpsClientFactory
    34  	project       string
    35  	repo          string
    36  	labels        []string
    37  }
    38  
    39  var _ PullRequestService = (*AzureDevOpsService)(nil)
    40  var _ AzureDevOpsClientFactory = &devopsFactoryImpl{}
    41  
    42  func NewAzureDevOpsService(ctx context.Context, token, url, organization, project, repo string, labels []string) (PullRequestService, error) {
    43  	organizationUrl := buildURL(url, organization)
    44  
    45  	var connection *azuredevops.Connection
    46  	if token == "" {
    47  		connection = azuredevops.NewAnonymousConnection(organizationUrl)
    48  	} else {
    49  		connection = azuredevops.NewPatConnection(organizationUrl, token)
    50  	}
    51  
    52  	return &AzureDevOpsService{
    53  		clientFactory: &devopsFactoryImpl{connection: connection},
    54  		project:       project,
    55  		repo:          repo,
    56  		labels:        labels,
    57  	}, nil
    58  }
    59  
    60  func (a *AzureDevOpsService) List(ctx context.Context) ([]*PullRequest, error) {
    61  	client, err := a.clientFactory.GetClient(ctx)
    62  	if err != nil {
    63  		return nil, fmt.Errorf("failed to get Azure DevOps client: %w", err)
    64  	}
    65  
    66  	args := git.GetPullRequestsByProjectArgs{
    67  		Project:        &a.project,
    68  		SearchCriteria: &git.GitPullRequestSearchCriteria{},
    69  	}
    70  
    71  	azurePullRequests, err := client.GetPullRequestsByProject(ctx, args)
    72  	if err != nil {
    73  		return nil, fmt.Errorf("failed to get pull requests by project: %w", err)
    74  	}
    75  
    76  	pullRequests := []*PullRequest{}
    77  
    78  	for _, pr := range *azurePullRequests {
    79  		if pr.Repository == nil ||
    80  			pr.Repository.Name == nil ||
    81  			pr.PullRequestId == nil ||
    82  			pr.SourceRefName == nil ||
    83  			pr.LastMergeSourceCommit == nil ||
    84  			pr.LastMergeSourceCommit.CommitId == nil {
    85  			continue
    86  		}
    87  
    88  		azureDevOpsLabels := convertLabels(pr.Labels)
    89  		if !containAzureDevOpsLabels(a.labels, azureDevOpsLabels) {
    90  			continue
    91  		}
    92  
    93  		if *pr.Repository.Name == a.repo {
    94  			pullRequests = append(pullRequests, &PullRequest{
    95  				Number:  *pr.PullRequestId,
    96  				Branch:  strings.Replace(*pr.SourceRefName, "refs/heads/", "", 1),
    97  				HeadSHA: *pr.LastMergeSourceCommit.CommitId,
    98  				Labels:  azureDevOpsLabels,
    99  			})
   100  		}
   101  	}
   102  
   103  	return pullRequests, nil
   104  }
   105  
   106  // convertLabels converts WebApiTagDefinitions to strings
   107  func convertLabels(tags *[]core.WebApiTagDefinition) []string {
   108  	if tags == nil {
   109  		return []string{}
   110  	}
   111  	labelStrings := make([]string, len(*tags))
   112  	for i, label := range *tags {
   113  		labelStrings[i] = *label.Name
   114  	}
   115  	return labelStrings
   116  }
   117  
   118  // containAzureDevOpsLabels returns true if gotLabels contains expectedLabels
   119  func containAzureDevOpsLabels(expectedLabels []string, gotLabels []string) bool {
   120  	for _, expected := range expectedLabels {
   121  		found := false
   122  		for _, got := range gotLabels {
   123  			if expected == got {
   124  				found = true
   125  				break
   126  			}
   127  		}
   128  		if !found {
   129  			return false
   130  		}
   131  	}
   132  	return true
   133  }
   134  
   135  func buildURL(url, organization string) string {
   136  	if url == "" {
   137  		url = AZURE_DEVOPS_DEFAULT_URL
   138  	}
   139  	separator := ""
   140  	if !strings.HasSuffix(url, "/") {
   141  		separator = "/"
   142  	}
   143  	devOpsURL := fmt.Sprintf("%s%s%s", url, separator, organization)
   144  	return devOpsURL
   145  }