JENKINS-36837# Split of Pipeline specific API implementation in to se… (#364)

* JENKINS-36837# Split of Pipeline specific API implementation in to separate module

* doc improvement

* Fixed .js, .jsx with changed pipeline related impl class names

* Fixed BranchImpl package

* Removed uneeded error message
This commit is contained in:
vivek 2016-07-21 16:28:57 -07:00 committed by GitHub
parent 86c8039863
commit ca7d54e99f
62 changed files with 1812 additions and 749 deletions

View File

@ -29,7 +29,13 @@ Java interfaces and classes that specify the definition of the REST API. See the
## blueocean-rest-impl
Provides the default implementation of the REST Api defined in the `blueocean-rest` plugin.
Provides the default implementation of the core REST Apis defined in the `blueocean-rest` plugin. It comes with only free style job support.
## blueocean-pipeline-api-impl
Provides implementation of Pipeline apis for Jenkins pipeline and multi-branch job types support
## blueocean-web

View File

@ -11,7 +11,7 @@ import * as urlUtils from '../util/UrlUtils';
import * as sse from '@jenkins-cd/sse-gateway';
import assert from 'assert';
const MULTI_BRANCH_PIPELINE_CLASS_NAME = 'io.jenkins.blueocean.service.embedded.rest.MultiBranchPipelineImpl';
const MULTI_BRANCH_PIPELINE_CLASS_NAME = 'io.jenkins.blueocean.rest.impl.pipeline.MultiBranchPipelineImpl';
const TYPE = 'Pipeline';
export default class Pipeline {

View File

@ -38,7 +38,8 @@ export class RunDetailsPipeline extends Component {
this.mergedConfig = this.generateConfig(this.props);
const supportsNode = result && result._class === 'io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl';
// It should really be using capability using /rest/classes API
const supportsNode = result && result._class === 'io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl';
if (supportsNode) {
fetchNodes(this.mergedConfig);
} else {

View File

@ -1,5 +1,5 @@
export default [{
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -34,7 +34,7 @@ export default [{
"fullName": "tfprdemo/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -211,7 +211,7 @@ export default [{
"startTime": "2016-07-02T18:25:06.063+0100",
"state": "FINISHED",
"steps": [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -219,7 +219,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -227,7 +227,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -235,7 +235,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -243,7 +243,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -259,7 +259,7 @@ export default [{
"weatherScore": 100,
"pullRequest": null
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -294,7 +294,7 @@ export default [{
"fullName": "tfprdemo/quicker",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -443,7 +443,7 @@ export default [{
"startTime": "2016-07-01T17:20:23.071+0100",
"state": "FINISHED",
"steps": [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -451,7 +451,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -459,7 +459,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -467,7 +467,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -475,7 +475,7 @@ export default [{
}
}
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -491,7 +491,7 @@ export default [{
"weatherScore": 100,
"pullRequest": null
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -526,7 +526,7 @@ export default [{
"fullName": "tfprdemo/tfennelly-patch-1",
"lastSuccessfulRun": null,
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -602,4 +602,4 @@ export default [{
"organization": "jenkins",
"weatherScore": 100,
"pullRequest": null
}]
}]

View File

@ -1,7 +1,7 @@
/* eslint-disable quotes,quote-props,comma-dangle */
export const pipelinesDupName = [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.MultiBranchPipelineImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.MultiBranchPipelineImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -42,7 +42,7 @@ export const pipelinesDupName = [
"totalNumberOfPullRequests": 0
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.MultiBranchPipelineImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.MultiBranchPipelineImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",

View File

@ -1,5 +1,5 @@
export const nodes = [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -16,9 +16,9 @@ export const nodes = [{
"result": "SUCCESS",
"startTime": "2016-07-01T14:02:38.829+0200",
"state": "FINISHED",
"edges": [{"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl", "id": "23"}]
"edges": [{"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "23"}]
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -36,11 +36,11 @@ export const nodes = [{
"startTime": "2016-07-01T14:03:09.608+0200",
"state": "FINISHED",
"edges": [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "26"
}, {"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl", "id": "27"}]
}, {"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "27"}]
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -57,9 +57,9 @@ export const nodes = [{
"result": "SUCCESS",
"startTime": "2016-07-01T14:03:09.609+0200",
"state": "FINISHED",
"edges": [{"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl", "id": "45"}]
"edges": [{"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "45"}]
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -76,9 +76,9 @@ export const nodes = [{
"result": "SUCCESS",
"startTime": "2016-07-01T14:03:09.609+0200",
"state": "FINISHED",
"edges": [{"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl", "id": "45"}]
"edges": [{"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl", "id": "45"}]
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -98,7 +98,7 @@ export const nodes = [{
"edges": []
}];
export const stepsNode5 = [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -112,7 +112,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:38.830+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -126,7 +126,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:43.219+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -140,7 +140,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:43.221+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -154,7 +154,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:47.611+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -168,7 +168,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:47.612+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -182,7 +182,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:52.003+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -196,7 +196,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:52.005+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -210,7 +210,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:56.394+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -224,7 +224,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:02:56.396+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -238,7 +238,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:03:00.782+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -252,7 +252,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:03:00.784+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -266,7 +266,7 @@ export const stepsNode5 = [{
"startTime": "2016-07-01T14:03:05.168+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -282,7 +282,7 @@ export const stepsNode5 = [{
}];
export const stepsNode45 = [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -296,7 +296,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:29.844+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -310,7 +310,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:36.571+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -324,7 +324,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:36.572+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -338,7 +338,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:43.298+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -352,7 +352,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:43.299+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -366,7 +366,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:43.300+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -380,7 +380,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:50.037+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -394,7 +394,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:50.037+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -408,7 +408,7 @@ export const stepsNode45 = [{
"startTime": "2016-07-01T14:03:50.038+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineStepImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",

View File

@ -173,7 +173,7 @@ describe("push events - started run tests", () => {
actions.fetchJson = function(url, onSuccess, onError) {
assert.equal(url, '/jenkins/rest/organizations/jenkins/pipelines/PR-demo/branches/quicker/runs/12');
onSuccess({
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"artifacts": [],
"changeSet": [],
"durationInMillis": 0,

View File

@ -1,9 +1,9 @@
export const finishedMultipleFailure = [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 1",
"durationInMillis": 10264,
"edges": [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "12"
}],
"id": "5",
@ -11,17 +11,17 @@ export const finishedMultipleFailure = [{
"startTime": "2016-05-25T13:47:40.534+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 2",
"durationInMillis": 22143,
"edges": [{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "16"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "17"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "18"
}],
"id": "12",
@ -29,7 +29,7 @@ export const finishedMultipleFailure = [{
"startTime": "2016-05-25T13:47:50.798+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "firstBranch",
"durationInMillis": 22004,
"edges": [],
@ -38,7 +38,7 @@ export const finishedMultipleFailure = [{
"startTime": "2016-05-25T13:47:50.800+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "secondBranch",
"durationInMillis": 22053,
"edges": [],
@ -47,7 +47,7 @@ export const finishedMultipleFailure = [{
"startTime": "2016-05-25T13:47:50.801+0200",
"state": "FINISHED"
}, {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "thirdBranch",
"durationInMillis": 22069,
"edges": [],

View File

@ -1,11 +1,11 @@
export const firstFinishedSecondRunning = [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 1",
"durationInMillis": 10264,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "12"
}
],
@ -15,20 +15,20 @@ export const firstFinishedSecondRunning = [
"state": "FINISHED"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 2",
"durationInMillis": 7271,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "16"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "17"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "18"
}
],
@ -38,7 +38,7 @@ export const firstFinishedSecondRunning = [
"state": "RUNNING"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "firstBranch",
"durationInMillis": 7269,
"edges": [],
@ -48,7 +48,7 @@ export const firstFinishedSecondRunning = [
"state": "RUNNING"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "secondBranch",
"durationInMillis": 7268,
"edges": [],
@ -58,7 +58,7 @@ export const firstFinishedSecondRunning = [
"state": "RUNNING"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "thirdBranch",
"durationInMillis": 7267,
"edges": [],

View File

@ -1,11 +1,11 @@
export const firstRunning = [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 1",
"durationInMillis": 2996,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "12"
}
],
@ -15,16 +15,16 @@ export const firstRunning = [
"state": "RUNNING"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "Stage 2",
"durationInMillis": null,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "15"
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "16"
}
],
@ -34,12 +34,12 @@ export const firstRunning = [
"state": null
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "firstBranch",
"durationInMillis": null,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "28"
}
],
@ -49,12 +49,12 @@ export const firstRunning = [
"state": null
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "secondBranch",
"durationInMillis": null,
"edges": [
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl",
"id": "28"
}
],
@ -64,7 +64,7 @@ export const firstRunning = [
"state": null
},
{
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl",
"displayName": "deploy",
"durationInMillis": null,
"edges": [],

View File

@ -1,9 +1,9 @@
export const runNodesFail = [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'Stage 1',
durationInMillis: 10263,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '12'
}],
id: '5',
@ -11,14 +11,14 @@ export const runNodesFail = [{
startTime: '2016-05-24T13:42:07.833+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'Stage 2',
durationInMillis: 22141,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '15'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '16'
}],
id: '12',
@ -26,11 +26,11 @@ export const runNodesFail = [{
startTime: '2016-05-24T13:42:18.096+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'firstBranch',
durationInMillis: 22074,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '28'
}],
id: '15',
@ -38,11 +38,11 @@ export const runNodesFail = [{
startTime: '2016-05-24T13:42:18.098+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'secondBranch',
durationInMillis: 22076,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '28'
}],
id: '16',
@ -50,7 +50,7 @@ export const runNodesFail = [{
startTime: '2016-05-24T13:42:18.099+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'deploy',
durationInMillis: null,
edges: [],
@ -61,11 +61,11 @@ export const runNodesFail = [{
}];
export const runNodesSuccess = [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'Stage 1',
durationInMillis: 10260,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '12'
}],
id: '5',
@ -73,14 +73,14 @@ export const runNodesSuccess = [{
startTime: '2016-05-24T13:34:49.234+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'Stage 2',
durationInMillis: 22161,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '15'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '16'
}],
id: '12',
@ -88,11 +88,11 @@ export const runNodesSuccess = [{
startTime: '2016-05-24T13:34:59.494+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'firstBranch',
durationInMillis: 22081,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '28'
}],
id: '15',
@ -100,11 +100,11 @@ export const runNodesSuccess = [{
startTime: '2016-05-24T13:34:59.497+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'secondBranch',
durationInMillis: 22079,
edges: [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl$EdgeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl$EdgeImpl',
id: '28'
}],
id: '16',
@ -112,7 +112,7 @@ export const runNodesSuccess = [{
startTime: '2016-05-24T13:34:59.499+0200',
state: 'FINISHED'
}, {
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineNodeImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineNodeImpl',
displayName: 'deploy',
durationInMillis: 10211,
edges: [],
@ -123,7 +123,7 @@ export const runNodesSuccess = [{
}];
export const runNodesRunning = [{
'_class': 'io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl',
'_class': 'io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl',
artifacts: [],
changeSet: [],
durationInMillis: 0,

View File

@ -20,7 +20,7 @@
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-rest-impl</artifactId>
<artifactId>blueocean-pipeline-api-impl</artifactId>
</dependency>
</dependencies>

View File

@ -152,7 +152,7 @@ export class DashboardCards extends Component {
let pipelineName;
let branchName;
if (pipeline._class === 'io.jenkins.blueocean.service.embedded.rest.BranchImpl') {
if (pipeline._class === 'io.jenkins.blueocean.rest.impl.pipeline.BranchImpl') {
// branch.fullName is in the form folder1/folder2/pipeline/branch ...
// "pipeline"
pipelineName = extractPath(pipeline.fullName, -2, -1);

View File

@ -9,7 +9,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -34,7 +34,7 @@ export const favorites = [
"fullName": "blueocean/UX-301",
"lastSuccessfulRun": null,
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -89,7 +89,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -114,7 +114,7 @@ export const favorites = [
"fullName": "jenkinsfile-experiments/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/jenkinsfile-experiments/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -180,7 +180,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -205,7 +205,7 @@ export const favorites = [
"fullName": "jenkinsfile-experiments/test-branch-1",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/jenkinsfile-experiments/branches/test-branch-1/runs/53/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -271,7 +271,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -296,7 +296,7 @@ export const favorites = [
"fullName": "jdl1/docker-test",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/jdl1/branches/docker-test/runs/3/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -351,7 +351,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -376,7 +376,7 @@ export const favorites = [
"fullName": "test1/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test1/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -442,7 +442,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -467,7 +467,7 @@ export const favorites = [
"fullName": "test2/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test2/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -533,7 +533,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -558,7 +558,7 @@ export const favorites = [
"fullName": "test3/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test3/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -624,7 +624,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -649,7 +649,7 @@ export const favorites = [
"fullName": "test4/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test4/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -715,7 +715,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -740,7 +740,7 @@ export const favorites = [
"fullName": "test5/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test5/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -806,7 +806,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -831,7 +831,7 @@ export const favorites = [
"fullName": "jdl1/docker-test",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jankins/pipelines/jdl1/branches/docker-test/runs/4/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -886,7 +886,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -911,7 +911,7 @@ export const favorites = [
"fullName": "test6/master",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/test6/branches/master/runs/95/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -977,7 +977,7 @@ export const favorites = [
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -1002,7 +1002,7 @@ export const favorites = [
"fullName": "jdl2/docker-test",
"lastSuccessfulRun": "http://localhost:8080/jenkins/blue/rest/organizations/jenkins/pipelines/jdl2/branches/docker-test/runs/3/",
"latestRun": {
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.PipelineRunImpl",
"_links": {
"nodes": {
"_class": "io.jenkins.blueocean.rest.hal.Link",

View File

@ -18,7 +18,7 @@ const getDefaultFavorites = () =>
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",
@ -36,7 +36,7 @@ const getDefaultFavorites = () =>
}
},
"item": {
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
"_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl",
"_links": {
"self": {
"_class": "io.jenkins.blueocean.rest.hal.Link",

View File

@ -0,0 +1,21 @@
The MIT License
Copyright (c) 2016 CloudBees Inc and a number of other of contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@ -0,0 +1,11 @@
# BlueOCean REST API implementation
Implementation of BlueOcean REST API from `bleuocean-rest` module.
See README.md in `blueocean-rest` module.

View File

@ -0,0 +1,175 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>io.jenkins.blueocean</groupId>
<artifactId>blueocean-parent</artifactId>
<version>1.0-alpha-4-SNAPSHOT</version>
</parent>
<artifactId>blueocean-pipeline-api-impl</artifactId>
<packaging>hpi</packaging>
<name>BlueOcean :: Pipeline REST API implementation</name>
<url>https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin</url>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-rest-impl</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-multibranch</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<version>2.0</version>
</dependency>
<!-- Not needed by blueocean runtime but adds to blueocean experience -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>github-branch-source</artifactId>
<version>1.8.1</version>
</dependency>
<!-- Test plugins -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-stage-step</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-scm-step</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.mashape.unirest</groupId>
<artifactId>unirest-java</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<!-- Do not retry failing test -->
<rerunFailingTestsCount>0</rerunFailingTestsCount>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<!-- implementation is needed only for Maven 2 -->
<rule implementation="org.jacoco.maven.RuleConfiguration">
<element>BUNDLE</element>
<limits>
<!-- implementation is needed only for Maven 2 -->
<limit implementation="org.jacoco.report.check.Limit">
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.60</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.Job;
import io.jenkins.blueocean.rest.hal.Link;

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.Extension;
import hudson.Util;
@ -9,6 +9,8 @@ import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.Resource;
import jenkins.branch.MultiBranchProject;
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import jenkins.scm.api.SCMHead;
import jenkins.scm.api.actions.ChangeRequestAction;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
@ -22,9 +24,11 @@ public class BranchImpl extends PipelineImpl {
private static final String PULL_REQUEST = "pullRequest";
private final Link parent;
protected final Job job;
public BranchImpl(Job job, Link parent) {
super(job);
this.job = job;
this.parent = parent;
}

View File

@ -0,0 +1,70 @@
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.Extension;
import hudson.model.Queue;
import hudson.model.Run;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* @author Vivek Pandey
*/
@Extension
public class LinkResolverImpl extends LinkResolver {
private final Logger logger = LoggerFactory.getLogger(io.jenkins.blueocean.service.embedded.LinkResolverImpl.class);
@Override
public Link resolve(Object modelObject) {
if (modelObject instanceof FlowNode) {
FlowNode flowNode = (FlowNode) modelObject;
BlueRun r = resolveFlowNodeRun(flowNode);
if (PipelineNodeUtil.isParallelBranch(flowNode) || PipelineNodeUtil.isStage(flowNode)) { // its Node
if (r != null) {
return r.getLink().rel("nodes/" + flowNode.getId());
}
} else if (flowNode instanceof StepAtomNode && !PipelineNodeUtil.isStage(flowNode)) {
if (r != null) {
return r.getLink().rel("steps/" + flowNode.getId());
}
}
}
return null;
}
private BlueRun resolveFlowNodeRun(FlowNode flowNode) {
try {
Queue.Executable executable = flowNode.getExecution().getOwner().getExecutable();
if (executable != null && executable instanceof WorkflowRun) {
WorkflowRun run = (WorkflowRun) executable;
return (BlueRun) resolveRun(run);
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
return null;
}
return null;
}
private Resource resolveRun(Run run){
Resource resource = BluePipelineFactory.resolve(run.getParent());
if(resource instanceof BluePipeline){
BluePipeline pipeline = (BluePipeline) resource;
return pipeline.getRuns().get(run.getId());
}
return null;
}
}

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.Extension;
import hudson.model.Item;
@ -20,6 +20,11 @@ import io.jenkins.blueocean.rest.model.BlueQueueItem;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.BlueRunContainer;
import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.rest.BlueFavoriteResolver;
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
import io.jenkins.blueocean.service.embedded.rest.FavoriteImpl;
import io.jenkins.blueocean.service.embedded.rest.OrganizationImpl;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import jenkins.branch.MultiBranchProject;
import jenkins.scm.api.SCMHead;
@ -312,7 +317,7 @@ public class MultiBranchPipelineImpl extends BlueMultiBranchPipeline {
}
@Extension(ordinal = 2)
public static class PipelineFactoryImpl extends BluePipelineFactory{
public static class PipelineFactoryImpl extends BluePipelineFactory {
@Override
public MultiBranchPipelineImpl getPipeline(Item item, Reachable parent) {

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.Job;
import hudson.model.Queue;
@ -7,6 +7,8 @@ import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BlueQueueContainer;
import io.jenkins.blueocean.rest.model.BlueQueueItem;
import io.jenkins.blueocean.service.embedded.rest.QueueContainerImpl;
import io.jenkins.blueocean.service.embedded.rest.QueueItemImpl;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.support.steps.ExecutorStepExecution;
@ -34,7 +36,7 @@ public class MultiBranchPipelineQueueContainer extends BlueQueueContainer {
try {
Queue.Item item = Jenkins.getActiveInstance().getQueue().getItem(Long.parseLong(name));
if(item != null){
PipelineImpl pipeline = (PipelineImpl) multiBranchPipeline.getBranches().get(item.task.getOwnerTask().getName());
BranchImpl pipeline = (BranchImpl) multiBranchPipeline.getBranches().get(item.task.getOwnerTask().getName());
if(pipeline != null) {
if(item.task instanceof ExecutorStepExecution.PlaceholderTask) {
@ -78,7 +80,7 @@ public class MultiBranchPipelineQueueContainer extends BlueQueueContainer {
}
}
for(final BluePipeline p:multiBranchPipeline.getBranches()){
Job job = ((PipelineImpl)p).job;
Job job = ((BranchImpl)p).job;
List<Queue.Item> its = queueMap.get(job.getName());
if(its == null || its.isEmpty()){
continue;

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.Result;
import io.jenkins.blueocean.commons.ServiceException;

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
@ -6,6 +6,7 @@ import io.jenkins.blueocean.rest.model.BluePipelineNode;
import io.jenkins.blueocean.rest.model.BluePipelineStep;
import io.jenkins.blueocean.rest.model.BluePipelineStepContainer;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import org.jenkinsci.plugins.workflow.actions.TimingAction;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import com.google.common.base.Predicate;
import io.jenkins.blueocean.rest.model.BlueRun;

View File

@ -0,0 +1,117 @@
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.Extension;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.plugins.git.util.BuildData;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
import io.jenkins.blueocean.rest.model.BluePipelineNodeContainer;
import io.jenkins.blueocean.rest.model.BluePipelineStepContainer;
import io.jenkins.blueocean.rest.model.BlueQueueItem;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.Container;
import io.jenkins.blueocean.rest.model.Containers;
import io.jenkins.blueocean.service.embedded.rest.AbstractRunImpl;
import io.jenkins.blueocean.service.embedded.rest.BlueRunFactory;
import io.jenkins.blueocean.service.embedded.rest.ChangeSetResource;
import io.jenkins.blueocean.service.embedded.rest.QueueContainerImpl;
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.kohsuke.stapler.export.Exported;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Pipeline Run
*
* @author Vivek Pandey
*/
public class PipelineRunImpl extends AbstractRunImpl<WorkflowRun> {
public PipelineRunImpl(WorkflowRun run, Link parent) {
super(run, parent);
}
@Override
public Container<BlueChangeSetEntry> getChangeSet() {
Map<String, BlueChangeSetEntry> m = new LinkedHashMap<>();
int cnt = 0;
for (ChangeLogSet<? extends Entry> cs : run.getChangeSets()) {
for (ChangeLogSet.Entry e : cs) {
cnt++;
String id = e.getCommitId();
if (id == null) id = String.valueOf(cnt);
m.put(id, new ChangeSetResource(e, this));
}
}
return Containers.fromResourceMap(getLink(),m);
}
@Override
public BlueQueueItem replay() {
ReplayAction replayAction = run.getAction(ReplayAction.class);
if(replayAction == null) {
throw new ServiceException.BadRequestExpception("This run does not support replay");
}
Queue.Item item = replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());
BlueQueueItem queueItem = QueueContainerImpl.getQueuedItem(item, run.getParent());
if(queueItem == null) {
throw new ServiceException.UnexpectedErrorException("Run was not added to queue.");
} else {
return queueItem;
}
}
@Override
public BluePipelineNodeContainer getNodes() {
if (run != null) {
return new PipelineNodeContainerImpl(run, getLink());
}
return null;
}
@Override
public BluePipelineStepContainer getSteps() {
return new PipelineStepContainerImpl(null, new PipelineNodeGraphBuilder(run), getLink());
}
@Override
public BlueRun stop() {
run.doStop();
return this;
}
@Exported(name = "commitId")
public String getCommitId() {
BuildData data = run.getAction(BuildData.class);
if (data == null
|| data.getLastBuiltRevision() == null
|| data.getLastBuiltRevision().getSha1String() == null) {
return null;
} else {
return data.getLastBuiltRevision().getSha1String();
}
}
@Extension(ordinal = 1)
public static class FactoryImpl extends BlueRunFactory {
@Override
public BlueRun getRun(Run run, Reachable parent) {
if(run instanceof WorkflowRun) {
return new PipelineRunImpl((WorkflowRun) run, parent.getLink());
}
return null;
}
}
}

View File

@ -1,4 +1,4 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.hal.Link;

View File

@ -1,9 +1,11 @@
package io.jenkins.blueocean.service.embedded.rest;
package io.jenkins.blueocean.rest.impl.pipeline;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BluePipelineStep;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.service.embedded.rest.LogResource;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import org.jenkinsci.plugins.workflow.actions.LogAction;
import org.jenkinsci.plugins.workflow.actions.TimingAction;
import org.jenkinsci.plugins.workflow.graph.FlowNode;

View File

@ -0,0 +1,4 @@
<?jelly escape-by-default='true'?>
<div>
This plugin is a part of BlueOcean Plugin
</div>

View File

@ -1,17 +1,14 @@
package io.jenkins.blueocean.service.embedded;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.Label;
import hudson.model.Queue;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl;
import io.jenkins.blueocean.service.embedded.scm.GitSampleRepoRule;
import io.jenkins.blueocean.rest.impl.pipeline.scm.GitSampleRepoRule;
import jenkins.branch.BranchProperty;
import jenkins.branch.BranchSource;
import jenkins.branch.DefaultBranchPropertyStrategy;
import jenkins.plugins.git.GitSCMSource;
import jenkins.scm.api.SCMSource;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
@ -27,7 +24,7 @@ import static org.junit.Assert.assertEquals;
/**
* @author Ivan Meredith
*/
public class AbstractRunImplTest extends BaseTest {
public class AbstractRunImplTest extends PipelineBaseTest {
@Rule
public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
@ -66,7 +63,7 @@ public class AbstractRunImplTest extends BaseTest {
j.waitForCompletion(job1.getLastBuild());
Map r = request().get("/organizations/jenkins/pipelines/pipeline1/runs/3/").build(Map.class);
Assert.assertEquals(r.get("commitId"), new PipelineRunImpl(b2,null).getCommitId());
assertEquals(r.get("commitId"), new PipelineRunImpl(b2,null).getCommitId());
}
@Test
@ -113,6 +110,6 @@ public class AbstractRunImplTest extends BaseTest {
WorkflowRun replayedRun = (WorkflowRun)item.getFuture().get();
Map r = request().get("/organizations/jenkins/pipelines/p/branches/master/runs/"+replayedRun.getNumber()+"/").build(Map.class);
Assert.assertEquals(new PipelineRunImpl(b1,null).getCommitId(), r.get("commitId"));
assertEquals(new PipelineRunImpl(b1,null).getCommitId(), r.get("commitId"));
}
}

View File

@ -0,0 +1,135 @@
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.FreeStyleProject;
import hudson.model.Project;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.MockFolder;
import java.io.IOException;
import java.util.List;
/**
* @author Vivek Pandey
*/
public class LinkResolverTest extends PipelineBaseTest {
@Override
public void setup() throws Exception {
super.setup();
}
@Test
public void nestedFolderJobLinkResolveTest() throws IOException {
Project f = j.createFreeStyleProject("fstyle1");
MockFolder folder1 = j.createFolder("folder1");
Project p1 = folder1.createProject(FreeStyleProject.class, "test1");
MockFolder folder2 = folder1.createProject(MockFolder.class, "folder2");
MockFolder folder3 = folder2.createProject(MockFolder.class, "folder3");
Project p2 = folder2.createProject(FreeStyleProject.class, "test2");
Project p3 = folder3.createProject(FreeStyleProject.class, "test3");
WorkflowJob pipelineJob1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
pipelineJob1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n"));
WorkflowJob pipelineJob2 = folder2.createProject(WorkflowJob.class, "pipeline2");
pipelineJob2.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n"));
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/pipeline1/",LinkResolver.resolveLink(pipelineJob1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/pipeline2/",LinkResolver.resolveLink(pipelineJob2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/fstyle1/",LinkResolver.resolveLink(f).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/",LinkResolver.resolveLink(folder1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/test1/",LinkResolver.resolveLink(p1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/",LinkResolver.resolveLink(folder2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/test2/",LinkResolver.resolveLink(p2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/",LinkResolver.resolveLink(folder3).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/test3/",LinkResolver.resolveLink(p3).getHref());
}
@Test
public void resolveNodeLink() throws Exception {
{
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Not yet.'\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/%s/",
b1.getId(),nodes.get(0).getId()),
LinkResolver.resolveLink(nodes.get(0)).getHref());
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/%s/",
b1.getId(),parallelNodes.get(0).getId()),
LinkResolver.resolveLink(parallelNodes.get(0)).getHref());
PipelineNodeGraphBuilder graphBuilder = new PipelineNodeGraphBuilder(b1);
List<FlowNode> steps = graphBuilder.getAllSteps();
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/steps/%s/",
b1.getId(),steps.get(0).getId()),
LinkResolver.resolveLink(steps.get(0)).getHref());
}
}
}

View File

@ -1,15 +1,13 @@
package io.jenkins.blueocean.service.embedded;
package io.jenkins.blueocean.rest.impl.pipeline;
import com.google.common.collect.ImmutableMap;
import com.google.inject.Inject;
import hudson.Util;
import hudson.model.FreeStyleProject;
import hudson.plugins.favorite.user.FavoriteUserProperty;
import hudson.plugins.git.util.BuildData;
import hudson.scm.ChangeLogSet;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import io.jenkins.blueocean.service.embedded.rest.BranchImpl;
import io.jenkins.blueocean.service.embedded.scm.GitSampleRepoRule;
import io.jenkins.blueocean.rest.impl.pipeline.scm.GitSampleRepoRule;
import jenkins.branch.BranchProperty;
import jenkins.branch.BranchSource;
import jenkins.branch.DefaultBranchPropertyStrategy;
@ -44,7 +42,7 @@ import static org.junit.Assert.*;
/**
* @author Vivek Pandey
*/
public class MultiBranchTest extends BaseTest{
public class MultiBranchTest extends PipelineBaseTest {
@ClassRule
public static BuildWatcher buildWatcher = new BuildWatcher();
@ -52,9 +50,6 @@ public class MultiBranchTest extends BaseTest{
@Rule
public GitSampleRepoRule sampleRepo = new GitSampleRepoRule();
@Inject
private LinkResolver linkResolver;
private final String[] branches={"master", "feature%2Fux-1", "feature2"};
@ -76,7 +71,6 @@ public class MultiBranchTest extends BaseTest{
@Test
public void resolveMbpLink() throws Exception {
j.jenkins.getInjector().injectMembers(this);
WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "p");
FreeStyleProject f = j.jenkins.createProject(FreeStyleProject.class, "f");
mp.getSourcesList().add(new BranchSource(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", false),
@ -89,11 +83,11 @@ public class MultiBranchTest extends BaseTest{
j.waitUntilNoActivity();
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/",linkResolver.resolve(mp).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/master/",linkResolver.resolve(mp.getBranch("master")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature%252Fux-1/",linkResolver.resolve(mp.getBranch("feature%2Fux-1")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature2/",linkResolver.resolve(mp.getBranch("feature2")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/f/",linkResolver.resolve(f).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/",LinkResolver.resolveLink(mp).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/master/",LinkResolver.resolveLink(mp.getBranch("master")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature%252Fux-1/",LinkResolver.resolveLink(mp.getBranch("feature%2Fux-1")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/p/branches/feature2/",LinkResolver.resolveLink(mp.getBranch("feature2")).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/f/",LinkResolver.resolveLink(f).getHref());
}
@ -590,6 +584,25 @@ public class MultiBranchTest extends BaseTest{
}
@Test
public void getPipelinesTest() throws Exception {
WorkflowMultiBranchProject mp = j.jenkins.createProject(WorkflowMultiBranchProject.class, "p");
mp.getSourcesList().add(new BranchSource(new GitSCMSource(null, sampleRepo.toString(), "", "*", "", false),
new DefaultBranchPropertyStrategy(new BranchProperty[0])));
for (SCMSource source : mp.getSCMSources()) {
assertEquals(mp, source.getOwner());
}
WorkflowJob p = scheduleAndFindBranchProject(mp, "master");
j.waitUntilNoActivity();
List<Map> responses = get("/search/?q=type:pipeline;excludedFromFlattening:jenkins.branch.MultiBranchProject", List.class);
Assert.assertEquals(1, responses.size());
}
private void setupScm() throws Exception {
// create git repo

View File

@ -0,0 +1,185 @@
package io.jenkins.blueocean.rest.impl.pipeline;
import com.mashape.unirest.http.HttpResponse;
import hudson.model.FreeStyleBuild;
import hudson.model.FreeStyleProject;
import hudson.model.Result;
import hudson.model.Run;
import hudson.tasks.Shell;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.junit.Assert;
import org.junit.Test;
import org.kohsuke.stapler.AcceptHeader;
import java.io.IOException;
import java.util.List;
import java.util.Map;
/**
* @author Vivek Pandey
*/
public class PipelineApiTest extends PipelineBaseTest {
@Test
public void getPipelineRunStopTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" sh('sleep 60') " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).waitForStart();
Map r=null;
for (int i = 0; i < 10; i++) {
r = request().put("/organizations/jenkins/pipelines/pipeline1/runs/1/stop")
.build(Map.class);
if(((String) r.get("state")).equalsIgnoreCase("FINISHED"))
continue;
Thread.sleep(1000);
}
Assert.assertEquals(r.get("state"), "FINISHED");
Assert.assertEquals(r.get("result"), "ABORTED");
j.assertBuildStatus(Result.ABORTED, b1);
FreeStyleProject p = j.createFreeStyleProject("pipeline5");
p.getBuildersList().add(new Shell("echo hello!\nsleep 69"));
FreeStyleBuild b2 = p.scheduleBuild2(0).waitForStart();
for (int i = 0; i < 10; i++) {
r = put("/organizations/jenkins/pipelines/pipeline5/runs/1/stop",null);
if(((String) r.get("state")).equalsIgnoreCase("finished"))
continue;
Thread.sleep(1000);
}
Assert.assertEquals(r.get("state"), "FINISHED");
Assert.assertEquals(r.get("result"), "ABORTED");
j.assertBuildStatus(Result.ABORTED, b2);
}
@Test
public void getPipelineJobsTest() throws IOException {
WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "pipeline2");
List<Map> resp = get("/organizations/jenkins/pipelines/", List.class);
WorkflowJob[] projects = {p1,p2};
Assert.assertEquals(projects.length, resp.size());
for(int i=0; i<projects.length; i++){
Map lr = resp.get(i);
validatePipeline(projects[i], lr);
}
}
@Test
public void getPipelineJobRunTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
Map resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1");
validateRun(b1, resp);
}
@Test
public void getPipelineJobAbortTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" sh('sleep 60') " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).waitForStart();
for (int i = 0; i < 10; i++) {
b1.doStop();
if (b1.getResult() != null) {
break;
}
Thread.sleep(1000);
}
j.assertBuildStatus(Result.ABORTED, b1);
Map r = get("/organizations/jenkins/pipelines/pipeline1/runs/1");
validateRun(b1, r);
}
@Test
public void getPipelineJobRunsTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
WorkflowRun b2 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b2);
Run[] runs = {b2,b1};
List<Map> runResponses = get("/organizations/jenkins/pipelines/pipeline1/runs", List.class);
for(int i=0; i < runs.length; i++){
validateRun(runs[i], runResponses.get(i));
};
}
@Test
public void getPipelineJobRunsLogTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
HttpResponse<String> response = get("/organizations/jenkins/pipelines/pipeline1/runs/"+b1.getId()+"/log?start=0", 200,HttpResponse.class);
AcceptHeader acceptHeader = new AcceptHeader(response.getHeaders().getFirst("Content-Type"));
Assert.assertNotNull(acceptHeader.select("text/plain"));
int size = Integer.parseInt(response.getHeaders().getFirst("X-Text-Size"));
System.out.println(response.getBody());
Assert.assertTrue(size > 0);
}
}

View File

@ -0,0 +1,467 @@
package io.jenkins.blueocean.rest.impl.pipeline;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.base.Strings;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.ObjectMapper;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.HttpRequest;
import com.mashape.unirest.request.HttpRequestWithBody;
import hudson.Util;
import hudson.model.Job;
import hudson.model.Run;
import io.jenkins.blueocean.commons.JsonConverter;
import jenkins.branch.MultiBranchProject;
import org.jenkinsci.plugins.workflow.actions.ThreadNameAction;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.jvnet.hudson.test.JenkinsRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.LogManager;
/**
* @author Vivek Pandey
*/
public abstract class PipelineBaseTest{
private static final Logger LOGGER = LoggerFactory.getLogger(PipelineBaseTest.class);
@Rule
public JenkinsRule j = new JenkinsRule();
protected String baseUrl;
protected String getContextPath(){
return "blue/rest";
}
@Before
public void setup() throws Exception {
if(System.getProperty("DISABLE_HTTP_HEADER_TRACE") == null) {
InputStream is = this.getClass().getResourceAsStream("/logging.properties");
LogManager.getLogManager().readConfiguration(is);
}
this.baseUrl = j.jenkins.getRootUrl() + getContextPath();
Unirest.setObjectMapper(new ObjectMapper() {
public <T> T readValue(String value, Class<T> valueType) {
try {
if(value.isEmpty()){
value = "{}";
}
T r = JsonConverter.om.readValue(value, valueType);
LOGGER.info("Response:\n"+JsonConverter.om.writeValueAsString(r));
return r;
} catch (IOException e) {
LOGGER.info("Failed to parse JSON: "+value+". "+e.getMessage());
throw new RuntimeException(e);
}
}
public String writeValue(Object value) {
try {
String str = JsonConverter.om.writeValueAsString(value);
LOGGER.info("Request:\n"+str);
return str;
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
});
// HttpClientParams params = new HttpClientParams();
//
// HttpClient client = new HttpClient();
// Unirest.setHttpClient();
}
protected <T> T get(String path, Class<T> type){
return get(path,200, type);
}
protected Map<String, Object> get(String path){
return get(path,200, Map.class);
}
@SuppressWarnings("unchecked")
protected <T> T get(String path, int expectedStatus, Class<T> type){
assert path.startsWith("/");
return get(path, expectedStatus, "*/*", type);
}
@SuppressWarnings("unchecked")
protected <T> T get(String path, int expectedStatus, String accept, Class<T> type){
assert path.startsWith("/");
try {
if(HttpResponse.class.isAssignableFrom(type)){
HttpResponse<String> response = Unirest.get(getBaseUrl(path)).header("Accept", accept)
.header("Accept-Encoding","")
.asString();
Assert.assertEquals(expectedStatus, response.getStatus());
return (T) response;
}
HttpResponse<T> response = Unirest.get(getBaseUrl(path)).header("Accept", accept).asObject(type);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
LOGGER.error(e.getMessage());
throw new RuntimeException(e);
}
}
protected Map delete(String path){
assert path.startsWith("/");
try {
HttpResponse<Map> response = Unirest.delete(getBaseUrl(path)).asObject(Map.class);
Assert.assertEquals(200, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected Map<String, Object> post(String path, Object body) {
return post(path,body,200);
}
@SuppressWarnings("unchecked")
protected Map<String, Object> post(String path, Object body, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<Map> response = Unirest.post(getBaseUrl(path))
.header("Content-Type","application/json")
.body(body).asObject(Map.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected String post(String path, String body, String contentType, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<String> response = Unirest.post(getBaseUrl(path))
.header("Content-Type",contentType)
.header("Accept-Encoding","")
.body(body).asObject(String.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected Map<String, Object> put(String path, Object body) {
return put(path, body, 200);
}
@SuppressWarnings("unchecked")
protected Map<String, Object> put(String path, Object body, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<Map> response = Unirest.put(getBaseUrl(path))
.header("Content-Type","application/json")
.header("Accept","application/json")
//Unirest by default sets accept-encoding to gzip but stapler is sending malformed gzip value if
// the response length is small (in this case its 20 chars).
// Needs investigation in stapler to see whats going on there.
// For time being gzip compression is disabled
.header("Accept-Encoding","")
.body(body).asObject(Map.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected String put(String path, String body, String contentType, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<String> response = Unirest.put(getBaseUrl(path))
.header("Content-Type",contentType)
.body(body).asObject(String.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected Map<String, Object> patch(String path, Object body) {
return patch(path, body, 200);
}
@SuppressWarnings("unchecked")
protected Map<String, Object> patch(String path, Object body, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<Map> response = Unirest.patch(getBaseUrl(path))
.header("Content-Type","application/json")
.body(body).asObject(Map.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected String patch(String path, String body, String contentType, int expectedStatus){
assert path.startsWith("/");
try {
HttpResponse<String> response = Unirest.patch(getBaseUrl(path))
.header("Content-Type",contentType)
.body(body).asObject(String.class);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches){
validateMultiBranchPipeline(p, resp, numBranches, -1, -1);
}
protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches, int numSuccBranches, int numOfFailingBranches){
Assert.assertEquals("jenkins", resp.get("organization"));
Assert.assertEquals(p.getName(), resp.get("name"));
Assert.assertEquals(p.getDisplayName(), resp.get("displayName"));
Assert.assertNull(resp.get("lastSuccessfulRun"));
Assert.assertEquals(numBranches, resp.get("totalNumberOfBranches"));
if(numOfFailingBranches >= 0) {
Assert.assertEquals(numOfFailingBranches, resp.get("numberOfFailingBranches"));
}
if(numSuccBranches >= 0) {
Assert.assertEquals(numSuccBranches, resp.get("numberOfSuccessfulBranches"));
}
Assert.assertEquals(p.getBuildHealth().getScore(), resp.get("weatherScore"));
}
protected void validatePipeline(Job p, Map resp){
Assert.assertEquals("jenkins", resp.get("organization"));
Assert.assertEquals(p.getName(), resp.get("name"));
Assert.assertEquals(p.getDisplayName(), resp.get("displayName"));
Assert.assertEquals(p.getFullName(), resp.get("fullName"));
Assert.assertEquals(p.getBuildHealth().getScore(), resp.get("weatherScore"));
if(p.getLastSuccessfulBuild() != null){
Run b = p.getLastSuccessfulBuild();
String s = baseUrl + "/organizations/jenkins/pipelines/" +
p.getName() + "/runs/" + b.getId()+"/";
if(p instanceof WorkflowJob && p.getParent() instanceof MultiBranchProject){
s = baseUrl + "/organizations/jenkins/pipelines/" +
((MultiBranchProject) p.getParent()).getName() +"/branches/"+ Util.rawEncode(p.getName())+"/runs/" + b.getId()+"/";
}
Assert.assertEquals(s, resp.get("lastSuccessfulRun"));
}else{
Assert.assertNull(resp.get("lastSuccessfulRun"));
}
if(p.getLastBuild() != null){
Run r = p.getLastBuild();
validateRun(r, (Map) resp.get("latestRun"), "FINISHED");
}else{
Assert.assertNull(resp.get("latestRun"));
}
}
protected void validateRun(Run r, Map resp){
validateRun(r,resp, "FINISHED");
}
protected void validateRun(Run r, Map resp, String state){
Assert.assertNotNull(resp);
Assert.assertEquals(r.getId(), resp.get("id"));
Assert.assertEquals("jenkins", resp.get("organization"));
Assert.assertEquals(r.getParent().getName(), resp.get("pipeline"));
Assert.assertEquals(new SimpleDateFormat(JsonConverter.DATE_FORMAT_STRING)
.format(new Date(r.getStartTimeInMillis())), resp.get("startTime"));
Assert.assertEquals(r.getResult().toString(), resp.get("result"));
Assert.assertEquals(state, resp.get("state"));
}
protected String getNodeName(FlowNode n){
return n.getAction(ThreadNameAction.class) != null
? n.getAction(ThreadNameAction.class).getThreadName()
: n.getDisplayName();
}
private String getBaseUrl(String path){
return baseUrl + path;
}
protected List<FlowNode> getStages(FlowGraphTable nodeGraphTable){
List<FlowNode> nodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isStage(row.getNode()) ||
PipelineNodeUtil.isParallelBranch(row.getNode())){
nodes.add(row.getNode());
}
}
return nodes;
}
protected String getHrefFromLinks(Map resp, String link){
Map links = (Map) resp.get("_links");
if(links == null){
return null;
}
Map l = (Map)links.get(link);
if(l == null){
return null;
}
return (String) l.get("href");
}
protected List<FlowNode> getParallelNodes(FlowGraphTable nodeGraphTable){
List<FlowNode> parallelNodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isParallelBranch(row.getNode())){
parallelNodes.add(row.getNode());
}
}
return parallelNodes;
}
public RequestBuilder request() {
return new RequestBuilder(baseUrl);
}
public static class RequestBuilder {
private String url;
private String username;
private String method;
private String password;
private Map data;
private String contentType = "application/json";
private String baseUrl;
private int expectedStatus = 200;
private String getBaseUrl(String path){
return baseUrl + path;
}
public RequestBuilder status(int status) {
this.expectedStatus = status;
return this;
}
public RequestBuilder(String baseUrl) {
this.baseUrl = baseUrl;
}
public RequestBuilder url(String url) {
this.url = url;
return this;
}
public RequestBuilder auth(String username, String password) {
this.username = username;
this.password = password;
return this;
}
public RequestBuilder authAlice() {
this.username = "alice";
this.password = "alice";
return this;
}
public RequestBuilder data(Map data) {
this.data = data;
return this;
}
public RequestBuilder contentType(String contentType) {
this.contentType = contentType;
return this;
}
public RequestBuilder put(String url) {
this.url = url;
this.method = "PUT";
return this;
}
public RequestBuilder get(String url) {
this.url = url;
this.method = "GET";
return this;
}
public RequestBuilder post(String url) {
this.url = url;
this.method = "POST";
return this;
}
public RequestBuilder delete(String url) {
this.url = url;
this.method = "DELETE";
return this;
}
public <T> T build(Class<T> clzzz) {
assert url != null;
assert url.startsWith("/");
try {
HttpRequest request;
switch (method) {
case "PUT":
request = Unirest.put(getBaseUrl(url));
break;
case "POST":
request = Unirest.post(getBaseUrl(url));
break;
case "GET":
request = Unirest.get(getBaseUrl(url));
break;
case "DELETE":
request = Unirest.delete(getBaseUrl(url));
break;
default:
throw new RuntimeException("No default options");
}
request.header("Accept-Encoding","");
request.header("Content-Type", contentType);
if(!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)){
request.basicAuth(username, password);
}
if(request instanceof HttpRequestWithBody && data != null) {
((HttpRequestWithBody)request).body(data);
}
HttpResponse<T> response = request.asObject(clzzz);
Assert.assertEquals(expectedStatus, response.getStatus());
return response.getBody();
} catch (UnirestException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@ -1,8 +1,6 @@
package io.jenkins.blueocean.service.embedded;
package io.jenkins.blueocean.rest.impl.pipeline;
import hudson.model.Result;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeGraphBuilder;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeUtil;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
@ -22,7 +20,7 @@ import static org.junit.Assert.assertNotNull;
/**
* @author Vivek Pandey
*/
public class PipelineNodeTest extends BaseTest {
public class PipelineNodeTest extends PipelineBaseTest {
//TODO: Enable this test if there is way to determine when test starts running and not waiting till launched
// @Test

View File

@ -0,0 +1,71 @@
/*
* The MIT License
*
* Copyright 2015 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.jenkins.blueocean.rest.impl.pipeline.scm;
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public abstract class AbstractSampleDVCSRepoRule extends AbstractSampleRepoRule {
protected File sampleRepo;
@Override protected void before() throws Throwable {
super.before();
sampleRepo = tmp.newFolder();
}
public final void write(String rel, String text) throws IOException {
FileUtils.write(new File(sampleRepo, rel), text);
}
@Override public final String toString() {
return sampleRepo.getAbsolutePath();
}
public abstract void init() throws Exception;
protected final void run(String tool, String... cmds) throws Exception {
List<String> args = new ArrayList<String>();
args.add(tool);
args.addAll(Arrays.asList(cmds));
run(false, sampleRepo, args.toArray(new String[args.size()]));
}
public final String bareUrl() throws UnsupportedEncodingException {
return URLEncoder.encode(toString(), "UTF-8");
}
public final String fileUrl() {
return sampleRepo.toURI().toString();
}
}

View File

@ -0,0 +1,84 @@
/*
* The MIT License
*
* Copyright 2015 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.jenkins.blueocean.rest.impl.pipeline.scm;
import hudson.triggers.SCMTrigger;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.rules.ExternalResource;
import org.junit.rules.TemporaryFolder;
import org.jvnet.hudson.test.JenkinsRule;
import java.io.File;
import java.util.Arrays;
import static org.hamcrest.Matchers.is;
public abstract class AbstractSampleRepoRule extends ExternalResource {
public static void run(boolean probing, File cwd, String... cmds) throws Exception {
try {
ProcessBuilder pb = new ProcessBuilder(cmds);
try {
ProcessBuilder.class.getMethod("inheritIO").invoke(pb);
} catch (NoSuchMethodException x) {
// TODO remove when Java 7+
}
int r = pb.directory(cwd).start().waitFor();
String message = Arrays.toString(cmds) + " failed with error code";
if (probing) {
Assume.assumeThat(message, r, is(0));
} else {
Assert.assertThat(message, r, is(0));
}
} catch (Exception x) {
if (probing) {
Assume.assumeNoException(Arrays.toString(cmds) + " failed with exception (required tooling not installed?)", x);
} else {
throw x;
}
}
}
protected final TemporaryFolder tmp;
protected AbstractSampleRepoRule() {
this.tmp = new TemporaryFolder();
}
@Override protected void before() throws Throwable {
tmp.create();
}
@Override protected void after() {
tmp.delete();
}
/** Otherwise {@link JenkinsRule#waitUntilNoActivity()} is ineffective when we have just pinged a commit notification endpoint. */
protected final void synchronousPolling(JenkinsRule r) {
r.jenkins.getDescriptorByType(SCMTrigger.DescriptorImpl.class).synchronousPolling = true;
}
}

View File

@ -0,0 +1,60 @@
/*
* The MIT License
*
* Copyright 2015 CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package io.jenkins.blueocean.rest.impl.pipeline.scm;
import com.gargoylesoftware.htmlunit.WebResponse;
import com.gargoylesoftware.htmlunit.util.NameValuePair;
import org.jvnet.hudson.test.JenkinsRule;
/**
* Manages a sample Git repository.
*/
public final class GitSampleRepoRule extends AbstractSampleDVCSRepoRule {
public void git(String... cmds) throws Exception {
run("git", cmds);
}
@Override public void init() throws Exception {
run(true, tmp.getRoot(), "git", "version");
git("init");
write("file", "");
git("add", "file");
git("commit", "--message=init");
}
public void notifyCommit(JenkinsRule r) throws Exception {
synchronousPolling(r);
WebResponse webResponse = r.createWebClient().goTo("git/notifyCommit?url=" + bareUrl(), "text/plain").getWebResponse();
System.out.println(webResponse.getContentAsString());
for (NameValuePair pair : webResponse.getResponseHeaders()) {
if (pair.getName().equals("Triggered")) {
System.out.println("Triggered: " + pair.getValue());
}
}
r.waitUntilNoActivity();
}
}

View File

@ -0,0 +1,7 @@
.level = INFO
handlers=java.util.logging.ConsoleHandler
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.level = ALL
org.apache.http.wire.level = FINE

View File

@ -39,7 +39,11 @@
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-rest-impl</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-pipeline-api-impl</artifactId>
</dependency>
<!-- Test deps -->
<dependency>
<groupId>${project.groupId}</groupId>
@ -53,7 +57,7 @@
<artifactId>unirest-java</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@ -102,6 +106,7 @@
linkHPI('blueocean-rest');
linkHPI('blueocean-commons');
linkHPI('blueocean-rest-impl');
linkHPI('blueocean-pipeline-api-impl')
</source>
</configuration>
</plugin>

View File

@ -23,84 +23,13 @@
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>mailer</artifactId>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.3</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
<version>2.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-multibranch</artifactId>
<version>2.8</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>git</artifactId>
<version>2.4.2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>scm-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-durable-task-step</artifactId>
<version>2.0</version>
</dependency>
<!-- Not needed by blueocean runtime but adds to blueocean experience -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>github-branch-source</artifactId>
<version>1.8.1</version>
</dependency>
<!-- Test plugins -->
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-stage-step</artifactId>
<version>2.1-beta-1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-scm-step</artifactId>
<version>2.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>structs</artifactId>
@ -123,6 +52,20 @@
<version>1.12.1</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>matrix-project</artifactId>
<version>1.6</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>junit</artifactId>
<version>1.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@ -6,7 +6,6 @@ import com.google.inject.Module;
import hudson.Extension;
import hudson.model.RootAction;
import io.jenkins.blueocean.BlueOceanUI;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import org.kohsuke.stapler.StaplerProxy;
/**
@ -49,7 +48,6 @@ public class BlueOceanRootAction implements RootAction, StaplerProxy {
@Override
public void configure(Binder binder) {
binder.bind(BlueOceanUI.class).toInstance(new BlueOceanUI(URL_BASE));
binder.bind(LinkResolver.class).to(LinkResolverImpl.class);
}
}
}

View File

@ -1,31 +1,25 @@
package io.jenkins.blueocean.service.embedded;
import hudson.Extension;
import hudson.model.Item;
import hudson.model.ItemGroup;
import hudson.model.Job;
import hudson.model.Queue;
import hudson.model.Run;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeUtil;
import org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
/**
* Implementation of {@link LinkResolver}
*
* @author Kohsuke Kawaguchi
* @author Vivek Pandey
*/
@Extension
public class LinkResolverImpl extends LinkResolver {
private final Logger logger = LoggerFactory.getLogger(LinkResolverImpl.class);
@ -48,18 +42,6 @@ public class LinkResolverImpl extends LinkResolver {
if(resource != null){
return resource.getLink();
}
}else if(modelObject instanceof FlowNode){
FlowNode flowNode = (FlowNode) modelObject;
BlueRun r = resolveFlowNodeRun(flowNode);
if(PipelineNodeUtil.isParallelBranch(flowNode) || PipelineNodeUtil.isStage(flowNode)){ // its Node
if(r != null){
return r.getLink().rel("nodes/"+flowNode.getId());
}
}else if(flowNode instanceof StepAtomNode && !PipelineNodeUtil.isStage(flowNode)) {
if(r != null){
return r.getLink().rel("steps/"+flowNode.getId());
}
}
}
return null;
}
@ -81,18 +63,4 @@ public class LinkResolverImpl extends LinkResolver {
return null;
}
private BlueRun resolveFlowNodeRun(FlowNode flowNode){
try {
Queue.Executable executable = flowNode.getExecution().getOwner().getExecutable();
if(executable!= null && executable instanceof WorkflowRun){
WorkflowRun run = (WorkflowRun) executable;
return (BlueRun) resolveRun(run);
}
} catch (IOException e) {
logger.error(e.getMessage(), e);
return null;
}
return null;
}
}

View File

@ -1,11 +1,9 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.model.Action;
import hudson.model.FreeStyleBuild;
import hudson.model.Queue;
import hudson.model.Run;
import hudson.plugins.git.util.BuildData;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
@ -16,10 +14,7 @@ import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.Container;
import io.jenkins.blueocean.rest.model.Containers;
import io.jenkins.blueocean.rest.model.GenericResource;
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.export.Exported;
import java.util.Collection;
import java.util.Date;
@ -134,20 +129,7 @@ public class AbstractRunImpl<T extends Run> extends BlueRun {
@Override
public BlueQueueItem replay() {
ReplayAction replayAction = run.getAction(ReplayAction.class);
if(replayAction == null) {
throw new ServiceException.BadRequestExpception("This run does not support replay");
}
Queue.Item item = replayAction.run2(replayAction.getOriginalScript(), replayAction.getOriginalLoadedScripts());
BlueQueueItem queueItem = QueueContainerImpl.getQueuedItem(item, run.getParent());
if(queueItem == null) {
throw new ServiceException.UnexpectedErrorException("Run was not added to queue.");
} else {
return queueItem;
}
return null;
}
@Override
@ -200,28 +182,14 @@ public class AbstractRunImpl<T extends Run> extends BlueRun {
return PipelineImpl.getActionProxies(run.getAllActions(), this);
}
protected static BlueRun getBlueRun(Run r, Link parent){
//TODO: We need to take care several other job types
if (r instanceof FreeStyleBuild) {
return new FreeStyleRunImpl((FreeStyleBuild)r, parent);
}else if(r instanceof WorkflowRun){
return new PipelineRunImpl((WorkflowRun)r, parent);
}else{
return new AbstractRunImpl<>(r, parent);
}
}
@Exported(name = "commitId")
public String getCommitId(){
BuildData data = run.getAction(BuildData.class);
if(data == null
|| data.getLastBuiltRevision() == null
|| data.getLastBuiltRevision().getSha1String() == null) {
return null;
} else {
return data.getLastBuiltRevision().getSha1String();
protected static BlueRun getBlueRun(Run r, Reachable parent){
for(BlueRunFactory runFactory:BlueRunFactory.all()){
BlueRun blueRun = runFactory.getRun(r,parent);
if(blueRun != null){
return blueRun;
}
}
return new AbstractRunImpl<>(r, parent.getLink());
}
@Override

View File

@ -0,0 +1,27 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Run;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.model.BlueRun;
/**
* Factory that gives instance of {@link BlueRun}
*
* @author Vivek Pandey
*/
public abstract class BlueRunFactory implements ExtensionPoint {
/**
* Gives instance of {@link BlueRun} that this factory knows about
* @param run Jenkins run model object
* @param parent {@link Reachable} parent. This is to be used to create this BlueRun instance's Link.
* @return null if it doesn't knows about this instance of run object, otherwise instance of BlueRun
*/
public abstract BlueRun getRun(Run run, Reachable parent);
public static ExtensionList<BlueRunFactory> all(){
return ExtensionList.lookup(BlueRunFactory.class);
}
}

View File

@ -1,8 +1,11 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.Extension;
import hudson.model.FreeStyleBuild;
import hudson.model.Run;
import hudson.scm.ChangeLogSet;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
import io.jenkins.blueocean.rest.model.BlueRun;
@ -45,4 +48,15 @@ public class FreeStyleRunImpl extends AbstractRunImpl<FreeStyleBuild> {
throw new ServiceException.UnexpectedErrorException("Error while trying to stop run", e);
}
}
@Extension
public static class FactoryImpl extends BlueRunFactory{
@Override
public BlueRun getRun(Run run, Reachable parent) {
if (run instanceof FreeStyleBuild) {
return new FreeStyleRunImpl((FreeStyleBuild)run, parent.getLink());
}
return null;
}
}
}

View File

@ -60,7 +60,7 @@ public class PipelineContainerImpl extends BluePipelineContainer {
return getPipelines(itemGroup.getItems());
}
protected Iterator<BluePipeline> getPipelines(Collection<? extends Item> items){
public Iterator<BluePipeline> getPipelines(Collection<? extends Item> items){
List<BluePipeline> pipelines = new ArrayList<>();
for (Item item : items) {
BluePipeline pipeline = get(item);

View File

@ -6,6 +6,7 @@ import hudson.model.ItemGroup;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueFavorite;
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
@ -13,14 +14,11 @@ import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BluePipelineContainer;
import io.jenkins.blueocean.rest.model.BluePipelineFolder;
import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import org.kohsuke.stapler.json.JsonBody;
import java.util.Collection;
import java.util.Collections;
import static io.jenkins.blueocean.service.embedded.rest.PipelineImpl.getRecursivePathFromFullName;
/**
* @author Vivek Pandey
*/
@ -99,7 +97,7 @@ public class PipelineFolderImpl extends BluePipelineFolder {
@Override
public Link getLink() {
return OrganizationImpl.INSTANCE.getLink().rel("pipelines").rel(getRecursivePathFromFullName(this));
return OrganizationImpl.INSTANCE.getLink().rel("pipelines").rel(PipelineImpl.getRecursivePathFromFullName(this));
}
@Extension(ordinal = 0)

View File

@ -8,6 +8,7 @@ import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.Navigable;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import io.jenkins.blueocean.rest.model.BlueActionProxy;
import io.jenkins.blueocean.rest.model.BlueFavorite;
import io.jenkins.blueocean.rest.model.BlueFavoriteAction;
@ -16,7 +17,6 @@ import io.jenkins.blueocean.rest.model.BlueQueueContainer;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.BlueRunContainer;
import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.util.FavoriteUtil;
import org.kohsuke.stapler.Stapler;
import org.kohsuke.stapler.WebMethod;
import org.kohsuke.stapler.json.JsonBody;
@ -62,7 +62,7 @@ public class PipelineImpl extends BluePipeline {
if(job.getLastBuild() == null){
return null;
}
return AbstractRunImpl.getBlueRun(job.getLastBuild(), this.getLink());
return AbstractRunImpl.getBlueRun(job.getLastBuild(), this);
}
@Override
@ -128,7 +128,7 @@ public class PipelineImpl extends BluePipeline {
return OrganizationImpl.INSTANCE.getLink().rel("pipelines").rel(getRecursivePathFromFullName(this));
}
protected static String getRecursivePathFromFullName(BluePipeline pipeline){
public static String getRecursivePathFromFullName(BluePipeline pipeline){
StringBuilder pipelinePath = new StringBuilder();
String[] names = pipeline.getFullName().split("/");
int count = 1;

View File

@ -1,60 +0,0 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.scm.ChangeLogSet;
import hudson.scm.ChangeLogSet.Entry;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueChangeSetEntry;
import io.jenkins.blueocean.rest.model.BluePipelineNodeContainer;
import io.jenkins.blueocean.rest.model.BluePipelineStepContainer;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.Container;
import io.jenkins.blueocean.rest.model.Containers;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Pipeline Run
*
* @author Vivek Pandey
*/
public class PipelineRunImpl extends AbstractRunImpl<WorkflowRun> {
public PipelineRunImpl(WorkflowRun run, Link parent) {
super(run, parent);
}
@Override
public Container<BlueChangeSetEntry> getChangeSet() {
Map<String, BlueChangeSetEntry> m = new LinkedHashMap<>();
int cnt = 0;
for (ChangeLogSet<? extends Entry> cs : run.getChangeSets()) {
for (ChangeLogSet.Entry e : cs) {
cnt++;
String id = e.getCommitId();
if (id == null) id = String.valueOf(cnt);
m.put(id, new ChangeSetResource(e, this));
}
}
return Containers.fromResourceMap(getLink(),m);
}
@Override
public BluePipelineNodeContainer getNodes() {
if (run != null) {
return new PipelineNodeContainerImpl(run, getLink());
}
return null;
}
@Override
public BluePipelineStepContainer getSteps() {
return new PipelineStepContainerImpl(null, new PipelineNodeGraphBuilder(run), getLink());
}
@Override
public BlueRun stop() {
run.doStop();
return this;
}
}

View File

@ -1,6 +1,7 @@
package io.jenkins.blueocean.service.embedded.rest;
import hudson.Extension;
import hudson.Plugin;
import hudson.model.Item;
import hudson.model.ItemGroup;
import io.jenkins.blueocean.commons.ServiceException;
@ -10,6 +11,8 @@ import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.pageable.Pageable;
import io.jenkins.blueocean.rest.pageable.Pageables;
import jenkins.model.Jenkins;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
@ -38,6 +41,8 @@ public class PipelineSearch extends OmniSearch<BluePipeline>{
private static final String EXCLUDED_FROM_FLATTENING_PARAM ="excludedFromFlattening";
private static final String ORGANIZATION_PARAM="organization";
private static final Logger logger = LoggerFactory.getLogger(PipelineSearch.class);
@Override
public String getType() {
return "pipeline";
@ -55,11 +60,26 @@ public class PipelineSearch extends OmniSearch<BluePipeline>{
List<Class> excludeList=new ArrayList<>();
if(s!=null){
for(String s1:s.split(",")){
Class c = null;
try {
Class c = Class.forName(s1);
excludeList.add(c);
c = Class.forName(s1);
} catch (ClassNotFoundException e) {
throw new ServiceException.BadRequestExpception(String.format("%s parameter has invalid value: %s", EXCLUDED_FROM_FLATTENING_PARAM, s1), e);
try {
//TODO: There should be better ways to find a class from a plugin.
Plugin p = Jenkins.getInstance().getPlugin("blueocean-pipeline-api-impl");
if(p != null){
c = p.getWrapper().classLoader.loadClass(s1);
}else{
logger.error("blueocean-pipeline-api-impl plugin not found!");
}
} catch (ClassNotFoundException e1) {
logger.error(e.getMessage(), e1);
}
//ignored, give other OmniSearch implementations chance, they might handle it
//throw new ServiceException.BadRequestExpception(String.format("%s parameter has invalid value: %s", EXCLUDED_FROM_FLATTENING_PARAM, s1), e);
}
if(c!=null){
excludeList.add(c);
}
}
}

View File

@ -1,6 +1,5 @@
package io.jenkins.blueocean.service.embedded.rest;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import hudson.model.BuildableItem;
import hudson.model.Job;
@ -11,9 +10,7 @@ import io.jenkins.blueocean.rest.model.BluePipeline;
import io.jenkins.blueocean.rest.model.BlueQueueContainer;
import io.jenkins.blueocean.rest.model.BlueQueueItem;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.github.util.FluentIterableWrapper;
import javax.annotation.Nullable;
import java.util.Iterator;
import java.util.List;
@ -74,13 +71,13 @@ public class QueueContainerImpl extends BlueQueueContainer {
}
public static BlueQueueItem getQueuedItem(final Queue.Item item, Job job) {
return FluentIterableWrapper.from(QueueContainerImpl.getQueuedItems(job))
.firstMatch(new Predicate<BlueQueueItem>() {
@Override
public boolean apply(@Nullable BlueQueueItem input) {
return input.getId().equalsIgnoreCase(Long.toString(item.getId()));
}
}).orNull();
for(BlueQueueItem qi:QueueContainerImpl.getQueuedItems(job)){
if(qi.getId().equalsIgnoreCase(Long.toString(item.getId()))){
return qi;
}
}
return null;
}
@Override
public Link getLink() {

View File

@ -1,6 +1,5 @@
package io.jenkins.blueocean.service.embedded.rest;
import com.google.common.base.Predicate;
import hudson.model.Cause;
import hudson.model.CauseAction;
import hudson.model.Job;
@ -14,10 +13,8 @@ import io.jenkins.blueocean.rest.model.BlueQueueItem;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.model.BlueRunContainer;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.github.util.FluentIterableWrapper;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Iterator;
/**
@ -58,7 +55,7 @@ public class RunContainerImpl extends BlueRunContainer {
} else {
run = runList.getLastBuild();
}
return AbstractRunImpl.getBlueRun(run, pipeline.getLink());
return AbstractRunImpl.getBlueRun(run, pipeline);
}
@Override

View File

@ -9,6 +9,7 @@ import hudson.util.RunList;
import io.jenkins.blueocean.commons.ServiceException;
import io.jenkins.blueocean.rest.OmniSearch;
import io.jenkins.blueocean.rest.Query;
import io.jenkins.blueocean.rest.Reachable;
import io.jenkins.blueocean.rest.hal.Link;
import io.jenkins.blueocean.rest.model.BlueRun;
import io.jenkins.blueocean.rest.pageable.Pageable;
@ -58,7 +59,7 @@ public class RunSearch extends OmniSearch<BlueRun> {
}
return Pageables.wrap(findRuns(null));
}
public static Iterable<BlueRun> findRuns(Job job, Link parent){
public static Iterable<BlueRun> findRuns(Job job, final Link parent){
final List<BlueRun> runs = new ArrayList<>();
Iterable<Job> pipelines;
if(job != null){
@ -70,7 +71,12 @@ public class RunSearch extends OmniSearch<BlueRun> {
RunList<? extends Run> runList = p.getBuilds();
for (Run r : runList) {
runs.add(AbstractRunImpl.getBlueRun(r,parent));
runs.add(AbstractRunImpl.getBlueRun(r, new Reachable() {
@Override
public Link getLink() {
return parent;
}
}));
}
}
@ -85,7 +91,7 @@ public class RunSearch extends OmniSearch<BlueRun> {
if(job != null){
Run r = job.getLastBuild();
if(r != null) {
AbstractRunImpl.getBlueRun(r, new PipelineContainerImpl().get(job.getFullName()).getLink());
AbstractRunImpl.getBlueRun(r, new PipelineContainerImpl().get(job.getFullName()));
}
}
return null;

View File

@ -84,9 +84,7 @@ public class FavoriteUtil {
}
public static BlueFavorite getFavorite(Item item){
LinkResolver linkResolver = Jenkins.getInstance().getInjector().getInstance(LinkResolver.class);
final Link l = linkResolver.resolve(item);
final Link l = LinkResolver.resolveLink(item);
if(l !=null) {
return getFavorite(item, new Reachable() {
@Override

View File

@ -8,17 +8,9 @@ import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.HttpRequest;
import com.mashape.unirest.request.HttpRequestWithBody;
import hudson.Util;
import hudson.model.Job;
import hudson.model.Run;
import io.jenkins.blueocean.commons.JsonConverter;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeUtil;
import jenkins.branch.MultiBranchProject;
import org.jenkinsci.plugins.workflow.actions.ThreadNameAction;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.multibranch.WorkflowMultiBranchProject;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
@ -29,9 +21,7 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.logging.LogManager;
@ -237,24 +227,24 @@ public abstract class BaseTest {
throw new RuntimeException(e);
}
}
protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches){
validateMultiBranchPipeline(p, resp, numBranches, -1, -1);
}
protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches, int numSuccBranches, int numOfFailingBranches){
Assert.assertEquals("jenkins", resp.get("organization"));
Assert.assertEquals(p.getName(), resp.get("name"));
Assert.assertEquals(p.getDisplayName(), resp.get("displayName"));
Assert.assertNull(resp.get("lastSuccessfulRun"));
Assert.assertEquals(numBranches, resp.get("totalNumberOfBranches"));
if(numOfFailingBranches >= 0) {
Assert.assertEquals(numOfFailingBranches, resp.get("numberOfFailingBranches"));
}
if(numSuccBranches >= 0) {
Assert.assertEquals(numSuccBranches, resp.get("numberOfSuccessfulBranches"));
}
Assert.assertEquals(p.getBuildHealth().getScore(), resp.get("weatherScore"));
}
//
// protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches){
// validateMultiBranchPipeline(p, resp, numBranches, -1, -1);
// }
// protected void validateMultiBranchPipeline(WorkflowMultiBranchProject p, Map resp, int numBranches, int numSuccBranches, int numOfFailingBranches){
// Assert.assertEquals("jenkins", resp.get("organization"));
// Assert.assertEquals(p.getName(), resp.get("name"));
// Assert.assertEquals(p.getDisplayName(), resp.get("displayName"));
// Assert.assertNull(resp.get("lastSuccessfulRun"));
// Assert.assertEquals(numBranches, resp.get("totalNumberOfBranches"));
// if(numOfFailingBranches >= 0) {
// Assert.assertEquals(numOfFailingBranches, resp.get("numberOfFailingBranches"));
// }
// if(numSuccBranches >= 0) {
// Assert.assertEquals(numSuccBranches, resp.get("numberOfSuccessfulBranches"));
// }
// Assert.assertEquals(p.getBuildHealth().getScore(), resp.get("weatherScore"));
// }
protected void validatePipeline(Job p, Map resp){
Assert.assertEquals("jenkins", resp.get("organization"));
@ -266,10 +256,7 @@ public abstract class BaseTest {
Run b = p.getLastSuccessfulBuild();
String s = baseUrl + "/organizations/jenkins/pipelines/" +
p.getName() + "/runs/" + b.getId()+"/";
if(p instanceof WorkflowJob && p.getParent() instanceof MultiBranchProject){
s = baseUrl + "/organizations/jenkins/pipelines/" +
((MultiBranchProject) p.getParent()).getName() +"/branches/"+ Util.rawEncode(p.getName())+"/runs/" + b.getId()+"/";
}
Assert.assertEquals(s, resp.get("lastSuccessfulRun"));
}else{
@ -298,38 +285,38 @@ public abstract class BaseTest {
Assert.assertEquals(state, resp.get("state"));
}
protected String getNodeName(FlowNode n){
return n.getAction(ThreadNameAction.class) != null
? n.getAction(ThreadNameAction.class).getThreadName()
: n.getDisplayName();
}
// protected String getNodeName(FlowNode n){
// return n.getAction(ThreadNameAction.class) != null
// ? n.getAction(ThreadNameAction.class).getThreadName()
// : n.getDisplayName();
// }
private String getBaseUrl(String path){
return baseUrl + path;
}
protected List<FlowNode> getStages(FlowGraphTable nodeGraphTable){
List<FlowNode> nodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isStage(row.getNode()) ||
PipelineNodeUtil.isParallelBranch(row.getNode())){
nodes.add(row.getNode());
}
}
return nodes;
}
// protected List<FlowNode> getStages(FlowGraphTable nodeGraphTable){
// List<FlowNode> nodes = new ArrayList<>();
// for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
// if(PipelineNodeUtil.isStage(row.getNode()) ||
// PipelineNodeUtil.isParallelBranch(row.getNode())){
// nodes.add(row.getNode());
// }
// }
// return nodes;
// }
protected List<FlowNode> getParallelNodes(FlowGraphTable nodeGraphTable){
List<FlowNode> parallelNodes = new ArrayList<>();
for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
if(PipelineNodeUtil.isParallelBranch(row.getNode())){
parallelNodes.add(row.getNode());
}
}
return parallelNodes;
}
// protected List<FlowNode> getParallelNodes(FlowGraphTable nodeGraphTable){
// List<FlowNode> parallelNodes = new ArrayList<>();
//
// for(FlowGraphTable.Row row: nodeGraphTable.getRows()){
// if(PipelineNodeUtil.isParallelBranch(row.getNode())){
// parallelNodes.add(row.getNode());
// }
// }
// return parallelNodes;
// }
protected String getHrefFromLinks(Map resp, String link){
Map links = (Map) resp.get("_links");

View File

@ -1,36 +1,24 @@
package io.jenkins.blueocean.service.embedded;
import com.google.inject.Inject;
import hudson.model.FreeStyleProject;
import hudson.model.Project;
import hudson.model.Run;
import io.jenkins.blueocean.rest.hal.LinkResolver;
import io.jenkins.blueocean.service.embedded.rest.PipelineNodeGraphBuilder;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.graph.FlowNode;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.jenkinsci.plugins.workflow.support.visualization.table.FlowGraphTable;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.MockFolder;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
/**
* @author Vivek Pandey
*/
public class LinkResolverTest extends BaseTest {
@Inject
private LinkResolver linkResolver;
@Override
public void setup() throws Exception {
super.setup();
j.jenkins.getInjector().injectMembers(this);
}
@Test
@ -43,32 +31,13 @@ public class LinkResolverTest extends BaseTest {
Project p2 = folder2.createProject(FreeStyleProject.class, "test2");
Project p3 = folder3.createProject(FreeStyleProject.class, "test3");
WorkflowJob pipelineJob1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
pipelineJob1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n"));
WorkflowJob pipelineJob2 = folder2.createProject(WorkflowJob.class, "pipeline2");
pipelineJob2.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n"));
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/pipeline1/",linkResolver.resolve(pipelineJob1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/pipeline2/",linkResolver.resolve(pipelineJob2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/fstyle1/",linkResolver.resolve(f).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/",linkResolver.resolve(folder1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/test1/",linkResolver.resolve(p1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/",linkResolver.resolve(folder2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/test2/",linkResolver.resolve(p2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/",linkResolver.resolve(folder3).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/test3/",linkResolver.resolve(p3).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/fstyle1/",LinkResolver.resolveLink(f).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/",LinkResolver.resolveLink(folder1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/test1/",LinkResolver.resolveLink(p1).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/",LinkResolver.resolveLink(folder2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/test2/",LinkResolver.resolveLink(p2).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/",LinkResolver.resolveLink(folder3).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/test3/",LinkResolver.resolveLink(p3).getHref());
}
@ -83,85 +52,16 @@ public class LinkResolverTest extends BaseTest {
Project p3 = folder3.createProject(FreeStyleProject.class, "test3");
Run r = (Run) f.scheduleBuild2(0).get();
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/fstyle1/runs/"+r.getId()+"/",linkResolver.resolve(r).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/fstyle1/runs/"+r.getId()+"/",LinkResolver.resolveLink(r).getHref());
r = (Run) p1.scheduleBuild2(0).get();
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/test1/runs/"+r.getId()+"/",linkResolver.resolve(r).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/test1/runs/"+r.getId()+"/",LinkResolver.resolveLink(r).getHref());
r = (Run) p2.scheduleBuild2(0).get();
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/test2/runs/"+r.getId()+"/",linkResolver.resolve(r).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/test2/runs/"+r.getId()+"/",LinkResolver.resolveLink(r).getHref());
r = (Run) p3.scheduleBuild2(0).get();
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/test3/runs/"+r.getId()+"/",linkResolver.resolve(r).getHref());
Assert.assertEquals("/blue/rest/organizations/jenkins/pipelines/folder1/pipelines/folder2/pipelines/folder3/pipelines/test3/runs/"+r.getId()+"/",LinkResolver.resolveLink(r).getHref());
}
@Test
public void resolveNodeLink() throws Exception {
{
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("stage \"Build\"\n" +
" node {\n" +
" sh \"echo here\"\n" +
" }\n" +
"\n" +
"stage \"Test\"\n" +
" parallel (\n" +
" \"Firefox\" : {\n" +
" node {\n" +
" sh \"echo ffox\"\n" +
" }\n" +
" },\n" +
" \"Chrome\" : {\n" +
" node {\n" +
" sh \"echo chrome\"\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"stage \"CrashyMcgee\"\n" +
" parallel (\n" +
" \"SlowButSuccess\" : {\n" +
" node {\n" +
" echo 'This is time well spent.'\n" +
" }\n" +
" },\n" +
" \"DelayThenFail\" : {\n" +
" node {\n" +
" echo 'Not yet.'\n" +
" }\n" +
" }\n" +
" )\n" +
"\n" +
"\n" +
"stage \"Deploy\"\n" +
" node {\n" +
" sh \"echo deploying\"\n" +
" }"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
FlowGraphTable nodeGraphTable = new FlowGraphTable(b1.getExecution());
nodeGraphTable.build();
List<FlowNode> nodes = getStages(nodeGraphTable);
List<FlowNode> parallelNodes = getParallelNodes(nodeGraphTable);
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/%s/",
b1.getId(),nodes.get(0).getId()),
linkResolver.resolve(nodes.get(0)).getHref());
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/nodes/%s/",
b1.getId(),parallelNodes.get(0).getId()),
linkResolver.resolve(parallelNodes.get(0)).getHref());
PipelineNodeGraphBuilder graphBuilder = new PipelineNodeGraphBuilder(b1);
List<FlowNode> steps = graphBuilder.getAllSteps();
Assert.assertEquals(String.format("/blue/rest/organizations/jenkins/pipelines/pipeline1/runs/%s/steps/%s/",
b1.getId(),steps.get(0).getId()),
linkResolver.resolve(steps.get(0)).getHref());
}
}
}

View File

@ -1,7 +1,6 @@
package io.jenkins.blueocean.service.embedded;
import com.google.common.collect.ImmutableMap;
import com.mashape.unirest.http.HttpResponse;
import hudson.Extension;
import hudson.FilePath;
import hudson.Launcher;
@ -16,7 +15,6 @@ import hudson.model.Job;
import hudson.model.ParametersAction;
import hudson.model.ParametersDefinitionProperty;
import hudson.model.Project;
import hudson.model.Result;
import hudson.model.Run;
import hudson.model.StringParameterDefinition;
import hudson.model.StringParameterValue;
@ -31,14 +29,10 @@ import io.jenkins.blueocean.rest.model.Resource;
import io.jenkins.blueocean.service.embedded.rest.BluePipelineFactory;
import io.jenkins.blueocean.service.embedded.rest.PipelineImpl;
import jenkins.model.Jenkins;
import org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition;
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
import org.junit.Assert;
import org.junit.Test;
import org.jvnet.hudson.test.MockFolder;
import org.jvnet.hudson.test.TestBuilder;
import org.kohsuke.stapler.AcceptHeader;
import org.kohsuke.stapler.export.Exported;
import java.io.IOException;
@ -216,48 +210,6 @@ public class PipelineApiTest extends BaseTest {
validateRun(b,resp);
}
@Test
public void getPipelineRunStopTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" sh('sleep 60') " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).waitForStart();
Map r=null;
for (int i = 0; i < 10; i++) {
r = request().put("/organizations/jenkins/pipelines/pipeline1/runs/1/stop")
.build(Map.class);
if(((String) r.get("state")).equalsIgnoreCase("FINISHED"))
continue;
Thread.sleep(1000);
}
Assert.assertEquals(r.get("state"), "FINISHED");
Assert.assertEquals(r.get("result"), "ABORTED");
j.assertBuildStatus(Result.ABORTED, b1);
FreeStyleProject p = j.createFreeStyleProject("pipeline5");
p.getBuildersList().add(new Shell("echo hello!\nsleep 69"));
FreeStyleBuild b2 = p.scheduleBuild2(0).waitForStart();
for (int i = 0; i < 10; i++) {
r = put("/organizations/jenkins/pipelines/pipeline5/runs/1/stop",null);
if(((String) r.get("state")).equalsIgnoreCase("finished"))
continue;
Thread.sleep(1000);
}
Assert.assertEquals(r.get("state"), "FINISHED");
Assert.assertEquals(r.get("result"), "ABORTED");
j.assertBuildStatus(Result.ABORTED, b2);
}
@Test
@ -293,121 +245,6 @@ public class PipelineApiTest extends BaseTest {
}
@Test
public void getPipelineJobsTest() throws IOException {
WorkflowJob p1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
WorkflowJob p2 = j.jenkins.createProject(WorkflowJob.class, "pipeline2");
List<Map> resp = get("/organizations/jenkins/pipelines/", List.class);
WorkflowJob[] projects = {p1,p2};
Assert.assertEquals(projects.length, resp.size());
for(int i=0; i<projects.length; i++){
Map lr = resp.get(i);
validatePipeline(projects[i], lr);
String cls = (String) lr.get("_class");
Assert.assertEquals(PipelineImpl.class.getName(), cls);
}
}
@Test
public void getPipelineJobRunTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
Map resp = get("/organizations/jenkins/pipelines/pipeline1/runs/1");
validateRun(b1, resp);
}
@Test
public void getPipelineJobAbortTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" sh('sleep 60') " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).waitForStart();
for (int i = 0; i < 10; i++) {
b1.doStop();
if (b1.getResult() != null) {
break;
}
Thread.sleep(1000);
}
j.assertBuildStatus(Result.ABORTED, b1);
Map r = get("/organizations/jenkins/pipelines/pipeline1/runs/1");
validateRun(b1, r);
}
@Test
public void getPipelineJobRunsTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
WorkflowRun b2 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b2);
Run[] runs = {b2,b1};
List<Map> runResponses = get("/organizations/jenkins/pipelines/pipeline1/runs", List.class);
for(int i=0; i < runs.length; i++){
validateRun(runs[i], runResponses.get(i));
};
}
@Test
public void getPipelineJobRunsLogTest() throws Exception {
WorkflowJob job1 = j.jenkins.createProject(WorkflowJob.class, "pipeline1");
job1.setDefinition(new CpsFlowDefinition("" +
"node {" +
" stage ('Build1'); " +
" echo ('Building'); " +
" stage ('Test1'); " +
" echo ('Testing'); " +
"}"));
WorkflowRun b1 = job1.scheduleBuild2(0).get();
j.assertBuildStatusSuccess(b1);
HttpResponse<String> response = get("/organizations/jenkins/pipelines/pipeline1/runs/"+b1.getId()+"/log?start=0", 200,HttpResponse.class);
AcceptHeader acceptHeader = new AcceptHeader(response.getHeaders().getFirst("Content-Type"));
Assert.assertNotNull(acceptHeader.select("text/plain"));
int size = Integer.parseInt(response.getHeaders().getFirst("X-Text-Size"));
System.out.println(response.getBody());
Assert.assertTrue(size > 0);
}
@Test
public void findPipelineRunsForAPipelineTest() throws Exception {
FreeStyleProject p1 = j.createFreeStyleProject("pipeline1");
@ -611,11 +448,11 @@ public class PipelineApiTest extends BaseTest {
Assert.assertTrue(m.isEmpty());
// get classes map for given classes in the query
resp = get("/classes/?q=io.jenkins.blueocean.service.embedded.rest.PipelineImpl,io.jenkins.blueocean.service.embedded.rest.MultiBranchPipelineImpl,"+TestPipelineImpl.class.getName());
resp = get("/classes/?q=io.jenkins.blueocean.service.embedded.rest.PipelineImpl,"+TestPipelineImpl.class.getName());
Assert.assertNotNull(resp);
m = (Map) resp.get("map");
Assert.assertNotNull(m);
Assert.assertEquals(3, m.size());
Assert.assertEquals(2, m.size());
Map v = (Map) m.get("io.jenkins.blueocean.service.embedded.rest.PipelineImpl");
Assert.assertNotNull(v);

View File

@ -1,5 +1,8 @@
package io.jenkins.blueocean.rest.hal;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
/**
*
* Resolves a {@link Link} for a given model object
@ -7,7 +10,7 @@ package io.jenkins.blueocean.rest.hal;
* @author Kohsuke Kawaguchi
* @author Vivek Pandey
*/
public abstract class LinkResolver {
public abstract class LinkResolver implements ExtensionPoint{
/**
*
@ -19,4 +22,18 @@ public abstract class LinkResolver {
* to the given model object.
*/
public abstract Link resolve(Object modelObject);
public static ExtensionList<LinkResolver> all(){
return ExtensionList.lookup(LinkResolver.class);
}
public static Link resolveLink(Object modeObject){
for(LinkResolver resolver:all()){
Link link = resolver.resolve(modeObject);
if(link != null){
return link;
}
}
return null;
}
}

View File

@ -100,6 +100,7 @@
<module>blueocean-web</module>
<module>blueocean-rest</module>
<module>blueocean-rest-impl</module>
<module>blueocean-pipeline-api-impl</module>
<module>blueocean-events</module>
<module>blueocean-dashboard</module>
<module>blueocean-personalization</module>
@ -165,6 +166,12 @@
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-pipeline-api-impl</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>blueocean-plugin</artifactId>