Skip to content

Commit cf7ee9f

Browse files
committed
feat(v7): allow custom HTTP client for: connection, core, git
1 parent 3045bdf commit cf7ee9f

File tree

10 files changed

+170
-28
lines changed

10 files changed

+170
-28
lines changed

azuredevops/client.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,17 @@ var baseUserAgent = "go/" + runtime.Version() + " (" + runtime.GOOS + " " + runt
5353
// NewClient provides an Azure DevOps client
5454
// and copies the TLS config and timeout from the supplied connection
5555
func NewClient(connection *Connection, baseUrl string) *Client {
56-
httpClient := &http.Client{}
57-
if connection.TlsConfig != nil {
58-
httpClient.Transport = &http.Transport{TLSClientConfig: connection.TlsConfig}
59-
}
60-
if connection.Timeout != nil {
61-
httpClient.Timeout = *connection.Timeout
56+
var httpClient *http.Client
57+
if connection.httpClient != nil {
58+
httpClient = connection.httpClient
59+
} else {
60+
httpClient = &http.Client{}
61+
if connection.TlsConfig != nil {
62+
httpClient.Transport = &http.Transport{TLSClientConfig: connection.TlsConfig}
63+
}
64+
if connection.Timeout != nil {
65+
httpClient.Timeout = *connection.Timeout
66+
}
6267
}
6368

6469
return NewClientWithOptions(connection, baseUrl, WithHTTPClient(httpClient))

azuredevops/connection.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"crypto/tls"
99
"encoding/base64"
10+
"net/http"
1011
"strings"
1112
"sync"
1213
"time"
@@ -16,21 +17,29 @@ import (
1617

1718
// Creates a new Azure DevOps connection instance using a personal access token.
1819
func NewPatConnection(organizationUrl string, personalAccessToken string) *Connection {
19-
authorizationString := CreateBasicAuthHeaderValue("", personalAccessToken)
20-
organizationUrl = normalizeUrl(organizationUrl)
21-
return &Connection{
22-
AuthorizationString: authorizationString,
23-
BaseUrl: organizationUrl,
24-
SuppressFedAuthRedirect: true,
25-
}
20+
return NewConnectionWithOptions(organizationUrl, WithConnectionPersonalAccessToken(personalAccessToken))
2621
}
2722

23+
// NewAnonymousConnection creates a new connection without specifying any authentication.
24+
// This is equivalent to calling NewConnectionWithOptions without specifying any options.
2825
func NewAnonymousConnection(organizationUrl string) *Connection {
26+
return NewConnectionWithOptions(organizationUrl)
27+
}
28+
29+
// NewConnectionWithOptions creates a new connection using the specified options. See WithConnection*() functions.
30+
func NewConnectionWithOptions(organizationUrl string, options ...ConnectionOptionFunc) *Connection {
2931
organizationUrl = normalizeUrl(organizationUrl)
30-
return &Connection{
32+
connection := &Connection{
3133
BaseUrl: organizationUrl,
3234
SuppressFedAuthRedirect: true,
35+
httpClient: &http.Client{},
36+
}
37+
38+
for _, fn := range options {
39+
fn(connection)
3340
}
41+
42+
return connection
3443
}
3544

3645
type Connection struct {
@@ -45,6 +54,7 @@ type Connection struct {
4554
clientCacheLock sync.RWMutex
4655
resourceAreaCache map[uuid.UUID]ResourceAreaInfo
4756
resourceAreaCacheLock sync.RWMutex
57+
httpClient *http.Client
4858
}
4959

5060
func CreateBasicAuthHeaderValue(username, password string) string {

azuredevops/connection_options.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package azuredevops
2+
3+
import "net/http"
4+
5+
type ConnectionOptionFunc func(*Connection)
6+
7+
// WithConnectionHTTPClient sets the HTTP client that will be used by the connection.
8+
func WithConnectionHTTPClient(client *http.Client) ConnectionOptionFunc {
9+
return func(c *Connection) {
10+
c.httpClient = client
11+
}
12+
}
13+
14+
// WithConnectionPersonalAccessToken specifies the PAT to use for authentication with Azure DevOps.
15+
func WithConnectionPersonalAccessToken(personalAccessToken string) ConnectionOptionFunc {
16+
return func(c *Connection) {
17+
authorizationString := CreateBasicAuthHeaderValue("", personalAccessToken)
18+
c.AuthorizationString = authorizationString
19+
}
20+
}

azuredevops/core/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ func NewClient(ctx context.Context, connection *azuredevops.Connection) (Client,
9393
}, nil
9494
}
9595

96+
func NewClientWithOptions(ctx context.Context, connection *azuredevops.Connection, options ...azuredevops.ClientOptionFunc) (Client, error) {
97+
client, err := connection.GetClientByResourceAreaId(ctx, ResourceAreaId)
98+
if err != nil {
99+
return nil, err
100+
}
101+
102+
for _, fn := range options {
103+
if fn == nil {
104+
continue
105+
}
106+
fn(client)
107+
}
108+
109+
return &ClientImpl{
110+
Client: *client,
111+
}, nil
112+
}
113+
96114
// [Preview API]
97115
func (client *ClientImpl) CreateConnectedService(ctx context.Context, args CreateConnectedServiceArgs) (*WebApiConnectedService, error) {
98116
if args.ConnectedServiceCreationData == nil {

azuredevops/git/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,24 @@ func NewClient(ctx context.Context, connection *azuredevops.Connection) (Client,
274274
}, nil
275275
}
276276

277+
func NewClientWithOptions(ctx context.Context, connection *azuredevops.Connection, options ...azuredevops.ClientOptionFunc) (Client, error) {
278+
client, err := connection.GetClientByResourceAreaId(ctx, ResourceAreaId)
279+
if err != nil {
280+
return nil, err
281+
}
282+
283+
for _, fn := range options {
284+
if fn == nil {
285+
continue
286+
}
287+
fn(client)
288+
}
289+
290+
return &ClientImpl{
291+
Client: *client,
292+
}, nil
293+
}
294+
277295
// [Preview API] Create an annotated tag.
278296
func (client *ClientImpl) CreateAnnotatedTag(ctx context.Context, args CreateAnnotatedTagArgs) (*GitAnnotatedTag, error) {
279297
if args.TagObject == nil {

azuredevops/v7/client.go

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,12 +53,17 @@ var baseUserAgent = "go/" + runtime.Version() + " (" + runtime.GOOS + " " + runt
5353
// NewClient provides an Azure DevOps client
5454
// and copies the TLS config and timeout from the supplied connection
5555
func NewClient(connection *Connection, baseUrl string) *Client {
56-
httpClient := &http.Client{}
57-
if connection.TlsConfig != nil {
58-
httpClient.Transport = &http.Transport{TLSClientConfig: connection.TlsConfig}
59-
}
60-
if connection.Timeout != nil {
61-
httpClient.Timeout = *connection.Timeout
56+
var httpClient *http.Client
57+
if connection.httpClient != nil {
58+
httpClient = connection.httpClient
59+
} else {
60+
httpClient = &http.Client{}
61+
if connection.TlsConfig != nil {
62+
httpClient.Transport = &http.Transport{TLSClientConfig: connection.TlsConfig}
63+
}
64+
if connection.Timeout != nil {
65+
httpClient.Timeout = *connection.Timeout
66+
}
6267
}
6368

6469
return NewClientWithOptions(connection, baseUrl, WithHTTPClient(httpClient))

azuredevops/v7/connection.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"context"
88
"crypto/tls"
99
"encoding/base64"
10+
"net/http"
1011
"strings"
1112
"sync"
1213
"time"
@@ -16,21 +17,29 @@ import (
1617

1718
// Creates a new Azure DevOps connection instance using a personal access token.
1819
func NewPatConnection(organizationUrl string, personalAccessToken string) *Connection {
19-
authorizationString := CreateBasicAuthHeaderValue("", personalAccessToken)
20-
organizationUrl = normalizeUrl(organizationUrl)
21-
return &Connection{
22-
AuthorizationString: authorizationString,
23-
BaseUrl: organizationUrl,
24-
SuppressFedAuthRedirect: true,
25-
}
20+
return NewConnectionWithOptions(organizationUrl, WithConnectionPersonalAccessToken(personalAccessToken))
2621
}
2722

23+
// NewAnonymousConnection creates a new connection without specifying any authentication.
24+
// This is equivalent to calling NewConnectionWithOptions without specifying any options.
2825
func NewAnonymousConnection(organizationUrl string) *Connection {
26+
return NewConnectionWithOptions(organizationUrl)
27+
}
28+
29+
// NewConnectionWithOptions creates a new connection using the specified options. See WithConnection*() functions.
30+
func NewConnectionWithOptions(organizationUrl string, options ...ConnectionOptionFunc) *Connection {
2931
organizationUrl = normalizeUrl(organizationUrl)
30-
return &Connection{
32+
connection := &Connection{
3133
BaseUrl: organizationUrl,
3234
SuppressFedAuthRedirect: true,
35+
httpClient: &http.Client{},
36+
}
37+
38+
for _, fn := range options {
39+
fn(connection)
3340
}
41+
42+
return connection
3443
}
3544

3645
type Connection struct {
@@ -45,6 +54,7 @@ type Connection struct {
4554
clientCacheLock sync.RWMutex
4655
resourceAreaCache map[uuid.UUID]ResourceAreaInfo
4756
resourceAreaCacheLock sync.RWMutex
57+
httpClient *http.Client
4858
}
4959

5060
func CreateBasicAuthHeaderValue(username, password string) string {

azuredevops/v7/connection_options.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package azuredevops
2+
3+
import "net/http"
4+
5+
type ConnectionOptionFunc func(*Connection)
6+
7+
// WithConnectionHTTPClient sets the HTTP client that will be used by the connection.
8+
func WithConnectionHTTPClient(client *http.Client) ConnectionOptionFunc {
9+
return func(c *Connection) {
10+
c.httpClient = client
11+
}
12+
}
13+
14+
// WithConnectionPersonalAccessToken specifies the PAT to use for authentication with Azure DevOps.
15+
func WithConnectionPersonalAccessToken(personalAccessToken string) ConnectionOptionFunc {
16+
return func(c *Connection) {
17+
authorizationString := CreateBasicAuthHeaderValue("", personalAccessToken)
18+
c.AuthorizationString = authorizationString
19+
}
20+
}

azuredevops/v7/core/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,24 @@ func NewClient(ctx context.Context, connection *azuredevops.Connection) (Client,
9393
}, nil
9494
}
9595

96+
func NewClientWithOptions(ctx context.Context, connection *azuredevops.Connection, options ...azuredevops.ClientOptionFunc) (Client, error) {
97+
client, err := connection.GetClientByResourceAreaId(ctx, ResourceAreaId)
98+
if err != nil {
99+
return nil, err
100+
}
101+
102+
for _, fn := range options {
103+
if fn == nil {
104+
continue
105+
}
106+
fn(client)
107+
}
108+
109+
return &ClientImpl{
110+
Client: *client,
111+
}, nil
112+
}
113+
96114
// [Preview API]
97115
func (client *ClientImpl) CreateConnectedService(ctx context.Context, args CreateConnectedServiceArgs) (*WebApiConnectedService, error) {
98116
if args.ConnectedServiceCreationData == nil {

azuredevops/v7/git/client.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,24 @@ func NewClient(ctx context.Context, connection *azuredevops.Connection) (Client,
280280
}, nil
281281
}
282282

283+
func NewClientWithOptions(ctx context.Context, connection *azuredevops.Connection, options ...azuredevops.ClientOptionFunc) (Client, error) {
284+
client, err := connection.GetClientByResourceAreaId(ctx, ResourceAreaId)
285+
if err != nil {
286+
return nil, err
287+
}
288+
289+
for _, fn := range options {
290+
if fn == nil {
291+
continue
292+
}
293+
fn(client)
294+
}
295+
296+
return &ClientImpl{
297+
Client: *client,
298+
}, nil
299+
}
300+
283301
// [Preview API] Create an annotated tag.
284302
func (client *ClientImpl) CreateAnnotatedTag(ctx context.Context, args CreateAnnotatedTagArgs) (*GitAnnotatedTag, error) {
285303
if args.TagObject == nil {

0 commit comments

Comments
 (0)