@pipedream/linear_app 0.5.1 → 0.5.3

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.
@@ -5,7 +5,7 @@ export default {
5
5
  key: "linear_app-create-issue",
6
6
  name: "Create Issue",
7
7
  description: "Create an issue (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#creating-and-editing-issues)",
8
- version: "0.4.1",
8
+ version: "0.4.3",
9
9
  props: {
10
10
  linearApp,
11
11
  teamId: {
@@ -1,12 +1,10 @@
1
1
  import linearApp from "../../linear_app.app.mjs";
2
- import utils from "../../common/utils.mjs";
3
- const getAdditionalIssueInformation = utils.getAdditionalIssueInformation;
4
2
 
5
3
  export default {
6
4
  key: "linear_app-get-issue",
7
5
  name: "Get Issue",
8
6
  description: "Get an issue by ID (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
9
- version: "0.1.1",
7
+ version: "0.1.3",
10
8
  type: "action",
11
9
  props: {
12
10
  linearApp,
@@ -18,14 +16,9 @@ export default {
18
16
  description: "The issue ID",
19
17
  },
20
18
  },
21
- methods: {
22
- getAdditionalIssueInformation,
23
- },
24
19
  async run({ $ }) {
25
20
  const issue = await this.linearApp.getIssue(this.issueId);
26
21
  $.export("$summary", `Found issue with ID ${this.issueId}`);
27
- return (await this.getAdditionalIssueInformation([
28
- issue,
29
- ]))[0];
22
+ return issue;
30
23
  },
31
24
  };
@@ -4,7 +4,7 @@ export default {
4
4
  key: "linear_app-get-teams",
5
5
  name: "Get Teams",
6
6
  description: "Get all the teams (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
7
- version: "0.2.1",
7
+ version: "0.2.3",
8
8
  type: "action",
9
9
  props: {
10
10
  linearApp,
@@ -1,14 +1,12 @@
1
1
  import linearApp from "../../linear_app.app.mjs";
2
- import constants from "../../common/constants.mjs";
3
2
  import utils from "../../common/utils.mjs";
4
- const getAdditionalIssueInformation = utils.getAdditionalIssueInformation;
5
3
 
6
4
  export default {
7
5
  key: "linear_app-search-issues",
8
6
  name: "Search Issues",
9
7
  description: "Search issues (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api)",
10
8
  type: "action",
11
- version: "0.2.1",
9
+ version: "0.2.3",
12
10
  props: {
13
11
  linearApp,
14
12
  query: {
@@ -55,58 +53,27 @@ export default {
55
53
  ],
56
54
  },
57
55
  },
58
- methods: {
59
- getAdditionalIssueInformation,
60
- buildFilter() {
61
- return {
62
- title: {
63
- containsIgnoreCase: this.query,
64
- },
65
- team: {
66
- id: {
67
- eq: this.teamId,
68
- },
69
- },
70
- project: {
71
- id: {
72
- eq: this.projectId,
73
- },
74
- },
75
- assignee: {
76
- id: {
77
- eq: this.assigneeId,
78
- },
79
- },
80
- labels: {
81
- name: {
82
- in: this.issueLabels,
83
- },
84
- },
85
- };
86
- },
87
- },
88
56
  async run({ $ }) {
89
- const {
90
- orderBy,
91
- includeArchived,
92
- } = this;
93
-
94
57
  const issues = [];
95
58
  let hasNextPage;
96
59
  let after;
97
- const filter = this.buildFilter();
98
60
 
99
61
  do {
62
+ const variables = utils.buildVariables(after, {
63
+ filter: {
64
+ query: this.query,
65
+ teamId: this.teamId,
66
+ projectId: this.projectId,
67
+ assigneeId: this.assigneeId,
68
+ issueLabels: this.issueLabels,
69
+ },
70
+ orderBy: this.orderBy,
71
+ includeArchived: this.includeArchived,
72
+ });
100
73
  const {
101
74
  nodes,
102
75
  pageInfo,
103
- } = await this.linearApp.searchIssues({
104
- filter,
105
- orderBy,
106
- after,
107
- includeArchived,
108
- first: constants.DEFAULT_LIMIT,
109
- });
76
+ } = await this.linearApp.listIssues(variables);
110
77
 
111
78
  issues.push(...nodes);
112
79
  after = pageInfo.endCursor;
@@ -115,6 +82,6 @@ export default {
115
82
 
116
83
  $.export("$summary", `Found ${issues.length} issues`);
117
84
 
118
- return await this.getAdditionalIssueInformation(issues);
85
+ return issues;
119
86
  },
120
87
  };
@@ -5,7 +5,7 @@ export default {
5
5
  name: "Update Issue",
6
6
  description: "Update an issue (API Key). See the docs [here](https://developers.linear.app/docs/graphql/working-with-the-graphql-api#creating-and-editing-issues)",
7
7
  type: "action",
8
- version: "0.1.1",
8
+ version: "0.1.3",
9
9
  props: {
10
10
  linearApp,
11
11
  teamId: {
@@ -43,6 +43,65 @@ const ORDER_BY_OPTIONS = [
43
43
  },
44
44
  ];
45
45
 
46
+ const ISSUE_NODES = `
47
+ id
48
+ title
49
+ description
50
+ boardOrder
51
+ branchName
52
+ createdAt
53
+ customerTicketCount
54
+ identifier
55
+ number
56
+ priority
57
+ priorityLabel
58
+ sortOrder
59
+ updatedAt
60
+ url
61
+ assignee {
62
+ id
63
+ name
64
+ email
65
+ }
66
+ creator {
67
+ id
68
+ name
69
+ email
70
+ }
71
+ project {
72
+ id
73
+ name
74
+ }
75
+ state {
76
+ id
77
+ name
78
+ }
79
+ team {
80
+ id
81
+ name
82
+ }
83
+ `;
84
+
85
+ const COMMENT_NODES = `
86
+ id
87
+ body
88
+ createdAt
89
+ reactionData
90
+ updatedAt
91
+ issue {
92
+ id
93
+ title
94
+ project {
95
+ id
96
+ name
97
+ }
98
+ }
99
+ user {
100
+ id
101
+ name
102
+ }
103
+ `;
104
+
46
105
  export default {
47
106
  WEBHOOK_ID,
48
107
  LINEAR_DELIVERY_HEADER,
@@ -54,4 +113,6 @@ export default {
54
113
  CLIENT_IPS,
55
114
  ORDER_BY_OPTIONS,
56
115
  FIELD,
116
+ ISSUE_NODES,
117
+ COMMENT_NODES,
57
118
  };
package/common/utils.mjs CHANGED
@@ -1,3 +1,5 @@
1
+ import constants from "./constants.mjs";
2
+
1
3
  async function streamIterator(stream) {
2
4
  const resources = [];
3
5
  for await (const resource of stream) {
@@ -6,33 +8,49 @@ async function streamIterator(stream) {
6
8
  return resources;
7
9
  }
8
10
 
9
- async function getAdditionalIssueInformation(issues = []) {
10
- const updatedIssues = [];
11
- for (const issue of issues) {
12
- const {
13
- _assignee, _creator, _project, _state, _team,
14
- } = issue;
15
- if (_assignee?.id) {
16
- issue._assignee = await this.linearApp.getUser(_assignee.id);
17
- }
18
- if (_creator?.id) {
19
- issue._creator = await this.linearApp.getUser(_creator.id);
20
- }
21
- if (_project?.id) {
22
- issue._project = await this.linearApp.getProject(_project.id);
23
- }
24
- if (_state?.id) {
25
- issue._state = await this.linearApp.getState(_state.id);
26
- }
27
- if (_team?.id) {
28
- issue._team = await this.linearApp.getTeam(_team.id);
29
- }
30
- updatedIssues.push(issue);
11
+ function buildVariables(endCursor, args) {
12
+ const title = args.filter.query
13
+ ? `title: { containsIgnoreCase: "${args.filter.query}" }`
14
+ : "";
15
+ const teamId = args.filter.teamId
16
+ ? `, team: { id: { eq: "${args.filter.teamId}" } }`
17
+ : "";
18
+ const projectId = args.filter.projectId
19
+ ? `, project: { id: { eq: "${args.filter.projectId}" } }`
20
+ : "";
21
+ const team = args.filter.team
22
+ ? `, team: { id: { in: ${JSON.stringify(args.filter.team.id.in)} } }`
23
+ : "";
24
+ const project = args.filter.project && args.filter.project.id.eq
25
+ ? `, project: { id: { eq: "${args.filter.project.id.eq}" } }`
26
+ : "";
27
+ const state = args.filter.state
28
+ ? `, state: { id: { eq: "${args.filter.state.id.eq}" } }`
29
+ : "";
30
+ const assigneeId = args.filter.assigneeId
31
+ ? `, assignee: { id: { eq: "${args.filter.assigneeId}" } }`
32
+ : "";
33
+ const issueLabels = args.filter.issueLabels
34
+ ? `, labels: { name: { in: ${JSON.stringify(args.filter.issueLabels)} } }`
35
+ : "";
36
+ let filter = `${title}${teamId}${projectId}${team}${project}${state}${assigneeId}${issueLabels}`;
37
+ if (filter[0] === ",") {
38
+ filter = filter.substring(2, filter.length);
31
39
  }
32
- return updatedIssues;
40
+
41
+ const orderBy = args.orderBy
42
+ ? `, orderBy: ${args.orderBy}`
43
+ : "";
44
+ const includeArchived = args.includeArchived
45
+ ? `, includeArchived: ${args.includeArchived}`
46
+ : "";
47
+ const after = endCursor
48
+ ? `, after: "${endCursor}"`
49
+ : "";
50
+ return `filter: { ${filter} }, first: ${constants.DEFAULT_LIMIT}${orderBy}${includeArchived}${after}`;
33
51
  }
34
52
 
35
53
  export default {
36
54
  streamIterator,
37
- getAdditionalIssueInformation,
55
+ buildVariables,
38
56
  };
@@ -1,5 +1,6 @@
1
1
  import { LinearClient } from "@linear/sdk";
2
2
  import constants from "./common/constants.mjs";
3
+ import utils from "./common/utils.mjs";
3
4
  import { axios } from "@pipedream/platform";
4
5
 
5
6
  export default {
@@ -203,11 +204,22 @@ export default {
203
204
  }) {
204
205
  return this.client().updateIssue(issueId, input);
205
206
  },
206
- async searchIssues(variables) {
207
+ async listIssues(variables) {
207
208
  return this.client().issues(variables);
208
209
  },
209
210
  async getIssue(id) {
210
- return this.client().issue(id);
211
+ const { data: { issue } } = await this.makeAxiosRequest({
212
+ method: "POST",
213
+ data: {
214
+ query: `
215
+ {
216
+ issue(id: "${id}") {
217
+ ${constants.ISSUE_NODES}
218
+ }
219
+ }`,
220
+ },
221
+ });
222
+ return issue;
211
223
  },
212
224
  async getUser(id) {
213
225
  return this.client().user(id);
@@ -239,15 +251,26 @@ export default {
239
251
  async listStates(variables = {}) {
240
252
  return this.client().workflowStates(variables);
241
253
  },
242
- async listIssues(variables = {}) {
243
- return this.client().issues(variables);
244
- },
245
254
  async listIssueLabels(variables = {}) {
246
255
  return this.client().issueLabels(variables);
247
256
  },
248
257
  async listComments(variables = {}) {
249
258
  return this.client().comments(variables);
250
259
  },
260
+ async getComment(id) {
261
+ const { data: { comment } } = await this.makeAxiosRequest({
262
+ method: "POST",
263
+ data: {
264
+ query: `
265
+ {
266
+ comment(id: "${id}") {
267
+ ${constants.COMMENT_NODES}
268
+ }
269
+ }`,
270
+ },
271
+ });
272
+ return comment;
273
+ },
251
274
  async listResourcesOptions({
252
275
  prevContext, resourcesFn, resourcesArgs, resouceMapper,
253
276
  } = {}) {
@@ -282,19 +305,23 @@ export default {
282
305
  resourcesFn,
283
306
  resourcesFnArgs,
284
307
  max = constants.DEFAULT_MAX_RECORDS,
308
+ useGraphQl = true,
285
309
  }) {
286
310
  let counter = 0;
287
311
  let hasNextPage;
288
312
  let endCursor;
289
313
  do {
314
+ const variables = useGraphQl
315
+ ? utils.buildVariables(endCursor, resourcesFnArgs)
316
+ : {
317
+ after: endCursor,
318
+ first: constants.DEFAULT_LIMIT,
319
+ ...resourcesFnArgs,
320
+ };
290
321
  const {
291
322
  nodes,
292
323
  pageInfo,
293
- } = await resourcesFn({
294
- after: endCursor,
295
- first: constants.DEFAULT_LIMIT,
296
- ...resourcesFnArgs,
297
- });
324
+ } = await resourcesFn(variables);
298
325
  for (const node of nodes) {
299
326
  counter += 1;
300
327
  yield node;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pipedream/linear_app",
3
- "version": "0.5.1",
3
+ "version": "0.5.3",
4
4
  "description": "Pipedream Linear_app Components",
5
5
  "main": "linear_app.app.mjs",
6
6
  "keywords": [
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Created Comment (Instant)",
8
8
  description: "Emit new event when a new comment is created. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.1.1",
10
+ version: "0.1.3",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -22,6 +22,13 @@ export default {
22
22
  getResourcesFn() {
23
23
  return this.linearApp.listComments;
24
24
  },
25
+ useGraphQl() {
26
+ return false;
27
+ },
28
+ async isFromProject(body) {
29
+ const comment = await this.linearApp.getComment(body.data.id);
30
+ return !this.projectId || comment?.issue?.project?.id == this.projectId;
31
+ },
25
32
  getResourcesFnArgs() {
26
33
  return {
27
34
  sortBy: "createdAt",
@@ -1,7 +1,6 @@
1
1
  import linearApp from "../../linear_app.app.mjs";
2
2
  import constants from "../../common/constants.mjs";
3
3
  import utils from "../../common/utils.mjs";
4
- const getAdditionalIssueInformation = utils.getAdditionalIssueInformation;
5
4
 
6
5
  export default {
7
6
  props: {
@@ -24,7 +23,6 @@ export default {
24
23
  db: "$.service.db",
25
24
  },
26
25
  methods: {
27
- getAdditionalIssueInformation,
28
26
  setWebhookId(teamId, id) {
29
27
  this.db.set(`webhook-${teamId}`, id);
30
28
  },
@@ -40,6 +38,9 @@ export default {
40
38
  isRelevant() {
41
39
  return true;
42
40
  },
41
+ useGraphQl() {
42
+ return true;
43
+ },
43
44
  getResourceTypes() {
44
45
  throw new Error("getResourceTypes is not implemented");
45
46
  },
@@ -66,12 +67,9 @@ export default {
66
67
  const stream = this.linearApp.paginateResources({
67
68
  resourcesFn: this.getResourcesFn(),
68
69
  resourcesFnArgs: this.getResourcesFnArgs(),
70
+ useGraphQl: this.useGraphQl(),
69
71
  });
70
- let resources = await utils.streamIterator(stream);
71
-
72
- if (this.getResourceTypes().includes(constants.RESOURCE_TYPE.ISSUE)) {
73
- resources = await this.getAdditionalIssueInformation(resources);
74
- }
72
+ const resources = await utils.streamIterator(stream);
75
73
 
76
74
  resources
77
75
  .reverse()
@@ -80,7 +78,10 @@ export default {
80
78
  });
81
79
  },
82
80
  async activate() {
83
- for (const teamId of this.teamIds) {
81
+ const teamIds = this.teamIds || [
82
+ this.teamId,
83
+ ];
84
+ for (const teamId of teamIds) {
84
85
  const { _webhook: webhook } =
85
86
  await this.linearApp.createWebhook({
86
87
  teamId,
@@ -92,7 +93,10 @@ export default {
92
93
  }
93
94
  },
94
95
  async deactivate() {
95
- for (const teamId of this.teamIds) {
96
+ const teamIds = this.teamIds || [
97
+ this.teamId,
98
+ ];
99
+ for (const teamId of teamIds) {
96
100
  const webhookId = this.getWebhookId(teamId);
97
101
  if (webhookId) {
98
102
  await this.linearApp.deleteWebhook(webhookId);
@@ -119,7 +123,7 @@ export default {
119
123
  return;
120
124
  }
121
125
 
122
- if (!this.isFromProject(body) || !this.isRelevant(body)) {
126
+ if (!(await this.isFromProject(body)) || !this.isRelevant(body)) {
123
127
  return;
124
128
  }
125
129
 
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Created Issue (Instant)",
8
8
  description: "Emit new event when a new issue is created. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.3.1",
10
+ version: "0.3.3",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -24,7 +24,7 @@ export default {
24
24
  },
25
25
  getResourcesFnArgs() {
26
26
  return {
27
- sortBy: "createdAt",
27
+ orderBy: "createdAt",
28
28
  filter: {
29
29
  team: {
30
30
  id: {
@@ -7,7 +7,7 @@ export default {
7
7
  name: "New Updated Issue (Instant)",
8
8
  description: "Emit new event when an issue is updated. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.3.1",
10
+ version: "0.3.3",
11
11
  dedupe: "unique",
12
12
  methods: {
13
13
  ...common.methods,
@@ -24,7 +24,7 @@ export default {
24
24
  },
25
25
  getResourcesFnArgs() {
26
26
  return {
27
- sortBy: "updatedAt",
27
+ orderBy: "updatedAt",
28
28
  filter: {
29
29
  team: {
30
30
  id: {
@@ -7,8 +7,37 @@ export default {
7
7
  name: "New Issue Status Updated (Instant)",
8
8
  description: "Emit new event when the status of an issue is updated. See the docs [here](https://developers.linear.app/docs/graphql/webhooks)",
9
9
  type: "source",
10
- version: "0.1.1",
10
+ version: "0.1.3",
11
11
  dedupe: "unique",
12
+ props: {
13
+ linearApp: common.props.linearApp,
14
+ http: common.props.http,
15
+ db: common.props.db,
16
+ teamId: {
17
+ label: "Team ID",
18
+ type: "string",
19
+ propDefinition: [
20
+ common.props.linearApp,
21
+ "teamId",
22
+ ],
23
+ },
24
+ projectId: {
25
+ propDefinition: [
26
+ common.props.linearApp,
27
+ "projectId",
28
+ ],
29
+ },
30
+ stateId: {
31
+ propDefinition: [
32
+ common.props.linearApp,
33
+ "stateId",
34
+ ({ teamId }) => ({
35
+ teamId,
36
+ }),
37
+ ],
38
+ description: "Emit issues that are updated to this state",
39
+ },
40
+ },
12
41
  methods: {
13
42
  ...common.methods,
14
43
  getResourceTypes() {
@@ -28,7 +57,9 @@ export default {
28
57
  filter: {
29
58
  team: {
30
59
  id: {
31
- in: this.teamIds,
60
+ in: [
61
+ this.teamId,
62
+ ],
32
63
  },
33
64
  },
34
65
  project: {
@@ -36,11 +67,16 @@ export default {
36
67
  eq: this.projectId,
37
68
  },
38
69
  },
70
+ state: {
71
+ id: {
72
+ eq: this.stateId,
73
+ },
74
+ },
39
75
  },
40
76
  };
41
77
  },
42
78
  isRelevant(body) {
43
- return body?.updatedFrom?.stateId;
79
+ return body?.updatedFrom?.stateId && (!this.stateId || body.data.stateId === this.stateId);
44
80
  },
45
81
  getMetadata(resource) {
46
82
  const {