diff --git a/lib/event.js b/lib/event.js index a66589cb..5b407ba6 100644 --- a/lib/event.js +++ b/lib/event.js @@ -54,9 +54,9 @@ class EventModel extends BaseModel { /* eslint-disable global-require */ const BuildFactory = require('./buildFactory'); /* eslint-enable global-require */ - const factory = BuildFactory.getInstance(); + const buildFactory = BuildFactory.getInstance(); - return factory.list(listConfig); + return buildFactory.list(listConfig); } /** diff --git a/lib/pipeline.js b/lib/pipeline.js index c8354490..af65d910 100644 --- a/lib/pipeline.js +++ b/lib/pipeline.js @@ -20,6 +20,7 @@ const MAX_EVENT_DELETE_COUNT = 100; // The default page for fetching not by aggregatedInteval // And the start page for fetching by aggregatedInteval const DEFAULT_PAGE = 1; +const DEFAULT_COUNT = 10; const SCM_NO_ACCESS_STATUSES = [401, 404]; const { getAllRecords, getBuildClusterName, getFullStageJobName } = require('./helper'); @@ -1658,6 +1659,75 @@ class PipelineModel extends BaseModel { return factory.list(listConfig); } + /** + * Fetch builds belonging to a pipeline or events + * @param {Object} [config] + * @param {Number} [config.sort] Sort rangekey by ascending or descending + * @param {Number} [config.sortBy] Sortby field + * @param {Object} [config.paginate] Pagination parameters + * @param {Number} [config.paginate.count] Number of items per page + * @param {Number} [config.paginate.page] Specific page of the set to return + * @param {Number} [config.groupEventId] Group event ID + * @param {Boolean} [config.latest] If we want to return latest in groupEventId, default false + * @return {Promise} Resolves to an array of builds + */ + async getBuilds(config = {}) { + const { sort } = config; + const latest = hoek.reach(config, 'params.latest'); + const groupEventId = hoek.reach(config, 'params.groupEventId'); + + // Fetch all builds for each event with same groupEventId + if (groupEventId && !latest) { + // Lazy load factory dependency to prevent circular dependency issues + // https://nodejs.org/api/modules.html#modules_cycles + /* eslint-disable global-require */ + const EventFactory = require('./eventFactory'); + /* eslint-enable global-require */ + const eventFactory = EventFactory.getInstance(); + const events = await eventFactory.list({ + params: { groupEventId } + }); + const processed = []; + + events.forEach(e => processed.push(e.getBuilds())); + + return Promise.all(processed).then(builds => { + // flatten array of arrays + return builds.flat(1); + }); + } + // Lazy load factory dependency to prevent circular dependency issues + // https://nodejs.org/api/modules.html#modules_cycles + /* eslint-disable global-require */ + const BuildFactory = require('./buildFactory'); + /* eslint-enable global-require */ + const buildFactory = BuildFactory.getInstance(); + + // Fetch only latest builds with same groupEventId + if (latest && groupEventId) { + return buildFactory.getLatestBuilds({ + groupEventId: config.params.groupEventId + }); + } + + // Latest should not be passed to list config + if (latest !== undefined) { + delete config.params.latest; + } + + // Fetch builds for this pipeline with default count and page (implicitly set to 1) + const defaultConfig = { + params: { pipelineId: this.id }, + paginate: { + count: DEFAULT_COUNT + }, + sort: sort ? sort.toLowerCase() : 'descending' // Sort by primary sort key + }; + const listConfig = config ? hoek.applyToDefaults(defaultConfig, config) : defaultConfig; + + return buildFactory.list(listConfig); + } + /** * Update the repository and branch * @method update diff --git a/test/lib/pipeline.test.js b/test/lib/pipeline.test.js index 993e3e85..22078c6a 100644 --- a/test/lib/pipeline.test.js +++ b/test/lib/pipeline.test.js @@ -265,7 +265,8 @@ describe('Pipeline Model', () => { list: sinon.stub() }; buildFactoryMock = { - list: sinon.stub() + list: sinon.stub(), + getLatestBuilds: sinon.stub() }; userFactoryMock = { get: sinon.stub(), @@ -2593,6 +2594,122 @@ describe('Pipeline Model', () => { }); }); + describe('get builds', () => { + const builds = [ + { + id: '777' + }, + { + id: '778' + }, + { + id: '779' + } + ]; + const events = [ + { + id: '12345f642bbfd1886623964b4cff12db59869e5d', + getBuilds: sinon.stub().resolves(builds) + }, + { + id: '12855123cc7f1b808aac07feff24d7d5362cc215', + getBuilds: sinon.stub().resolves(builds) + } + ]; + const groupEventId = 999; + + it('gets a list of builds by groupEventId', () => { + const expected = { + params: { groupEventId } + }; + + eventFactoryMock.list.resolves(events); + + return pipeline.getBuilds({ params: { groupEventId } }).then(result => { + assert.calledWith(eventFactoryMock.list, expected); + assert.deepEqual(result, builds.concat(builds)); + }); + }); + + it('returns empty array when no events found for groupEventId', () => { + const expected = { + params: { groupEventId } + }; + + eventFactoryMock.list.resolves([]); + + return pipeline.getBuilds({ params: { groupEventId } }).then(result => { + assert.calledWith(eventFactoryMock.list, expected); + assert.deepEqual(result, []); + }); + }); + + it('gets latest builds', () => { + const expected = { + groupEventId + }; + + buildFactoryMock.getLatestBuilds.resolves(builds); + + return pipeline + .getBuilds({ + params: { + groupEventId, + latest: true + } + }) + .then(result => { + assert.calledWith(buildFactoryMock.getLatestBuilds, expected); + assert.notCalled(buildFactoryMock.list); + assert.deepEqual(result, builds); + }); + }); + + it('gets a list of builds with default pagination', () => { + const expected = { + params: { pipelineId: 123 }, + paginate: { count: 10 }, + sort: 'descending' + }; + + buildFactoryMock.list.resolves(builds); + + return pipeline.getBuilds({}).then(result => { + assert.calledWith(buildFactoryMock.list, expected); + assert.deepEqual(result, builds); + }); + }); + + it('gets a list of builds and does not pass through latest when groupEventId not set', () => { + const expected = { + params: { pipelineId: 123 }, + paginate: { count: 300, page: 2 }, + sort: 'descending' + }; + + buildFactoryMock.list.resolves(builds); + + return pipeline.getBuilds({ params: { latest: true }, paginate: { count: 300, page: 2 } }).then(result => { + assert.calledWith(buildFactoryMock.list, expected); + assert.deepEqual(result, builds); + }); + }); + + it('rejects with errors', () => { + buildFactoryMock.list.rejects(new Error('cannotgetit')); + + return pipeline + .getBuilds() + .then(() => { + assert.fail('Should not get here'); + }) + .catch(err => { + assert.instanceOf(err, Error); + assert.equal(err.message, 'cannotgetit'); + }); + }); + }); + describe('getConfiguration', () => { let parserConfig; let getFileConfig;