diff --git a/blueocean-git-pipeline/pom.xml b/blueocean-git-pipeline/pom.xml index b91e787beb4..f5de29c75fc 100644 --- a/blueocean-git-pipeline/pom.xml +++ b/blueocean-git-pipeline/pom.xml @@ -17,10 +17,28 @@ ${project.groupId} - blueocean-pipeline-api-impl + blueocean-pipeline-api + + + org.jenkins-ci.plugins + git + + + commons-lang + commons-lang + + io.jenkins.blueocean + blueocean-rest-impl + test + + + io.jenkins.blueocean + blueocean-pipeline-api-impl + test + ${project.groupId} blueocean-pipeline-api-impl diff --git a/blueocean-git-pipeline/src/main/java/io/jenkins/blueocean/blueocean_git_pipeline/GitPipelineCreateRequest.java b/blueocean-git-pipeline/src/main/java/io/jenkins/blueocean/blueocean_git_pipeline/GitPipelineCreateRequest.java index 2615de54864..3b366eea5ce 100644 --- a/blueocean-git-pipeline/src/main/java/io/jenkins/blueocean/blueocean_git_pipeline/GitPipelineCreateRequest.java +++ b/blueocean-git-pipeline/src/main/java/io/jenkins/blueocean/blueocean_git_pipeline/GitPipelineCreateRequest.java @@ -1,145 +1,57 @@ package io.jenkins.blueocean.blueocean_git_pipeline; import com.cloudbees.plugins.credentials.common.StandardCredentials; -import com.cloudbees.plugins.credentials.domains.Domain; -import hudson.model.Cause; -import hudson.model.Failure; -import hudson.model.TopLevelItem; -import hudson.model.User; +import com.google.common.collect.Lists; import io.jenkins.blueocean.commons.ErrorMessage; -import io.jenkins.blueocean.commons.ServiceException; -import io.jenkins.blueocean.rest.Reachable; -import io.jenkins.blueocean.rest.impl.pipeline.MultiBranchPipelineImpl; -import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanCredentialsProvider; -import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanDomainRequirement; -import io.jenkins.blueocean.rest.impl.pipeline.credential.CredentialsUtils; -import io.jenkins.blueocean.rest.model.BluePipeline; +import io.jenkins.blueocean.commons.ErrorMessage.Error; +import io.jenkins.blueocean.pipeline.api.AbstractMultiBranchCreateRequest; import io.jenkins.blueocean.rest.model.BlueScmConfig; -import io.jenkins.blueocean.service.embedded.rest.AbstractPipelineCreateRequestImpl; -import jenkins.branch.BranchSource; -import jenkins.branch.MultiBranchProjectDescriptor; +import jenkins.branch.MultiBranchProject; import jenkins.model.Jenkins; import jenkins.plugins.git.GitSCMSource; -import org.apache.commons.lang3.StringUtils; -import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject; +import jenkins.scm.api.SCMSource; +import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.io.IOException; -import java.util.ArrayList; +import javax.annotation.Nonnull; import java.util.List; /** * @author Vivek Pandey */ -public class GitPipelineCreateRequest extends AbstractPipelineCreateRequestImpl { - - private static final String MODE = "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject"; - private static final Logger logger = LoggerFactory.getLogger(GitPipelineCreateRequest.class); - - private BlueScmConfig scmConfig; +public class GitPipelineCreateRequest extends AbstractMultiBranchCreateRequest { @DataBoundConstructor public GitPipelineCreateRequest(String name, BlueScmConfig scmConfig) { - validate(name, scmConfig); - setName(name); - this.scmConfig = scmConfig; + super(name, scmConfig); } @Override - public BluePipeline create(Reachable parent) throws IOException { - User authenticatedUser = User.current(); - if(authenticatedUser == null){ - throw new ServiceException.UnauthorizedException("Must login to create a pipeline"); - } - - String sourceUri = scmConfig.getUri(); - - if (sourceUri == null) { - throw new ServiceException.BadRequestExpception(new ErrorMessage(400, "Failed to create Git pipeline:"+getName()) - .add(new ErrorMessage.Error("scmConfig.uri", ErrorMessage.Error.ErrorCodes.MISSING.toString(), "uri is required"))); - } - - TopLevelItem item = create(Jenkins.getInstance(), getName(), MODE, MultiBranchProjectDescriptor.class); - - if (item instanceof WorkflowMultiBranchProject) { - WorkflowMultiBranchProject project = (WorkflowMultiBranchProject) item; - - if(StringUtils.isNotBlank(scmConfig.getCredentialId())) { - Domain domain = CredentialsUtils.findDomain(scmConfig.getCredentialId(), authenticatedUser); - if(domain == null){ - throw new ServiceException.BadRequestExpception( - new ErrorMessage(400, "Failed to create pipeline") - .add(new ErrorMessage.Error("scm.credentialId", - ErrorMessage.Error.ErrorCodes.INVALID.toString(), - "No domain in user credentials found for credentialId: "+ scmConfig.getCredentialId()))); - } - if(domain.test(new BlueOceanDomainRequirement())) { //this is blueocean specific domain - project.addProperty( - new BlueOceanCredentialsProvider.FolderPropertyImpl(authenticatedUser.getId(), - scmConfig.getCredentialId(), - BlueOceanCredentialsProvider.createDomain(sourceUri))); - } - } - - String credentialId = StringUtils.defaultString(scmConfig.getCredentialId()); - - project.getSourcesList().add(new BranchSource(new GitSCMSource(null, sourceUri, credentialId, "*", "", false))); - project.scheduleBuild(new Cause.UserIdCause()); - return new MultiBranchPipelineImpl(project); - } else { - try { - item.delete(); // we don't know about this project type - } catch (InterruptedException e) { - throw new ServiceException.UnexpectedErrorException("Failed to delete pipeline: " + getName()); - } - } - return null; + protected SCMSource createSource(@Nonnull MultiBranchProject project, @Nonnull BlueScmConfig scmConfig) { + return new GitSCMSource(null, StringUtils.defaultString(scmConfig.getUri()), scmConfig.getCredentialId(), "*", "", false); } - private void validate(String name, BlueScmConfig scmConfig){ - if(scmConfig == null){ - throw new ServiceException.BadRequestExpception(new ErrorMessage(400, "Failed to create Git pipeline") - .add(new ErrorMessage.Error("scmConfig", ErrorMessage.Error.ErrorCodes.MISSING.toString(), "scmConfig is required"))); - } - - List errors = new ArrayList<>(); - - String sourceUri = scmConfig.getUri(); - - if (sourceUri == null) { + @Override + protected List validate(String name, BlueScmConfig scmConfig) { + List errors = Lists.newArrayList(); + if (scmConfig.getUri() == null) { errors.add(new ErrorMessage.Error("scmConfig.uri", ErrorMessage.Error.ErrorCodes.MISSING.toString(), "uri is required")); }else { StandardCredentials credentials = null; if(scmConfig.getCredentialId() != null){ - credentials = GitUtils.getCredentials(Jenkins.getInstance(), sourceUri, scmConfig.getCredentialId()); + credentials = GitUtils.getCredentials(Jenkins.getInstance(), scmConfig.getUri(), scmConfig.getCredentialId()); if (credentials == null) { errors.add(new ErrorMessage.Error("scmConfig.credentialId", - ErrorMessage.Error.ErrorCodes.NOT_FOUND.toString(), - String.format("credentialId: %s not found", scmConfig.getCredentialId()))); + ErrorMessage.Error.ErrorCodes.NOT_FOUND.toString(), + String.format("credentialId: %s not found", scmConfig.getCredentialId()))); } } //validate credentials if no credential id (perhaps git repo doesn't need auth or credentials is present) if(scmConfig.getCredentialId() == null || credentials != null) { - errors.addAll(GitUtils.validateCredentials(sourceUri, credentials)); + errors.addAll(GitUtils.validateCredentials(scmConfig.getUri(), credentials)); } } - - try { - Jenkins.getInstance().getProjectNamingStrategy().checkName(getName()); - }catch (Failure f){ - errors.add(new ErrorMessage.Error("scmConfig.name", ErrorMessage.Error.ErrorCodes.INVALID.toString(), name + "in not a valid name")); - } - - if(Jenkins.getInstance().getItem(name)!=null) { - errors.add(new ErrorMessage.Error("name", - ErrorMessage.Error.ErrorCodes.ALREADY_EXISTS.toString(), name + " already exists")); - } - - if(!errors.isEmpty()){ - throw new ServiceException.BadRequestExpception(new ErrorMessage(400, "Failed to create Git pipeline:"+name).addAll(errors)); - } + return errors; } } diff --git a/blueocean-git-pipeline/src/test/java/io/jenkins/blueocean/blueocean_git_pipeline/GitScmTest.java b/blueocean-git-pipeline/src/test/java/io/jenkins/blueocean/blueocean_git_pipeline/GitScmTest.java index 98ef1a9bc05..e45faa9e4af 100644 --- a/blueocean-git-pipeline/src/test/java/io/jenkins/blueocean/blueocean_git_pipeline/GitScmTest.java +++ b/blueocean-git-pipeline/src/test/java/io/jenkins/blueocean/blueocean_git_pipeline/GitScmTest.java @@ -57,6 +57,7 @@ private String needsGithubAccessToken(){ public void shouldCreateWithRemoteGitRepo() throws IOException, UnirestException { String accessToken = needsGithubAccessToken(); User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); Map resp = createCredentials(user, ImmutableMap.of("credentials", new ImmutableMap.Builder() .put("password", accessToken) @@ -90,6 +91,7 @@ public void shouldCreateWithRemoteGitRepo() throws IOException, UnirestException @Test public void shouldGetForbiddenForBadCredentialIdOnCreate1() throws IOException, UnirestException { User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); Map resp = createCredentials(user, ImmutableMap.of("credentials", new ImmutableMap.Builder() @@ -120,6 +122,7 @@ public void shouldGetForbiddenForBadCredentialIdOnCreate1() throws IOException, @Test public void shouldGetForbiddenForBadCredentialIdOnCreate2() throws IOException, UnirestException { User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); Map resp = createCredentials(user, ImmutableMap.of("credentials", new ImmutableMap.Builder() .put("password", "abcd") @@ -144,7 +147,10 @@ public void shouldGetForbiddenForBadCredentialIdOnCreate2() throws IOException, } @Test - public void shouldGetBadRequestForBadGitUriOnCreate() throws IOException { + public void shouldGetBadRequestForBadGitUriOnCreate() throws Exception { + + User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); post("/organizations/jenkins/pipelines/", ImmutableMap.of("name", "demo", @@ -267,14 +273,18 @@ public void shouldFailOnValidation1(){ List errors = (List) resp.get("errors"); - assertEquals(errors.get(0).get("field"), "name"); - assertEquals(errors.get(0).get("code"), "MISSING"); - assertEquals(errors.get(1).get("field"), "$class"); - assertEquals(errors.get(1).get("code"), "MISSING"); + assertEquals("name", errors.get(0).get("field")); + assertEquals("MISSING", errors.get(0).get("code")); + assertEquals("$class", errors.get(1).get("field")); + assertEquals("MISSING", errors.get(1).get("code")); } @Test - public void shouldFailOnValidation2(){ + public void shouldFailOnValidation2() throws Exception { + + User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); + Map resp = post("/organizations/jenkins/pipelines/", ImmutableMap.of("name", "demo", "$class", "io.jenkins.blueocean.blueocean_git_pipeline.GitPipelineCreateRequest" @@ -284,8 +294,8 @@ public void shouldFailOnValidation2(){ List errors = (List) resp.get("errors"); - assertEquals(errors.get(0).get("field"), "scmConfig"); - assertEquals(errors.get(0).get("code"), "MISSING"); + assertEquals("scmConfig", errors.get(0).get("field")); + assertEquals("MISSING", errors.get(0).get("code")); assertNull(Jenkins.getInstance().getItem("demo")); } @@ -344,10 +354,10 @@ public void shouldFailOnValidation4() throws IOException, UnirestException { for(Map error:errors){ if(error.get("field").equals("name")){ nameFound = true; - assertEquals(error.get("code"), "ALREADY_EXISTS"); + assertEquals("ALREADY_EXISTS", error.get("code")); }else if(error.get("field").equals("scmConfig.credentialId")){ credentialIdFound = true; - assertEquals(error.get("code"), "NOT_FOUND"); + assertEquals("NOT_FOUND", error.get("code")); } } assertTrue(nameFound); @@ -355,7 +365,10 @@ public void shouldFailOnValidation4() throws IOException, UnirestException { } @Test - public void shouldFailOnValidation5(){ + public void shouldFailOnValidation5() throws Exception { + + User user = login(); + this.jwtToken = getJwtToken(j.jenkins, user.getId(), user.getId()); Map resp = post("/organizations/jenkins/pipelines/", ImmutableMap.of("name", "demo", diff --git a/blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubPipelineCreateRequest.java b/blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubPipelineCreateRequest.java index 76ff0c1c881..ca4f946085b 100644 --- a/blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubPipelineCreateRequest.java +++ b/blueocean-github-pipeline/src/main/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubPipelineCreateRequest.java @@ -10,13 +10,13 @@ import hudson.model.User; import io.jenkins.blueocean.commons.ErrorMessage; import io.jenkins.blueocean.commons.ServiceException; +import io.jenkins.blueocean.pipeline.api.AbstractPipelineCreateRequest; import io.jenkins.blueocean.rest.Reachable; import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanCredentialsProvider; import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanDomainRequirement; import io.jenkins.blueocean.rest.impl.pipeline.credential.CredentialsUtils; import io.jenkins.blueocean.rest.model.BluePipeline; import io.jenkins.blueocean.rest.model.BlueScmConfig; -import io.jenkins.blueocean.service.embedded.rest.AbstractPipelineCreateRequestImpl; import jenkins.branch.CustomOrganizationFolderDescriptor; import jenkins.branch.MultiBranchProject; import jenkins.branch.OrganizationFolder; @@ -54,17 +54,14 @@ /** * @author Vivek Pandey */ -public class GithubPipelineCreateRequest extends AbstractPipelineCreateRequestImpl { +public class GithubPipelineCreateRequest extends AbstractPipelineCreateRequest { private static final String DESCRIPTOR = "jenkins.branch.OrganizationFolder.org.jenkinsci.plugins.github_branch_source.GitHubSCMNavigator"; private static final Logger logger = LoggerFactory.getLogger(GithubPipelineCreateRequest.class); - private BlueScmConfig scmConfig; - @DataBoundConstructor public GithubPipelineCreateRequest(String name, BlueScmConfig scmConfig) { - setName(name); - this.scmConfig = scmConfig; + super(name, scmConfig); } @SuppressWarnings("unchecked") @@ -95,9 +92,6 @@ public BluePipeline create(Reachable parent) throws IOException { String singleRepo = repos.size() == 1 ? repos.get(0) : null; User authenticatedUser = User.current(); - if(authenticatedUser == null){ - throw new ServiceException.UnauthorizedException("Must login to create a pipeline"); - } Item item = Jenkins.getInstance().getItemByFullName(orgName); boolean creatingNewItem = item == null; @@ -108,7 +102,7 @@ public BluePipeline create(Reachable parent) throws IOException { } if (item == null) { - item = create(Jenkins.getInstance(), getName(), DESCRIPTOR, CustomOrganizationFolderDescriptor.class); + item = createProject(getName(), DESCRIPTOR, CustomOrganizationFolderDescriptor.class); } if (item instanceof OrganizationFolder) { diff --git a/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubApiTest.java b/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubApiTest.java index 356c32634bf..695a222f148 100644 --- a/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubApiTest.java +++ b/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubApiTest.java @@ -12,7 +12,9 @@ import java.util.List; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** * @author Vivek Pandey diff --git a/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubOrgFolderTest.java b/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubOrgFolderTest.java index 798b7e9aab2..39e5b8b1b41 100644 --- a/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubOrgFolderTest.java +++ b/blueocean-github-pipeline/src/test/java/io/jenkins/blueocean/blueocean_github_pipeline/GithubOrgFolderTest.java @@ -28,7 +28,10 @@ import java.util.Collections; import java.util.Map; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; /** diff --git a/blueocean-pipeline-api-impl/pom.xml b/blueocean-pipeline-api-impl/pom.xml index 1d68e4f5c47..3396263b3d9 100644 --- a/blueocean-pipeline-api-impl/pom.xml +++ b/blueocean-pipeline-api-impl/pom.xml @@ -11,10 +11,14 @@ blueocean-pipeline-api-impl hpi - Pipeline REST API for Blue Ocean + Pipeline implementation for Blue Ocean https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin + + ${project.groupId} + blueocean-pipeline-api + ${project.groupId} blueocean-rest-impl diff --git a/blueocean-pipeline-api/pom.xml b/blueocean-pipeline-api/pom.xml new file mode 100644 index 00000000000..1e828f1ed67 --- /dev/null +++ b/blueocean-pipeline-api/pom.xml @@ -0,0 +1,39 @@ + + + 4.0.0 + + + io.jenkins.blueocean + blueocean-parent + 1.1.0-beta-3-SNAPSHOT + + + blueocean-pipeline-api + hpi + + Pipeline REST API for Blue Ocean + https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin + + + + ${project.groupId} + blueocean-rest + + + org.jenkins-ci.plugins + branch-api + + + org.jenkins-ci.plugins.workflow + workflow-multibranch + + + org.jenkins-ci.plugins + credentials + + + commons-lang + commons-lang + + + diff --git a/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractMultiBranchCreateRequest.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractMultiBranchCreateRequest.java new file mode 100644 index 00000000000..6608a54c1e8 --- /dev/null +++ b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractMultiBranchCreateRequest.java @@ -0,0 +1,161 @@ + package io.jenkins.blueocean.pipeline.api; + +import com.cloudbees.plugins.credentials.domains.Domain; +import com.google.common.collect.Lists; +import hudson.model.Cause; +import hudson.model.Failure; +import hudson.model.TopLevelItem; +import hudson.model.User; +import io.jenkins.blueocean.commons.ErrorMessage; +import io.jenkins.blueocean.commons.ErrorMessage.Error; +import io.jenkins.blueocean.commons.ErrorMessage.Error.ErrorCodes; +import io.jenkins.blueocean.commons.ServiceException; +import io.jenkins.blueocean.rest.Reachable; +import io.jenkins.blueocean.rest.factory.BluePipelineFactory; +import io.jenkins.blueocean.rest.factory.OrganizationResolver; +import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanCredentialsProvider; +import io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanDomainRequirement; +import io.jenkins.blueocean.rest.impl.pipeline.credential.CredentialsUtils; +import io.jenkins.blueocean.rest.model.BluePipeline; +import io.jenkins.blueocean.rest.model.BlueScmConfig; +import jenkins.branch.BranchSource; +import jenkins.branch.MultiBranchProject; +import jenkins.branch.MultiBranchProjectDescriptor; +import jenkins.model.Jenkins; +import jenkins.scm.api.SCMSource; +import org.apache.commons.lang.StringUtils; +import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; + +/** + * Creates {@link MultiBranchProject}s with a single {@link SCMSource} + */ +public abstract class AbstractMultiBranchCreateRequest extends AbstractPipelineCreateRequest { + + private static final String DESCRIPTOR_NAME = "org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject"; + + private static final String ERROR_FIELD_SCM_CONFIG_URI = "scmConfig.uri"; + private static final String ERROR_FIELD_SCM_CONFIG_NAME = "scmConfig.name"; + private static final String ERROR_NAME = "name"; + private static final String ERROR_FIELD_SCM_CREDENTIAL_ID = "scm.credentialId"; + + public AbstractMultiBranchCreateRequest(String name, BlueScmConfig scmConfig) { + super(name, scmConfig); + } + + @Override + @SuppressWarnings("unchecked") + public BluePipeline create(Reachable parent) throws IOException { + validateInternal(getName(), scmConfig); + MultiBranchProject project = createMultiBranchProject(); + assignCredentialToProject(scmConfig, project); + SCMSource source = createSource(project, scmConfig); + project.getSourcesList().add(new BranchSource(source)); + project.save(); + project.scheduleBuild(new Cause.UserIdCause()); + return BluePipelineFactory.getPipelineInstance(project, OrganizationResolver.getInstance().getContainingOrg(project.getItemGroup())); + } + + /** + * Create the source for the MultiBranchProject created with this request + * @param project that was created + * @param scmConfig config + * @return valid SCMSource + */ + protected abstract SCMSource createSource(@Nonnull MultiBranchProject project, @Nonnull BlueScmConfig scmConfig); + + /** + * Validate the provided SCMConfig and test that a connection can be made to the SCM server + * @param name of pipeline being created + * @param scmConfig to validate + * @return errors occuring during validation + */ + protected abstract List validate(String name, BlueScmConfig scmConfig); + + private MultiBranchProject createMultiBranchProject() throws IOException { + TopLevelItem item = createProject(getName(), DESCRIPTOR_NAME, MultiBranchProjectDescriptor.class); + if (!(item instanceof WorkflowMultiBranchProject)) { + try { + item.delete(); // we don't know about this project type + } catch (InterruptedException e) { + throw new ServiceException.UnexpectedErrorException("Failed to delete pipeline: " + getName()); + } + } + return (MultiBranchProject) item; + } + + private void assignCredentialToProject(BlueScmConfig scmConfig, MultiBranchProject project) throws IOException { + User authenticatedUser = User.current(); + if(StringUtils.isNotBlank(scmConfig.getCredentialId())) { + Domain domain = CredentialsUtils.findDomain(scmConfig.getCredentialId(), authenticatedUser); + if(domain == null){ + throw new ServiceException.BadRequestExpception( + new ErrorMessage(400, "Failed to create pipeline") + .add(new Error(ERROR_FIELD_SCM_CREDENTIAL_ID, + Error.ErrorCodes.INVALID.toString(), + "No domain in user credentials found for credentialId: "+ scmConfig.getCredentialId()))); + } + if (StringUtils.isEmpty(scmConfig.getUri())) { + throw new ServiceException.BadRequestExpception("uri not specified"); + } + if(domain.test(new BlueOceanDomainRequirement())) { //this is blueocean specific domain + project.addProperty( + new BlueOceanCredentialsProvider.FolderPropertyImpl(authenticatedUser.getId(), + scmConfig.getCredentialId(), + BlueOceanCredentialsProvider.createDomain(scmConfig.getUri()))); + } + } + } + + private void validateInternal(String name, BlueScmConfig scmConfig) { + User authenticatedUser = User.current(); + if(authenticatedUser == null){ + throw new ServiceException.UnauthorizedException("Must login to create a pipeline"); + } + + // If scmConfig is empty then we are missing the uri and name + if (scmConfig == null) { + throw fail(new Error("scmConfig", ErrorCodes.MISSING.toString(), "scmConfig is required")); + } + + if (scmConfig.getUri() == null) { + throw fail(new Error(ERROR_FIELD_SCM_CONFIG_URI, ErrorCodes.MISSING.toString(), ERROR_FIELD_SCM_CONFIG_URI + "is required")); + } + + if (getName() == null) { + throw fail(new Error(ERROR_FIELD_SCM_CONFIG_NAME, ErrorCodes.MISSING.toString(), ERROR_FIELD_SCM_CONFIG_NAME + " is required")); + } + + List errors = Lists.newLinkedList(validate(name, scmConfig)); + + // Validate that name matches rules + try { + Jenkins.getInstance().getProjectNamingStrategy().checkName(getName()); + }catch (Failure f){ + errors.add(new Error(ERROR_FIELD_SCM_CONFIG_NAME, Error.ErrorCodes.INVALID.toString(), getName() + " in not a valid name")); + } + + if(Jenkins.getInstance().getItem(name)!=null) { + errors.add(new Error(ERROR_NAME, Error.ErrorCodes.ALREADY_EXISTS.toString(), getName() + " already exists")); + } + + if(!errors.isEmpty()){ + throw fail(errors); + } + } + + private static ServiceException fail(List errors) { + ErrorMessage errorMessage = new ErrorMessage(400, "Failed to create pipeline"); + errorMessage.addAll(errors); + return new ServiceException.BadRequestExpception(errorMessage); + } + + private static ServiceException fail(Error... errors) { + return fail(Arrays.asList(errors)); + } +} diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractPipelineCreateRequestImpl.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractPipelineCreateRequest.java similarity index 69% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractPipelineCreateRequestImpl.java rename to blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractPipelineCreateRequest.java index 37b6d5d4963..f9c0395872e 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractPipelineCreateRequestImpl.java +++ b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/pipeline/api/AbstractPipelineCreateRequest.java @@ -1,13 +1,13 @@ -package io.jenkins.blueocean.service.embedded.rest; +package io.jenkins.blueocean.pipeline.api; import hudson.model.Item; -import hudson.model.ItemGroup; import hudson.model.Items; import hudson.model.TopLevelItem; import hudson.model.TopLevelItemDescriptor; import hudson.security.ACL; import io.jenkins.blueocean.commons.ServiceException; import io.jenkins.blueocean.rest.model.BluePipelineCreateRequest; +import io.jenkins.blueocean.rest.model.BlueScmConfig; import jenkins.model.Jenkins; import jenkins.model.ModifiableTopLevelItemGroup; import org.acegisecurity.Authentication; @@ -18,9 +18,16 @@ /** * @author Vivek Pandey */ -public abstract class AbstractPipelineCreateRequestImpl extends BluePipelineCreateRequest { +public abstract class AbstractPipelineCreateRequest extends BluePipelineCreateRequest { - public @Nonnull TopLevelItem create(ModifiableTopLevelItemGroup parent, String name, String descriptorName, Class descriptorClass) throws IOException{ + protected final BlueScmConfig scmConfig; + + public AbstractPipelineCreateRequest(String name, BlueScmConfig scmConfig) { + setName(name); + this.scmConfig = scmConfig; + } + + protected @Nonnull TopLevelItem createProject(String name, String descriptorName, Class descriptorClass) throws IOException{ ACL acl = Jenkins.getInstance().getACL(); Authentication a = Jenkins.getAuthentication(); if(!acl.hasPermission(a, Item.CREATE)){ @@ -32,7 +39,7 @@ public abstract class AbstractPipelineCreateRequestImpl extends BluePipelineCrea throw new ServiceException.BadRequestExpception(String.format("Failed to create pipeline: %s, descriptor %s is not found", name, descriptorName)); } - ItemGroup p = Jenkins.getInstance(); + ModifiableTopLevelItemGroup p = getParent(); if(!descriptor.isApplicableIn(p)){ throw new ServiceException.ForbiddenException( String.format("Failed to create pipeline: %s. pipeline can't be created in Jenkins root folder", name)); @@ -41,6 +48,10 @@ public abstract class AbstractPipelineCreateRequestImpl extends BluePipelineCrea if(!acl.hasCreatePermission(a, p, descriptor)){ throw new ServiceException.ForbiddenException("Missing permission: " +Item.CREATE.group.title+"/"+Item.CREATE.name + Item.CREATE + "/" + descriptor.getDisplayName()); } - return parent.createProject(descriptor, name, true); + return p.createProject(descriptor, name, true); + } + + protected ModifiableTopLevelItemGroup getParent() { + return Jenkins.getInstance(); } } diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java similarity index 99% rename from blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java rename to blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java index c39b08f4ae7..e5bae3530bc 100644 --- a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java +++ b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanCredentialsProvider.java @@ -20,7 +20,7 @@ import hudson.security.ACL; import hudson.security.Permission; import hudson.util.ListBoxModel; -import io.jenkins.blueocean.rest.impl.pipeline.Messages; +import io.jenkins.blueocean.pipeline.credential.Messages; import jenkins.model.Jenkins; import net.sf.json.JSONObject; import org.acegisecurity.Authentication; diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java similarity index 71% rename from blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java rename to blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java index 97ee6ba1a84..47070dc0b2e 100644 --- a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java +++ b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainRequirement.java @@ -2,8 +2,6 @@ import com.cloudbees.plugins.credentials.domains.DomainRequirement; -import static io.jenkins.blueocean.rest.impl.pipeline.credential.BlueOceanDomainSpecification.DOMAIN_SPECIFICATION; - /** * This is BlueOcean specific {@link DomainRequirement}. * diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainSpecification.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainSpecification.java similarity index 100% rename from blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainSpecification.java rename to blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/BlueOceanDomainSpecification.java diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java similarity index 99% rename from blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java rename to blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java index 9b4be143c52..e9e693d0198 100644 --- a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java +++ b/blueocean-pipeline-api/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/credential/CredentialsUtils.java @@ -18,7 +18,7 @@ import hudson.model.User; import io.jenkins.blueocean.commons.ServiceException; import jenkins.model.Jenkins; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang.StringUtils; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; diff --git a/blueocean-pipeline-api-impl/src/main/resources/io/jenkins/blueocean/rest/impl/pipeline/Messages.properties b/blueocean-pipeline-api/src/main/resources/io/jenkins/blueocean/pipeline/credential/Messages.properties similarity index 100% rename from blueocean-pipeline-api-impl/src/main/resources/io/jenkins/blueocean/rest/impl/pipeline/Messages.properties rename to blueocean-pipeline-api/src/main/resources/io/jenkins/blueocean/pipeline/credential/Messages.properties diff --git a/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BluePipelineCreateRequest.java b/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BluePipelineCreateRequest.java index 29f638650e6..f57fef5dc21 100644 --- a/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BluePipelineCreateRequest.java +++ b/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/model/BluePipelineCreateRequest.java @@ -10,7 +10,7 @@ * * @author Vivek Pandey */ -public abstract class BluePipelineCreateRequest{ +public abstract class BluePipelineCreateRequest { private String name; diff --git a/pom.xml b/pom.xml index 5306dc54950..d7bb011615e 100644 --- a/pom.xml +++ b/pom.xml @@ -108,6 +108,7 @@ blueocean-i18n blueocean-web blueocean-rest + blueocean-pipeline-api blueocean-rest-impl blueocean-pipeline-api-impl blueocean-events @@ -236,6 +237,12 @@ 1.2 + + ${project.groupId} + blueocean-pipeline-api + ${project.version} + + ${project.groupId} blueocean-pipeline-api-impl