screwdriver-api 8.0.20 → 8.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screwdriver-api",
3
- "version": "8.0.20",
3
+ "version": "8.0.21",
4
4
  "description": "API server for the Screwdriver.cd service",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -111,7 +111,7 @@
111
111
  "screwdriver-config-parser": "^12.0.0",
112
112
  "screwdriver-coverage-bookend": "^3.0.0",
113
113
  "screwdriver-coverage-sonar": "^5.0.0",
114
- "screwdriver-data-schema": "^25.2.0",
114
+ "screwdriver-data-schema": "^25.4.0",
115
115
  "screwdriver-datastore-sequelize": "^10.0.0",
116
116
  "screwdriver-executor-base": "^11.0.0",
117
117
  "screwdriver-executor-docker": "^8.0.1",
@@ -120,7 +120,7 @@
120
120
  "screwdriver-executor-queue": "^6.0.0",
121
121
  "screwdriver-executor-router": "^5.0.0",
122
122
  "screwdriver-logger": "^3.0.0",
123
- "screwdriver-models": "^32.0.0",
123
+ "screwdriver-models": "^32.3.0",
124
124
  "screwdriver-notifications-email": "^5.0.0",
125
125
  "screwdriver-notifications-slack": "^7.0.0",
126
126
  "screwdriver-request": "^3.0.0",
@@ -130,7 +130,7 @@
130
130
  "screwdriver-scm-gitlab": "^5.0.1",
131
131
  "screwdriver-scm-router": "^9.0.0",
132
132
  "screwdriver-template-validator": "^10.0.0",
133
- "screwdriver-workflow-parser": "^6.0.0",
133
+ "screwdriver-workflow-parser": "^6.1.0",
134
134
  "sqlite3": "^5.1.4",
135
135
  "stream": "0.0.3",
136
136
  "tinytim": "^0.1.1",
@@ -309,6 +309,52 @@ const uriTrimmer = uri => {
309
309
  return uriToArray.join(':');
310
310
  };
311
311
 
