diff --git a/README.md b/README.md index 8d800c26..a48589de 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/blueocean-commons/pom.xml b/blueocean-commons/pom.xml index 7c8b0965..b39919b8 100644 --- a/blueocean-commons/pom.xml +++ b/blueocean-commons/pom.xml @@ -5,7 +5,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT blueocean-commons diff --git a/blueocean-dashboard/package.json b/blueocean-dashboard/package.json index 8bb1d0b0..4838c70f 100644 --- a/blueocean-dashboard/package.json +++ b/blueocean-dashboard/package.json @@ -35,7 +35,7 @@ "skin-deep": "^0.16.0" }, "dependencies": { - "@jenkins-cd/design-language": "0.0.63", + "@jenkins-cd/design-language": "0.0.64", "@jenkins-cd/js-extensions": "0.0.19", "@jenkins-cd/js-modules": "0.0.5", "@jenkins-cd/sse-gateway": "0.0.6", diff --git a/blueocean-dashboard/pom.xml b/blueocean-dashboard/pom.xml index a7f01ec0..29d137cf 100644 --- a/blueocean-dashboard/pom.xml +++ b/blueocean-dashboard/pom.xml @@ -3,7 +3,7 @@ blueocean-parent io.jenkins.blueocean - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT 4.0.0 diff --git a/blueocean-dashboard/src/main/js/Dashboard.jsx b/blueocean-dashboard/src/main/js/Dashboard.jsx index 40f03320..5ee0e4b4 100644 --- a/blueocean-dashboard/src/main/js/Dashboard.jsx +++ b/blueocean-dashboard/src/main/js/Dashboard.jsx @@ -4,12 +4,16 @@ import appConfig from './config'; const { object, node } = PropTypes; +appConfig.loadConfig(); + // Connect to the SSE Gateway and allocate a // dispatcher for blueocean. // TODO: We might want to move this code to a local SSE util module. -sse.connect('jenkins_blueocean'); - -appConfig.loadConfig(); +sse.connect({ + clientId: 'jenkins_blueocean', + onConnect: undefined, + jenkinsUrl: `${appConfig.getJenkinsRootURL()}/`, // FIXME sse should not require this to end with a / +}); class Dashboard extends Component { diff --git a/blueocean-dashboard/src/main/js/api/Pipeline.js b/blueocean-dashboard/src/main/js/api/Pipeline.js index fd9bbfed..d3f8302e 100644 --- a/blueocean-dashboard/src/main/js/api/Pipeline.js +++ b/blueocean-dashboard/src/main/js/api/Pipeline.js @@ -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 { diff --git a/blueocean-dashboard/src/main/js/components/LogConsole.jsx b/blueocean-dashboard/src/main/js/components/LogConsole.jsx index 6db45fa4..6478edc7 100644 --- a/blueocean-dashboard/src/main/js/components/LogConsole.jsx +++ b/blueocean-dashboard/src/main/js/components/LogConsole.jsx @@ -86,9 +86,8 @@ export class LogConsole extends Component { this.timeouts.render = setTimeout(() => { this._processNextLines(); }, RERENDER_DELAY); - } else { - this.scroll(); } + this.scroll(); } scroll() { @@ -100,7 +99,7 @@ export class LogConsole extends Component { * React needs the timeout to have the dom ready */ if (this.props.scrollToBottom && !match) { - this.timeouts.scroll = setTimeout(() => this.props.scrollBottom(), INITIAL_RENDER_DELAY + 1); + this.timeouts.scroll = setTimeout(() => this.props.scrollBottom(), RERENDER_DELAY + 1); } else if (match) { // we need to scroll to a certain line now this.timeouts.scroll = this.props.scrollToAnchorTimeOut(RERENDER_DELAY + 1); diff --git a/blueocean-dashboard/src/main/js/components/Pipelines.jsx b/blueocean-dashboard/src/main/js/components/Pipelines.jsx index ce2d6f95..e97d3344 100644 --- a/blueocean-dashboard/src/main/js/components/Pipelines.jsx +++ b/blueocean-dashboard/src/main/js/components/Pipelines.jsx @@ -38,7 +38,7 @@ export default class Pipelines extends Component { ]; const baseUrl = config.getRootURL(); - const newJobUrl = `${baseUrl}view/All/newJob`; + const newJobUrl = `${baseUrl}/view/All/newJob`; return ( diff --git a/blueocean-dashboard/src/main/js/components/RunDetailsPipeline.jsx b/blueocean-dashboard/src/main/js/components/RunDetailsPipeline.jsx index 98858e86..b29b263b 100644 --- a/blueocean-dashboard/src/main/js/components/RunDetailsPipeline.jsx +++ b/blueocean-dashboard/src/main/js/components/RunDetailsPipeline.jsx @@ -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 { diff --git a/blueocean-dashboard/src/main/js/components/testing/TestResults.jsx b/blueocean-dashboard/src/main/js/components/testing/TestResults.jsx index 88b66137..8475c8d4 100644 --- a/blueocean-dashboard/src/main/js/components/testing/TestResults.jsx +++ b/blueocean-dashboard/src/main/js/components/testing/TestResults.jsx @@ -116,31 +116,31 @@ export default class TestResult extends Component { ); if (newFailures.length > 0) { - newFailureBlock = [ -

New failing - {newFailures.length}

, - newFailures.map((t, i) => ), - ]; + newFailureBlock = (
+

New failing - {newFailures.length}

+ {newFailures.map((t, i) => )} +
); } if (existingFailures.length > 0) { - existingFailureBlock = [ -

Existing failures - {existingFailures.length}

, - existingFailures.map((t, i) => ), - ]; + existingFailureBlock = (
+

Existing failures - {existingFailures.length}

+ {existingFailures.map((t, i) => )} +
); } if (fixed.length > 0) { - fixedBlock = [ -

Fixed

, - fixed.map((t, i) => ), - ]; + fixedBlock = (
+

Fixed

+ {fixed.map((t, i) => )} +
); } if (skipped.length > 0) { - skippedBlock = [ -

Skipped - {skipped.length}

, - skipped.map((t, i) => ), - ]; + skippedBlock = (
+

Skipped - {skipped.length}

+ {skipped.map((t, i) => )} +
); } } diff --git a/blueocean-dashboard/src/main/less/testing.less b/blueocean-dashboard/src/main/less/testing.less index 50100dfb..5c352da3 100644 --- a/blueocean-dashboard/src/main/less/testing.less +++ b/blueocean-dashboard/src/main/less/testing.less @@ -1,9 +1,12 @@ .test-results-container { - h4 { - margin: 1em 0 .4em 0; + .test-result-block { + margin: 1em 0 0 0; &:first-child { margin-top: 0; } + h4 { + margin: 0 0 .4em 0; + } } .test-console { padding: 1em; diff --git a/blueocean-dashboard/src/test/js/data/branches/latestBranches.js b/blueocean-dashboard/src/test/js/data/branches/latestBranches.js index bb87211a..90ddbb2e 100644 --- a/blueocean-dashboard/src/test/js/data/branches/latestBranches.js +++ b/blueocean-dashboard/src/test/js/data/branches/latestBranches.js @@ -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 -}] \ No newline at end of file +}] diff --git a/blueocean-dashboard/src/test/js/data/pipelines/pipelinesTwoJobsSameName.js b/blueocean-dashboard/src/test/js/data/pipelines/pipelinesTwoJobsSameName.js index e3b30930..af607b7d 100644 --- a/blueocean-dashboard/src/test/js/data/pipelines/pipelinesTwoJobsSameName.js +++ b/blueocean-dashboard/src/test/js/data/pipelines/pipelinesTwoJobsSameName.js @@ -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", diff --git a/blueocean-dashboard/src/test/js/nodes.js b/blueocean-dashboard/src/test/js/nodes.js index a97fcfb1..bf505d47 100644 --- a/blueocean-dashboard/src/test/js/nodes.js +++ b/blueocean-dashboard/src/test/js/nodes.js @@ -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", diff --git a/blueocean-dashboard/src/test/js/push-events-actions-spec.js b/blueocean-dashboard/src/test/js/push-events-actions-spec.js index 96ed3546..56459e6b 100644 --- a/blueocean-dashboard/src/test/js/push-events-actions-spec.js +++ b/blueocean-dashboard/src/test/js/push-events-actions-spec.js @@ -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, diff --git a/blueocean-dashboard/src/test/js/runNodes-finishedMultipleFailure.js b/blueocean-dashboard/src/test/js/runNodes-finishedMultipleFailure.js index 0c429943..024d6b57 100644 --- a/blueocean-dashboard/src/test/js/runNodes-finishedMultipleFailure.js +++ b/blueocean-dashboard/src/test/js/runNodes-finishedMultipleFailure.js @@ -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": [], diff --git a/blueocean-dashboard/src/test/js/runNodes-firstFinishedSecondRunning.js b/blueocean-dashboard/src/test/js/runNodes-firstFinishedSecondRunning.js index 27326aa8..ab8c0f44 100644 --- a/blueocean-dashboard/src/test/js/runNodes-firstFinishedSecondRunning.js +++ b/blueocean-dashboard/src/test/js/runNodes-firstFinishedSecondRunning.js @@ -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": [], diff --git a/blueocean-dashboard/src/test/js/runNodes-firstRunning.js b/blueocean-dashboard/src/test/js/runNodes-firstRunning.js index 16a96403..9f24069f 100644 --- a/blueocean-dashboard/src/test/js/runNodes-firstRunning.js +++ b/blueocean-dashboard/src/test/js/runNodes-firstRunning.js @@ -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": [], diff --git a/blueocean-dashboard/src/test/js/runNodes.js b/blueocean-dashboard/src/test/js/runNodes.js index b6f0b626..d6b2cd7a 100644 --- a/blueocean-dashboard/src/test/js/runNodes.js +++ b/blueocean-dashboard/src/test/js/runNodes.js @@ -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, diff --git a/blueocean-events/pom.xml b/blueocean-events/pom.xml index 47919fcf..482953ee 100644 --- a/blueocean-events/pom.xml +++ b/blueocean-events/pom.xml @@ -3,7 +3,7 @@ blueocean-parent io.jenkins.blueocean - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT 4.0.0 @@ -20,7 +20,7 @@ ${project.groupId} - blueocean-rest-impl + blueocean-pipeline-api-impl diff --git a/blueocean-personalization/pom.xml b/blueocean-personalization/pom.xml index e266fdb4..2be52b3e 100644 --- a/blueocean-personalization/pom.xml +++ b/blueocean-personalization/pom.xml @@ -3,7 +3,7 @@ blueocean-parent io.jenkins.blueocean - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT 4.0.0 diff --git a/blueocean-personalization/src/main/js/components/DashboardCards.jsx b/blueocean-personalization/src/main/js/components/DashboardCards.jsx index 5e5e827a..9a752cb3 100644 --- a/blueocean-personalization/src/main/js/components/DashboardCards.jsx +++ b/blueocean-personalization/src/main/js/components/DashboardCards.jsx @@ -110,7 +110,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); diff --git a/blueocean-personalization/src/test/js/data/favorites.js b/blueocean-personalization/src/test/js/data/favorites.js index 635be317..c1ac5677 100644 --- a/blueocean-personalization/src/test/js/data/favorites.js +++ b/blueocean-personalization/src/test/js/data/favorites.js @@ -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", diff --git a/blueocean-personalization/src/test/js/redux/FavoritesStore-spec.js b/blueocean-personalization/src/test/js/redux/FavoritesStore-spec.js index 04c07a03..1d7bb8e1 100644 --- a/blueocean-personalization/src/test/js/redux/FavoritesStore-spec.js +++ b/blueocean-personalization/src/test/js/redux/FavoritesStore-spec.js @@ -7,44 +7,46 @@ import Store from '../../../main/js/redux/FavoritesStore'; import { ACTION_TYPES, FavoritesState } from '../../../main/js/redux/FavoritesStore'; const getDefaultFavorites = () => - [ - { - _class: 'io.jenkins.blueocean.service.embedded.rest.FavoriteImpl', - _links: { - self: { - _class: 'io.jenkins.blueocean.rest.hal.Link', - href: '/blue/rest/users/cmeyers/favorites/blueocean%2FUX-301/', + JSON.parse(` + [ + { + "_class": "io.jenkins.blueocean.service.embedded.rest.FavoriteImpl", + "_links": { + "self": { + "_class": "io.jenkins.blueocean.rest.hal.Link", + "href": "/blue/rest/users/cmeyers/favorites/blueocean%2FUX-301/" + } }, + "item": { + "_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl", + "_links": { + "self": { + "_class": "io.jenkins.blueocean.rest.hal.Link", + "href": "/blue/rest/organizations/jenkins/pipelines/blueocean/branches/UX-301/" + } + } + } }, - item: { - _class: 'io.jenkins.blueocean.service.embedded.rest.BranchImpl', - _links: { - self: { - _class: 'io.jenkins.blueocean.rest.hal.Link', - href: '/blue/rest/organizations/jenkins/pipelines/blueocean/branches/UX-301/', - }, + { + "_class": "io.jenkins.blueocean.service.embedded.rest.FavoriteImpl", + "_links": { + "self": { + "_class": "io.jenkins.blueocean.rest.hal.Link", + "href": "/blue/rest/users/cmeyers/favorites/jenkinsfile-experiments%2Fmaster/" + } }, - }, - }, - { - _class: 'io.jenkins.blueocean.service.embedded.rest.FavoriteImpl', - _links: { - self: { - _class: 'io.jenkins.blueocean.rest.hal.Link', - href: '/blue/rest/users/cmeyers/favorites/jenkinsfile-experiments%2Fmaster/', - }, - }, - item: { - _class: 'io.jenkins.blueocean.service.embedded.rest.BranchImpl', - _links: { - self: { - _class: 'io.jenkins.blueocean.rest.hal.Link', - href: '/blue/rest/organizations/jenkins/pipelines/jenkinsfile-experiments/branches/master/', - }, - }, - }, - }, - ]; + "item": { + "_class": "io.jenkins.blueocean.rest.impl.pipeline.BranchImpl", + "_links": { + "self": { + "_class": "io.jenkins.blueocean.rest.hal.Link", + "href": "/blue/rest/organizations/jenkins/pipelines/jenkinsfile-experiments/branches/master/" + } + } + } + } + ] + `); const createBranch = (selfHref) => { return { diff --git a/blueocean-pipeline-api-impl/LICENSE.txt b/blueocean-pipeline-api-impl/LICENSE.txt new file mode 100644 index 00000000..26cfa52a --- /dev/null +++ b/blueocean-pipeline-api-impl/LICENSE.txt @@ -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. diff --git a/blueocean-pipeline-api-impl/README.md b/blueocean-pipeline-api-impl/README.md new file mode 100644 index 00000000..a70bb8b3 --- /dev/null +++ b/blueocean-pipeline-api-impl/README.md @@ -0,0 +1,11 @@ +# BlueOCean REST API implementation + +Implementation of BlueOcean REST API from `bleuocean-rest` module. + +See README.md in `blueocean-rest` module. + + + + + + diff --git a/blueocean-pipeline-api-impl/pom.xml b/blueocean-pipeline-api-impl/pom.xml new file mode 100644 index 00000000..63f5577b --- /dev/null +++ b/blueocean-pipeline-api-impl/pom.xml @@ -0,0 +1,175 @@ + + + 4.0.0 + + + io.jenkins.blueocean + blueocean-parent + 1.0-alpha-5-SNAPSHOT + + + blueocean-pipeline-api-impl + hpi + + BlueOcean :: Pipeline REST API implementation + https://wiki.jenkins-ci.org/display/JENKINS/Blue+Ocean+Plugin + + + + ${project.groupId} + blueocean-rest-impl + + + org.jenkins-ci.plugins.workflow + workflow-job + 2.3 + + + + org.jenkins-ci.plugins.workflow + workflow-cps + 2.8 + + + + org.jenkins-ci.plugins.workflow + workflow-api + 2.1 + + + + org.jenkins-ci.plugins.workflow + workflow-step-api + 2.1 + + + + org.jenkins-ci.plugins.workflow + workflow-support + 2.1 + + + + org.jenkins-ci.plugins.workflow + workflow-multibranch + 2.8 + + + org.jenkins-ci.plugins + git + 2.4.2 + + + org.jenkins-ci.plugins + scm-api + 1.1 + + + org.jenkins-ci.plugins.workflow + workflow-durable-task-step + 2.0 + + + + + org.jenkins-ci.plugins + github-branch-source + 1.8.1 + + + + + org.jenkins-ci.plugins + pipeline-stage-step + 2.1 + test + + + org.jenkins-ci.plugins.workflow + workflow-basic-steps + 2.0 + test + + + org.jenkins-ci.plugins.workflow + workflow-scm-step + 2.0 + test + + + com.mashape.unirest + unirest-java + test + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.19.1 + + + 0 + + + + org.jacoco + jacoco-maven-plugin + 0.7.6.201602180812 + + + default-prepare-agent + + prepare-agent + + + + default-report + prepare-package + + report + + + + default-check + + check + + + + + + BUNDLE + + + + COMPLEXITY + COVEREDRATIO + 0.60 + + + + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + package + + test-jar + + + + + + + diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchContainerImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchContainerImpl.java similarity index 96% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchContainerImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchContainerImpl.java index bd27f826..c60b8603 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchContainerImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchContainerImpl.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchImpl.java similarity index 93% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchImpl.java index 6647541d..8dcf6972 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BranchImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/BranchImpl.java @@ -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; } diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverImpl.java new file mode 100644 index 00000000..6b602b67 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverImpl.java @@ -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; + } +} diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java similarity index 96% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java index b98b0ffe..d40d0e85 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineImpl.java @@ -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) { diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineQueueContainer.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineQueueContainer.java similarity index 91% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineQueueContainer.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineQueueContainer.java index e4b64dfa..224432b6 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/MultiBranchPipelineQueueContainer.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchPipelineQueueContainer.java @@ -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 its = queueMap.get(job.getName()); if(its == null || its.isEmpty()){ continue; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeContainerImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeContainerImpl.java similarity index 97% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeContainerImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeContainerImpl.java index 74ea56c1..80c22085 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeContainerImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeContainerImpl.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeGraphBuilder.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeGraphBuilder.java similarity index 99% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeGraphBuilder.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeGraphBuilder.java index c4a96781..75c225f0 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeGraphBuilder.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeGraphBuilder.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeImpl.java similarity index 97% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeImpl.java index c547a929..24604c1a 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeImpl.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeUtil.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeUtil.java similarity index 98% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeUtil.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeUtil.java index 5c8d8720..f51b7890 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineNodeUtil.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeUtil.java @@ -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; diff --git a/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineRunImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineRunImpl.java new file mode 100644 index 00000000..37b5eb0a --- /dev/null +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineRunImpl.java @@ -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 { + public PipelineRunImpl(WorkflowRun run, Link parent) { + super(run, parent); + } + + @Override + public Container getChangeSet() { + Map m = new LinkedHashMap<>(); + int cnt = 0; + for (ChangeLogSet 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; + } + } + +} diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepContainerImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepContainerImpl.java similarity index 97% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepContainerImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepContainerImpl.java index 5f05a616..c19e5e20 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepContainerImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepContainerImpl.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepImpl.java b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepImpl.java similarity index 92% rename from blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepImpl.java rename to blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepImpl.java index d4ea3cda..74db5866 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineStepImpl.java +++ b/blueocean-pipeline-api-impl/src/main/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineStepImpl.java @@ -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; diff --git a/blueocean-pipeline-api-impl/src/main/resources/index.jelly b/blueocean-pipeline-api-impl/src/main/resources/index.jelly new file mode 100644 index 00000000..fa39ccdd --- /dev/null +++ b/blueocean-pipeline-api-impl/src/main/resources/index.jelly @@ -0,0 +1,4 @@ + +
+ This plugin is a part of BlueOcean Plugin +
diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/AbstractRunImplTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/AbstractRunImplTest.java similarity index 88% rename from blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/AbstractRunImplTest.java rename to blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/AbstractRunImplTest.java index 984a483e..5a4d3cf0 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/AbstractRunImplTest.java +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/AbstractRunImplTest.java @@ -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")); } } diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverTest.java new file mode 100644 index 00000000..ea4a4aa8 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/LinkResolverTest.java @@ -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 nodes = getStages(nodeGraphTable); + List 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 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()); + + } + } +} diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/MultiBranchTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java similarity index 94% rename from blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/MultiBranchTest.java rename to blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java index 615fe8af..4e39e0ac 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/MultiBranchTest.java +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/MultiBranchTest.java @@ -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 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 diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineApiTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineApiTest.java new file mode 100644 index 00000000..d2294773 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineApiTest.java @@ -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 resp = get("/organizations/jenkins/pipelines/", List.class); + + WorkflowJob[] projects = {p1,p2}; + + Assert.assertEquals(projects.length, resp.size()); + + for(int i=0; i 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 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); + } + +} diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java new file mode 100644 index 00000000..738cdeb2 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineBaseTest.java @@ -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 readValue(String value, Class 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 get(String path, Class type){ + return get(path,200, type); + } + + protected Map get(String path){ + return get(path,200, Map.class); + } + @SuppressWarnings("unchecked") + protected T get(String path, int expectedStatus, Class type){ + assert path.startsWith("/"); + return get(path, expectedStatus, "*/*", type); + } + + @SuppressWarnings("unchecked") + protected T get(String path, int expectedStatus, String accept, Class type){ + assert path.startsWith("/"); + try { + if(HttpResponse.class.isAssignableFrom(type)){ + HttpResponse response = Unirest.get(getBaseUrl(path)).header("Accept", accept) + .header("Accept-Encoding","") + .asString(); + Assert.assertEquals(expectedStatus, response.getStatus()); + return (T) response; + } + + HttpResponse 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 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 post(String path, Object body) { + return post(path,body,200); + } + + @SuppressWarnings("unchecked") + protected Map post(String path, Object body, int expectedStatus){ + assert path.startsWith("/"); + try { + HttpResponse 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 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 put(String path, Object body) { + return put(path, body, 200); + } + @SuppressWarnings("unchecked") + protected Map put(String path, Object body, int expectedStatus){ + assert path.startsWith("/"); + try { + HttpResponse 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 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 patch(String path, Object body) { + return patch(path, body, 200); + } + @SuppressWarnings("unchecked") + protected Map patch(String path, Object body, int expectedStatus){ + assert path.startsWith("/"); + try { + HttpResponse 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 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 getStages(FlowGraphTable nodeGraphTable){ + List 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 getParallelNodes(FlowGraphTable nodeGraphTable){ + List 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 build(Class 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 response = request.asObject(clzzz); + Assert.assertEquals(expectedStatus, response.getStatus()); + return response.getBody(); + } catch (UnirestException e) { + throw new RuntimeException(e); + } + } + } +} diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineNodeTest.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeTest.java similarity index 99% rename from blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineNodeTest.java rename to blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeTest.java index f63c7f1e..0f0b68cd 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineNodeTest.java +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/PipelineNodeTest.java @@ -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 diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleDVCSRepoRule.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleDVCSRepoRule.java new file mode 100644 index 00000000..e513a809 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleDVCSRepoRule.java @@ -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 args = new ArrayList(); + 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(); + } + +} diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleRepoRule.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleRepoRule.java new file mode 100644 index 00000000..cd829259 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/AbstractSampleRepoRule.java @@ -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; + } + +} diff --git a/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/GitSampleRepoRule.java b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/GitSampleRepoRule.java new file mode 100644 index 00000000..5f49b8d9 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/java/io/jenkins/blueocean/rest/impl/pipeline/scm/GitSampleRepoRule.java @@ -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(); + } + +} diff --git a/blueocean-pipeline-api-impl/src/test/resources/logging.properties b/blueocean-pipeline-api-impl/src/test/resources/logging.properties new file mode 100644 index 00000000..7757b8c3 --- /dev/null +++ b/blueocean-pipeline-api-impl/src/test/resources/logging.properties @@ -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 diff --git a/blueocean-plugin/pom.xml b/blueocean-plugin/pom.xml index 423b07e3..430d81a7 100644 --- a/blueocean-plugin/pom.xml +++ b/blueocean-plugin/pom.xml @@ -5,7 +5,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT blueocean @@ -39,7 +39,11 @@ ${project.groupId} blueocean-rest-impl - + + ${project.groupId} + blueocean-pipeline-api-impl + + ${project.groupId} @@ -53,7 +57,7 @@ unirest-java test - + @@ -102,6 +106,7 @@ linkHPI('blueocean-rest'); linkHPI('blueocean-commons'); linkHPI('blueocean-rest-impl'); + linkHPI('blueocean-pipeline-api-impl') diff --git a/blueocean-rest-impl/pom.xml b/blueocean-rest-impl/pom.xml index 095428b3..a5fb989a 100644 --- a/blueocean-rest-impl/pom.xml +++ b/blueocean-rest-impl/pom.xml @@ -5,7 +5,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT blueocean-rest-impl @@ -23,84 +23,13 @@ org.jenkins-ci.plugins mailer - - org.jenkins-ci.plugins.workflow - workflow-job - 2.3 - - - - org.jenkins-ci.plugins.workflow - workflow-cps - 2.8 - - - - org.jenkins-ci.plugins.workflow - workflow-api - 2.1 - - - - - org.jenkins-ci.plugins.workflow - workflow-step-api - 2.1 - - - - org.jenkins-ci.plugins.workflow - workflow-support - 2.1 - - - - org.jenkins-ci.plugins.workflow - workflow-multibranch - 2.8 - - - org.jenkins-ci.plugins - git - 2.4.2 - org.jenkins-ci.plugins scm-api 1.2 - - org.jenkins-ci.plugins.workflow - workflow-durable-task-step - 2.0 - - - - - org.jenkins-ci.plugins - github-branch-source - 1.8.1 - - - org.jenkins-ci.plugins - pipeline-stage-step - 2.1-beta-1 - test - - - org.jenkins-ci.plugins.workflow - workflow-basic-steps - 2.0 - test - - - org.jenkins-ci.plugins.workflow - workflow-scm-step - 2.0 - test - org.jenkins-ci.plugins structs @@ -123,6 +52,20 @@ 1.12.1 + + org.jenkins-ci.plugins + matrix-project + 1.6 + test + + + + org.jenkins-ci.plugins + junit + 1.2 + test + + diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/BlueOceanRootAction.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/BlueOceanRootAction.java index 580f65c2..154832e5 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/BlueOceanRootAction.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/BlueOceanRootAction.java @@ -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); } } } diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/LinkResolverImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/LinkResolverImpl.java index 713b995f..2f7c69f9 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/LinkResolverImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/LinkResolverImpl.java @@ -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; - } - } diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractRunImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractRunImpl.java index a9d2c97b..72ddeb68 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractRunImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/AbstractRunImpl.java @@ -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 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 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 diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BlueRunFactory.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BlueRunFactory.java new file mode 100644 index 00000000..dc6ce75a --- /dev/null +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/BlueRunFactory.java @@ -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 all(){ + return ExtensionList.lookup(BlueRunFactory.class); + } +} diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/FreeStyleRunImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/FreeStyleRunImpl.java index 6cde7947..d7ec0630 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/FreeStyleRunImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/FreeStyleRunImpl.java @@ -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 { 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; + } + } } diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineContainerImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineContainerImpl.java index 311e6ed8..280c5583 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineContainerImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineContainerImpl.java @@ -60,7 +60,7 @@ public class PipelineContainerImpl extends BluePipelineContainer { return getPipelines(itemGroup.getItems()); } - protected Iterator getPipelines(Collection items){ + public Iterator getPipelines(Collection items){ List pipelines = new ArrayList<>(); for (Item item : items) { BluePipeline pipeline = get(item); diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineFolderImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineFolderImpl.java index 4b2958ab..fced7cd6 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineFolderImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineFolderImpl.java @@ -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) diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineImpl.java index 4a6bdbf4..63afcd3a 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineImpl.java @@ -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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineRunImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineRunImpl.java deleted file mode 100644 index 11d7dd8e..00000000 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineRunImpl.java +++ /dev/null @@ -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 { - public PipelineRunImpl(WorkflowRun run, Link parent) { - super(run, parent); - } - - @Override - public Container getChangeSet() { - Map m = new LinkedHashMap<>(); - int cnt = 0; - for (ChangeLogSet 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; - } -} diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineSearch.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineSearch.java index 41773330..6907149a 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineSearch.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/PipelineSearch.java @@ -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{ 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{ List 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); } } } diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/QueueContainerImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/QueueContainerImpl.java index 9feabbb0..c1a22c2a 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/QueueContainerImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/QueueContainerImpl.java @@ -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() { - @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() { diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunContainerImpl.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunContainerImpl.java index 5d23f2a8..1d24eb0b 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunContainerImpl.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunContainerImpl.java @@ -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 diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunSearch.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunSearch.java index 81bbbab1..be7e4229 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunSearch.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/rest/RunSearch.java @@ -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 { } return Pageables.wrap(findRuns(null)); } - public static Iterable findRuns(Job job, Link parent){ + public static Iterable findRuns(Job job, final Link parent){ final List runs = new ArrayList<>(); Iterable pipelines; if(job != null){ @@ -70,7 +71,12 @@ public class RunSearch extends OmniSearch { RunList 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 { 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; diff --git a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java index 5739778e..6d9b6b01 100644 --- a/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java +++ b/blueocean-rest-impl/src/main/java/io/jenkins/blueocean/service/embedded/util/FavoriteUtil.java @@ -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 diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java index b069c9e4..d05f2f63 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java +++ b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/BaseTest.java @@ -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 getStages(FlowGraphTable nodeGraphTable){ - List 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 getStages(FlowGraphTable nodeGraphTable){ +// List 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 getParallelNodes(FlowGraphTable nodeGraphTable){ - List parallelNodes = new ArrayList<>(); - - for(FlowGraphTable.Row row: nodeGraphTable.getRows()){ - if(PipelineNodeUtil.isParallelBranch(row.getNode())){ - parallelNodes.add(row.getNode()); - } - } - return parallelNodes; - } +// protected List getParallelNodes(FlowGraphTable nodeGraphTable){ +// List 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"); diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/LinkResolverTest.java b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/LinkResolverTest.java index 18a44e12..fa2e3155 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/LinkResolverTest.java +++ b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/LinkResolverTest.java @@ -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 nodes = getStages(nodeGraphTable); - List 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 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()); - - } - } } diff --git a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineApiTest.java b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineApiTest.java index bcc520ad..b9519929 100644 --- a/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineApiTest.java +++ b/blueocean-rest-impl/src/test/java/io/jenkins/blueocean/service/embedded/PipelineApiTest.java @@ -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 resp = get("/organizations/jenkins/pipelines/", List.class); - - WorkflowJob[] projects = {p1,p2}; - - Assert.assertEquals(projects.length, resp.size()); - - for(int i=0; i 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 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); diff --git a/blueocean-rest/pom.xml b/blueocean-rest/pom.xml index b0a3c003..8f96adf1 100644 --- a/blueocean-rest/pom.xml +++ b/blueocean-rest/pom.xml @@ -5,7 +5,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT blueocean-rest diff --git a/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/hal/LinkResolver.java b/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/hal/LinkResolver.java index 6fd359aa..014fd0d3 100644 --- a/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/hal/LinkResolver.java +++ b/blueocean-rest/src/main/java/io/jenkins/blueocean/rest/hal/LinkResolver.java @@ -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 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; + } } diff --git a/blueocean-web/package.json b/blueocean-web/package.json index f92079cc..be0f2894 100644 --- a/blueocean-web/package.json +++ b/blueocean-web/package.json @@ -18,14 +18,14 @@ "babel-preset-react": "^6.5.0", "eslint": "2.8.0", "eslint-plugin-react": "^5.0.1", - "giti": "^1.0.6", + "giti": "1.1.3", "gulp": "^3.9.1", "jquery-detached": "^2.1.4-v4", "ncp": "^2.0.0", "zombie": "^4.2.1" }, "dependencies": { - "@jenkins-cd/design-language": "0.0.63", + "@jenkins-cd/design-language": "0.0.64", "@jenkins-cd/js-extensions": "0.0.19", "@jenkins-cd/js-modules": "0.0.5", "history": "2.0.2", diff --git a/blueocean-web/pom.xml b/blueocean-web/pom.xml index 0e989594..40f5f0fa 100644 --- a/blueocean-web/pom.xml +++ b/blueocean-web/pom.xml @@ -5,7 +5,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT blueocean-web diff --git a/blueocean-web/src/main/java/io/jenkins/blueocean/BlueOceanUI.java b/blueocean-web/src/main/java/io/jenkins/blueocean/BlueOceanUI.java index 2cdc0e5f..c48e9988 100644 --- a/blueocean-web/src/main/java/io/jenkins/blueocean/BlueOceanUI.java +++ b/blueocean-web/src/main/java/io/jenkins/blueocean/BlueOceanUI.java @@ -1,8 +1,6 @@ package io.jenkins.blueocean; import hudson.ExtensionList; -import hudson.model.UsageStatistics; -import jenkins.model.Jenkins; /** * Root of Blue Ocean UI @@ -36,19 +34,4 @@ public class BlueOceanUI { public String getUrlBase() { return urlBase; } - - /** - * @return True if jenkins reports usage statistics. - */ - public boolean includeRollbar() { - return false; -// return Jenkins.getInstance().isUsageStatisticsCollected() && !UsageStatistics.DISABLED; - } - - /** - * @return Version on the plugin e.g 1.0-SNAPSHOT (private-f9a14d3e-jenkins) - */ - public String getPluginVersion() { - return Jenkins.getInstance().getPlugin("blueocean-web").getWrapper().getVersion(); - } } diff --git a/blueocean-web/src/main/js/DevelopmentFooter.jsx b/blueocean-web/src/main/js/DevelopmentFooter.jsx index 3e2e2913..d07204fd 100644 --- a/blueocean-web/src/main/js/DevelopmentFooter.jsx +++ b/blueocean-web/src/main/js/DevelopmentFooter.jsx @@ -5,13 +5,12 @@ import revisionInfo from '../../../target/classes/io/jenkins/blueocean/revisionI export class DevelopmentFooter extends Component { render() { - if (!revisionInfo || !revisionInfo.name) { - var blueOceanVersion = document.getElementsByTagName('head')[0].getAttribute('data-blue-ocean-version'); - return ( -
- Blue Ocean UI v{blueOceanVersion} -
- ); + // testing basic integrity + if (!revisionInfo || !revisionInfo.sha) { + // TODO: At minimum we should return Jenkins version. Jenkins version is always present + // in X-Hudson HTTP header. Something to be handled elsewhere during load time by + // inspecting HTTP response headers + return null; } return (
diff --git a/blueocean-web/src/main/js/config.js b/blueocean-web/src/main/js/config.js index 97d64e26..f5dac3c7 100644 --- a/blueocean-web/src/main/js/config.js +++ b/blueocean-web/src/main/js/config.js @@ -6,10 +6,10 @@ export default class Config { constructor(options) { - this._appURLBase = options.appURLBase || "/"; - this._rootURL = options.rootURL || "/"; - this._resourceURL = options.resourceURL || "/"; - this._adjunctURL = options.adjunctURL || "/"; + this._appURLBase = options.appURLBase || ''; + this._rootURL = options.rootURL || ''; + this._resourceURL = options.resourceURL || ''; + this._adjunctURL = options.adjunctURL || ''; } getAppURLBase() { diff --git a/blueocean-web/src/main/js/main.jsx b/blueocean-web/src/main/js/main.jsx index a1282c65..72dba87f 100644 --- a/blueocean-web/src/main/js/main.jsx +++ b/blueocean-web/src/main/js/main.jsx @@ -84,7 +84,7 @@ function startApp(routes, stores) { let appURLBase = headElement.getAttribute("data-appurl"); if (typeof appURLBase !== "string") { - appURLBase = "/"; + appURLBase = ''; } // Look up some other URLs we may need diff --git a/blueocean-web/src/main/resources/io/jenkins/blueocean/BlueOceanUI/index.jelly b/blueocean-web/src/main/resources/io/jenkins/blueocean/BlueOceanUI/index.jelly index c310025c..76283452 100644 --- a/blueocean-web/src/main/resources/io/jenkins/blueocean/BlueOceanUI/index.jelly +++ b/blueocean-web/src/main/resources/io/jenkins/blueocean/BlueOceanUI/index.jelly @@ -9,11 +9,10 @@ ${h.initPageVariables(context)} - + data-adjuncturl="${rootURL}/${j.getAdjuncts('').rootURL}"> Jenkins Blue Ocean @@ -30,37 +29,6 @@ - - - - diff --git a/pom.xml b/pom.xml index 859fca0a..447cdbe5 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ io.jenkins.blueocean blueocean-parent - 1.0-alpha-4-SNAPSHOT + 1.0-alpha-5-SNAPSHOT pom Blue Ocean UI Parent @@ -100,6 +100,7 @@ blueocean-web blueocean-rest blueocean-rest-impl + blueocean-pipeline-api-impl blueocean-events blueocean-dashboard blueocean-personalization @@ -165,6 +166,12 @@ ${project.version} + + ${project.groupId} + blueocean-pipeline-api-impl + ${project.version} + + ${project.groupId} blueocean-plugin