Skip to content

Commit 1fa4701

Browse files
authored
Merge pull request #123 from cdancy/add-overrides
Exposing jclouds overrides option through client builder, sys-props, and env-vars.
2 parents 9760e65 + 734ac97 commit 1fa4701

File tree

7 files changed

+563
-128
lines changed

7 files changed

+563
-128
lines changed

README.md

+67-32
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99

1010
java client, based on jclouds, to interact with Bitbucket's REST API.
1111

12-
1312
## On jclouds, apis and endpoints
1413
Being built on top of `jclouds` means things are broken up into [Apis](https://github.com/cdancy/bitbucket-rest/tree/master/src/main/java/com/cdancy/bitbucket/rest/features).
1514
`Apis` are just Interfaces that are analagous to a resource provided by the server-side program (e.g. /api/branches, /api/pullrequest, /api/commits, etc..).
@@ -44,68 +43,104 @@ Can be sourced from jcenter like so:
4443

4544
javadocs can be found via [github pages here](http://cdancy.github.io/bitbucket-rest/docs/javadoc/)
4645

47-
## Property based setup
46+
## Examples on how to build a _BitbucketClient_
47+
48+
When using `Basic` (e.g. username and password) authentication:
49+
50+
BitbucketClient client = BitbucketClient.builder()
51+
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
52+
.credentials("admin:password") // Optional and can be sourced from system/env and can be Base64 encoded.
53+
.build();
54+
55+
Version version = client.api().systemApi().version();
56+
57+
When using `Bearer` (e.g. token) authentication:
58+
59+
BitbucketClient client = BitbucketClient.builder()
60+
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
61+
.token("123456789abcdef") // Optional and can be sourced from system/env.
62+
.build();
63+
64+
Version version = client.api().systemApi().version();
65+
66+
When using `Anonymous` authentication or sourcing from system/environment (as described above):
67+
68+
BitbucketClient client = BitbucketClient.builder()
69+
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
70+
.build();
71+
72+
Version version = client.api().systemApi().version();
73+
74+
## On `System Property` and `Environment Variable` setup
4875

4976
Client's do NOT need to supply the endPoint or authentication as part of instantiating the
50-
_BitbucketClient_ object. Instead one can supply them through system properties, environment
51-
variables, or a combination of the 2. _System Properties_ will be searched first and if not
52-
found we will attempt to query the _Environment Variables_. If neither turns up anything
77+
_BitbucketClient_ object. Instead one can supply them through `System Properties`, `Environment
78+
Variables`, or a combination of the 2. `System Properties` will be searched first and if not
79+
found we will attempt to query the `Environment Variables`. If neither turns up anything
5380
than anonymous access is assumed.
5481

55-
Setting the `endpoint` can be done with any of the following (searched in order):
82+
Setting the `endpoint` can be done like so (searched in order):
5683

57-
- `bitbucket.rest.endpoint`
58-
- `bitbucketRestEndpoint`
59-
- `BITBUCKET_REST_ENDPOINT`
84+
`System.setProperty("bitbucket.rest.endpoint", "http://my-bitbucket-instance:12345")`
85+
`export BITBUCKET_REST_ENDPOINT=http://my-bitbucket-instance:12345`
6086

61-
Setting the `credentials` can be done with any of the following (searched in order):
87+
Setting the `credentials`, which represents `Basic` authentication and is optionally Base64 encoded, can be done like so (searched in order):
6288

63-
- `bitbucket.rest.credentials`
64-
- `bitbucketRestCredentials`
65-
- `BITBUCKET_REST_CREDENTIALS`
89+
`System.setProperty("bitbucket.rest.credentials", "username:password")`
90+
`export BITBUCKET_REST_CREDENTIALS=username:password`
6691

67-
Setting the `token` can be done with any of the following (searched in order):
92+
Setting the `token`, which represents `Bearer` authentication, can be done like so (searched in order):
6893

69-
- `bitbucket.rest.token`
70-
- `bitbucketRestToken`
71-
- `BITBUCKET_REST_TOKEN`
94+
`System.setProperty("bitbucket.rest.token", "abcdefg1234567")`
95+
`export BITBUCKET_REST_TOKEN=abcdefg1234567`
7296

73-
## Authentication
97+
## On Overrides
7498

75-
Authentication/Credentials for `bitbucket-rest` can take 1 of 3 forms:
99+
Because we are built on top of jclouds we can take advantage of overriding various internal _HTTP_ properties by
100+
passing in a `Properties` object or, and in following with the spirit of this library, configuring them
101+
through `System Properties` of `Environment Variables`. The properties a given client can configure can be
102+
found [HERE](https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/Constants.java).
76103

77-
- Colon delimited username and password: __admin:password__
78-
- Base64 encoded username and password: __YWRtaW46cGFzc3dvcmQ=__
79-
- Personal access token: __9DfK3AF9Jeke1O0dkKX5kDswps43FEDlf5Frkspma21M__
80-
81-
## Examples on how to build a _BitbucketClient_
104+
When configuring through a `Properties` object you must pass in the keys exactly as they are named within jclouds:
82105

83-
When using `Basic` (e.g. username and password) authentication:
106+
Properties props = new Properties();
107+
props.setProperty("jclouds.so-timeout", "60000");
108+
props.setProperty("jclouds.connection-timeout", "120000");
84109

85110
BitbucketClient client = BitbucketClient.builder()
86-
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
87-
.credentials("admin:password") // Optional and can be sourced from system/env.
111+
.overrides(props)
88112
.build();
89113

90114
Version version = client.api().systemApi().version();
91115

92-
When using `Bearer` (e.g. token) authentication:
116+
When configuring through `System Properties` you must prepend the jclouds name with `bitbucket.rest.`:
117+
118+
System.setProperty("bitbucket.rest.jclouds.so-timeout", "60000");
119+
System.setProperty("bitbucket.rest.jclouds.connection-timeout", "120000");
93120

94121
BitbucketClient client = BitbucketClient.builder()
95-
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
96-
.token("123456789abcdef") // Optional and can be sourced from system/env.
97122
.build();
98123

99124
Version version = client.api().systemApi().version();
100125

101-
When using `Anonymous` authentication or sourcing from system/environment (as described above):
126+
When configuring through `Environment Variables` you must CAPITALIZE all characters,
127+
replace any `.` with `_`, and prepend the jclouds name with `BITBUCKET_REST_`:
128+
129+
export BITBUCKET_REST_JCLOUDS_SO-TIMEOUT=60000
130+
export BITBUCKET_REST_JCLOUDS_CONNECTION-TIMEOUT=120000
102131

103132
BitbucketClient client = BitbucketClient.builder()
104-
.endPoint("http://127.0.0.1:7990") // Optional and can be sourced from system/env. Falls back to http://127.0.0.1:7990
105133
.build();
106134

107135
Version version = client.api().systemApi().version();
108136

137+
It should be noted that when using this feature a merge happens behind the scenes between all
138+
possible ways one can pass in _overrides_. Meaning if you pass in a `Properties` object, and
139+
there are `System Properties` and `Environment Variables` set, then all 3 will be merged into
140+
a single `Properties` object which in turn will be passed along to _jclouds_. When it comes to
141+
precedence passed in `Properties` take precedence over `System Properties` which in turn
142+
take precedence over `Environment Variables`.
143+
109144
## Understanding Error objects
110145

111146
When something pops server-side `bitbucket` will hand us back a list of [Error](https://github.com/cdancy/bitbucket-rest/blob/master/src/main/java/com/cdancy/bitbucket/rest/error/Error.java) objects. Instead of failing and/or throwing an exception at runtime we attach this List of `Error` objects

src/main/java/com/cdancy/bitbucket/rest/BitbucketClient.java

+72-35
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.cdancy.bitbucket.rest.config.BitbucketAuthenticationModule;
2222
import com.google.common.collect.Lists;
2323
import java.util.Objects;
24+
import java.util.Properties;
2425
import org.jclouds.ContextBuilder;
2526
import org.jclouds.javax.annotation.Nullable;
2627

@@ -29,15 +30,14 @@ public final class BitbucketClient {
2930
private final String endPoint;
3031
private final BitbucketAuthentication credentials;
3132
private final BitbucketApi bitbucketApi;
33+
private final Properties overrides;
3234

3335
/**
3436
* Create a BitbucketClient inferring endpoint and authentication from
3537
* environment and system properties.
3638
*/
3739
public BitbucketClient() {
38-
this.endPoint = BitbucketUtils.inferEndpoint();
39-
this.credentials = BitbucketUtils.inferCredentials();
40-
this.bitbucketApi = createApi(this.endPoint(), credentials);
40+
this(null, null, null);
4141
}
4242

4343
/**
@@ -46,13 +46,8 @@ public BitbucketClient() {
4646
*
4747
* @param endPoint URL of Bitbucket instance
4848
*/
49-
@Deprecated //@Nullable annotation will be removed in 2.x releases
5049
public BitbucketClient(@Nullable final String endPoint) {
51-
this.endPoint = endPoint != null
52-
? endPoint
53-
: BitbucketUtils.inferEndpoint();
54-
this.credentials = BitbucketUtils.inferCredentials();
55-
this.bitbucketApi = createApi(this.endPoint(), credentials);
50+
this(endPoint, null, null);
5651
}
5752

5853
/**
@@ -63,54 +58,84 @@ public BitbucketClient(@Nullable final String endPoint) {
6358
*/
6459
@Deprecated //Constructor will be deleted in favor of 'String, BitbucketCredentials' version in 2.x releases
6560
public BitbucketClient(@Nullable final String endPoint, @Nullable final String basicCredentials) {
66-
this.endPoint = endPoint != null
67-
? endPoint
68-
: BitbucketUtils.inferEndpoint();
69-
this.credentials = basicCredentials != null
70-
? BitbucketAuthentication.builder().credentials(basicCredentials).build()
71-
: BitbucketUtils.inferCredentials();
72-
this.bitbucketApi = createApi(this.endPoint(), credentials);
61+
this(endPoint,
62+
basicCredentials != null
63+
? BitbucketAuthentication.builder().credentials(basicCredentials).build()
64+
: null,
65+
null);
7366
}
7467

7568
/**
76-
* Create an BitbucketClient using the passed in endpoint and BitbucketCredentials instance.
69+
* Create an BitbucketClient. If any of the passed in variables are null we
70+
* will query System Properties and Environment Variables, in order, to
71+
* search for values that may be set in a devops/CI fashion. The only
72+
* difference is the `overrides` which gets merged, but takes precedence,
73+
* with those System Properties and Environment Variables found.
7774
*
78-
* @param endPoint URL of Bitbucket instance
79-
* @param credentials Credentials used to connect to Bitbucket instance.
75+
* @param endPoint URL of Bitbucket instance.
76+
* @param authentication authentication used to connect to Bitbucket instance.
77+
* @param overrides jclouds Properties to override defaults when creating a new BitbucketApi.
8078
*/
81-
public BitbucketClient(final String endPoint, final BitbucketAuthentication credentials) {
82-
this.endPoint = endPoint;
83-
this.credentials = credentials;
84-
this.bitbucketApi = createApi(endPoint, Objects.requireNonNull(credentials));
79+
public BitbucketClient(@Nullable final String endPoint,
80+
@Nullable final BitbucketAuthentication authentication,
81+
@Nullable final Properties overrides) {
82+
this.endPoint = endPoint != null
83+
? endPoint
84+
: BitbucketUtils.inferEndpoint();
85+
this.credentials = authentication != null
86+
? authentication
87+
: BitbucketUtils.inferAuthentication();
88+
this.overrides = mergeOverrides(overrides);
89+
this.bitbucketApi = createApi(this.endPoint, Objects.requireNonNull(this.credentials), this.overrides);
8590
}
8691

87-
private BitbucketApi createApi(final String endPoint, final BitbucketAuthentication authentication) {
92+
private BitbucketApi createApi(final String endPoint, final BitbucketAuthentication authentication, final Properties overrides) {
8893
return ContextBuilder
8994
.newBuilder(new BitbucketApiMetadata.Builder().build())
9095
.endpoint(endPoint)
9196
.modules(Lists.newArrayList(new BitbucketAuthenticationModule(authentication)))
97+
.overrides(overrides)
9298
.buildApi(BitbucketApi.class);
9399
}
94100

101+
/**
102+
* Query System Properties and Environment Variables for overrides and merge
103+
* the potentially passed in overrides with those.
104+
*
105+
* @param possibleOverrides Optional passed in overrides.
106+
* @return Properties object.
107+
*/
108+
private Properties mergeOverrides(final Properties possibleOverrides) {
109+
final Properties inferOverrides = BitbucketUtils.inferOverrides();
110+
if (possibleOverrides != null) {
111+
inferOverrides.putAll(possibleOverrides);
112+
}
113+
return inferOverrides;
114+
}
115+
95116
public String endPoint() {
96117
return this.endPoint;
97118
}
98119

99120
@Deprecated
100121
public String credentials() {
101-
return authValue();
122+
return this.authValue();
123+
}
124+
125+
public Properties overrides() {
126+
return this.overrides;
102127
}
103128

104129
public String authValue() {
105-
return credentials.authValue();
130+
return this.credentials.authValue();
106131
}
107132

108133
public AuthenticationType authType() {
109-
return credentials.authType();
134+
return this.credentials.authType();
110135
}
111136

112137
public BitbucketApi api() {
113-
return bitbucketApi;
138+
return this.bitbucketApi;
114139
}
115140

116141
public static Builder builder() {
@@ -121,6 +146,7 @@ public static class Builder {
121146

122147
private String endPoint;
123148
private BitbucketAuthentication.Builder authBuilder;
149+
private Properties overrides;
124150

125151
/**
126152
* Define the base endpoint to connect to.
@@ -148,7 +174,7 @@ public Builder credentials(final String optionallyBase64EncodedCredentials) {
148174

149175
/**
150176
* Optional token to use for authentication.
151-
*
177+
*
152178
* @param token authentication token.
153179
* @return this Builder.
154180
*/
@@ -158,22 +184,33 @@ public Builder token(final String token) {
158184
return this;
159185
}
160186

187+
/**
188+
* Optional jclouds Properties to override. What can be overridden can
189+
* be found here:
190+
*
191+
* <p>https://github.com/jclouds/jclouds/blob/master/core/src/main/java/org/jclouds/Constants.java
192+
*
193+
* @param overrides optional jclouds Properties to override.
194+
* @return this Builder.
195+
*/
196+
public Builder overrides(final Properties overrides) {
197+
this.overrides = overrides;
198+
return this;
199+
}
200+
161201
/**
162202
* Build an instance of BitbucketClient.
163203
*
164204
* @return BitbucketClient
165205
*/
166206
public BitbucketClient build() {
167207

168-
// 1.) Use passed-in endpoint or attempt to infer one from system/environment.
169-
final String foundEndpoint = (endPoint != null) ? endPoint : BitbucketUtils.inferEndpoint();
170-
171-
// 2.) Use passed-in credentials or attempt to infer them from system/environment.
208+
// 1.) If user passed in some auth use/build that.
172209
final BitbucketAuthentication authentication = authBuilder != null
173210
? authBuilder.build()
174-
: BitbucketUtils.inferCredentials();
211+
: null;
175212

176-
return new BitbucketClient(foundEndpoint, authentication);
213+
return new BitbucketClient(endPoint, authentication, overrides);
177214
}
178215
}
179216
}

src/main/java/com/cdancy/bitbucket/rest/BitbucketConstants.java

+15-14
Original file line numberDiff line numberDiff line change
@@ -17,27 +17,28 @@
1717

1818
package com.cdancy.bitbucket.rest;
1919

20-
import java.util.Arrays;
21-
import java.util.Collections;
22-
import java.util.List;
23-
2420
/**
2521
* Various constants that can be used in a global context.
2622
*/
2723
public class BitbucketConstants {
2824

29-
public static final List<String> ENDPOINT_PROPERTIES = Collections
30-
.unmodifiableList(Arrays
31-
.asList("bitbucket.rest.endpoint", "bitbucketRestEndpoint", "BITBUCKET_REST_ENDPOINT"));
32-
public static final List<String> CREDENTIALS_PROPERTIES = Collections
33-
.unmodifiableList(Arrays
34-
.asList("bitbucket.rest.credentials", "bitbucketRestCredentials", "BITBUCKET_REST_CREDENTIALS"));
35-
public static final List<String> TOKEN_PROPERTIES = Collections
36-
.unmodifiableList(Arrays
37-
.asList("bitbucket.rest.token", "bitbucketRestToken", "BITBUCKET_REST_TOKEN"));
25+
public static final String ENDPOINT_SYSTEM_PROPERTY = "bitbucket.rest.endpoint";
26+
public static final String ENDPOINT_ENVIRONMENT_VARIABLE = ENDPOINT_SYSTEM_PROPERTY.replaceAll("\\.", "_").toUpperCase();
27+
28+
public static final String CREDENTIALS_SYSTEM_PROPERTY = "bitbucket.rest.credentials";
29+
public static final String CREDENTIALS_ENVIRONMENT_VARIABLE = CREDENTIALS_SYSTEM_PROPERTY.replaceAll("\\.", "_").toUpperCase();
30+
31+
public static final String TOKEN_SYSTEM_PROPERTY = "bitbucket.rest.token";
32+
public static final String TOKEN_ENVIRONMENT_VARIABLE = TOKEN_SYSTEM_PROPERTY.replaceAll("\\.", "_").toUpperCase();
3833

3934
public static final String DEFAULT_ENDPOINT = "http://127.0.0.1:7990";
40-
35+
36+
public static final String JCLOUDS_PROPERTY_ID = "jclouds.";
37+
public static final String BITBUCKET_REST_PROPERTY_ID = "bitbucket.rest." + JCLOUDS_PROPERTY_ID;
38+
39+
public static final String JCLOUDS_VARIABLE_ID = "JCLOUDS_";
40+
public static final String BITBUCKET_REST_VARIABLE_ID = "BITBUCKET_REST_" + JCLOUDS_VARIABLE_ID;
41+
4142
protected BitbucketConstants() {
4243
throw new UnsupportedOperationException("Purposefully not implemented");
4344
}

0 commit comments

Comments
 (0)