312
+ /**
313
+ * Create metadata by the parsed event
314
+ * @param {Object} parsed It has information to create metadata
315
+ * @returns {Object} Metadata
316
+ */
317
+ function createMeta(parsed) {
318
+ const { action, ref, releaseId, releaseName, releaseAuthor, prMerged, prNum, prRef } = parsed;
319
+
320
+ if (action === 'release') {
321
+ return {
322
+ sd: {
323
+ release: {
324
+ id: releaseId,
325
+ name: releaseName,
326
+ author: releaseAuthor
327
+ },
328
+ tag: {
329
+ name: ref
330
+ }
331
+ }
332
+ };
333
+ }
334
+ if (action === 'tag') {
335
+ return {
336
+ sd: {
337
+ tag: {
338
+ name: ref
339
+ }
340
+ }
341
+ };
342
+ }
343
+ if (action.toLowerCase() === 'closed') {
344
+ return {
345
+ sd: {
346
+ pr: {
347
+ name: prRef,
348
+ merged: prMerged,
349
+ number: prNum
350
+ }
351
+ }
352
+ };
353
+ }
354
+
355
+ return {};
356
+ }
357
+
312
358
  /**
313
359
  * Get all pipelines which has triggered job
314
360
  * @method triggeredPipelines
@@ -697,6 +743,101 @@ async function pullRequestOpened(options, request, h) {
697
743
  });
698
744
  }
699
745
 
746
+ /**
747
+ * Create events for each pipeline
748
+ * @async createPREvents
749
+ * @param {Object} options
750
+ * @param {String} options.username User who created the PR
751
+ * @param {String} options.scmConfig Has the token and scmUri to get branches
752
+ * @param {String} options.sha Specific SHA1 commit to start the build with
753
+ * @param {String} options.prNum Pull request number
754
+ * @param {Array} options.changedFiles List of changed files
755
+ * @param {String} options.branch The branch against which pr is opened
756
+ * @param {String} options.action Event action
757
+ * @param {String} options.prSource The origin of this PR
758
+ * @param {String} options.restrictPR Restrict PR setting
759
+ * @param {Boolean} options.chainPR Chain PR flag
760
+ * @param {Boolean} options.ref Chain PR flag
761
+ * @param {Hapi.request} request Request from user
762
+ * @return {Promise}
763
+ */
764
+ async function createPrClosedEvent(options, request) {
765
+ const { username, scmConfig, prNum, pipelines, changedFiles, branch, action, ref, prSource, restrictPR, chainPR } =
766
+ options;
767
+
768
+ const { scm } = request.server.app.pipelineFactory;
769
+ const { pipelineFactory } = request.server.app;
770
+ const scmDisplayName = scm.getDisplayName({ scmContext: scmConfig.scmContext });
771
+ const userDisplayName = `${scmDisplayName}:${username}`;
772
+ const { sha } = options;
773
+
774
+ scmConfig.prNum = prNum;
775
+
776
+ const eventConfigs = await Promise.all(
777
+ pipelines.map(async p => {
778
+ try {
779
+ const b = await p.branch;
780
+ let eventConfig = {};
781
+
782
+ let configPipelineSha = '';
783
+
784
+ try {
785
+ configPipelineSha = await pipelineFactory.scm.getCommitSha(scmConfig);
786
+ } catch (err) {
787
+ if (err.status >= 500) {
788
+ throw err;
789
+ } else {
790
+ logger.info(`skip create event for branch: ${p.branch}`);
791
+ }
792
+ }
793
+
794
+ const { skipMessage, resolvedChainPR } = getSkipMessageAndChainPR({
795
+ pipeline: !p.annotations ? { annotations: {}, ...p } : p,
796
+ prSource,
797
+ restrictPR,
798
+ chainPR
799
+ });
800
+
801
+ const startFrom = `~pr-closed`;
802
+ const causeMessage = `PR-${prNum} ${action.toLowerCase()} by ${userDisplayName}`;
803
+ const isPipelineBranch = b === branch;
804
+
805
+ eventConfig = {
806
+ pipelineId: p.id,
807
+ type: 'pipeline',
808
+ webhooks: true,
809
+ username,
810
+ scmContext: scmConfig.scmContext,
811
+ sha,
812
+ startFrom: isPipelineBranch ? startFrom : `${startFrom}:${branch}`,
813
+ changedFiles,
814
+ causeMessage: isPipelineBranch ? causeMessage : `${causeMessage} on branch ${branch}`,
815
+ ref,
816
+ baseBranch: branch,
817
+ meta: createMeta(options),
818
+ configPipelineSha,
819
+ prNum,
820
+ chainPR: resolvedChainPR
821
+ };
822
+
823
+ if (skipMessage) {
824
+ eventConfig.skipMessage = skipMessage;
825
+ }
826
+
827
+ return eventConfig;
828
+ } catch (err) {
829
+ logger.warn(`pipeline:${p.id} error in starting event`, err);
830
+
831
+ return null;
832
+ }
833
+ })
834
+ );
835
+
836
+ const events = await startEvents(eventConfigs, request.server);
837
+
838
+ return events;
839
+ }
840
+
700
841
  /**
701
842
  * Stop any running builds and disable the job for closed pull-request
702
843
  * @async pullRequestClosed
@@ -722,23 +863,51 @@ async function pullRequestClosed(options, request, h) {
722
863
  })
723
864
  .then(() => request.log(['webhook', hookId, job.id], `${job.name} disabled and archived`));
724
865
 
725
- return Promise.all(
726
- pipelines.map(p =>
727
- p.getJobs({ type: 'pr' }).then(jobs => {
728
- const prJobs = jobs.filter(j => j.name.includes(name));
866
+ try {
867
+ await Promise.all(
868
+ pipelines.map(p =>
869
+ p.getJobs({ type: 'pr' }).then(jobs => {
870
+ const prJobs = jobs.filter(j => j.name.includes(name));
871
+
872
+ return Promise.all(prJobs.map(j => updatePRJobs(j)));
873
+ })
874
+ )
875
+ );
729
876
 
730
- return Promise.all(prJobs.map(j => updatePRJobs(j)));
731
- })
732
- )
733
- )
734
- .then(() => h.response().code(200))
735
- .catch(err => {
736
- logger.error(
737
- `Failed to pullRequestClosed: [${hookId}, pipeline:${options.pipeline && options.pipeline.id}]: ${err}`
877
+ const prClosedJobs = [];
878
+
879
+ for (const p of pipelines) {
880
+ const jobs = await p.getJobs({ type: 'pipeline' });
881
+ const filteredJobs = jobs.filter(
882
+ j =>
883
+ j.permutations &&
884
+ j.permutations.length > 0 &&
885
+ j.permutations[0] &&
886
+ j.permutations[0].requires &&
887
+ j.permutations[0].requires.includes('~pr-closed')
738
888
  );
739
889
 
740
- throw err;
890
+ prClosedJobs.push(...filteredJobs);
891
+ }
892
+
893
+ if (prClosedJobs.length === 0) {
894
+ return h.response().code(200);
895
+ }
896
+
897
+ const events = await createPrClosedEvent(options, request);
898
+
899
+ events.forEach(e => {
900
+ request.log(['webhook', hookId, e.id], `Event ${e.id} started`);
741
901
  });
902
+
903
+ return h.response().code(201);
904
+ } catch (err) {
905
+ logger.error(
906
+ `Failed to pullRequestClosed: [${hookId}, pipeline:${options.pipeline && options.pipeline.id}]: ${err}`
907
+ );
908
+
909
+ throw err;
910
+ }
742
911
  }
743
912
 
744
913
  /**
@@ -818,41 +987,6 @@ async function obtainScmToken({ pluginOptions, userFactory, username, scmContext
818
987
  return user.unsealToken();
819
988
  }
820
989
 
821
- /**
822
- * Create metadata by the parsed event
823
- * @param {Object} parsed It has information to create metadata
824
- * @returns {Object} Metadata
825
- */
826
- function createMeta(parsed) {
827
- const { action, ref, releaseId, releaseName, releaseAuthor } = parsed;
828
-
829
- if (action === 'release') {
830
- return {
831
- sd: {
832
- release: {
833
- id: releaseId,
834
- name: releaseName,
835
- author: releaseAuthor
836
- },
837
- tag: {
838
- name: ref
839
- }
840
- }
841
- };
842
- }
843
- if (action === 'tag') {
844
- return {
845
- sd: {
846
- tag: {
847
- name: ref
848
- }
849
- }
850
- };
851
- }
852
-
853
- return {};
854
- }
855
-
856
990
  /**
857
991
  * Act on a Pull Request change (create, sync, close)
858
992
  * - Opening a PR should sync the pipeline (creating the job) and start the new PR job
@@ -885,7 +1019,8 @@ function pullRequestEvent(pluginOptions, request, h, parsed, token) {
885
1019
  changedFiles,
886
1020
  type,
887
1021
  releaseName,
888
- ref
1022
+ ref,
1023
+ prMerged
889
1024
  } = parsed;
890
1025
  const fullCheckoutUrl = `${checkoutUrl}#${branch}`;
891
1026
  const scmConfig = {
@@ -935,7 +1070,8 @@ function pullRequestEvent(pluginOptions, request, h, parsed, token) {
935
1070
  chainPR,
936
1071
  pipelines,
937
1072
  ref,
938
- releaseName
1073
+ releaseName,
1074
+ prMerged
939
1075
  };
940
1076
 
941
1077
  await batchUpdateAdmins({ userFactory, pipelines, username, scmContext, pipelineFactory });