[FIX JENKINS-36055] Update branches list when new branch jobs are created (#313)
* [FIX JENKINS-36055] Update branches list when new branch jobs are created * [FIX JENKINS-36055] Move latestRuns data module to "data/runs" * [FIX JENKINS-36055] A few unit tests for actions.updateBranchList
This commit is contained in:
parent
02665e161c
commit
eb9334a63f
|
@ -48,7 +48,7 @@ class OrganizationPipelines extends Component {
|
|||
case 'job_crud_created':
|
||||
case 'job_crud_deleted':
|
||||
case 'job_crud_renamed':
|
||||
// Just refetch and update the pipelines list.
|
||||
// Just refetch and update the pipelines and branches list.
|
||||
// Yes, in some of these cases it would be possible to
|
||||
// update the redux store state without making a REST call.
|
||||
// Trading off for simplicity and view consistency here.
|
||||
|
@ -59,6 +59,7 @@ class OrganizationPipelines extends Component {
|
|||
// benefit to be got from optimizing things here.
|
||||
// TODO: fix https://issues.jenkins-ci.org/browse/JENKINS-35153 for delete
|
||||
_this.props.fetchPipelines(_this.context.config, _this.props.organization);
|
||||
_this.props.updateBranchList(eventCopy, _this.context.config);
|
||||
break;
|
||||
case 'job_run_queue_buildable':
|
||||
case 'job_run_queue_enter':
|
||||
|
@ -129,6 +130,7 @@ OrganizationPipelines.propTypes = {
|
|||
processJobQueuedEvent: func.isRequired,
|
||||
updateRunState: func.isRequired,
|
||||
updateBranchState: func.isRequired,
|
||||
updateBranchList: func.isRequired,
|
||||
organization: string,
|
||||
params: object, // From react-router
|
||||
children: node, // From react-router
|
||||
|
|
|
@ -522,6 +522,39 @@ export const actions = {
|
|||
};
|
||||
},
|
||||
|
||||
updateBranchList(event, config) {
|
||||
return (dispatch, getState) => {
|
||||
if (event.job_ismultibranch) {
|
||||
const multibranchPipelines = getState().adminStore.branches || {};
|
||||
const pipelineName = event.blueocean_job_pipeline_name;
|
||||
|
||||
// We're only interested in this event if we're already managing branch state
|
||||
// associated with this multi-branch job.
|
||||
if (!multibranchPipelines[pipelineName]) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch/refetch the latest set of branches for the pipeline.
|
||||
const url = `${config.getAppURLBase()}/rest/organizations/${event.jenkins_org}` +
|
||||
`/pipelines/${pipelineName}/branches`;
|
||||
exports.fetchJson(url, (latestPipelineBranches) => {
|
||||
if (event.blueocean_is_for_current_job) {
|
||||
dispatch({
|
||||
id: pipelineName,
|
||||
payload: latestPipelineBranches,
|
||||
type: ACTION_TYPES.SET_CURRENT_BRANCHES_DATA,
|
||||
});
|
||||
}
|
||||
dispatch({
|
||||
id: pipelineName,
|
||||
payload: latestPipelineBranches,
|
||||
type: ACTION_TYPES.SET_BRANCHES_DATA,
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
fetchRunsIfNeeded(config) {
|
||||
return (dispatch) => {
|
||||
const baseUrl = `${config.getAppURLBase()}/rest/organizations/jenkins` +
|
||||
|
|
|
@ -3,7 +3,7 @@ import {createRenderer} from 'react-addons-test-utils';
|
|||
import { assert} from 'chai';
|
||||
import sd from 'skin-deep';
|
||||
import Immutable from 'immutable';
|
||||
import { latestRuns as data } from './latestRuns';
|
||||
import { latestRuns as data } from './data/runs/latestRuns';
|
||||
import { RunsRecord } from '../../main/js/components/records.jsx';
|
||||
|
||||
import Branches from '../../main/js/components/Branches.jsx';
|
||||
|
|
|
@ -0,0 +1,605 @@
|
|||
export default [{
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/actions/"
|
||||
},
|
||||
"runs": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/"
|
||||
},
|
||||
"queue": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/queue/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "com.cloudbees.plugins.credentials.ViewCredentialsAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/credentials/"
|
||||
}
|
||||
},
|
||||
"stores": {},
|
||||
"urlName": "credentials"
|
||||
}],
|
||||
"displayName": "master",
|
||||
"estimatedDurationInMillis": 39110,
|
||||
"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",
|
||||
"_links": {
|
||||
"nodes": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/nodes/"
|
||||
},
|
||||
"log": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/log/"
|
||||
},
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/actions/"
|
||||
},
|
||||
"steps": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "hudson.model.CauseAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/cause/"
|
||||
}
|
||||
},
|
||||
"causes": [{"_class": "jenkins.branch.BranchIndexingCause", "shortDescription": "Branch indexing"}],
|
||||
"urlName": "cause"
|
||||
}, {
|
||||
"_class": "jenkins.metrics.impl.TimeInQueueAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/timings/"
|
||||
}
|
||||
},
|
||||
"queuingDurationMillis": 2,
|
||||
"totalDurationMillis": 42108,
|
||||
"urlName": "timings"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.util.BuildData",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/git/"
|
||||
}
|
||||
},
|
||||
"buildsByBranchName": {
|
||||
"master": {
|
||||
"_class": "hudson.plugins.git.util.Build",
|
||||
"buildNumber": 3,
|
||||
"buildResult": null,
|
||||
"marked": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
},
|
||||
"revision": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastBuiltRevision": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
},
|
||||
"remoteUrls": ["https://github.com/TomTestOrg/PR-demo.git"],
|
||||
"scmName": "",
|
||||
"urlName": "git"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.GitTagAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/tagBuild/"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"urlName": "tagBuild"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.util.BuildData",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/git/"
|
||||
}
|
||||
},
|
||||
"buildsByBranchName": {
|
||||
"master": {
|
||||
"_class": "hudson.plugins.git.util.Build",
|
||||
"buildNumber": 3,
|
||||
"buildResult": null,
|
||||
"marked": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
},
|
||||
"revision": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastBuiltRevision": {
|
||||
"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"branch": [{"SHA1": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64", "name": "master"}]
|
||||
},
|
||||
"remoteUrls": ["https://github.com/TomTestOrg/PR-demo.git"],
|
||||
"scmName": "",
|
||||
"urlName": "git"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.GitTagAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/tagBuild/"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"urlName": "tagBuild"
|
||||
}, {
|
||||
"_class": "org.jenkinsci.plugins.workflow.job.views.FlowGraphAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/flowGraph/"
|
||||
}
|
||||
},
|
||||
"nodes": [{"_class": "org.jenkinsci.plugins.workflow.graph.FlowStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.graph.FlowEndNode"}],
|
||||
"urlName": "flowGraph"
|
||||
}],
|
||||
"artifacts": [],
|
||||
"changeSet": [{
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.ChangeSetResource",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/changeset/7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64/"
|
||||
}
|
||||
},
|
||||
"author": {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.UserImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/users/noreply/"
|
||||
}
|
||||
},
|
||||
"email": "noreply@github.com",
|
||||
"fullName": "noreply",
|
||||
"id": "noreply"
|
||||
},
|
||||
"affectedPaths": ["Jenkinsfile"],
|
||||
"commitId": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"comment": "Update Jenkinsfile\n",
|
||||
"date": "2016-07-02 18:24:38 +0100",
|
||||
"id": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64",
|
||||
"msg": "Update Jenkinsfile",
|
||||
"paths": [{"editType": "edit", "file": "Jenkinsfile"}],
|
||||
"timestamp": "2016-07-02T18:24:38.000+0100"
|
||||
}],
|
||||
"durationInMillis": 42106,
|
||||
"enQueueTime": "2016-07-02T18:25:06.061+0100",
|
||||
"endTime": "2016-07-02T18:25:48.169+0100",
|
||||
"estimatedDurationInMillis": 39110,
|
||||
"id": "3",
|
||||
"organization": "jenkins",
|
||||
"pipeline": "master",
|
||||
"result": "SUCCESS",
|
||||
"runSummary": "stable",
|
||||
"startTime": "2016-07-02T18:25:06.063+0100",
|
||||
"state": "FINISHED",
|
||||
"steps": [{
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/3/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/6/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/7/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/10/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/master/runs/3/steps/11/"
|
||||
}
|
||||
}
|
||||
}],
|
||||
"type": "WorkflowRun",
|
||||
"commitId": "7d7e6b1589bf8be0ffbdd99bb3fd79581f0e7c64"
|
||||
},
|
||||
"name": "master",
|
||||
"organization": "jenkins",
|
||||
"weatherScore": 100,
|
||||
"pullRequest": null
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/actions/"
|
||||
},
|
||||
"runs": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/"
|
||||
},
|
||||
"queue": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/queue/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "com.cloudbees.plugins.credentials.ViewCredentialsAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/credentials/"
|
||||
}
|
||||
},
|
||||
"stores": {},
|
||||
"urlName": "credentials"
|
||||
}],
|
||||
"displayName": "quicker",
|
||||
"estimatedDurationInMillis": 18710,
|
||||
"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",
|
||||
"_links": {
|
||||
"nodes": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/nodes/"
|
||||
},
|
||||
"log": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/log/"
|
||||
},
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/actions/"
|
||||
},
|
||||
"steps": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "hudson.model.CauseAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/cause/"
|
||||
}
|
||||
},
|
||||
"causes": [{"_class": "jenkins.branch.BranchIndexingCause", "shortDescription": "Branch indexing"}],
|
||||
"urlName": "cause"
|
||||
}, {
|
||||
"_class": "jenkins.metrics.impl.TimeInQueueAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/timings/"
|
||||
}
|
||||
},
|
||||
"queuingDurationMillis": 2,
|
||||
"totalDurationMillis": 18712,
|
||||
"urlName": "timings"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.util.BuildData",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/git/"
|
||||
}
|
||||
},
|
||||
"buildsByBranchName": {
|
||||
"quicker": {
|
||||
"_class": "hudson.plugins.git.util.Build",
|
||||
"buildNumber": 1,
|
||||
"buildResult": null,
|
||||
"marked": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
},
|
||||
"revision": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastBuiltRevision": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
},
|
||||
"remoteUrls": ["https://github.com/TomTestOrg/PR-demo.git"],
|
||||
"scmName": "",
|
||||
"urlName": "git"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.GitTagAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/tagBuild/"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"urlName": "tagBuild"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.util.BuildData",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/git/"
|
||||
}
|
||||
},
|
||||
"buildsByBranchName": {
|
||||
"quicker": {
|
||||
"_class": "hudson.plugins.git.util.Build",
|
||||
"buildNumber": 1,
|
||||
"buildResult": null,
|
||||
"marked": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
},
|
||||
"revision": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
}
|
||||
}
|
||||
},
|
||||
"lastBuiltRevision": {
|
||||
"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c",
|
||||
"branch": [{"SHA1": "ffd80d68b6c3bc7552feff5a7b77525625500a7c", "name": "quicker"}]
|
||||
},
|
||||
"remoteUrls": ["https://github.com/TomTestOrg/PR-demo.git"],
|
||||
"scmName": "",
|
||||
"urlName": "git"
|
||||
}, {
|
||||
"_class": "hudson.plugins.git.GitTagAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/tagBuild/"
|
||||
}
|
||||
},
|
||||
"tags": [],
|
||||
"urlName": "tagBuild"
|
||||
}, {
|
||||
"_class": "org.jenkinsci.plugins.workflow.job.views.FlowGraphAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/flowGraph/"
|
||||
}
|
||||
},
|
||||
"nodes": [{"_class": "org.jenkinsci.plugins.workflow.graph.FlowStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepStartNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepEndNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.cps.nodes.StepAtomNode"}, {"_class": "org.jenkinsci.plugins.workflow.graph.FlowEndNode"}],
|
||||
"urlName": "flowGraph"
|
||||
}],
|
||||
"artifacts": [],
|
||||
"changeSet": [],
|
||||
"durationInMillis": 18710,
|
||||
"enQueueTime": "2016-07-01T17:20:23.071+0100",
|
||||
"endTime": "2016-07-01T17:20:41.781+0100",
|
||||
"estimatedDurationInMillis": 18710,
|
||||
"id": "1",
|
||||
"organization": "jenkins",
|
||||
"pipeline": "quicker",
|
||||
"result": "SUCCESS",
|
||||
"runSummary": "stable",
|
||||
"startTime": "2016-07-01T17:20:23.071+0100",
|
||||
"state": "FINISHED",
|
||||
"steps": [{
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/3/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/6/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/7/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/10/"
|
||||
}
|
||||
}
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineStepImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/quicker/runs/1/steps/11/"
|
||||
}
|
||||
}
|
||||
}],
|
||||
"type": "WorkflowRun",
|
||||
"commitId": "ffd80d68b6c3bc7552feff5a7b77525625500a7c"
|
||||
},
|
||||
"name": "quicker",
|
||||
"organization": "jenkins",
|
||||
"weatherScore": 100,
|
||||
"pullRequest": null
|
||||
}, {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.BranchImpl",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/actions/"
|
||||
},
|
||||
"runs": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/"
|
||||
},
|
||||
"queue": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/queue/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "com.cloudbees.plugins.credentials.ViewCredentialsAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/credentials/"
|
||||
}
|
||||
},
|
||||
"stores": {},
|
||||
"urlName": "credentials"
|
||||
}],
|
||||
"displayName": "tfennelly-patch-1",
|
||||
"estimatedDurationInMillis": -1,
|
||||
"fullName": "tfprdemo/tfennelly-patch-1",
|
||||
"lastSuccessfulRun": null,
|
||||
"latestRun": {
|
||||
"_class": "io.jenkins.blueocean.service.embedded.rest.PipelineRunImpl",
|
||||
"_links": {
|
||||
"nodes": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/nodes/"
|
||||
},
|
||||
"log": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/log/"
|
||||
},
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/"
|
||||
},
|
||||
"actions": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/actions/"
|
||||
},
|
||||
"steps": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/steps/"
|
||||
}
|
||||
},
|
||||
"actions": [{
|
||||
"_class": "hudson.model.CauseAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/cause/"
|
||||
}
|
||||
},
|
||||
"causes": [{"_class": "jenkins.branch.BranchIndexingCause", "shortDescription": "Branch indexing"}],
|
||||
"urlName": "cause"
|
||||
}, {
|
||||
"_class": "jenkins.metrics.impl.TimeInQueueAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/timings/"
|
||||
}
|
||||
},
|
||||
"queuingDurationMillis": 2,
|
||||
"totalDurationMillis": 2,
|
||||
"urlName": "timings"
|
||||
}, {
|
||||
"_class": "org.jenkinsci.plugins.workflow.job.views.FlowGraphAction",
|
||||
"_links": {
|
||||
"self": {
|
||||
"_class": "io.jenkins.blueocean.rest.hal.Link",
|
||||
"href": "/blue/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/runs/1/flowGraph/"
|
||||
}
|
||||
},
|
||||
"nodes": [],
|
||||
"urlName": "flowGraph"
|
||||
}],
|
||||
"artifacts": [],
|
||||
"changeSet": [],
|
||||
"durationInMillis": 0,
|
||||
"enQueueTime": "2016-07-04T16:13:59.226+0100",
|
||||
"endTime": null,
|
||||
"estimatedDurationInMillis": -1,
|
||||
"id": "1",
|
||||
"organization": "jenkins",
|
||||
"pipeline": "tfennelly-patch-1",
|
||||
"result": "UNKNOWN",
|
||||
"runSummary": "?",
|
||||
"startTime": "2016-07-04T16:13:59.227+0100",
|
||||
"state": "QUEUED",
|
||||
"steps": [],
|
||||
"type": "WorkflowRun",
|
||||
"commitId": null
|
||||
},
|
||||
"name": "tfennelly-patch-1",
|
||||
"organization": "jenkins",
|
||||
"weatherScore": 100,
|
||||
"pullRequest": null
|
||||
}]
|
|
@ -0,0 +1,14 @@
|
|||
export default {
|
||||
"jenkins_object_type": "org.jenkinsci.plugins.workflow.job.WorkflowJob",
|
||||
"job_name": "tfprdemo/tfennelly-patch-1",
|
||||
"jenkins_org": "jenkins",
|
||||
"job_ismultibranch": "true",
|
||||
"jenkins_object_name": "tfprdemo/tfennelly-patch-1",
|
||||
"blueocean_job_rest_url": "/rest/organizations/jenkins/pipelines/tfprdemo/branches/tfennelly-patch-1/",
|
||||
"blueocean_job_branch_name": "tfennelly-patch-1",
|
||||
"jenkins_event": "job_crud_created",
|
||||
"blueocean_job_pipeline_name": "tfprdemo",
|
||||
"jenkins_object_url": "job/tfprdemo/job/tfennelly-patch-1/",
|
||||
"jenkins_channel": "job",
|
||||
"blueocean_is_for_current_job": true
|
||||
};
|
|
@ -5,7 +5,7 @@ import sd from 'skin-deep';
|
|||
|
||||
import PullRequest from '../../main/js/components/PullRequest.jsx';
|
||||
import { RunsRecord } from '../../main/js/components/records.jsx';
|
||||
import { latestRuns as data } from './latestRuns';
|
||||
import { latestRuns as data } from './data/runs/latestRuns';
|
||||
|
||||
const pr = data.filter((run) => run.pullRequest);
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import React from 'react';
|
||||
import { assert} from 'chai';
|
||||
import { shallow } from 'enzyme';
|
||||
import { latestRuns as branches } from './latestRuns';
|
||||
import { latestRuns as branches } from './data/runs/latestRuns';
|
||||
|
||||
import {PullRequests} from '../../main/js/components/PullRequests.jsx';
|
||||
|
||||
|
|
|
@ -26,236 +26,237 @@ const CONFIG = {
|
|||
};
|
||||
const originalFetchJson = actions.fetchJson;
|
||||
|
||||
try {
|
||||
describe("push events - queued run tests", () => {
|
||||
describe("push events - queued run tests", () => {
|
||||
afterEach(() => {
|
||||
actions.fetchJson = originalFetchJson;
|
||||
});
|
||||
|
||||
// Test queued event for when the event is for the pipeline that
|
||||
// the user is actually "currently" looking at.
|
||||
it("currently displayed pipeline", () => {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
// Test queued event for when the event is for the pipeline that
|
||||
// the user is actually "currently" looking at.
|
||||
it("currently displayed pipeline", () => {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const dispatchedEvents = [];
|
||||
dispatcher(function(actualDispatchObj) {
|
||||
//console.log(actualDispatchObj);
|
||||
dispatchedEvents.push(actualDispatchObj);
|
||||
}, function() {
|
||||
return {
|
||||
adminStore: {
|
||||
runs: {
|
||||
'PR-demo': []
|
||||
}
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const dispatchedEvents = [];
|
||||
dispatcher(function(actualDispatchObj) {
|
||||
//console.log(actualDispatchObj);
|
||||
dispatchedEvents.push(actualDispatchObj);
|
||||
}, function() {
|
||||
return {
|
||||
adminStore: {
|
||||
runs: {
|
||||
'PR-demo': []
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The queued event should get dispatched twice:
|
||||
// 1. To update the redux store's view of the set of 'currentRuns' because
|
||||
// the event is associated with the currently active pipeline.
|
||||
// 2. To update the redux store's view of the set of runs associated with the
|
||||
// pipeline itself. Every time the user navs to a pipeline, the runs for
|
||||
// that pipeline are cached in the redux store. This dispatch updates
|
||||
// that state.
|
||||
assert.equal(dispatchedEvents.length, 2);
|
||||
assert.equal(dispatchedEvents[0].type, actions.ACTION_TYPES.SET_CURRENT_RUN_DATA);
|
||||
assert.equal(dispatchedEvents[0].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[0].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[0].payload[0].state, 'QUEUED');
|
||||
assert.equal(dispatchedEvents[1].type, actions.ACTION_TYPES.SET_RUNS_DATA);
|
||||
assert.equal(dispatchedEvents[1].id, 'PR-demo');
|
||||
assert.equal(dispatchedEvents[1].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[1].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[1].payload[0].state, 'QUEUED');
|
||||
}
|
||||
});
|
||||
|
||||
// Test queued event for when the event is for a different pipeline to
|
||||
// the one that the user is actually "currently" looking at.
|
||||
it("not currently displayed pipeline", () => {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
// The queued event should get dispatched twice:
|
||||
// 1. To update the redux store's view of the set of 'currentRuns' because
|
||||
// the event is associated with the currently active pipeline.
|
||||
// 2. To update the redux store's view of the set of runs associated with the
|
||||
// pipeline itself. Every time the user navs to a pipeline, the runs for
|
||||
// that pipeline are cached in the redux store. This dispatch updates
|
||||
// that state.
|
||||
assert.equal(dispatchedEvents.length, 2);
|
||||
assert.equal(dispatchedEvents[0].type, actions.ACTION_TYPES.SET_CURRENT_RUN_DATA);
|
||||
assert.equal(dispatchedEvents[0].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[0].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[0].payload[0].state, 'QUEUED');
|
||||
assert.equal(dispatchedEvents[1].type, actions.ACTION_TYPES.SET_RUNS_DATA);
|
||||
assert.equal(dispatchedEvents[1].id, 'PR-demo');
|
||||
assert.equal(dispatchedEvents[1].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[1].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[1].payload[0].state, 'QUEUED');
|
||||
});
|
||||
|
||||
// Test queued event for when the event is for a different pipeline to
|
||||
// the one that the user is actually "currently" looking at.
|
||||
it("not currently displayed pipeline", () => {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
|
||||
// modify the event to turn off the blueocean_is_for_current_job flag.
|
||||
// This should result in just one dispatch.
|
||||
event.blueocean_is_for_current_job = false;
|
||||
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const dispatchedEvents = [];
|
||||
dispatcher(function(actualDispatchObj) {
|
||||
// console.log(actualDispatchObj);
|
||||
dispatchedEvents.push(actualDispatchObj);
|
||||
}, function() {
|
||||
return {
|
||||
adminStore: {
|
||||
runs: {
|
||||
'PR-demo': []
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// The queued event should get dispatched once only i.e. to update the
|
||||
// "global" run state. See the previous test comments for more details.
|
||||
assert.equal(dispatchedEvents.length, 1);
|
||||
assert.equal(dispatchedEvents[0].type, actions.ACTION_TYPES.SET_RUNS_DATA);
|
||||
assert.equal(dispatchedEvents[0].id, 'PR-demo');
|
||||
assert.equal(dispatchedEvents[0].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[0].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[0].payload[0].state, 'QUEUED');
|
||||
});
|
||||
|
||||
// Test queued event is ignored if already received. This can happen because
|
||||
// there are multiple events relating to the run queue lifecycle.
|
||||
it("ignore multiple events with same queueId", () => {
|
||||
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const adminStore = {runs: { 'PR-demo': [] } };
|
||||
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
// modify the event to turn off the blueocean_is_for_current_job flag.
|
||||
// This should result in just one dispatch.
|
||||
// This should result in max of one dispatch per call to dispatcher.
|
||||
event.blueocean_is_for_current_job = false;
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: adminStore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// fire the dispatcher for the first time...
|
||||
fireEvent();
|
||||
// Should have been dispatched i.e. count === 1 ...
|
||||
assert.equal(adminStore.runs['PR-demo'].length, 1);
|
||||
// fire the dispatcher a second time (same event)...
|
||||
fireEvent();
|
||||
// Should not have been dispatched i.e. count
|
||||
// should still be 1 ...
|
||||
assert.equal(adminStore.runs['PR-demo'].length, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("push events - started run tests", () => {
|
||||
afterEach(() => {
|
||||
actions.fetchJson = originalFetchJson;
|
||||
});
|
||||
|
||||
// Test run started event for when the event is for the pipeline that
|
||||
// the user is actually "currently" looking at.
|
||||
it("run fetch ok", () => {
|
||||
// Mimic the run being in the queued state before the start
|
||||
const adminStore = {
|
||||
runs: {
|
||||
'PR-demo': [{
|
||||
job_run_queueId: '12',
|
||||
pipeline: 'quicker',
|
||||
state: 'QUEUED',
|
||||
result: 'UNKNOWN'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_started');
|
||||
event.blueocean_is_for_current_job = false;
|
||||
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
// Mock the fetchJson
|
||||
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",
|
||||
"artifacts": [],
|
||||
"changeSet": [],
|
||||
"durationInMillis": 0,
|
||||
"enQueueTime": "2016-05-19T22:05:39.301+0100",
|
||||
"endTime": null,
|
||||
"estimatedDurationInMillis": 17882,
|
||||
"id": "12",
|
||||
"organization": "jenkins",
|
||||
"pipeline": "quicker",
|
||||
"result": "UNKNOWN",
|
||||
"runSummary": "?",
|
||||
"startTime": "2016-05-19T22:05:39.303+0100",
|
||||
"state": "RUNNING",
|
||||
"type": "WorkflowRun",
|
||||
"commitId": null
|
||||
});
|
||||
};
|
||||
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const dispatchedEvents = [];
|
||||
dispatcher(function(actualDispatchObj) {
|
||||
// console.log(actualDispatchObj);
|
||||
dispatchedEvents.push(actualDispatchObj);
|
||||
}, function() {
|
||||
const dispatcher = actions.actions.updateRunState(event, CONFIG, true);
|
||||
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: {
|
||||
runs: {
|
||||
'PR-demo': []
|
||||
}
|
||||
}
|
||||
adminStore: adminStore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// The queued event should get dispatched once only i.e. to update the
|
||||
// "global" run state. See the previous test comments for more details.
|
||||
assert.equal(dispatchedEvents.length, 1);
|
||||
assert.equal(dispatchedEvents[0].type, actions.ACTION_TYPES.SET_RUNS_DATA);
|
||||
assert.equal(dispatchedEvents[0].id, 'PR-demo');
|
||||
assert.equal(dispatchedEvents[0].payload.length, 1);
|
||||
assert.equal(dispatchedEvents[0].payload[0].pipeline, 'quicker');
|
||||
assert.equal(dispatchedEvents[0].payload[0].state, 'QUEUED');
|
||||
});
|
||||
// Fire the start event and then check that the run state
|
||||
// has changed as expected.
|
||||
fireEvent();
|
||||
|
||||
// Test queued event is ignored if already received. This can happen because
|
||||
// there are multiple events relating to the run queue lifecycle.
|
||||
it("ignore multiple events with same queueId", () => {
|
||||
|
||||
// mimic invocation of this action dispatcher and inspect the
|
||||
// actualDispatchObj passed to the dispatch function
|
||||
const adminStore = {runs: { 'PR-demo': [] } };
|
||||
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_queue_enter');
|
||||
// modify the event to turn off the blueocean_is_for_current_job flag.
|
||||
// This should result in max of one dispatch per call to dispatcher.
|
||||
event.blueocean_is_for_current_job = false;
|
||||
const dispatcher = actions.actions.processJobQueuedEvent(event);
|
||||
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: adminStore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// fire the dispatcher for the first time...
|
||||
fireEvent();
|
||||
// Should have been dispatched i.e. count === 1 ...
|
||||
assert.equal(adminStore.runs['PR-demo'].length, 1);
|
||||
// fire the dispatcher a second time (same event)...
|
||||
fireEvent();
|
||||
// Should not have been dispatched i.e. count
|
||||
// should still be 1 ...
|
||||
assert.equal(adminStore.runs['PR-demo'].length, 1);
|
||||
});
|
||||
var runs = adminStore.runs['PR-demo'];
|
||||
assert.equal(runs.length, 1);
|
||||
assert.equal(runs[0].enQueueTime, '2016-05-19T22:05:39.301+0100');
|
||||
assert.equal(runs[0].state, 'RUNNING');
|
||||
});
|
||||
|
||||
describe("push events - started run tests", () => {
|
||||
it("run fetch failed", () => {
|
||||
// Mimic the run being in the queued state before the start
|
||||
const adminStore = {
|
||||
runs: {
|
||||
'PR-demo': [{
|
||||
job_run_queueId: '12',
|
||||
pipeline: 'quicker',
|
||||
state: 'QUEUED',
|
||||
result: 'UNKNOWN'
|
||||
}]
|
||||
}
|
||||
};
|
||||
|
||||
// Test run started event for when the event is for the pipeline that
|
||||
// the user is actually "currently" looking at.
|
||||
it("run fetch ok", () => {
|
||||
// Mimic the run being in the queued state before the start
|
||||
const adminStore = {
|
||||
runs: {
|
||||
'PR-demo': [{
|
||||
job_run_queueId: '12',
|
||||
pipeline: 'quicker',
|
||||
state: 'QUEUED',
|
||||
result: 'UNKNOWN'
|
||||
}]
|
||||
}
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_started');
|
||||
event.blueocean_is_for_current_job = false;
|
||||
|
||||
// Mock the fetchJson
|
||||
actions.fetchJson = function(url, onSuccess, onError) {
|
||||
assert.equal(url, '/jenkins/rest/organizations/jenkins/pipelines/PR-demo/branches/quicker/runs/12');
|
||||
onError({});
|
||||
};
|
||||
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_started');
|
||||
event.blueocean_is_for_current_job = false;
|
||||
const dispatcher = actions.actions.updateRunState(event, CONFIG, true);
|
||||
|
||||
// Mock the fetchJson
|
||||
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",
|
||||
"artifacts": [],
|
||||
"changeSet": [],
|
||||
"durationInMillis": 0,
|
||||
"enQueueTime": "2016-05-19T22:05:39.301+0100",
|
||||
"endTime": null,
|
||||
"estimatedDurationInMillis": 17882,
|
||||
"id": "12",
|
||||
"organization": "jenkins",
|
||||
"pipeline": "quicker",
|
||||
"result": "UNKNOWN",
|
||||
"runSummary": "?",
|
||||
"startTime": "2016-05-19T22:05:39.303+0100",
|
||||
"state": "RUNNING",
|
||||
"type": "WorkflowRun",
|
||||
"commitId": null
|
||||
});
|
||||
};
|
||||
|
||||
const dispatcher = actions.actions.updateRunState(event, CONFIG, true);
|
||||
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: adminStore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fire the start event and then check that the run state
|
||||
// has changed as expected.
|
||||
fireEvent();
|
||||
|
||||
var runs = adminStore.runs['PR-demo'];
|
||||
assert.equal(runs.length, 1);
|
||||
assert.equal(runs[0].enQueueTime, '2016-05-19T22:05:39.301+0100');
|
||||
assert.equal(runs[0].state, 'RUNNING');
|
||||
});
|
||||
|
||||
it("run fetch failed", () => {
|
||||
// Mimic the run being in the queued state before the start
|
||||
const adminStore = {
|
||||
runs: {
|
||||
'PR-demo': [{
|
||||
job_run_queueId: '12',
|
||||
pipeline: 'quicker',
|
||||
state: 'QUEUED',
|
||||
result: 'UNKNOWN'
|
||||
}]
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: adminStore
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function fireEvent() {
|
||||
const event = newEvent('job_run_started');
|
||||
event.blueocean_is_for_current_job = false;
|
||||
// Fire the start event and then check that the run state
|
||||
// has changed as expected .
|
||||
fireEvent();
|
||||
|
||||
// Mock the fetchJson
|
||||
actions.fetchJson = function(url, onSuccess, onError) {
|
||||
assert.equal(url, '/jenkins/rest/organizations/jenkins/pipelines/PR-demo/branches/quicker/runs/12');
|
||||
onError({});
|
||||
};
|
||||
|
||||
const dispatcher = actions.actions.updateRunState(event, CONFIG, true);
|
||||
|
||||
dispatcher(function (actualDispatchObj) {
|
||||
adminStore.runs['PR-demo'] = actualDispatchObj.payload;
|
||||
}, function () {
|
||||
return {
|
||||
adminStore: adminStore
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Fire the start event and then check that the run state
|
||||
// has changed as expected .
|
||||
fireEvent();
|
||||
|
||||
var runs = adminStore.runs['PR-demo'];
|
||||
assert.equal(runs.length, 1);
|
||||
// This time, the run state should have changed as expected
|
||||
// because we do it manually when the fetch fails, but we don't
|
||||
// see the time changes etc.
|
||||
assert.equal(runs[0].enQueueTime, undefined);
|
||||
assert.equal(runs[0].state, 'RUNNING');
|
||||
});
|
||||
var runs = adminStore.runs['PR-demo'];
|
||||
assert.equal(runs.length, 1);
|
||||
// This time, the run state should have changed as expected
|
||||
// because we do it manually when the fetch fails, but we don't
|
||||
// see the time changes etc.
|
||||
assert.equal(runs[0].enQueueTime, undefined);
|
||||
assert.equal(runs[0].state, 'RUNNING');
|
||||
});
|
||||
|
||||
} finally {
|
||||
actions.fetchJson = originalFetchJson;
|
||||
}
|
||||
});
|
|
@ -2,7 +2,7 @@ import { assert } from 'chai';
|
|||
import React from 'react';
|
||||
import sd from 'skin-deep';
|
||||
|
||||
import { latestRuns } from './latestRuns';
|
||||
import { latestRuns } from './data/runs/latestRuns';
|
||||
import RunDetailsArtifacts from '../../main/js/components/RunDetailsArtifacts';
|
||||
|
||||
describe('RunDetailsArtifacts', () => {
|
||||
|
|
|
@ -2,7 +2,7 @@ import { assert } from 'chai';
|
|||
import React from 'react';
|
||||
import sd from 'skin-deep';
|
||||
|
||||
import { latestRuns } from './latestRuns';
|
||||
import { latestRuns } from './data/runs/latestRuns';
|
||||
import RunDetailsChanges from '../../main/js/components/RunDetailsChanges';
|
||||
|
||||
describe('RunDetailsChanges', () => {
|
||||
|
|
|
@ -11,15 +11,21 @@ import {
|
|||
currentRuns as currentRunsSelector,
|
||||
} from '../../main/js/redux';
|
||||
import { pipelines } from './pipelines';
|
||||
import { latestRuns } from './latestRuns';
|
||||
import { latestRuns } from './data/runs/latestRuns';
|
||||
import job_crud_created_multibranch from './data/sse/job_crud_created_multibranch';
|
||||
import fetchedBranches from './data/branches/latestBranches';
|
||||
|
||||
const middlewares = [thunk];
|
||||
const mockStore = configureMockStore(middlewares);
|
||||
|
||||
describe("Store should work", () => {
|
||||
import * as actionsModule from '../../main/js/redux/actions';
|
||||
const actionsFetch = actionsModule.fetchJson;
|
||||
|
||||
describe("Redux Store - ", () => {
|
||||
afterEach(() => {
|
||||
nock.cleanAll()
|
||||
})
|
||||
nock.cleanAll();
|
||||
actionsModule.fetchJson = actionsFetch;
|
||||
});
|
||||
it("create store with pipeline data", () => {
|
||||
var ruleId = '/rest/organizations/jenkins/pipelines/';
|
||||
nock('http://example.com')
|
||||
|
@ -55,6 +61,77 @@ describe("Store should work", () => {
|
|||
assert.equal(store.getActions()[0].type, 'CLEAR_CURRENT_RUN_DATA');
|
||||
});
|
||||
});
|
||||
|
||||
const multi_branch_job_crud_job_created = (job_crud_sse_event) => {
|
||||
// Mock the fetching of the latest branches from the REST API.
|
||||
actionsModule.fetchJson = function (url, onSuccess) {
|
||||
onSuccess(fetchedBranches);
|
||||
};
|
||||
|
||||
const actionFunc = actions.updateBranchList(job_crud_sse_event, {
|
||||
getAppURLBase() {
|
||||
return 'http://example.com';
|
||||
}
|
||||
});
|
||||
|
||||
const dispatches = [];
|
||||
|
||||
actionFunc((dispatchConfig) => {
|
||||
dispatches.push(dispatchConfig);
|
||||
}, () => {
|
||||
// fetchedBranches is a 3 branch array. First 2 branches
|
||||
// are older branches (what's in the store) and the 3rd branch is
|
||||
// the new branch relating to the sse event.
|
||||
const currentStoreBranches = [
|
||||
fetchedBranches[0],
|
||||
fetchedBranches[1]
|
||||
];
|
||||
return {
|
||||
adminStore: {
|
||||
branches: {
|
||||
tfprdemo: currentStoreBranches
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
//console.log('------------------');
|
||||
//console.log(dispatches);
|
||||
//console.log('------------------');
|
||||
|
||||
return dispatches;
|
||||
};
|
||||
|
||||
it("multi-branch job_crud_job_created blueocean_is_for_current_job=true", () => {
|
||||
const dispatches = multi_branch_job_crud_job_created(job_crud_created_multibranch);
|
||||
|
||||
// Should be 2 events dispatched because
|
||||
// blueocean_is_for_current_job=true
|
||||
assert.equal(dispatches.length, 2);
|
||||
assert.equal(dispatches[0].id, 'tfprdemo');
|
||||
assert.equal(dispatches[0].type, 'SET_CURRENT_BRANCHES_DATA');
|
||||
assert.equal(dispatches[0].payload.length, 3); // 3 branches as returned by the fetch
|
||||
assert.equal(dispatches[1].id, 'tfprdemo');
|
||||
assert.equal(dispatches[1].type, 'SET_BRANCHES_DATA');
|
||||
assert.equal(dispatches[1].payload.length, 3); // 3 branches as returned by the fetch
|
||||
});
|
||||
|
||||
it("multi-branch job_crud_job_created blueocean_is_for_current_job=false", () => {
|
||||
// Copy the job_crud_created_multibranch event object and modify the
|
||||
// blueocean_is_for_current_job property to false. This switch off
|
||||
// one of the event dispatches.
|
||||
const sse_event = Object.assign({}, job_crud_created_multibranch);
|
||||
sse_event.blueocean_is_for_current_job = false;
|
||||
|
||||
const dispatches = multi_branch_job_crud_job_created(sse_event);
|
||||
|
||||
// Should only be 1 event dispatched because
|
||||
// blueocean_is_for_current_job=false
|
||||
assert.equal(dispatches.length, 1);
|
||||
assert.equal(dispatches[0].id, 'tfprdemo');
|
||||
assert.equal(dispatches[0].type, 'SET_BRANCHES_DATA');
|
||||
assert.equal(dispatches[0].payload.length, 3); // 3 branches as returned by the fetch
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue