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 }