Skip to content

Commit abb9aa5

Browse files
lukasz-lesiakLukasz Lesiaklifeofguenter
authored
Leverage Project Key property in Cloud Bitbucket API - fetching repositories, pullrequest and push hook processors. (#654)
Co-authored-by: Lukasz Lesiak <[email protected]> Co-authored-by: Günter Grodotzki <[email protected]>
1 parent d1aaf82 commit abb9aa5

File tree

19 files changed

+133
-19
lines changed

19 files changed

+133
-19
lines changed

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMNavigator.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ public class BitbucketSCMNavigator extends SCMNavigator {
108108
private String credentialsId;
109109
@NonNull
110110
private final String repoOwner;
111+
@CheckForNull
112+
private String projectKey;
111113
@NonNull
112114
private List<SCMTrait<? extends SCMTrait<?>>> traits;
113115
@Deprecated
@@ -211,6 +213,15 @@ public String getRepoOwner() {
211213
return repoOwner;
212214
}
213215

216+
public String getProjectKey() {
217+
return projectKey;
218+
}
219+
220+
@DataBoundSetter
221+
public void setProjectKey(@CheckForNull String projectKey) {
222+
this.projectKey = Util.fixEmpty(projectKey);
223+
}
224+
214225
@Override
215226
@NonNull
216227
public List<SCMTrait<? extends SCMTrait<?>>> getTraits() {
@@ -486,7 +497,7 @@ public void visitSources(SCMSourceObserver observer) throws IOException, Interru
486497

487498
BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials);
488499

489-
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null);
500+
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, projectKey, null);
490501
BitbucketTeam team = bitbucket.getTeam();
491502
if (team != null) {
492503
// Navigate repositories of the team
@@ -535,7 +546,7 @@ public List<Action> retrieveActions(@NonNull SCMNavigatorOwner owner,
535546

536547
BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials);
537548

538-
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null);
549+
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null, null);
539550
BitbucketTeam team = bitbucket.getTeam();
540551
if (team != null) {
541552
String defaultTeamUrl;

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketSCMSource.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,7 +524,7 @@ public BitbucketApi buildBitbucketClient(PullRequestSCMHead head) {
524524
}
525525

526526
public BitbucketApi buildBitbucketClient(String repoOwner, String repository) {
527-
return BitbucketApiFactory.newInstance(getServerUrl(), authenticator(), repoOwner, repository);
527+
return BitbucketApiFactory.newInstance(getServerUrl(), authenticator(), repoOwner, null, repository);
528528
}
529529

530530
@Override
@@ -667,6 +667,7 @@ class Skip extends IOException {
667667
getServerUrl(),
668668
authenticator(),
669669
pullRepoOwner,
670+
null,
670671
pullRepository
671672
)
672673
: originBitbucket;
@@ -1261,7 +1262,7 @@ public ListBoxModel doFillRepositoryItems(@AncestorInPath SCMSourceOwner context
12611262
BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials);
12621263

12631264
try {
1264-
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null);
1265+
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null, null);
12651266
BitbucketTeam team = bitbucket.getTeam();
12661267
List<? extends BitbucketRepository> repositories =
12671268
bitbucket.getRepositories(team != null ? null : UserRoleInRepository.CONTRIBUTOR);

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/BitbucketTeamMetadataAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ private StandardCredentials findCredentials() {
127127
private AvatarImage doFetch(StandardCredentials credentials) throws IOException, InterruptedException {
128128
BitbucketAuthenticator authenticator = AuthenticationTokens
129129
.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials);
130-
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null);
130+
BitbucketApi bitbucket = BitbucketApiFactory.newInstance(serverUrl, authenticator, repoOwner, null, null);
131131
return bitbucket.getTeamAvatar();
132132
}
133133

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/SCMHeadWithOwnerAndRepo.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ private static Map<String, String> getTargets(BitbucketSCMSource source) {
110110
source.getServerUrl(),
111111
source.authenticator(),
112112
source.getRepoOwner(),
113+
null,
113114
source.getRepository()
114115
);
115116
for (BitbucketPullRequest pr : bitbucket.getPullRequests()) {

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/api/BitbucketApiFactory.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ public abstract class BitbucketApiFactory implements ExtensionPoint {
3131
* @param serverUrl the server URL.
3232
* @param authenticator the (optional) authenticator.
3333
* @param owner the owner name.
34+
* @param projectKey the (optional) project key.
3435
* @param repository the (optional) repository name.
3536
* @return the {@link BitbucketApi}.
3637
*/
3738
@NonNull
3839
protected abstract BitbucketApi create(@Nullable String serverUrl,
3940
@Nullable BitbucketAuthenticator authenticator,
4041
@NonNull String owner,
42+
@CheckForNull String projectKey,
4143
@CheckForNull String repository);
4244

4345
@NonNull
@@ -47,7 +49,7 @@ protected BitbucketApi create(@Nullable String serverUrl,
4749
@NonNull String owner,
4850
@CheckForNull String repository) {
4951
BitbucketAuthenticator auth = credentials != null ? new BitbucketUsernamePasswordAuthenticator(credentials) : null;
50-
return create(serverUrl, auth, owner, repository);
52+
return create(serverUrl, auth, owner, null, repository);
5153
}
5254

5355
/**
@@ -57,6 +59,7 @@ protected BitbucketApi create(@Nullable String serverUrl,
5759
* @param serverUrl the server URL.
5860
* @param authenticator the (optional) authenticator.
5961
* @param owner the owner name.
62+
* @param projectKey the (optional) project key.
6063
* @param repository the (optional) repository name.
6164
* @return the {@link BitbucketApi}.
6265
* @throws IllegalArgumentException if the supplied URL is not supported.
@@ -65,10 +68,11 @@ protected BitbucketApi create(@Nullable String serverUrl,
6568
public static BitbucketApi newInstance(@Nullable String serverUrl,
6669
@Nullable BitbucketAuthenticator authenticator,
6770
@NonNull String owner,
71+
@CheckForNull String projectKey,
6872
@CheckForNull String repository) {
6973
for (BitbucketApiFactory factory : ExtensionList.lookup(BitbucketApiFactory.class)) {
7074
if (factory.isMatch(serverUrl)) {
71-
return factory.create(serverUrl, authenticator, owner, repository);
75+
return factory.create(serverUrl, authenticator, owner, projectKey, repository);
7276
}
7377
}
7478
throw new IllegalArgumentException("Unsupported Bitbucket server URL: " + serverUrl);
@@ -79,8 +83,9 @@ public static BitbucketApi newInstance(@Nullable String serverUrl,
7983
public static BitbucketApi newInstance(@Nullable String serverUrl,
8084
@Nullable StandardUsernamePasswordCredentials credentials,
8185
@NonNull String owner,
86+
@CheckForNull String projectKey,
8287
@CheckForNull String repository) {
8388
BitbucketAuthenticator auth = credentials != null ? new BitbucketUsernamePasswordAuthenticator(credentials) : null;
84-
return newInstance(serverUrl, auth, owner, repository);
89+
return newInstance(serverUrl, auth, owner, projectKey, repository);
8590
}
8691
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiClient.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ public class BitbucketCloudApiClient implements BitbucketApi {
137137
private CloseableHttpClient client;
138138
private HttpClientContext context;
139139
private final String owner;
140+
private final String projectKey;
140141
private final String repositoryName;
141142
private final boolean enableCache;
142143
private final BitbucketAuthenticator authenticator;
@@ -167,14 +168,15 @@ public static void clearCaches() {
167168
@Deprecated
168169
public BitbucketCloudApiClient(boolean enableCache, int teamCacheDuration, int repositoriesCacheDuration,
169170
String owner, String repositoryName, StandardUsernamePasswordCredentials credentials) {
170-
this(enableCache, teamCacheDuration, repositoriesCacheDuration, owner, repositoryName,
171+
this(enableCache, teamCacheDuration, repositoriesCacheDuration, owner, null, repositoryName,
171172
new BitbucketUsernamePasswordAuthenticator(credentials));
172173
}
173174

174175
public BitbucketCloudApiClient(boolean enableCache, int teamCacheDuration, int repositoriesCacheDuration,
175-
String owner, String repositoryName, BitbucketAuthenticator authenticator) {
176+
String owner, String projectKey, String repositoryName, BitbucketAuthenticator authenticator) {
176177
this.authenticator = authenticator;
177178
this.owner = owner;
179+
this.projectKey = projectKey;
178180
this.repositoryName = repositoryName;
179181
this.enableCache = enableCache;
180182
if (enableCache) {
@@ -752,9 +754,12 @@ public List<BitbucketCloudRepository> getRepositories(@CheckForNull UserRoleInRe
752754
cacheKey.append("::<anonymous>");
753755
}
754756

755-
final UriTemplate template = UriTemplate.fromTemplate(V2_API_BASE_URL + "{/owner}{?role,page,pagelen}")
757+
final UriTemplate template = UriTemplate.fromTemplate(V2_API_BASE_URL + "{/owner}{?role,page,pagelen,q}")
756758
.set("owner", owner)
757759
.set("pagelen", MAX_PAGE_LENGTH);
760+
if (StringUtils.isNotBlank(projectKey)) {
761+
template.set("q", "project.key=" + "\"" + projectKey + "\""); // q=project.key="<projectKey>"
762+
}
758763
if (role != null && authenticator != null) {
759764
template.set("role", role.getId());
760765
cacheKey.append("::").append(role.getId());

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/client/BitbucketCloudApiFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ protected boolean isMatch(@Nullable String serverUrl) {
2121
@NonNull
2222
@Override
2323
protected BitbucketApi create(@Nullable String serverUrl, @Nullable BitbucketAuthenticator authenticator,
24-
@NonNull String owner, @CheckForNull String repository) {
24+
@NonNull String owner, @CheckForNull String projectKey, @CheckForNull String repository) {
2525
AbstractBitbucketEndpoint endpoint = BitbucketEndpointConfiguration.get().findEndpoint(BitbucketCloudEndpoint.SERVER_URL);
2626
boolean enableCache = false;
2727
int teamCacheDuration = 0;
@@ -33,6 +33,6 @@ protected BitbucketApi create(@Nullable String serverUrl, @Nullable BitbucketAut
3333
}
3434
return new BitbucketCloudApiClient(
3535
enableCache, teamCacheDuration, repositoriesCacheDuration,
36-
owner, repository, authenticator);
36+
owner, projectKey, repository, authenticator);
3737
}
3838
}

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/filesystem/BitbucketSCMFileSystem.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public SCMFileSystem build(@NonNull SCMSource source, @NonNull SCMHead head, @Ch
155155

156156
BitbucketAuthenticator authenticator = AuthenticationTokens.convert(BitbucketAuthenticator.authenticationContext(serverUrl), credentials);
157157

158-
BitbucketApi apiClient = BitbucketApiFactory.newInstance(serverUrl, authenticator, owner, repository);
158+
BitbucketApi apiClient = BitbucketApiFactory.newInstance(serverUrl, authenticator, owner, null, repository);
159159
String ref = null;
160160

161161
if (head instanceof BranchSCMHead) {

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PullRequestHookProcessor.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import jenkins.scm.api.SCMRevision;
6060
import jenkins.scm.api.SCMSource;
6161
import jenkins.scm.api.mixin.ChangeRequestCheckoutStrategy;
62+
import org.apache.commons.lang.StringUtils;
6263

6364
import static com.cloudbees.jenkins.plugins.bitbucket.hooks.HookEventType.PULL_REQUEST_DECLINED;
6465
import static com.cloudbees.jenkins.plugins.bitbucket.hooks.HookEventType.PULL_REQUEST_MERGED;
@@ -113,12 +114,26 @@ public boolean isMatch(@NonNull SCMNavigator navigator) {
113114
return false;
114115
}
115116
BitbucketSCMNavigator bbNav = (BitbucketSCMNavigator) navigator;
117+
if (!isProjectKeyMatch(bbNav.getProjectKey())) {
118+
return false;
119+
}
120+
116121
if (!isServerUrlMatch(bbNav.getServerUrl())) {
117122
return false;
118123
}
119124
return bbNav.getRepoOwner().equalsIgnoreCase(getPayload().getRepository().getOwnerName());
120125
}
121126

127+
private boolean isProjectKeyMatch(String projectKey) {
128+
if (StringUtils.isBlank(projectKey)) {
129+
return true;
130+
}
131+
if (this.getPayload().getRepository().getProject() != null) {
132+
return projectKey.equals(this.getPayload().getRepository().getProject().getKey());
133+
}
134+
return true;
135+
}
136+
122137
private boolean isServerUrlMatch(String serverUrl) {
123138
if (serverUrl == null || BitbucketCloudEndpoint.SERVER_URL.equals(serverUrl)) {
124139
// this is a Bitbucket cloud navigator

src/main/java/com/cloudbees/jenkins/plugins/bitbucket/hooks/PushHookProcessor.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import jenkins.scm.api.SCMNavigator;
5656
import jenkins.scm.api.SCMRevision;
5757
import jenkins.scm.api.SCMSource;
58+
import org.apache.commons.lang.StringUtils;
5859

5960
public class PushHookProcessor extends HookProcessor {
6061

@@ -94,12 +95,25 @@ public boolean isMatch(@NonNull SCMNavigator navigator) {
9495
return false;
9596
}
9697
BitbucketSCMNavigator bbNav = (BitbucketSCMNavigator) navigator;
98+
if (!isProjectKeyMatch(bbNav.getProjectKey())) {
99+
return false;
100+
}
97101
if (!isServerUrlMatch(bbNav.getServerUrl())) {
98102
return false;
99103
}
100104
return bbNav.getRepoOwner().equalsIgnoreCase(getPayload().getRepository().getOwnerName());
101105
}
102106

107+
private boolean isProjectKeyMatch(String projectKey) {
108+
if (StringUtils.isBlank(projectKey)) {
109+
return true;
110+
}
111+
if (this.getPayload().getRepository().getProject() != null) {
112+
return projectKey.equals(this.getPayload().getRepository().getProject().getKey());
113+
}
114+
return true;
115+
}
116+
103117
private boolean isServerUrlMatch(String serverUrl) {
104118
if (serverUrl == null || BitbucketCloudEndpoint.SERVER_URL.equals(serverUrl)) {
105119
// this is a Bitbucket cloud navigator

0 commit comments

Comments
 (0)