Respect schema set by the provider url

Modify the Azure DevOps notifier to allow compatibiliy
with running behind a proxy.
Check existing commit statuses to avoid spamming the
same status when reconciling.

Signed-off-by: Philip Laine <philip.laine@xenit.se>
This commit is contained in:
Philip Laine 2021-03-05 11:00:03 +01:00
parent fcbadf36fc
commit 11f732d852
5 changed files with 91 additions and 20 deletions

View File

@ -21,6 +21,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"github.com/fluxcd/pkg/recorder"
"github.com/microsoft/azure-devops-go-api/azuredevops"
@ -31,9 +32,9 @@ const genre string = "fluxcd"
// AzureDevOps is a Azure DevOps notifier.
type AzureDevOps struct {
Project string
Repo string
Connection *azuredevops.Connection
Project string
Repo string
Client git.Client
}
// NewAzureDevOps creates and returns a new AzureDevOps notifier.
@ -55,11 +56,16 @@ func NewAzureDevOps(addr string, token string) (*AzureDevOps, error) {
proj := comp[1]
repo := comp[3]
c := azuredevops.NewPatConnection(fmt.Sprintf("%v/%v", host, org), token)
orgURL := fmt.Sprintf("%v/%v", host, org)
connection := azuredevops.NewPatConnection(orgURL, token)
client := connection.GetClientByUrl(orgURL)
gitClient := &git.ClientImpl{
Client: *client,
}
return &AzureDevOps{
Project: proj,
Repo: repo,
Connection: c,
Project: proj,
Repo: repo,
Client: gitClient,
}, nil
}
@ -83,15 +89,13 @@ func (a AzureDevOps) Post(event recorder.Event) error {
return err
}
ctx := context.Background()
client, err := git.NewClient(ctx, a.Connection)
if err != nil {
return err
}
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
defer cancel()
// Check if the exact status is already set
g := genre
name, desc := formatNameAndDescription(event)
args := git.CreateCommitStatusArgs{
createArgs := git.CreateCommitStatusArgs{
Project: &a.Project,
RepositoryId: &a.Repo,
CommitId: &rev,
@ -104,11 +108,24 @@ func (a AzureDevOps) Post(event recorder.Event) error {
},
},
}
_, err = client.CreateCommitStatus(ctx, args)
getArgs := git.GetStatusesArgs{
Project: &a.Project,
RepositoryId: &a.Repo,
CommitId: &rev,
}
statuses, err := a.Client.GetStatuses(ctx, getArgs)
if err != nil {
return err
return fmt.Errorf("could not list commit statuses: %v", err)
}
if duplicateAzureDevOpsStatus(statuses, createArgs.GitCommitStatusToCreate) {
return nil
}
// Create a new status
_, err = a.Client.CreateCommitStatus(context.Background(), createArgs)
if err != nil {
return fmt.Errorf("could not create commit status: %v", err)
}
return nil
}
@ -122,3 +139,19 @@ func toAzureDevOpsState(severity string) (git.GitStatusState, error) {
return "", errors.New("can't convert to azure devops state")
}
}
// duplicateStatus return true if the latest status
// with a matching context has the same state and description
func duplicateAzureDevOpsStatus(statuses *[]git.GitStatus, status *git.GitStatus) bool {
for _, s := range *statuses {
if *s.Context.Name == *status.Context.Name && *s.Context.Genre == *status.Context.Genre {
if *s.State == *status.State && *s.Description == *status.Description {
return true
}
return false
}
}
return false
}

View File

@ -19,6 +19,7 @@ package notifier
import (
"testing"
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
"github.com/stretchr/testify/assert"
)
@ -38,3 +39,35 @@ func TestNewAzureDevOpsMissingToken(t *testing.T) {
_, err := NewAzureDevOps("https://dev.azure.com/foo/bar/baz", "")
assert.NotNil(t, err)
}
func TestDuplicateAzureDevOpsStatus(t *testing.T) {
assert := assert.New(t)
var tests = []struct {
ss *[]git.GitStatus
s *git.GitStatus
dup bool
}{
{&[]git.GitStatus{*azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar")}, azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar"), true},
{&[]git.GitStatus{*azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar")}, azStatus(git.GitStatusStateValues.Failed, "foo", "bar"), false},
{&[]git.GitStatus{*azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar")}, azStatus(git.GitStatusStateValues.Succeeded, "baz", "bar"), false},
{&[]git.GitStatus{*azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar")}, azStatus(git.GitStatusStateValues.Succeeded, "foo", "baz"), false},
{&[]git.GitStatus{*azStatus(git.GitStatusStateValues.Succeeded, "baz", "bar"), *azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar")}, azStatus(git.GitStatusStateValues.Succeeded, "foo", "bar"), true},
}
for _, test := range tests {
assert.Equal(test.dup, duplicateAzureDevOpsStatus(test.ss, test.s))
}
}
func azStatus(state git.GitStatusState, context string, description string) *git.GitStatus {
genre := "fluxcd"
return &git.GitStatus{
Context: &git.GitStatusContext{
Name: &context,
Genre: &genre,
},
Description: &description,
State: &state,
}
}

View File

@ -96,7 +96,7 @@ func (g *GitHub) Post(event recorder.Event) error {
if err != nil {
return fmt.Errorf("could not list commit statuses: %v", err)
}
if duplicateStatus(statuses, status) {
if duplicateGithubStatus(statuses, status) {
return nil
}
@ -121,7 +121,7 @@ func toGitHubState(severity string) (string, error) {
// duplicateStatus return true if the latest status
// with a matching context has the same state and description
func duplicateStatus(statuses []*github.RepoStatus, status *github.RepoStatus) bool {
func duplicateGithubStatus(statuses []*github.RepoStatus, status *github.RepoStatus) bool {
for _, s := range statuses {
if *s.Context == *status.Context {
if *s.State == *status.State && *s.Description == *status.Description {

View File

@ -40,7 +40,7 @@ func TestNewGitHubEmptyToken(t *testing.T) {
assert.NotNil(t, err)
}
func TestDuplicateState(t *testing.T) {
func TestDuplicateGithubStatus(t *testing.T) {
assert := assert.New(t)
var tests = []struct {
@ -56,7 +56,7 @@ func TestDuplicateState(t *testing.T) {
}
for _, test := range tests {
assert.Equal(test.dup, duplicateStatus(test.ss, test.s))
assert.Equal(test.dup, duplicateGithubStatus(test.ss, test.s))
}
}

View File

@ -32,9 +32,14 @@ func parseGitAddress(s string) (string, string, error) {
return "", "", nil
}
scheme := u.Scheme
if u.Scheme == "ssh" {
scheme = "https"
}
id := strings.TrimLeft(u.Path, "/")
id = strings.TrimSuffix(id, ".git")
host := fmt.Sprintf("https://%s", u.Host)
host := fmt.Sprintf("%s://%s", scheme, u.Host)
return host, id, nil
}