[FIXED JENKINS-50148] Handle SimpleBuildWrappers in editor (#1786)
* [FIXED JENKINS-50148] Handle SimpleBuildWrappers in editor * Add withSonarQubeEnv tests, update StepMetadata.json so tests actually do things.
This commit is contained in:
parent
e4b71e88b0
commit
9cd5d47167
|
@ -62,5 +62,15 @@
|
|||
<groupId>org.jenkinsci.plugins</groupId>
|
||||
<artifactId>pipeline-model-definition</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>sonar</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
package io.blueocean.rest.pipeline.editor;
|
||||
|
||||
import jenkins.tasks.SimpleBuildWrapper;
|
||||
import org.jenkinsci.plugins.structs.describable.DescribableModel;
|
||||
import org.kohsuke.stapler.export.Exported;
|
||||
import org.kohsuke.stapler.export.ExportedBean;
|
||||
|
@ -44,4 +45,12 @@ public class ExportedPipelineFunction extends ExportedDescribableModel {
|
|||
public String getFunctionName() {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates this step wraps a block of other steps
|
||||
*/
|
||||
@Exported
|
||||
public boolean getIsBlockContainer() {
|
||||
return SimpleBuildWrapper.class.isAssignableFrom(model.getType());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public class ExportedPipelineStep extends ExportedPipelineFunction {
|
|||
/**
|
||||
* Indicates this step wraps a block of other steps
|
||||
*/
|
||||
@Override
|
||||
@Exported
|
||||
public boolean getIsBlockContainer() {
|
||||
return descriptor.takesImplicitBlockArgument();
|
||||
|
|
|
@ -7,6 +7,7 @@ import hudson.Launcher;
|
|||
import hudson.model.Describable;
|
||||
import hudson.model.Descriptor;
|
||||
import hudson.security.csrf.CrumbIssuer;
|
||||
import hudson.tasks.BuildWrapper;
|
||||
import hudson.tasks.Builder;
|
||||
import hudson.tasks.Publisher;
|
||||
import hudson.tools.ToolDescriptor;
|
||||
|
@ -15,6 +16,7 @@ import io.jenkins.blueocean.commons.stapler.TreeResponse;
|
|||
import io.jenkins.blueocean.rest.ApiRoutable;
|
||||
import jenkins.model.Jenkins;
|
||||
import jenkins.tasks.SimpleBuildStep;
|
||||
import jenkins.tasks.SimpleBuildWrapper;
|
||||
import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgent;
|
||||
import org.jenkinsci.plugins.pipeline.modeldefinition.agent.DeclarativeAgentDescriptor;
|
||||
import org.jenkinsci.plugins.pipeline.modeldefinition.model.BuildCondition;
|
||||
|
@ -164,6 +166,7 @@ public class PipelineMetadataService implements ApiRoutable {
|
|||
List<Descriptor<?>> metaStepDescriptors = new ArrayList<Descriptor<?>>();
|
||||
populateMetaSteps(metaStepDescriptors, Builder.class);
|
||||
populateMetaSteps(metaStepDescriptors, Publisher.class);
|
||||
populateMetaSteps(metaStepDescriptors, BuildWrapper.class);
|
||||
|
||||
for (Descriptor<?> d : metaStepDescriptors) {
|
||||
ExportedPipelineFunction metaStep = getStepMetadata(d);
|
||||
|
@ -199,6 +202,8 @@ public class PipelineMetadataService implements ApiRoutable {
|
|||
for (Descriptor<?> d : j.getDescriptorList(c)) {
|
||||
if (SimpleBuildStep.class.isAssignableFrom(d.clazz) && symbolForObject(d) != null) {
|
||||
r.add(d);
|
||||
} else if (SimpleBuildWrapper.class.isAssignableFrom(d.clazz) && symbolForObject(d) != null) {
|
||||
r.add(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,17 +30,19 @@ public class PipelineMetadataServiceTest {
|
|||
@Test
|
||||
public void testBasicStepsReturned() throws IOException {
|
||||
JSONWebResponse rsp = j.getJSON("blue/rest/pipeline-metadata/pipelineStepMetadata");
|
||||
|
||||
assert(rsp != null) : "Should have results";
|
||||
JSONObject node = null;
|
||||
JSONObject withSonarQubeEnv = null;
|
||||
for (Object o : JSONArray.fromObject(rsp.getContentAsString())) {
|
||||
JSONObject meta = (JSONObject)o;
|
||||
if("node".equals(meta.get("functionName"))) {
|
||||
node = meta;
|
||||
break;
|
||||
} else if ("withSonarQubeEnv".equals(meta.get("functionName"))) {
|
||||
withSonarQubeEnv = meta;
|
||||
}
|
||||
}
|
||||
assert(node != null) : "PipelineStepMetadata node not found";
|
||||
assert(withSonarQubeEnv != null) : "PipelineStepMetadata withSonarQubeEnv not found";
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -131,6 +133,9 @@ public class PipelineMetadataServiceTest {
|
|||
|
||||
// Verify that we *do* have advanced steps that are explicitly whitelisted in.
|
||||
assertThat(steps, hasItem(stepWithName("catchError")));
|
||||
|
||||
// Verify that we have a Symbol-provided SimpleBuildWrapper
|
||||
assertThat(steps, hasItem(stepWithName("withSonarQubeEnv")));
|
||||
}
|
||||
|
||||
private Matcher<? super ExportedPipelineStep> stepWithName(String stepName) {
|
||||
|
|
|
@ -1241,5 +1241,57 @@
|
|||
"symbol": null,
|
||||
"type": "hudson.tasks.Fingerprinter",
|
||||
"functionName": "fingerprint"
|
||||
},
|
||||
{
|
||||
"_class": "io.blueocean.rest.pipeline.editor.ExportedPipelineFunction",
|
||||
"displayName": "With Ant",
|
||||
"hasSingleRequiredParameter": false,
|
||||
"help": "<div>\r\n Prepares an environment for Jenkins to run builds using Apache Ant.\r\n Annotates Ant-specific output to display executed targets.\r\n Optionally sets up an Ant and/or JDK installation.\r\n<\/div>\r\n",
|
||||
"parameters": [
|
||||
{
|
||||
"capitalizedName": "Installation",
|
||||
"collectionTypes": [],
|
||||
"descriptorUrl": null,
|
||||
"help": "<p>\r\n Name of an Ant installation to use so that <code>ant<\/code> will be in the path.\r\n<\/p>\r\n",
|
||||
"isDeprecated": false,
|
||||
"isRequired": false,
|
||||
"name": "installation",
|
||||
"type": "java.lang.String"
|
||||
},
|
||||
{
|
||||
"capitalizedName": "Jdk",
|
||||
"collectionTypes": [],
|
||||
"descriptorUrl": null,
|
||||
"help": "<p>\r\n Name of an Java installation to use when running Ant.\r\n<\/p>\r\n",
|
||||
"isDeprecated": false,
|
||||
"isRequired": false,
|
||||
"name": "jdk",
|
||||
"type": "java.lang.String"
|
||||
}
|
||||
],
|
||||
"symbol": null,
|
||||
"type": "hudson.tasks.AntWrapper",
|
||||
"functionName": "withAnt",
|
||||
"isBlockContainer": true
|
||||
},
|
||||
{
|
||||
"_class": "io.blueocean.rest.pipeline.editor.ExportedPipelineFunction",
|
||||
"displayName": "Prepare SonarQube Scanner environment",
|
||||
"hasSingleRequiredParameter": true,
|
||||
"help": null,
|
||||
"parameters": [ {
|
||||
"capitalizedName": "InstallationName",
|
||||
"collectionTypes": [],
|
||||
"descriptorUrl": null,
|
||||
"help": null,
|
||||
"isDeprecated": false,
|
||||
"isRequired": true,
|
||||
"name": "installationName",
|
||||
"type": "java.lang.String"
|
||||
}],
|
||||
"symbol": null,
|
||||
"type": "hudson.plugins.sonar.SonarBuildWrapper",
|
||||
"functionName": "withSonarQubeEnv",
|
||||
"isBlockContainer": true
|
||||
}
|
||||
]
|
||||
]
|
||||
|
|
|
@ -354,4 +354,142 @@ describe('Pipeline Syntax Converter', () => {
|
|||
assert(out.pipeline.stages[0].parallel[1].name == 'stage 2', "Bad parallel conversion");
|
||||
});
|
||||
|
||||
it('converts from JSON: SimpleBuildWrapper with named parameter', () => {
|
||||
const p = {"pipeline": {
|
||||
"stages": [{"name": "with wrapper",
|
||||
"branches": [{
|
||||
"name": "default","steps": [{
|
||||
"name": "withAnt","arguments": [
|
||||
{"key": "installation","value": {"isLiteral": true,"value": "default"}}],
|
||||
"children": [{"name": "echo","arguments":
|
||||
{"isLiteral": true,"value": "hello"}}]}]}]}],
|
||||
"agent": {"isLiteral": true,"value": "any"}}};
|
||||
const internal = convertJsonToInternalModel(p);
|
||||
const containerStep = internal.children[0].steps[0];
|
||||
assert(containerStep.name == 'withAnt', "Incorrect step function");
|
||||
// 'script' is the required parameter
|
||||
assert(containerStep.children.length == 1, "No children for nested step");
|
||||
});
|
||||
|
||||
it('converts from JSON: SimpleBuildWrapper with single required unnamed parameter', () => {
|
||||
const p = {"pipeline": {
|
||||
"stages": [{"name": "with wrapper",
|
||||
"branches": [{
|
||||
"name": "default","steps": [{
|
||||
"name": "withSonarQubeEnv","arguments": [
|
||||
{"isLiteral": true,"value": "default"}],
|
||||
"children": [{"name": "echo","arguments":
|
||||
{"isLiteral": true,"value": "hello"}}]}]}]}],
|
||||
"agent": {"isLiteral": true,"value": "any"}}};
|
||||
const internal = convertJsonToInternalModel(p);
|
||||
const containerStep = internal.children[0].steps[0];
|
||||
assert(containerStep.name == 'withSonarQubeEnv', "Incorrect step function");
|
||||
assert(containerStep.data.installationName.value == 'default', "Incorrect arguments value");
|
||||
// 'script' is the required parameter
|
||||
assert(containerStep.children.length == 1, "No children for nested step");
|
||||
});
|
||||
|
||||
it('converts from JSON: SimpleBuildWrapper with no required parameters', () => {
|
||||
const p = {"pipeline": {
|
||||
"stages": [{"name": "with wrapper",
|
||||
"branches": [{
|
||||
"name": "default","steps": [{
|
||||
"name": "withAnt","arguments": [],
|
||||
"children": [{"name": "echo","arguments":
|
||||
{"isLiteral": true,"value": "hello"}}]}]}]}],
|
||||
"agent": {"isLiteral": true,"value": "any"}}};
|
||||
const internal = convertJsonToInternalModel(p);
|
||||
const containerStep = internal.children[0].steps[0];
|
||||
assert(containerStep.name == 'withAnt', "Incorrect step function");
|
||||
// 'script' is the required parameter
|
||||
assert(containerStep.children.length == 1, "No children for nested step");
|
||||
});
|
||||
|
||||
it('converts to JSON: SimpleBuildWrapper', () => {
|
||||
const internal: Pipeline = {
|
||||
children: [
|
||||
{
|
||||
name: "with wrapper",
|
||||
steps: [
|
||||
{
|
||||
name: 'withAnt',
|
||||
data: {
|
||||
installation: {
|
||||
isLiteral: true,
|
||||
value: 'default',
|
||||
},
|
||||
},
|
||||
isContainer: true,
|
||||
children: [{
|
||||
name: "echo",
|
||||
data: {
|
||||
message: {
|
||||
isLiteral: true,
|
||||
value: "hello"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
};
|
||||
const out = convertInternalModelToJson(internal);
|
||||
assert(out.pipeline.
|
||||
stages[0].
|
||||
branches[0].
|
||||
steps[0].
|
||||
arguments[0].
|
||||
key == 'installation', "Incorrect conversion to JSON: expected installation as key");
|
||||
assert(out.pipeline.
|
||||
stages[0].
|
||||
branches[0].
|
||||
steps[0].
|
||||
children[0].
|
||||
name == 'echo', "Incorrect conversion to JSON: expected echo as nested step");
|
||||
});
|
||||
|
||||
it('converts to JSON: SimpleBuildWrapper with unnamed parameter', () => {
|
||||
const internal: Pipeline = {
|
||||
children: [
|
||||
{
|
||||
name: "with wrapper",
|
||||
steps: [
|
||||
{
|
||||
name: 'withSonarQubeEnv',
|
||||
data: {
|
||||
installationName: {
|
||||
isLiteral: true,
|
||||
value: 'default',
|
||||
},
|
||||
},
|
||||
isContainer: true,
|
||||
children: [{
|
||||
name: "echo",
|
||||
data: {
|
||||
message: {
|
||||
isLiteral: true,
|
||||
value: "hello"
|
||||
}
|
||||
}
|
||||
}]
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
};
|
||||
const out = convertInternalModelToJson(internal);
|
||||
assert(out.pipeline.
|
||||
stages[0].
|
||||
branches[0].
|
||||
steps[0].
|
||||
arguments[0].
|
||||
key == 'installationName', "Incorrect conversion to JSON: expected installationName as key");
|
||||
assert(out.pipeline.
|
||||
stages[0].
|
||||
branches[0].
|
||||
steps[0].
|
||||
children[0].
|
||||
name == 'echo', "Incorrect conversion to JSON: expected echo as nested step");
|
||||
});
|
||||
});
|
||||
|
|
12
pom.xml
12
pom.xml
|
@ -741,6 +741,18 @@
|
|||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- used in blueocean-pipeline-editor test -->
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>sonar</artifactId>
|
||||
<version>2.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jenkins-ci.plugins</groupId>
|
||||
<artifactId>ant</artifactId>
|
||||
<version>1.8</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.hamcrest</groupId>
|
||||
|
|
Loading…
Reference in New Issue