Skip to content

Commit

Permalink
[JENKINS-42955] Add support for folder credentials (#3)
Browse files Browse the repository at this point in the history
* [JENKINS-42955] Unit test for issue
* [JENKINS-42955] Use the Job as context for lookup credentials
  • Loading branch information
Raúl Arabaolaza Barquin committed Apr 7, 2017
1 parent 6d71a66 commit e036e84
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 41 deletions.
6 changes: 6 additions & 0 deletions pom.xml
Expand Up @@ -99,6 +99,12 @@
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>cloudbees-folder</artifactId>
<version>6.0.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
Expand Down
Expand Up @@ -33,6 +33,7 @@
import com.cloudbees.plugins.credentials.domains.DomainRequirement;
import hudson.Extension;
import hudson.Util;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Run;
import hudson.security.ACL;
Expand All @@ -55,6 +56,7 @@
import org.kohsuke.github.GHCommitState;
import org.kohsuke.github.GHRepository;
import org.kohsuke.github.GitHub;
import org.kohsuke.stapler.AncestorInPath;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
Expand Down Expand Up @@ -206,19 +208,19 @@ public String getTargetUrl() {
return this.targetUrl;
}

private static <T extends Credentials> T getCredentials(@Nonnull Class<T> type, @Nonnull String credentialsId) {
private static <T extends Credentials> T getCredentials(@Nonnull Class<T> type, @Nonnull String credentialsId, Item context) {
return CredentialsMatchers.firstOrNull(lookupCredentials(
type, (ItemGroup) Jenkins.getInstance(), ACL.SYSTEM,
type, context, ACL.SYSTEM,
Collections.<DomainRequirement>emptyList()), CredentialsMatchers.allOf(
CredentialsMatchers.withId(credentialsId),
CredentialsMatchers.instanceOf(type)));
}

private static GitHub getGitHubIfValid(String credentialsId, String gitApiUrl) throws IOException {
private static GitHub getGitHubIfValid(String credentialsId, String gitApiUrl, Item context) throws IOException {
if (credentialsId == null || credentialsId.isEmpty()) {
throw new IllegalArgumentException(NULL_CREDENTIALS_ID);
}
UsernamePasswordCredentials credentials = getCredentials(UsernamePasswordCredentials.class, credentialsId);
UsernamePasswordCredentials credentials = getCredentials(UsernamePasswordCredentials.class, credentialsId, context);
if (credentials == null) {
throw new IllegalArgumentException(CREDENTIALS_ID_NOT_EXISTS);
}
Expand All @@ -235,17 +237,17 @@ private static GitHub getGitHubIfValid(String credentialsId, String gitApiUrl) t
}
}

private static GHRepository getRepoIfValid(String credentialsId, String gitApiUrl, String account, String repo) throws IOException {
GitHub github = getGitHubIfValid(credentialsId, gitApiUrl);
private static GHRepository getRepoIfValid(String credentialsId, String gitApiUrl, String account, String repo, Item context) throws IOException {
GitHub github = getGitHubIfValid(credentialsId, gitApiUrl, context);
GHRepository repository = github.getUser(account).getRepository(repo);
if (repository == null) {
throw new IllegalArgumentException(INVALID_REPO);
}
return repository;
}

private static GHCommit getCommitIfValid(String credentialsId, String gitApiUrl, String account, String repo, String sha) throws IOException {
GHRepository repository = getRepoIfValid(credentialsId, gitApiUrl, account, repo);
private static GHCommit getCommitIfValid(String credentialsId, String gitApiUrl, String account, String repo, String sha, Item context) throws IOException {
GHRepository repository = getRepoIfValid(credentialsId, gitApiUrl, account, repo, context);
GHCommit commit = repository.getCommit(sha);
if (commit == null) {
throw new IllegalArgumentException(INVALID_COMMIT);
Expand Down Expand Up @@ -275,9 +277,9 @@ public String getDisplayName() {
return "Notifies GitHub of the status of a Pull Request";
}

public ListBoxModel doFillCredentialsIdItems() {
public ListBoxModel doFillCredentialsIdItems(@AncestorInPath Item project) {
AbstractIdCredentialsListBoxModel result = new StandardListBoxModel();
List<UsernamePasswordCredentials> credentialsList = CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, (ItemGroup) Jenkins.getInstance(), ACL.SYSTEM);
List<UsernamePasswordCredentials> credentialsList = CredentialsProvider.lookupCredentials(UsernamePasswordCredentials.class, project, ACL.SYSTEM);
for (UsernamePasswordCredentials credential : credentialsList) {
result = result.with((IdCredentials) credential);
}
Expand All @@ -292,29 +294,29 @@ public ListBoxModel doFillStatusItems() {
return list;
}

public FormValidation doTestConnection(@QueryParameter ("credentialsId") final String credentialsId, @QueryParameter ("gitApiUrl") final String gitApiUrl) {
public FormValidation doTestConnection(@QueryParameter ("credentialsId") final String credentialsId, @QueryParameter ("gitApiUrl") final String gitApiUrl, @AncestorInPath Item context) {
try {
getGitHubIfValid(credentialsId, gitApiUrl);
getGitHubIfValid(credentialsId, gitApiUrl, context);
return FormValidation.ok("Success");
} catch (Exception e) {
return FormValidation.error(e.getMessage());
}
}

public FormValidation doCheckRepo(@QueryParameter ("credentialsId") final String credentialsId,
@QueryParameter ("repo") final String repo, @QueryParameter ("account") final String account, @QueryParameter ("gitApiUrl") final String gitApiUrl) {
@QueryParameter ("repo") final String repo, @QueryParameter ("account") final String account, @QueryParameter ("gitApiUrl") final String gitApiUrl, @AncestorInPath Item context) {
try {
getRepoIfValid(credentialsId, gitApiUrl, account, repo);
getRepoIfValid(credentialsId, gitApiUrl, account, repo, context);
return FormValidation.ok("Success");
} catch (Exception e) {
return FormValidation.error(e.getMessage());
}
}

public FormValidation doCheckSha(@QueryParameter ("credentialsId") final String credentialsId, @QueryParameter ("repo") final String repo,
@QueryParameter ("sha") final String sha, @QueryParameter ("account") final String account, @QueryParameter ("gitApiUrl") final String gitApiUrl) {
@QueryParameter ("sha") final String sha, @QueryParameter ("account") final String account, @QueryParameter ("gitApiUrl") final String gitApiUrl, @AncestorInPath Item context) {
try {
getCommitIfValid(credentialsId, gitApiUrl, account, repo, sha);
getCommitIfValid(credentialsId, gitApiUrl, account, repo, sha, context);
return FormValidation.ok("Commit seems valid");

} catch (Exception e) {
Expand All @@ -341,7 +343,7 @@ protected Void run() throws Exception {
String credentialsId = getCredentialsId();
String repo = getRepo();
String account = getAccount();
GHRepository repository = getRepoIfValid(credentialsId, step.getGitApiUrl(), account, repo);
GHRepository repository = getRepoIfValid(credentialsId, step.getGitApiUrl(), account, repo, run.getParent());
String sha1 = getSha1();
GHCommit commit = null;
try {
Expand Down
@@ -1,8 +1,13 @@
package org.jenkinsci.plugins.pipeline.githubstatusnotification;

import com.cloudbees.hudson.plugins.folder.Folder;
import com.cloudbees.hudson.plugins.folder.properties.FolderCredentialsProvider;
import com.cloudbees.plugins.credentials.Credentials;
import com.cloudbees.plugins.credentials.CredentialsProvider;
import com.cloudbees.plugins.credentials.CredentialsScope;
import com.cloudbees.plugins.credentials.CredentialsStore;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.domains.Domain;
import hudson.model.Result;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
Expand Down Expand Up @@ -36,8 +41,8 @@ public class GitHubNotificationPipelineStepTest {
public void buildWithNullCredentialsIDMustFail() throws Exception {
WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"description: 'PCT Is OK', repo: 'acceptance-test-harness', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"description: 'All tests are OK', repo: 'acceptance-test-harness', " +
"sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', status: 'SUCCESS', " +
"targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -51,8 +56,8 @@ public void buildWithNullCredentialsIDMustFail() throws Exception {
public void buildWithNotExistingCredentialsMustFail() throws Exception {
WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'notExisting', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'notExisting', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -69,8 +74,8 @@ public void buildWithWrongCredentialsMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -87,8 +92,8 @@ public void buildWithWrongCredentialsMustFailEnterprise() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com', gitApiUrl:'https://api.example.com'"
));
Expand All @@ -114,8 +119,8 @@ public void buildWithWrongRepoMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -142,8 +147,8 @@ public void buildWithWrongCommitMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -170,8 +175,8 @@ public void buildWithInferWithoutCommitMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -198,8 +203,8 @@ public void buildWithInferWithoutAccountMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"githubNotify context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"repo: 'acceptance-test-harness', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -226,8 +231,8 @@ public void buildWithInferWithoutRepoMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();
Expand All @@ -253,8 +258,8 @@ public void buildWithInferWithoutCredentialsMustFail() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"description: 'PCT Is OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"description: 'All tests are OK', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487'," +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com', repo: 'acceptance-test-harness'"
));
WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();
Expand All @@ -281,8 +286,38 @@ public void build() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();
jenkins.assertBuildStatus(Result.SUCCESS, jenkins.waitForCompletion(b1));
}

@Test
public void buildWithFolderCredentials() throws Exception {

GitHub gh = PowerMockito.mock(GitHub.class);
PowerMockito.mockStatic(GitHub.class);
PowerMockito.when(GitHub.connect("user", "password")).thenReturn(gh);
PowerMockito.when(gh.isCredentialValid()).thenReturn(true);
GHRepository repo = PowerMockito.mock(GHRepository.class);
GHUser user = PowerMockito.mock(GHUser.class);
GHCommit commit = PowerMockito.mock(GHCommit.class);
PowerMockito.when(user.getRepository(anyString())).thenReturn(repo);
PowerMockito.when(gh.getUser(anyString())).thenReturn(user);
PowerMockito.when((repo.getCommit(anyString()))).thenReturn(commit);

Folder f = jenkins.jenkins.createProject(Folder.class, "folder" + jenkins.jenkins.getItems().size());
CredentialsStore folderStore = getFolderStore(f);
folderStore.addCredentials(Domain.global(),
new DummyCredentials(CredentialsScope.GLOBAL, "user", "password"));

WorkflowJob p = f.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com'"
));
Expand All @@ -309,13 +344,26 @@ public void buildEnterprise() throws Exception {

WorkflowJob p = jenkins.createProject(WorkflowJob.class, "p");
p.setDefinition(new CpsFlowDefinition(
"githubNotify account: 'raul-arabaolaza', context: 'PCT Results', " +
"credentialsId: 'dummy', description: 'PCT Is OK', " +
"githubNotify account: 'raul-arabaolaza', context: 'ATH Results', " +
"credentialsId: 'dummy', description: 'All tests are OK', " +
"repo: 'acceptance-test-harness', sha: '0b5936eb903d439ac0c0bf84940d73128d5e9487', " +
"status: 'SUCCESS', targetUrl: 'http://www.cloudbees.com', gitApiUrl:'https://api.example.com'"
));
WorkflowRun b1 = p.scheduleBuild2(0).waitForStart();
jenkins.assertBuildStatus(Result.SUCCESS, jenkins.waitForCompletion(b1));
}

private CredentialsStore getFolderStore(Folder f) {
Iterable<CredentialsStore> stores = CredentialsProvider.lookupStores(f);
CredentialsStore folderStore = null;
for (CredentialsStore s : stores) {
if (s.getProvider() instanceof FolderCredentialsProvider && s.getContext() == f) {
folderStore = s;
break;
}
}
return folderStore;
}


}

0 comments on commit e036e84

Please sign in to comment.