airbyte-faros-destination 0.1.53

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.
Files changed (280) hide show
  1. package/README.md +161 -0
  2. package/lib/common/write-stats.d.ts +16 -0
  3. package/lib/common/write-stats.js +48 -0
  4. package/lib/community/hasura-client.d.ts +27 -0
  5. package/lib/community/hasura-client.js +278 -0
  6. package/lib/community/hasura-writer.d.ts +12 -0
  7. package/lib/community/hasura-writer.js +44 -0
  8. package/lib/community/types.d.ts +26 -0
  9. package/lib/community/types.js +9 -0
  10. package/lib/converters/agileaccelerator/agileaccelerator_types.d.ts +315 -0
  11. package/lib/converters/agileaccelerator/agileaccelerator_types.js +81 -0
  12. package/lib/converters/agileaccelerator/common.d.ts +64 -0
  13. package/lib/converters/agileaccelerator/common.js +167 -0
  14. package/lib/converters/agileaccelerator/works.d.ts +7 -0
  15. package/lib/converters/agileaccelerator/works.js +105 -0
  16. package/lib/converters/asana/common.d.ts +39 -0
  17. package/lib/converters/asana/common.js +64 -0
  18. package/lib/converters/asana/projects.d.ts +7 -0
  19. package/lib/converters/asana/projects.js +29 -0
  20. package/lib/converters/asana/sections.d.ts +7 -0
  21. package/lib/converters/asana/sections.js +28 -0
  22. package/lib/converters/asana/stories.d.ts +7 -0
  23. package/lib/converters/asana/stories.js +32 -0
  24. package/lib/converters/asana/tags.d.ts +7 -0
  25. package/lib/converters/asana/tags.js +22 -0
  26. package/lib/converters/asana/tasks.d.ts +11 -0
  27. package/lib/converters/asana/tasks.js +160 -0
  28. package/lib/converters/asana/users.d.ts +7 -0
  29. package/lib/converters/asana/users.js +16 -0
  30. package/lib/converters/backlog/common.d.ts +20 -0
  31. package/lib/converters/backlog/common.js +59 -0
  32. package/lib/converters/backlog/issues.d.ts +7 -0
  33. package/lib/converters/backlog/issues.js +119 -0
  34. package/lib/converters/backlog/models.d.ts +156 -0
  35. package/lib/converters/backlog/models.js +23 -0
  36. package/lib/converters/backlog/projects.d.ts +7 -0
  37. package/lib/converters/backlog/projects.js +78 -0
  38. package/lib/converters/backlog/users.d.ts +7 -0
  39. package/lib/converters/backlog/users.js +26 -0
  40. package/lib/converters/bitbucket/branches.d.ts +7 -0
  41. package/lib/converters/bitbucket/branches.js +31 -0
  42. package/lib/converters/bitbucket/commits.d.ts +7 -0
  43. package/lib/converters/bitbucket/commits.js +50 -0
  44. package/lib/converters/bitbucket/common.d.ts +28 -0
  45. package/lib/converters/bitbucket/common.js +56 -0
  46. package/lib/converters/bitbucket/deployments.d.ts +11 -0
  47. package/lib/converters/bitbucket/deployments.js +100 -0
  48. package/lib/converters/bitbucket/issues.d.ts +12 -0
  49. package/lib/converters/bitbucket/issues.js +111 -0
  50. package/lib/converters/bitbucket/pipeline_steps.d.ts +10 -0
  51. package/lib/converters/bitbucket/pipeline_steps.js +83 -0
  52. package/lib/converters/bitbucket/pipelines.d.ts +8 -0
  53. package/lib/converters/bitbucket/pipelines.js +90 -0
  54. package/lib/converters/bitbucket/pull_request_activities.d.ts +13 -0
  55. package/lib/converters/bitbucket/pull_request_activities.js +112 -0
  56. package/lib/converters/bitbucket/pull_requests.d.ts +10 -0
  57. package/lib/converters/bitbucket/pull_requests.js +95 -0
  58. package/lib/converters/bitbucket/repositories.d.ts +9 -0
  59. package/lib/converters/bitbucket/repositories.js +41 -0
  60. package/lib/converters/bitbucket/types.d.ts +667 -0
  61. package/lib/converters/bitbucket/types.js +2 -0
  62. package/lib/converters/bitbucket/workspace_users.d.ts +7 -0
  63. package/lib/converters/bitbucket/workspace_users.js +31 -0
  64. package/lib/converters/bitbucket/workspaces.d.ts +8 -0
  65. package/lib/converters/bitbucket/workspaces.js +61 -0
  66. package/lib/converters/converter-registry.d.ts +25 -0
  67. package/lib/converters/converter-registry.js +64 -0
  68. package/lib/converters/converter.d.ts +63 -0
  69. package/lib/converters/converter.js +122 -0
  70. package/lib/converters/datadog/common.d.ts +27 -0
  71. package/lib/converters/datadog/common.js +34 -0
  72. package/lib/converters/datadog/incidents.d.ts +9 -0
  73. package/lib/converters/datadog/incidents.js +128 -0
  74. package/lib/converters/datadog/users.d.ts +7 -0
  75. package/lib/converters/datadog/users.js +27 -0
  76. package/lib/converters/docker/common.d.ts +87 -0
  77. package/lib/converters/docker/common.js +76 -0
  78. package/lib/converters/docker/tags.d.ts +8 -0
  79. package/lib/converters/docker/tags.js +98 -0
  80. package/lib/converters/github/assignees.d.ts +7 -0
  81. package/lib/converters/github/assignees.js +16 -0
  82. package/lib/converters/github/branches.d.ts +7 -0
  83. package/lib/converters/github/branches.js +28 -0
  84. package/lib/converters/github/collaborators.d.ts +7 -0
  85. package/lib/converters/github/collaborators.js +19 -0
  86. package/lib/converters/github/commits.d.ts +7 -0
  87. package/lib/converters/github/commits.js +48 -0
  88. package/lib/converters/github/common.d.ts +37 -0
  89. package/lib/converters/github/common.js +130 -0
  90. package/lib/converters/github/issue_labels.d.ts +7 -0
  91. package/lib/converters/github/issue_labels.js +20 -0
  92. package/lib/converters/github/issue_milestones.d.ts +8 -0
  93. package/lib/converters/github/issue_milestones.js +42 -0
  94. package/lib/converters/github/issues.d.ts +9 -0
  95. package/lib/converters/github/issues.js +90 -0
  96. package/lib/converters/github/organizations.d.ts +7 -0
  97. package/lib/converters/github/organizations.js +37 -0
  98. package/lib/converters/github/projects.d.ts +7 -0
  99. package/lib/converters/github/projects.js +21 -0
  100. package/lib/converters/github/pull_request_stats.d.ts +7 -0
  101. package/lib/converters/github/pull_request_stats.js +43 -0
  102. package/lib/converters/github/pull_requests.d.ts +7 -0
  103. package/lib/converters/github/pull_requests.js +63 -0
  104. package/lib/converters/github/releases.d.ts +7 -0
  105. package/lib/converters/github/releases.js +51 -0
  106. package/lib/converters/github/repositories.d.ts +7 -0
  107. package/lib/converters/github/repositories.js +44 -0
  108. package/lib/converters/github/review_comments.d.ts +7 -0
  109. package/lib/converters/github/review_comments.js +39 -0
  110. package/lib/converters/github/reviews.d.ts +7 -0
  111. package/lib/converters/github/reviews.js +58 -0
  112. package/lib/converters/github/tags.d.ts +7 -0
  113. package/lib/converters/github/tags.js +31 -0
  114. package/lib/converters/github/users.d.ts +7 -0
  115. package/lib/converters/github/users.js +19 -0
  116. package/lib/converters/gitlab/branches.d.ts +8 -0
  117. package/lib/converters/gitlab/branches.js +44 -0
  118. package/lib/converters/gitlab/commits.d.ts +7 -0
  119. package/lib/converters/gitlab/commits.js +33 -0
  120. package/lib/converters/gitlab/common.d.ts +30 -0
  121. package/lib/converters/gitlab/common.js +70 -0
  122. package/lib/converters/gitlab/group_labels.d.ts +7 -0
  123. package/lib/converters/gitlab/group_labels.js +15 -0
  124. package/lib/converters/gitlab/group_milestones.d.ts +8 -0
  125. package/lib/converters/gitlab/group_milestones.js +41 -0
  126. package/lib/converters/gitlab/groups.d.ts +7 -0
  127. package/lib/converters/gitlab/groups.js +43 -0
  128. package/lib/converters/gitlab/issues.d.ts +10 -0
  129. package/lib/converters/gitlab/issues.js +79 -0
  130. package/lib/converters/gitlab/jobs.d.ts +11 -0
  131. package/lib/converters/gitlab/jobs.js +75 -0
  132. package/lib/converters/gitlab/merge_request_commits.d.ts +7 -0
  133. package/lib/converters/gitlab/merge_request_commits.js +34 -0
  134. package/lib/converters/gitlab/merge_requests.d.ts +10 -0
  135. package/lib/converters/gitlab/merge_requests.js +65 -0
  136. package/lib/converters/gitlab/pipelines.d.ts +7 -0
  137. package/lib/converters/gitlab/pipelines.js +41 -0
  138. package/lib/converters/gitlab/project_labels.d.ts +7 -0
  139. package/lib/converters/gitlab/project_labels.js +15 -0
  140. package/lib/converters/gitlab/project_milestones.d.ts +8 -0
  141. package/lib/converters/gitlab/project_milestones.js +41 -0
  142. package/lib/converters/gitlab/projects.d.ts +7 -0
  143. package/lib/converters/gitlab/projects.js +51 -0
  144. package/lib/converters/gitlab/releases.d.ts +10 -0
  145. package/lib/converters/gitlab/releases.js +68 -0
  146. package/lib/converters/gitlab/tags.d.ts +10 -0
  147. package/lib/converters/gitlab/tags.js +41 -0
  148. package/lib/converters/gitlab/users.d.ts +7 -0
  149. package/lib/converters/gitlab/users.js +33 -0
  150. package/lib/converters/googlecalendar/calendar_models.d.ts +618 -0
  151. package/lib/converters/googlecalendar/calendar_models.js +2 -0
  152. package/lib/converters/googlecalendar/calendars.d.ts +7 -0
  153. package/lib/converters/googlecalendar/calendars.js +29 -0
  154. package/lib/converters/googlecalendar/common.d.ts +52 -0
  155. package/lib/converters/googlecalendar/common.js +130 -0
  156. package/lib/converters/googlecalendar/events.d.ts +8 -0
  157. package/lib/converters/googlecalendar/events.js +117 -0
  158. package/lib/converters/harness/common.d.ts +105 -0
  159. package/lib/converters/harness/common.js +16 -0
  160. package/lib/converters/harness/executions.d.ts +15 -0
  161. package/lib/converters/harness/executions.js +245 -0
  162. package/lib/converters/jenkins/builds.d.ts +9 -0
  163. package/lib/converters/jenkins/builds.js +74 -0
  164. package/lib/converters/jenkins/common.d.ts +25 -0
  165. package/lib/converters/jenkins/common.js +54 -0
  166. package/lib/converters/jenkins/jobs.d.ts +8 -0
  167. package/lib/converters/jenkins/jobs.js +29 -0
  168. package/lib/converters/jira/board_issues.d.ts +7 -0
  169. package/lib/converters/jira/board_issues.js +28 -0
  170. package/lib/converters/jira/boards.d.ts +7 -0
  171. package/lib/converters/jira/boards.js +34 -0
  172. package/lib/converters/jira/common.d.ts +61 -0
  173. package/lib/converters/jira/common.js +64 -0
  174. package/lib/converters/jira/epics.d.ts +8 -0
  175. package/lib/converters/jira/epics.js +45 -0
  176. package/lib/converters/jira/issue_fields.d.ts +7 -0
  177. package/lib/converters/jira/issue_fields.js +15 -0
  178. package/lib/converters/jira/issues.d.ts +52 -0
  179. package/lib/converters/jira/issues.js +545 -0
  180. package/lib/converters/jira/project_versions.d.ts +9 -0
  181. package/lib/converters/jira/project_versions.js +48 -0
  182. package/lib/converters/jira/projects.d.ts +7 -0
  183. package/lib/converters/jira/projects.js +40 -0
  184. package/lib/converters/jira/pull_requests.d.ts +7 -0
  185. package/lib/converters/jira/pull_requests.js +15 -0
  186. package/lib/converters/jira/sprint_issues.d.ts +7 -0
  187. package/lib/converters/jira/sprint_issues.js +15 -0
  188. package/lib/converters/jira/sprints.d.ts +16 -0
  189. package/lib/converters/jira/sprints.js +80 -0
  190. package/lib/converters/jira/users.d.ts +8 -0
  191. package/lib/converters/jira/users.js +33 -0
  192. package/lib/converters/jira/workflow_statuses.d.ts +7 -0
  193. package/lib/converters/jira/workflow_statuses.js +15 -0
  194. package/lib/converters/jsonata.d.ts +17 -0
  195. package/lib/converters/jsonata.js +47 -0
  196. package/lib/converters/okta/common.d.ts +8 -0
  197. package/lib/converters/okta/common.js +17 -0
  198. package/lib/converters/okta/groups.d.ts +7 -0
  199. package/lib/converters/okta/groups.js +47 -0
  200. package/lib/converters/okta/models.d.ts +102 -0
  201. package/lib/converters/okta/models.js +2 -0
  202. package/lib/converters/okta/users.d.ts +8 -0
  203. package/lib/converters/okta/users.js +73 -0
  204. package/lib/converters/okta_faros/common.d.ts +4 -0
  205. package/lib/converters/okta_faros/common.js +11 -0
  206. package/lib/converters/okta_faros/groups.d.ts +13 -0
  207. package/lib/converters/okta_faros/groups.js +23 -0
  208. package/lib/converters/okta_faros/users.d.ts +13 -0
  209. package/lib/converters/okta_faros/users.js +23 -0
  210. package/lib/converters/pagerduty/common.d.ts +37 -0
  211. package/lib/converters/pagerduty/common.js +40 -0
  212. package/lib/converters/pagerduty/incident_log_entries.d.ts +8 -0
  213. package/lib/converters/pagerduty/incident_log_entries.js +56 -0
  214. package/lib/converters/pagerduty/incidents.d.ts +10 -0
  215. package/lib/converters/pagerduty/incidents.js +127 -0
  216. package/lib/converters/pagerduty/priorities_resource.d.ts +11 -0
  217. package/lib/converters/pagerduty/priorities_resource.js +64 -0
  218. package/lib/converters/pagerduty/users.d.ts +7 -0
  219. package/lib/converters/pagerduty/users.js +26 -0
  220. package/lib/converters/phabricator/commits.d.ts +8 -0
  221. package/lib/converters/phabricator/commits.js +75 -0
  222. package/lib/converters/phabricator/common.d.ts +40 -0
  223. package/lib/converters/phabricator/common.js +107 -0
  224. package/lib/converters/phabricator/repositories.d.ts +7 -0
  225. package/lib/converters/phabricator/repositories.js +56 -0
  226. package/lib/converters/phabricator/revisions.d.ts +7 -0
  227. package/lib/converters/phabricator/revisions.js +83 -0
  228. package/lib/converters/phabricator/users.d.ts +7 -0
  229. package/lib/converters/phabricator/users.js +39 -0
  230. package/lib/converters/shortcut/common.d.ts +16 -0
  231. package/lib/converters/shortcut/common.js +68 -0
  232. package/lib/converters/shortcut/epics.d.ts +7 -0
  233. package/lib/converters/shortcut/epics.js +29 -0
  234. package/lib/converters/shortcut/iterations.d.ts +7 -0
  235. package/lib/converters/shortcut/iterations.js +29 -0
  236. package/lib/converters/shortcut/members.d.ts +7 -0
  237. package/lib/converters/shortcut/members.js +26 -0
  238. package/lib/converters/shortcut/models.d.ts +392 -0
  239. package/lib/converters/shortcut/models.js +30 -0
  240. package/lib/converters/shortcut/projects.d.ts +7 -0
  241. package/lib/converters/shortcut/projects.js +46 -0
  242. package/lib/converters/shortcut/stories.d.ts +7 -0
  243. package/lib/converters/shortcut/stories.js +127 -0
  244. package/lib/converters/squadcast/common.d.ts +169 -0
  245. package/lib/converters/squadcast/common.js +62 -0
  246. package/lib/converters/squadcast/events.d.ts +9 -0
  247. package/lib/converters/squadcast/events.js +53 -0
  248. package/lib/converters/squadcast/incidents.d.ts +10 -0
  249. package/lib/converters/squadcast/incidents.js +141 -0
  250. package/lib/converters/squadcast/services.d.ts +7 -0
  251. package/lib/converters/squadcast/services.js +28 -0
  252. package/lib/converters/squadcast/users.d.ts +7 -0
  253. package/lib/converters/squadcast/users.js +27 -0
  254. package/lib/converters/statuspage/common.d.ts +93 -0
  255. package/lib/converters/statuspage/common.js +80 -0
  256. package/lib/converters/statuspage/incident_updates.d.ts +8 -0
  257. package/lib/converters/statuspage/incident_updates.js +45 -0
  258. package/lib/converters/statuspage/incidents.d.ts +10 -0
  259. package/lib/converters/statuspage/incidents.js +128 -0
  260. package/lib/converters/statuspage/users.d.ts +7 -0
  261. package/lib/converters/statuspage/users.js +26 -0
  262. package/lib/converters/victorops/common.d.ts +16 -0
  263. package/lib/converters/victorops/common.js +24 -0
  264. package/lib/converters/victorops/incidents.d.ts +12 -0
  265. package/lib/converters/victorops/incidents.js +209 -0
  266. package/lib/converters/victorops/teams.d.ts +8 -0
  267. package/lib/converters/victorops/teams.js +30 -0
  268. package/lib/converters/victorops/users.d.ts +8 -0
  269. package/lib/converters/victorops/users.js +33 -0
  270. package/lib/destination-runner.d.ts +12 -0
  271. package/lib/destination-runner.js +22 -0
  272. package/lib/destination.d.ts +42 -0
  273. package/lib/destination.js +508 -0
  274. package/lib/index.d.ts +16 -0
  275. package/lib/index.js +39 -0
  276. package/lib/tsconfig.tsbuildinfo +1 -0
  277. package/package.json +71 -0
  278. package/resources/fetch-primary-keys.sql +16 -0
  279. package/resources/introspection-query.gql +61 -0
  280. package/resources/spec.json +468 -0
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Epics = void 0;
7
+ const turndown_1 = __importDefault(require("turndown"));
8
+ const common_1 = require("./common");
9
+ class Epics extends common_1.JiraConverter {
10
+ constructor() {
11
+ super(...arguments);
12
+ this.destinationModels = ['tms_Epic'];
13
+ this.turndown = new turndown_1.default();
14
+ }
15
+ async convert(record, ctx) {
16
+ var _a, _b, _c;
17
+ const epic = record.record.data;
18
+ const source = this.streamName.source;
19
+ const status = (_a = epic.fields.status) !== null && _a !== void 0 ? _a : {};
20
+ let description = null;
21
+ if (typeof epic.fields.description === 'string') {
22
+ description = epic.fields.description;
23
+ }
24
+ else if (epic.renderedFields.description) {
25
+ description = this.turndown.turndown(epic.renderedFields.description);
26
+ }
27
+ return [
28
+ {
29
+ model: 'tms_Epic',
30
+ record: {
31
+ uid: epic.key,
32
+ name: (_b = epic.fields.summary) !== null && _b !== void 0 ? _b : null,
33
+ description: this.truncate(ctx, description),
34
+ status: {
35
+ category: common_1.JiraStatusCategories.get(common_1.JiraCommon.normalize((_c = status.statusCategory) === null || _c === void 0 ? void 0 : _c.name)),
36
+ detail: status.name,
37
+ },
38
+ project: { uid: epic.projectKey, source },
39
+ source,
40
+ },
41
+ },
42
+ ];
43
+ }
44
+ }
45
+ exports.Epics = Epics;
@@ -0,0 +1,7 @@
1
+ import { AirbyteRecord } from 'faros-airbyte-cdk';
2
+ import { DestinationModel, DestinationRecord, StreamContext } from '../converter';
3
+ import { JiraConverter } from './common';
4
+ export declare class IssueFields extends JiraConverter {
5
+ readonly destinationModels: ReadonlyArray<DestinationModel>;
6
+ convert(record: AirbyteRecord, ctx: StreamContext): Promise<ReadonlyArray<DestinationRecord>>;
7
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IssueFields = void 0;
4
+ const common_1 = require("./common");
5
+ // Required as dependency by Issues and Sprints stream
6
+ class IssueFields extends common_1.JiraConverter {
7
+ constructor() {
8
+ super(...arguments);
9
+ this.destinationModels = [];
10
+ }
11
+ async convert(record, ctx) {
12
+ return [];
13
+ }
14
+ }
15
+ exports.IssueFields = IssueFields;
@@ -0,0 +1,52 @@
1
+ import { AirbyteRecord } from 'faros-airbyte-cdk';
2
+ import { DestinationModel, DestinationRecord, StreamContext, StreamName } from '../converter';
3
+ import { JiraConverter } from './common';
4
+ export declare class Issues extends JiraConverter {
5
+ private logger;
6
+ readonly destinationModels: ReadonlyArray<DestinationModel>;
7
+ private static readonly issueFieldsStream;
8
+ private static readonly pullRequestsStream;
9
+ private static readonly workflowStatusesStream;
10
+ private static readonly standardFieldIds;
11
+ private static readonly fieldsToIgnore;
12
+ private fieldIdsByName?;
13
+ private fieldNameById?;
14
+ private statusByName?;
15
+ private turndown;
16
+ get dependencies(): ReadonlyArray<StreamName>;
17
+ private static getFieldIdsByName;
18
+ private static getFieldNamesById;
19
+ private static getStatusesByName;
20
+ private static fieldChangelog;
21
+ private static assigneeChangelog;
22
+ private statusChangelog;
23
+ private getIssueEpic;
24
+ private getSprintId;
25
+ private getPoints;
26
+ private static extractRepo;
27
+ /**
28
+ * Attempts to retrieve a field's value from several typical locations within
29
+ * the field's JSON blob. If the blob is an array, then each item's value will
30
+ * be added to an array of strings which will be an entry in the returned
31
+ * object. Also each item in the array will be exploded across the returned
32
+ * object with the key '<name>_<index>'. If nothing can be done, then
33
+ * the JSON blob is set to the additional field's value after being stringified.
34
+ *
35
+ * @param name The name of the additional field
36
+ * @param jsonValue The field's JSON blob to retrieve the value from
37
+ * @return The Record of additional fields
38
+ */
39
+ private retrieveAdditionalFieldValue;
40
+ /**
41
+ * Check for existence of the members 'value', 'name' and then
42
+ * 'displayName'in that order and return when one is found
43
+ * (or undefined if none).
44
+ *
45
+ * @param jsonValue The object whose members should be considered
46
+ * @returns The value, name or displayName within the object
47
+ */
48
+ private retrieveFieldValue;
49
+ private getPullRequests;
50
+ private stringifyNonString;
51
+ convert(record: AirbyteRecord, ctx: StreamContext): Promise<ReadonlyArray<DestinationRecord>>;
52
+ }
@@ -0,0 +1,545 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.Issues = void 0;
7
+ const faros_airbyte_cdk_1 = require("faros-airbyte-cdk");
8
+ const faros_feeds_sdk_1 = require("faros-feeds-sdk");
9
+ const git_url_parse_1 = __importDefault(require("git-url-parse"));
10
+ const lodash_1 = require("lodash");
11
+ const turndown_1 = __importDefault(require("turndown"));
12
+ const converter_1 = require("../converter");
13
+ const common_1 = require("./common");
14
+ const dependencyRegex = /((is (?<type>\w+))|tested) by/;
15
+ const sprintRegex = /([\w]+)=([\w-:. ]+)/g;
16
+ const statusCategories = new Map(['Todo', 'InProgress', 'Done'].map((s) => [common_1.JiraCommon.normalize(s), s]));
17
+ const typeCategories = new Map(['Bug', 'Story', 'Task'].map((t) => [common_1.JiraCommon.normalize(t), t]));
18
+ class Issues extends common_1.JiraConverter {
19
+ constructor() {
20
+ super(...arguments);
21
+ this.logger = new faros_airbyte_cdk_1.AirbyteLogger();
22
+ this.destinationModels = [
23
+ 'tms_Task',
24
+ 'tms_TaskProjectRelationship',
25
+ 'tms_TaskReleaseRelationship',
26
+ 'tms_TaskBoardRelationship',
27
+ 'tms_TaskAssignment',
28
+ 'tms_TaskDependency',
29
+ 'tms_TaskTag',
30
+ 'tms_TaskPullRequestAssociation',
31
+ ];
32
+ this.turndown = new turndown_1.default();
33
+ }
34
+ get dependencies() {
35
+ return [
36
+ Issues.issueFieldsStream,
37
+ Issues.pullRequestsStream,
38
+ Issues.workflowStatusesStream,
39
+ ];
40
+ }
41
+ static getFieldIdsByName(ctx) {
42
+ const records = ctx.getAll(Issues.issueFieldsStream.asString);
43
+ return (0, lodash_1.invertBy)((0, lodash_1.mapValues)(records, (r) => r.record.data.name));
44
+ }
45
+ static getFieldNamesById(ctx) {
46
+ const records = ctx.getAll(Issues.issueFieldsStream.asString);
47
+ return (0, lodash_1.mapValues)(records, (r) => r.record.data.name);
48
+ }
49
+ static getStatusesByName(ctx) {
50
+ const records = ctx.getAll(Issues.workflowStatusesStream.asString);
51
+ return (0, lodash_1.keyBy)(Object.values(records).map((r) => {
52
+ const data = r.record.data;
53
+ return {
54
+ detail: data.name,
55
+ category: data.statusCategory.name,
56
+ };
57
+ }), (s) => s.detail);
58
+ }
59
+ static fieldChangelog(changelog, field, fromField = 'fromString', valueField = 'toString') {
60
+ const fieldChangelog = [];
61
+ // Changelog entries are sorted from most to least recent
62
+ for (const change of changelog) {
63
+ for (const item of change.items) {
64
+ if (item.field === field) {
65
+ const changed = faros_feeds_sdk_1.Utils.toDate(change.created);
66
+ if (!changed) {
67
+ continue;
68
+ }
69
+ fieldChangelog.push({
70
+ from: item[fromField],
71
+ field,
72
+ value: item[valueField],
73
+ changed,
74
+ });
75
+ }
76
+ }
77
+ }
78
+ return fieldChangelog;
79
+ }
80
+ static assigneeChangelog(changelog, currentAssignee, created) {
81
+ const assigneeChangelog = [];
82
+ const assigneeChanges = Issues.fieldChangelog(changelog, 'assignee', 'from', 'to');
83
+ if (assigneeChanges.length) {
84
+ // case where task was already assigned at creation
85
+ const firstChange = assigneeChanges[0];
86
+ if (firstChange.from) {
87
+ const assignee = { uid: firstChange.from, assignedAt: created };
88
+ assigneeChangelog.push(assignee);
89
+ }
90
+ for (const change of assigneeChanges) {
91
+ const assignee = { uid: change.value, assignedAt: change.changed };
92
+ assigneeChangelog.push(assignee);
93
+ }
94
+ }
95
+ else if (currentAssignee) {
96
+ // if task was assigned at creation and never changed
97
+ assigneeChangelog.push({ uid: currentAssignee, assignedAt: created });
98
+ }
99
+ return assigneeChangelog;
100
+ }
101
+ statusChangelog(changelog, currentStatus, created) {
102
+ const statusChangelog = [];
103
+ const pushStatusChange = (statusName, date) => {
104
+ const status = this.statusByName[statusName];
105
+ if (status)
106
+ statusChangelog.push({ status, changedAt: date });
107
+ };
108
+ const statusChanges = Issues.fieldChangelog(changelog, 'status');
109
+ if (statusChanges.length) {
110
+ // status that was assigned at creation
111
+ const firstChange = statusChanges[0];
112
+ if (firstChange.from) {
113
+ pushStatusChange(firstChange.from, created);
114
+ }
115
+ for (const change of statusChanges) {
116
+ pushStatusChange(change.value, change.changed);
117
+ }
118
+ }
119
+ else if (currentStatus) {
120
+ // if task was given status at creation and never changed
121
+ pushStatusChange(currentStatus, created);
122
+ }
123
+ return statusChangelog;
124
+ }
125
+ getIssueEpic(issue) {
126
+ var _a, _b;
127
+ for (const id of (_a = this.fieldIdsByName[common_1.JiraCommon.EPIC_LINK_FIELD_NAME]) !== null && _a !== void 0 ? _a : []) {
128
+ const epic = issue.fields[id];
129
+ if (epic) {
130
+ return epic.toString();
131
+ }
132
+ }
133
+ if (((_b = issue.fields.issuetype) === null || _b === void 0 ? void 0 : _b.name) === common_1.JiraCommon.EPIC_TYPE_NAME) {
134
+ return issue['key'];
135
+ }
136
+ return undefined;
137
+ }
138
+ getSprintId(issue) {
139
+ var _a, _b, _c, _d;
140
+ const sprints = [];
141
+ for (const fieldId of (_a = this.fieldIdsByName[common_1.JiraCommon.SPRINT_FIELD_NAME]) !== null && _a !== void 0 ? _a : []) {
142
+ for (const sprint of (_b = issue.fields[fieldId]) !== null && _b !== void 0 ? _b : []) {
143
+ // Workaround for string representation of sprint details which are supposedly deprecated
144
+ // https://developer.atlassian.com/cloud/jira/platform/deprecation-notice-tostring-representation-of-sprints-in-get-issue-response/
145
+ if (typeof sprint === 'string') {
146
+ let match;
147
+ const details = {};
148
+ while ((match = sprintRegex.exec(sprint)) !== null) {
149
+ details[match[1]] = match[2];
150
+ }
151
+ sprints.push(details);
152
+ }
153
+ else if ((0, lodash_1.isPlainObject)(sprint)) {
154
+ sprints.push({
155
+ id: (_c = sprint.id) === null || _c === void 0 ? void 0 : _c.toString(),
156
+ state: sprint.state,
157
+ startDate: sprint.startDate,
158
+ endDate: sprint.endDate,
159
+ });
160
+ }
161
+ }
162
+ }
163
+ // Sort array in descending order of end date sprints and return the first
164
+ // one. Future sprints may not have end dates but will take precedence.
165
+ sprints.sort(function (l, r) {
166
+ const lDate = faros_feeds_sdk_1.Utils.toDate(l.endDate);
167
+ const rDate = faros_feeds_sdk_1.Utils.toDate(r.endDate);
168
+ if (rDate && lDate) {
169
+ return rDate.getTime() - lDate.getTime();
170
+ }
171
+ else if ((0, lodash_1.toLower)(l.state) === 'future') {
172
+ return -1;
173
+ }
174
+ return 1;
175
+ });
176
+ return (_d = sprints[0]) === null || _d === void 0 ? void 0 : _d.id;
177
+ }
178
+ getPoints(issue) {
179
+ var _a;
180
+ for (const fieldName of common_1.JiraCommon.POINTS_FIELD_NAMES) {
181
+ const fieldIds = (_a = this.fieldIdsByName[fieldName]) !== null && _a !== void 0 ? _a : [];
182
+ for (const fieldId of fieldIds) {
183
+ const pointsString = issue.fields[fieldId];
184
+ if (!pointsString)
185
+ continue;
186
+ let points;
187
+ try {
188
+ points = faros_feeds_sdk_1.Utils.parseFloatFixedPoint(pointsString);
189
+ }
190
+ catch (err) {
191
+ this.logger.warn(`Failed to get story points for issue ${issue.key}: ${err.message}`);
192
+ }
193
+ return points;
194
+ }
195
+ }
196
+ return undefined;
197
+ }
198
+ static extractRepo(repoUrl) {
199
+ var _a;
200
+ const gitUrl = (0, git_url_parse_1.default)(repoUrl);
201
+ const lowerSource = (_a = gitUrl.source) === null || _a === void 0 ? void 0 : _a.toLowerCase();
202
+ let source;
203
+ if (lowerSource === null || lowerSource === void 0 ? void 0 : lowerSource.includes('bitbucket'))
204
+ source = common_1.RepoSource.BITBUCKET;
205
+ else if (lowerSource === null || lowerSource === void 0 ? void 0 : lowerSource.includes('gitlab'))
206
+ source = common_1.RepoSource.GITLAB;
207
+ else if (lowerSource === null || lowerSource === void 0 ? void 0 : lowerSource.includes('github'))
208
+ source = common_1.RepoSource.GITHUB;
209
+ else
210
+ source = common_1.RepoSource.VCS;
211
+ return {
212
+ source,
213
+ org: gitUrl.organization,
214
+ name: gitUrl.name,
215
+ };
216
+ }
217
+ /**
218
+ * Attempts to retrieve a field's value from several typical locations within
219
+ * the field's JSON blob. If the blob is an array, then each item's value will
220
+ * be added to an array of strings which will be an entry in the returned
221
+ * object. Also each item in the array will be exploded across the returned
222
+ * object with the key '<name>_<index>'. If nothing can be done, then
223
+ * the JSON blob is set to the additional field's value after being stringified.
224
+ *
225
+ * @param name The name of the additional field
226
+ * @param jsonValue The field's JSON blob to retrieve the value from
227
+ * @return The Record of additional fields
228
+ */
229
+ retrieveAdditionalFieldValue(ctx, name, jsonValue) {
230
+ const additionalFields = {};
231
+ if (!jsonValue || (0, lodash_1.isString)(jsonValue)) {
232
+ additionalFields[name] = jsonValue;
233
+ return additionalFields;
234
+ }
235
+ const retrievedValue = this.retrieveFieldValue(jsonValue);
236
+ if (retrievedValue) {
237
+ additionalFields[name] = this.stringifyNonString(retrievedValue);
238
+ return additionalFields;
239
+ }
240
+ if (Array.isArray(jsonValue)) {
241
+ // Truncate the array to the array limit
242
+ const inputArray = jsonValue.slice(0, this.additionalFieldsArrayLimit(ctx));
243
+ const resultArray = inputArray.map((item, index) => {
244
+ var _a;
245
+ const val = (_a = this.retrieveFieldValue(item)) !== null && _a !== void 0 ? _a : item;
246
+ // Also explode each item across additional fields
247
+ additionalFields[name + '_' + index] = this.stringifyNonString(val);
248
+ return val;
249
+ });
250
+ additionalFields[name] = JSON.stringify(resultArray);
251
+ return additionalFields;
252
+ }
253
+ // Nothing could be retrieved
254
+ additionalFields[name] = this.stringifyNonString(jsonValue);
255
+ return additionalFields;
256
+ }
257
+ /**
258
+ * Check for existence of the members 'value', 'name' and then
259
+ * 'displayName'in that order and return when one is found
260
+ * (or undefined if none).
261
+ *
262
+ * @param jsonValue The object whose members should be considered
263
+ * @returns The value, name or displayName within the object
264
+ */
265
+ retrieveFieldValue(jsonValue) {
266
+ let val;
267
+ if (jsonValue === null || jsonValue === void 0 ? void 0 : jsonValue.value) {
268
+ val = jsonValue.value;
269
+ }
270
+ else if (jsonValue === null || jsonValue === void 0 ? void 0 : jsonValue.name) {
271
+ val = jsonValue.name;
272
+ }
273
+ else if (jsonValue === null || jsonValue === void 0 ? void 0 : jsonValue.displayName) {
274
+ val = jsonValue.displayName;
275
+ }
276
+ return val;
277
+ }
278
+ getPullRequests(ctx, issueId) {
279
+ var _a, _b, _c;
280
+ const pulls = [];
281
+ const record = ctx.get(Issues.pullRequestsStream.asString, issueId);
282
+ if (!record)
283
+ return pulls;
284
+ const detail = record.record.data;
285
+ try {
286
+ const branchToRepoUrl = new Map();
287
+ for (const branch of (_a = detail.branches) !== null && _a !== void 0 ? _a : []) {
288
+ branchToRepoUrl.set(branch.url, branch.repository.url);
289
+ }
290
+ for (const pull of (_b = detail.pullRequests) !== null && _b !== void 0 ? _b : []) {
291
+ const repoUrl = branchToRepoUrl.get((_c = pull.source) === null || _c === void 0 ? void 0 : _c.url);
292
+ if (!repoUrl) {
293
+ continue;
294
+ }
295
+ pulls.push({
296
+ repo: Issues.extractRepo(repoUrl),
297
+ number: faros_feeds_sdk_1.Utils.parseInteger(pull.id.replace('#', '')),
298
+ });
299
+ }
300
+ }
301
+ catch (err) {
302
+ this.logger.warn(`Failed to get pull requests for issue ${issueId}: ${err.message}`);
303
+ }
304
+ return pulls;
305
+ }
306
+ stringifyNonString(value) {
307
+ return (0, lodash_1.isString)(value) ? value : JSON.stringify(value);
308
+ }
309
+ async convert(record, ctx) {
310
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
311
+ const issue = record.record.data;
312
+ const source = this.streamName.source;
313
+ const results = [];
314
+ if (!this.fieldIdsByName) {
315
+ this.fieldIdsByName = Issues.getFieldIdsByName(ctx);
316
+ }
317
+ if (!this.fieldNameById) {
318
+ this.fieldNameById = Issues.getFieldNamesById(ctx);
319
+ }
320
+ if (!this.statusByName) {
321
+ this.statusByName = Issues.getStatusesByName(ctx);
322
+ }
323
+ results.push({
324
+ model: 'tms_TaskProjectRelationship',
325
+ record: {
326
+ task: { uid: issue.key, source },
327
+ project: { uid: issue.projectKey, source },
328
+ },
329
+ });
330
+ if (!this.useBoardOwnership(ctx)) {
331
+ results.push({
332
+ model: 'tms_TaskBoardRelationship',
333
+ record: {
334
+ task: { uid: issue.key, source },
335
+ board: { uid: issue.projectKey, source },
336
+ },
337
+ });
338
+ }
339
+ for (const label of issue.fields.labels) {
340
+ results.push({
341
+ model: 'tms_TaskTag',
342
+ record: { label: { name: label }, task: { uid: issue.key, source } },
343
+ });
344
+ }
345
+ const pulls = this.getPullRequests(ctx, issue.id);
346
+ for (const pull of pulls) {
347
+ results.push({
348
+ model: 'tms_TaskPullRequestAssociation',
349
+ record: {
350
+ task: { uid: issue.key, source },
351
+ pullRequest: {
352
+ repository: {
353
+ organization: {
354
+ source: pull.repo.source,
355
+ uid: (0, lodash_1.toLower)(pull.repo.org),
356
+ },
357
+ name: (0, lodash_1.toLower)(pull.repo.name),
358
+ uid: (0, lodash_1.toLower)(pull.repo.name),
359
+ },
360
+ number: pull.number,
361
+ uid: pull.number.toString(),
362
+ },
363
+ },
364
+ });
365
+ }
366
+ const created = faros_feeds_sdk_1.Utils.toDate(issue.fields.created);
367
+ const assignee = ((_a = issue.fields.assignee) === null || _a === void 0 ? void 0 : _a.accountId) || ((_b = issue.fields.assignee) === null || _b === void 0 ? void 0 : _b.name);
368
+ const changelog = ((_c = issue.changelog) === null || _c === void 0 ? void 0 : _c.histories) || [];
369
+ changelog.sort((e1, e2) => {
370
+ // Sort changes from least to most recent
371
+ const created1 = +(faros_feeds_sdk_1.Utils.toDate(e1.created) || new Date(0));
372
+ const created2 = +(faros_feeds_sdk_1.Utils.toDate(e2.created) || new Date(0));
373
+ return created1 - created2;
374
+ });
375
+ const assigneeChangelog = Issues.assigneeChangelog(changelog, assignee, created);
376
+ for (const assignee of assigneeChangelog) {
377
+ results.push({
378
+ model: 'tms_TaskAssignment',
379
+ record: {
380
+ task: { uid: issue.key, source },
381
+ assignee: { uid: assignee.uid || 'Unassigned', source },
382
+ assignedAt: assignee.assignedAt,
383
+ },
384
+ });
385
+ }
386
+ const fixVersionChangelog = Issues.fieldChangelog(changelog, 'Fix Version', 'from', 'to');
387
+ for (const change of fixVersionChangelog) {
388
+ if (change.from) {
389
+ results.push({
390
+ model: 'tms_TaskReleaseRelationship__Deletion',
391
+ record: {
392
+ at: change.changed.getTime(),
393
+ where: {
394
+ task: { uid: issue.key, source },
395
+ release: { uid: change.from, source },
396
+ },
397
+ },
398
+ });
399
+ }
400
+ if (change.value) {
401
+ results.push({
402
+ model: 'tms_TaskReleaseRelationship__Upsert',
403
+ record: {
404
+ at: change.changed.getTime(),
405
+ data: {
406
+ task: { uid: issue.key, source },
407
+ release: { uid: change.value, source },
408
+ },
409
+ },
410
+ });
411
+ }
412
+ }
413
+ for (const fixVersion of (_d = issue.fields.fixVersions) !== null && _d !== void 0 ? _d : []) {
414
+ results.push({
415
+ model: 'tms_TaskReleaseRelationship__Upsert',
416
+ record: {
417
+ at: record.record.emitted_at,
418
+ data: {
419
+ task: { uid: issue.key, source },
420
+ release: { uid: fixVersion.id, source },
421
+ },
422
+ },
423
+ });
424
+ }
425
+ const statusChangelog = this.statusChangelog(changelog, (_e = issue.fields.status) === null || _e === void 0 ? void 0 : _e.name, created);
426
+ // Timestamp of most recent status change
427
+ let statusChanged;
428
+ if (statusChangelog.length) {
429
+ statusChanged = statusChangelog[statusChangelog.length - 1].changedAt;
430
+ }
431
+ for (const link of (_f = issue.fields.issuelinks) !== null && _f !== void 0 ? _f : []) {
432
+ const match = (_g = link.type.inward) === null || _g === void 0 ? void 0 : _g.match(dependencyRegex);
433
+ const dependency = (_h = link.inwardIssue) === null || _h === void 0 ? void 0 : _h.key;
434
+ if (match && dependency) {
435
+ const blocking = match.groups.type === 'blocked';
436
+ results.push({
437
+ model: 'tms_TaskDependency',
438
+ record: {
439
+ dependentTask: { uid: issue.key, source },
440
+ fulfillingTask: { uid: dependency, source },
441
+ blocking,
442
+ },
443
+ });
444
+ }
445
+ }
446
+ // Rewrite keys of additional fields to use names instead of ids
447
+ let additionalFieldsMap = {};
448
+ for (const [id, name] of Object.entries(this.fieldNameById)) {
449
+ const value = issue.fields[id];
450
+ if (Issues.standardFieldIds.includes(id) ||
451
+ Issues.fieldsToIgnore.includes(name)) {
452
+ continue;
453
+ }
454
+ else if (name && value) {
455
+ try {
456
+ additionalFieldsMap = Object.assign(additionalFieldsMap, this.retrieveAdditionalFieldValue(ctx, name, value));
457
+ }
458
+ catch (err) {
459
+ this.logger.warn(`Failed to extract custom field ${name} on issue ${issue.id}. Skipping.`);
460
+ }
461
+ }
462
+ }
463
+ const additionalFields = [];
464
+ for (const [name, value] of Object.entries(additionalFieldsMap)) {
465
+ additionalFields.push({ name, value });
466
+ }
467
+ let description = null;
468
+ if (typeof issue.fields.description === 'string') {
469
+ description = issue.fields.description;
470
+ }
471
+ else if ((_j = issue.renderedFields) === null || _j === void 0 ? void 0 : _j.description) {
472
+ description = this.turndown.turndown(issue.renderedFields.description);
473
+ }
474
+ const creator = ((_k = issue.fields.creator) === null || _k === void 0 ? void 0 : _k.accountId) || ((_l = issue.fields.creator) === null || _l === void 0 ? void 0 : _l.name);
475
+ const parent = ((_m = issue.fields.parent) === null || _m === void 0 ? void 0 : _m.key)
476
+ ? {
477
+ key: (_o = issue.fields.parent) === null || _o === void 0 ? void 0 : _o.key,
478
+ type: (_r = (_q = (_p = issue.fields.parent) === null || _p === void 0 ? void 0 : _p.fields) === null || _q === void 0 ? void 0 : _q.issuetype) === null || _r === void 0 ? void 0 : _r.name,
479
+ }
480
+ : null;
481
+ const epicKey = (parent === null || parent === void 0 ? void 0 : parent.type) === 'Epic' ? parent.key : this.getIssueEpic(issue);
482
+ const sprint = this.getSprintId(issue);
483
+ const type = (_s = issue.fields.issuetype) === null || _s === void 0 ? void 0 : _s.name;
484
+ const task = {
485
+ uid: issue.key,
486
+ name: issue.fields.summary,
487
+ description: this.truncate(ctx, description),
488
+ type: {
489
+ category: (_t = typeCategories.get(common_1.JiraCommon.normalize(type))) !== null && _t !== void 0 ? _t : 'Custom',
490
+ detail: type,
491
+ },
492
+ status: {
493
+ category: statusCategories.get(common_1.JiraCommon.normalize((_v = (_u = issue.fields.status) === null || _u === void 0 ? void 0 : _u.statusCategory) === null || _v === void 0 ? void 0 : _v.name)),
494
+ detail: (_w = issue.fields.status) === null || _w === void 0 ? void 0 : _w.name,
495
+ },
496
+ priority: (_x = issue.fields.priority) === null || _x === void 0 ? void 0 : _x.name,
497
+ createdAt: created,
498
+ updatedAt: faros_feeds_sdk_1.Utils.toDate(issue.fields.updated),
499
+ statusChangedAt: statusChanged,
500
+ statusChangelog,
501
+ points: (_y = this.getPoints(issue)) !== null && _y !== void 0 ? _y : null,
502
+ creator: creator ? { uid: creator, source } : null,
503
+ parent: (parent === null || parent === void 0 ? void 0 : parent.key) ? { uid: parent.key, source } : null,
504
+ epic: epicKey ? { uid: epicKey, source } : null,
505
+ sprint: sprint ? { uid: sprint, source } : null,
506
+ source,
507
+ additionalFields,
508
+ };
509
+ const excludeFields = this.excludeFields(ctx);
510
+ if (excludeFields.size > 0) {
511
+ const keys = Object.keys(task).filter((f) => !excludeFields.has(f));
512
+ results.push({ model: 'tms_Task', record: (0, lodash_1.pick)(task, keys) });
513
+ }
514
+ else {
515
+ results.push({ model: 'tms_Task', record: task });
516
+ }
517
+ return results;
518
+ }
519
+ }
520
+ exports.Issues = Issues;
521
+ Issues.issueFieldsStream = new converter_1.StreamName('jira', 'issue_fields');
522
+ Issues.pullRequestsStream = new converter_1.StreamName('jira', 'pull_requests');
523
+ Issues.workflowStatusesStream = new converter_1.StreamName('jira', 'workflow_statuses');
524
+ Issues.standardFieldIds = [
525
+ 'assignee',
526
+ 'created',
527
+ 'creator',
528
+ 'description',
529
+ 'issuelinks',
530
+ 'issuetype',
531
+ 'labels',
532
+ 'parent',
533
+ 'priority',
534
+ 'project',
535
+ 'status',
536
+ 'subtasks',
537
+ 'summary',
538
+ 'updated',
539
+ ];
540
+ Issues.fieldsToIgnore = [
541
+ ...common_1.JiraCommon.POINTS_FIELD_NAMES,
542
+ common_1.JiraCommon.DEV_FIELD_NAME,
543
+ common_1.JiraCommon.EPIC_LINK_FIELD_NAME,
544
+ common_1.JiraCommon.SPRINT_FIELD_NAME,
545
+ ];
@@ -0,0 +1,9 @@
1
+ import { AirbyteRecord } from 'faros-airbyte-cdk';
2
+ import { DestinationModel, DestinationRecord, StreamContext, StreamName } from '../converter';
3
+ import { JiraConverter } from './common';
4
+ export declare class ProjectVersions extends JiraConverter {
5
+ readonly destinationModels: ReadonlyArray<DestinationModel>;
6
+ private static readonly projectsStream;
7
+ get dependencies(): ReadonlyArray<StreamName>;
8
+ convert(record: AirbyteRecord, ctx: StreamContext): Promise<ReadonlyArray<DestinationRecord>>;
9
+ }