@gitkraken/core-gitlens 0.20.1 → 0.21.0
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/CHANGELOG.md +19 -1
- package/dist/git/models/issue.d.ts +30 -1
- package/dist/git/models/issue.js +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/providers/config.d.ts +4 -1
- package/dist/git/providers/remotes.d.ts +18 -0
- package/dist/git/utils/issue.utils.js +2 -1
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git-cli/exec/git.js +1 -1
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +6 -2
- package/dist/git-cli/providers/config.js +47 -7
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/remotes.d.ts +9 -1
- package/dist/git-cli/providers/remotes.js +79 -4
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +13 -1
- package/dist/plus/integrations/models/integration.js +8 -1
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +20 -4
- package/dist/plus/integrations/providers/linearIssuesEtag.js +42 -6
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -1
- package/dist/plus/integrations/providers/models.js +25 -13
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +2 -0
- package/dist/plus/integrations/providers/providerErrors.js +5 -2
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +1 -0
- package/dist/plus/integrations/reads/etag.js +3 -1
- package/dist/plus/integrations/reads/etag.js.map +1 -1
- package/docs/integrations.md +12 -1
- package/package.json +2 -2
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isLinearRateLimitedBody } from "./providerErrors.js";
|
|
2
|
+
import { linearSyncedWithEtagKeys } from "../models/integration.js";
|
|
1
3
|
//#region ../plus/integrations/src/providers/linearIssuesEtag.ts
|
|
2
4
|
const linearGraphQLUrl = "https://api.linear.app/graphql";
|
|
3
5
|
/** The most issue numbers one cheap check asks of one team. */
|
|
@@ -24,6 +26,17 @@ const linearIssuesEtagQuery = `
|
|
|
24
26
|
state {
|
|
25
27
|
type
|
|
26
28
|
}
|
|
29
|
+
syncedWith {
|
|
30
|
+
id
|
|
31
|
+
service
|
|
32
|
+
metadata {
|
|
33
|
+
... on ExternalEntityInfoGithubMetadata {
|
|
34
|
+
owner
|
|
35
|
+
repo
|
|
36
|
+
number
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
27
40
|
}
|
|
28
41
|
}
|
|
29
42
|
}
|
|
@@ -35,8 +48,12 @@ const linearIssuesEtagQuery = `
|
|
|
35
48
|
*
|
|
36
49
|
* Sent as provider-apis sends every Linear request: the token as the whole `Authorization` header, with no scheme.
|
|
37
50
|
* GraphQL `errors` reject the whole request, as provider-apis rejects them, but keep the response so a throttling
|
|
38
|
-
* code is still classified as one.
|
|
39
|
-
*
|
|
51
|
+
* code is still classified as one. The exception is the one provider-apis makes too: errors that all sit under
|
|
52
|
+
* `syncedWith`, a nullable list, leave every other field whole. An issue whose list Linear failed to resolve falls
|
|
53
|
+
* through to its full read (see {@link toLinearIssueEtagFields}); one whose list resolved but a link's coordinates
|
|
54
|
+
* didn't keys that link without them, as the full read's row carries it. Unlike provider-apis, a throttled response
|
|
55
|
+
* still throws here, so it is classified as a rate limit. A next page also rejects it: with every number unique within
|
|
56
|
+
* a team, more issues than were asked for means the filter was not applied as written.
|
|
40
57
|
*/
|
|
41
58
|
async function requestLinearIssuesEtagFields(request, accessToken, teamKey, numbers) {
|
|
42
59
|
const response = await request({
|
|
@@ -55,7 +72,8 @@ async function requestLinearIssuesEtagFields(request, accessToken, teamKey, numb
|
|
|
55
72
|
})
|
|
56
73
|
});
|
|
57
74
|
const body = response.body;
|
|
58
|
-
|
|
75
|
+
const syncedWithOnly = body?.data != null && Array.isArray(body.errors) && body.errors.every((e) => typeof e === "object" && e != null && "path" in e && Array.isArray(e.path) && e.path.includes("syncedWith")) && !isLinearRateLimitedBody(body);
|
|
76
|
+
if (body?.errors != null && !syncedWithOnly) {
|
|
59
77
|
const error = /* @__PURE__ */ new Error(`Linear GraphQL errors: ${JSON.stringify(body.errors)}`);
|
|
60
78
|
Object.assign(error, { response });
|
|
61
79
|
throw error;
|
|
@@ -67,25 +85,43 @@ async function requestLinearIssuesEtagFields(request, accessToken, teamKey, numb
|
|
|
67
85
|
}
|
|
68
86
|
/**
|
|
69
87
|
* A cheap-checked issue's change state, as the fields the full row's etag reads. The full read's row is provider-apis'
|
|
70
|
-
* Linear issue normalizer (0.65.0) then `fromProviderIssue`, so this mirrors both:
|
|
88
|
+
* Linear issue normalizer (0.65.0, `syncedWith` since GKDEV-3662) then `fromProviderIssue`, so this mirrors both:
|
|
71
89
|
*
|
|
72
90
|
* - provider-apis maps `state.type` to a category — `completed` to `DONE`, `canceled` and `duplicate` to `CANCELED`,
|
|
73
91
|
* `started` to `IN_PROGRESS`, anything else (`backlog`, `unstarted`, `triage`) to `TO_DO`, and no state to none —
|
|
74
92
|
* and sets `closedDate` from `archivedAt` (a falsy value reads as none);
|
|
75
93
|
* - `fromProviderIssue` closes an issue that has a `closedDate` or a terminal category, so an archived issue is closed
|
|
76
94
|
* whatever its state.
|
|
95
|
+
* - provider-apis keeps a `syncedWith` entry for a GitHub link with an id, with its coordinates only when owner, repo
|
|
96
|
+
* and a positive integer number are all there, so the etag lists each such link the same way.
|
|
77
97
|
*
|
|
78
98
|
* Throws on a missing or unparseable `updatedAt`, so the target falls through to the full read rather than matching an
|
|
79
99
|
* etag the full row would compute from a fallback date (`fromProviderIssue` falls back to `closedDate`, then
|
|
80
|
-
* `createdDate`).
|
|
100
|
+
* `createdDate`). Throws on a `syncedWith` Linear failed to resolve too: an unknown list must not match a full row
|
|
101
|
+
* read while Linear could resolve it, nor one read while it couldn't, which would keep that row unknown.
|
|
81
102
|
*/
|
|
82
103
|
function toLinearIssueEtagFields(issue) {
|
|
83
104
|
const updatedDate = new Date(issue.updatedAt || NaN);
|
|
84
105
|
if (Number.isNaN(updatedDate.getTime())) throw new Error(`Linear returned no update time for ${issue.identifier}`);
|
|
106
|
+
if (issue.syncedWith == null) throw new Error(`Linear could not resolve the sync links of ${issue.identifier}`);
|
|
85
107
|
const type = issue.state?.type;
|
|
86
108
|
return {
|
|
87
109
|
state: Boolean(issue.archivedAt) || type === "completed" || type === "canceled" || type === "duplicate" ? "closed" : "opened",
|
|
88
|
-
updatedDate
|
|
110
|
+
updatedDate,
|
|
111
|
+
syncedWithKeys: linearSyncedWithEtagKeys(issue.syncedWith.flatMap((synced) => {
|
|
112
|
+
if (synced.service !== "github" || !synced.id) return [];
|
|
113
|
+
const { owner, repo, number } = synced.metadata ?? {};
|
|
114
|
+
return [owner && repo && typeof number === "number" && Number.isInteger(number) && number > 0 ? {
|
|
115
|
+
provider: "github",
|
|
116
|
+
id: synced.id,
|
|
117
|
+
owner,
|
|
118
|
+
repo,
|
|
119
|
+
number
|
|
120
|
+
} : {
|
|
121
|
+
provider: "github",
|
|
122
|
+
id: synced.id
|
|
123
|
+
}];
|
|
124
|
+
}))
|
|
89
125
|
};
|
|
90
126
|
}
|
|
91
127
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"linearIssuesEtag.js","names":[],"sources":["../../../../../plus/integrations/src/providers/linearIssuesEtag.ts"],"sourcesContent":["import type { IssueEtagFields } from '../models/integration.js';\nimport type { ProviderRequestFunction } from './models.js';\n\nconst linearGraphQLUrl = 'https://api.linear.app/graphql';\n\n/** The most issue numbers one cheap check asks of one team. */\nexport const linearIssuesEtagMaxNumbers = 50;\n\n/**\n * Archived issues are left out of Linear's `issues` connection unless asked for, so `includeArchived` keeps an archived\n * issue answerable here as the full read's `issue(id:)` answers it.\n */\nconst linearIssuesEtagQuery = `\n\tquery GetIssuesEtagFields($teamKey: String!, $numbers: [Float!]!) {\n\t\tissues(\n\t\t\tfirst: ${linearIssuesEtagMaxNumbers}\n\t\t\tincludeArchived: true\n\t\t\tfilter: { team: { key: { eq: $teamKey } }, number: { in: $numbers } }\n\t\t) {\n\t\t\tpageInfo {\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tidentifier\n\t\t\t\tnumber\n\t\t\t\tupdatedAt\n\t\t\t\tarchivedAt\n\t\t\t\tstate {\n\t\t\t\t\ttype\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n`;\n\nexport type LinearIssueEtagNode = {\n\tidentifier: string;\n\tnumber: number;\n\tupdatedAt?: string | null;\n\tarchivedAt?: string | null;\n\tstate?: { type?: string | null } | null;\n};\n\ntype LinearIssuesEtagResponse = {\n\tdata?: {\n\t\tissues?: { pageInfo?: { hasNextPage?: boolean }; nodes?: LinearIssueEtagNode[] } | null;\n\t} | null;\n\terrors?: unknown[];\n};\n\n/**\n * The cheap check behind the batch issue read's etags: the change state of up to {@link linearIssuesEtagMaxNumbers}\n * issues of one team in ONE GraphQL request, where the full read sends provider-apis' `issue(id:)` once per issue.\n * Linear returns only the issues it found, in its own order, so a caller matches them by number, never by position.\n *\n * Sent as provider-apis sends every Linear request: the token as the whole `Authorization` header, with no scheme.\n * GraphQL `errors` reject the whole request, as provider-apis rejects them, but keep the response so a throttling\n * code is still classified as one. A next page also rejects it: with every number unique within a team, more
|
|
1
|
+
{"version":3,"file":"linearIssuesEtag.js","names":[],"sources":["../../../../../plus/integrations/src/providers/linearIssuesEtag.ts"],"sourcesContent":["import type { IssueSyncedWith } from '@gitlens/git/models/issue.js';\nimport type { IssueEtagFields } from '../models/integration.js';\nimport { linearSyncedWithEtagKeys } from '../models/integration.js';\nimport type { ProviderRequestFunction } from './models.js';\nimport { isLinearRateLimitedBody } from './providerErrors.js';\n\nconst linearGraphQLUrl = 'https://api.linear.app/graphql';\n\n/** The most issue numbers one cheap check asks of one team. */\nexport const linearIssuesEtagMaxNumbers = 50;\n\n/**\n * Archived issues are left out of Linear's `issues` connection unless asked for, so `includeArchived` keeps an archived\n * issue answerable here as the full read's `issue(id:)` answers it.\n */\nconst linearIssuesEtagQuery = `\n\tquery GetIssuesEtagFields($teamKey: String!, $numbers: [Float!]!) {\n\t\tissues(\n\t\t\tfirst: ${linearIssuesEtagMaxNumbers}\n\t\t\tincludeArchived: true\n\t\t\tfilter: { team: { key: { eq: $teamKey } }, number: { in: $numbers } }\n\t\t) {\n\t\t\tpageInfo {\n\t\t\t\thasNextPage\n\t\t\t}\n\t\t\tnodes {\n\t\t\t\tidentifier\n\t\t\t\tnumber\n\t\t\t\tupdatedAt\n\t\t\t\tarchivedAt\n\t\t\t\tstate {\n\t\t\t\t\ttype\n\t\t\t\t}\n\t\t\t\tsyncedWith {\n\t\t\t\t\tid\n\t\t\t\t\tservice\n\t\t\t\t\tmetadata {\n\t\t\t\t\t\t... on ExternalEntityInfoGithubMetadata {\n\t\t\t\t\t\t\towner\n\t\t\t\t\t\t\trepo\n\t\t\t\t\t\t\tnumber\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n`;\n\nexport type LinearIssueEtagNode = {\n\tidentifier: string;\n\tnumber: number;\n\tupdatedAt?: string | null;\n\tarchivedAt?: string | null;\n\tstate?: { type?: string | null } | null;\n\tsyncedWith?:\n\t\t| {\n\t\t\t\tid?: string | null;\n\t\t\t\tservice?: string | null;\n\t\t\t\tmetadata?: { owner?: string | null; repo?: string | null; number?: number | null } | null;\n\t\t }[]\n\t\t| null;\n};\n\ntype LinearIssuesEtagResponse = {\n\tdata?: {\n\t\tissues?: { pageInfo?: { hasNextPage?: boolean }; nodes?: LinearIssueEtagNode[] } | null;\n\t} | null;\n\terrors?: unknown[];\n};\n\n/**\n * The cheap check behind the batch issue read's etags: the change state of up to {@link linearIssuesEtagMaxNumbers}\n * issues of one team in ONE GraphQL request, where the full read sends provider-apis' `issue(id:)` once per issue.\n * Linear returns only the issues it found, in its own order, so a caller matches them by number, never by position.\n *\n * Sent as provider-apis sends every Linear request: the token as the whole `Authorization` header, with no scheme.\n * GraphQL `errors` reject the whole request, as provider-apis rejects them, but keep the response so a throttling\n * code is still classified as one. The exception is the one provider-apis makes too: errors that all sit under\n * `syncedWith`, a nullable list, leave every other field whole. An issue whose list Linear failed to resolve falls\n * through to its full read (see {@link toLinearIssueEtagFields}); one whose list resolved but a link's coordinates\n * didn't keys that link without them, as the full read's row carries it. Unlike provider-apis, a throttled response\n * still throws here, so it is classified as a rate limit. A next page also rejects it: with every number unique within\n * a team, more issues than were asked for means the filter was not applied as written.\n */\nexport async function requestLinearIssuesEtagFields(\n\trequest: ProviderRequestFunction,\n\taccessToken: string,\n\tteamKey: string,\n\tnumbers: readonly number[],\n): Promise<LinearIssueEtagNode[]> {\n\tconst response = await request<LinearIssuesEtagResponse | null>({\n\t\turl: linearGraphQLUrl,\n\t\tmethod: 'POST',\n\t\theaders: { Authorization: accessToken, 'Content-Type': 'application/json' },\n\t\tbody: JSON.stringify({ query: linearIssuesEtagQuery, variables: { teamKey: teamKey, numbers: numbers } }),\n\t});\n\n\tconst body = response.body;\n\tconst syncedWithOnly =\n\t\tbody?.data != null &&\n\t\tArray.isArray(body.errors) &&\n\t\tbody.errors.every(\n\t\t\te =>\n\t\t\t\ttypeof e === 'object' &&\n\t\t\t\te != null &&\n\t\t\t\t'path' in e &&\n\t\t\t\tArray.isArray(e.path) &&\n\t\t\t\te.path.includes('syncedWith'),\n\t\t) &&\n\t\t!isLinearRateLimitedBody(body);\n\tif (body?.errors != null && !syncedWithOnly) {\n\t\tconst error = new Error(`Linear GraphQL errors: ${JSON.stringify(body.errors)}`);\n\t\tObject.assign(error, { response: response });\n\t\tthrow error;\n\t}\n\n\tconst issues = body?.data?.issues;\n\tif (!Array.isArray(issues?.nodes)) throw new Error('Linear returned no issues');\n\tif (issues.pageInfo?.hasNextPage !== false) throw new Error('Linear returned more issues than were asked for');\n\n\treturn issues.nodes;\n}\n\n/**\n * A cheap-checked issue's change state, as the fields the full row's etag reads. The full read's row is provider-apis'\n * Linear issue normalizer (0.65.0, `syncedWith` since GKDEV-3662) then `fromProviderIssue`, so this mirrors both:\n *\n * - provider-apis maps `state.type` to a category — `completed` to `DONE`, `canceled` and `duplicate` to `CANCELED`,\n * `started` to `IN_PROGRESS`, anything else (`backlog`, `unstarted`, `triage`) to `TO_DO`, and no state to none —\n * and sets `closedDate` from `archivedAt` (a falsy value reads as none);\n * - `fromProviderIssue` closes an issue that has a `closedDate` or a terminal category, so an archived issue is closed\n * whatever its state.\n * - provider-apis keeps a `syncedWith` entry for a GitHub link with an id, with its coordinates only when owner, repo\n * and a positive integer number are all there, so the etag lists each such link the same way.\n *\n * Throws on a missing or unparseable `updatedAt`, so the target falls through to the full read rather than matching an\n * etag the full row would compute from a fallback date (`fromProviderIssue` falls back to `closedDate`, then\n * `createdDate`). Throws on a `syncedWith` Linear failed to resolve too: an unknown list must not match a full row\n * read while Linear could resolve it, nor one read while it couldn't, which would keep that row unknown.\n */\nexport function toLinearIssueEtagFields(issue: LinearIssueEtagNode): IssueEtagFields {\n\tconst updatedDate = new Date(issue.updatedAt || Number.NaN);\n\tif (Number.isNaN(updatedDate.getTime())) {\n\t\tthrow new Error(`Linear returned no update time for ${issue.identifier}`);\n\t}\n\n\tif (issue.syncedWith == null) {\n\t\tthrow new Error(`Linear could not resolve the sync links of ${issue.identifier}`);\n\t}\n\n\tconst type = issue.state?.type;\n\tconst closed = Boolean(issue.archivedAt) || type === 'completed' || type === 'canceled' || type === 'duplicate';\n\treturn {\n\t\tstate: closed ? 'closed' : 'opened',\n\t\tupdatedDate: updatedDate,\n\t\tsyncedWithKeys: linearSyncedWithEtagKeys(\n\t\t\tissue.syncedWith.flatMap((synced): IssueSyncedWith[] => {\n\t\t\t\tif (synced.service !== 'github' || !synced.id) return [];\n\n\t\t\t\tconst { owner, repo, number } = synced.metadata ?? {};\n\t\t\t\treturn [\n\t\t\t\t\towner && repo && typeof number === 'number' && Number.isInteger(number) && number > 0\n\t\t\t\t\t\t? { provider: 'github', id: synced.id, owner: owner, repo: repo, number: number }\n\t\t\t\t\t\t: { provider: 'github', id: synced.id },\n\t\t\t\t];\n\t\t\t}),\n\t\t),\n\t};\n}\n"],"mappings":";;;AAMA,MAAM,mBAAmB;;AAGzB,MAAa,6BAA6B;;;;;AAM1C,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsE9B,eAAsB,8BACrB,SACA,aACA,SACA,SACiC;CACjC,MAAM,WAAW,MAAM,QAAyC;EAC/D,KAAK;EACL,QAAQ;EACR,SAAS;GAAE,eAAe;GAAa,gBAAgB;EAAmB;EAC1E,MAAM,KAAK,UAAU;GAAE,OAAO;GAAuB,WAAW;IAAW;IAAkB;GAAQ;EAAE,CAAC;CACzG,CAAC;CAED,MAAM,OAAO,SAAS;CACtB,MAAM,iBACL,MAAM,QAAQ,QACd,MAAM,QAAQ,KAAK,MAAM,KACzB,KAAK,OAAO,OACX,MACC,OAAO,MAAM,YACb,KAAK,QACL,UAAU,KACV,MAAM,QAAQ,EAAE,IAAI,KACpB,EAAE,KAAK,SAAS,YAAY,CAC9B,KACA,CAAC,wBAAwB,IAAI;CAC9B,IAAI,MAAM,UAAU,QAAQ,CAAC,gBAAgB;EAC5C,MAAM,wBAAQ,IAAI,MAAM,0BAA0B,KAAK,UAAU,KAAK,MAAM,GAAG;EAC/E,OAAO,OAAO,OAAO,EAAY,SAAS,CAAC;EAC3C,MAAM;CACP;CAEA,MAAM,SAAS,MAAM,MAAM;CAC3B,IAAI,CAAC,MAAM,QAAQ,QAAQ,KAAK,GAAG,MAAM,IAAI,MAAM,2BAA2B;CAC9E,IAAI,OAAO,UAAU,gBAAgB,OAAO,MAAM,IAAI,MAAM,iDAAiD;CAE7G,OAAO,OAAO;AACf;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,wBAAwB,OAA6C;CACpF,MAAM,cAAc,IAAI,KAAK,MAAM,aAAa,GAAU;CAC1D,IAAI,OAAO,MAAM,YAAY,QAAQ,CAAC,GACrC,MAAM,IAAI,MAAM,sCAAsC,MAAM,YAAY;CAGzE,IAAI,MAAM,cAAc,MACvB,MAAM,IAAI,MAAM,8CAA8C,MAAM,YAAY;CAGjF,MAAM,OAAO,MAAM,OAAO;CAE1B,OAAO;EACN,OAFc,QAAQ,MAAM,UAAU,KAAK,SAAS,eAAe,SAAS,cAAc,SAAS,cAEnF,WAAW;EACd;EACb,gBAAgB,yBACf,MAAM,WAAW,SAAS,WAA8B;GACvD,IAAI,OAAO,YAAY,YAAY,CAAC,OAAO,IAAI,OAAO,CAAC;GAEvD,MAAM,EAAE,OAAO,MAAM,WAAW,OAAO,YAAY,CAAC;GACpD,OAAO,CACN,SAAS,QAAQ,OAAO,WAAW,YAAY,OAAO,UAAU,MAAM,KAAK,SAAS,IACjF;IAAE,UAAU;IAAU,IAAI,OAAO;IAAW;IAAa;IAAc;GAAO,IAC9E;IAAE,UAAU;IAAU,IAAI,OAAO;GAAG,CACxC;EACD,CAAC,CACF;CACD;AACD"}
|
|
@@ -625,12 +625,7 @@ function toIssueShape(issue, provider, options) {
|
|
|
625
625
|
avatarUrl: assignee.avatarUrl ?? void 0,
|
|
626
626
|
url: assignee.url ?? void 0
|
|
627
627
|
})) ?? [],
|
|
628
|
-
project: issue.project
|
|
629
|
-
id: issue.project.id,
|
|
630
|
-
name: issue.project.name,
|
|
631
|
-
resourceId: issue.project.resourceId,
|
|
632
|
-
resourceName: issue.project.namespace
|
|
633
|
-
} : void 0,
|
|
628
|
+
project: toIssueProject(issue.project, provider),
|
|
634
629
|
repository: issue.repository?.owner?.login != null ? {
|
|
635
630
|
owner: issue.repository.owner.login,
|
|
636
631
|
repo: issue.repository.name,
|
|
@@ -648,9 +643,31 @@ function toIssueShape(issue, provider, options) {
|
|
|
648
643
|
issueType: issue.type ?? void 0,
|
|
649
644
|
iterations: toIssueIterations(issue),
|
|
650
645
|
...options?.projection != null ? { projection: options.projection } : {},
|
|
651
|
-
...toIssueViewer(issue, options?.viewer)
|
|
646
|
+
...toIssueViewer(issue, options?.viewer),
|
|
647
|
+
...issue.syncedWith != null ? { syncedWith: toIssueSyncedWith(issue.syncedWith) } : {}
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
function toIssueProject(project, provider) {
|
|
651
|
+
if (!project?.id || !project.resourceId || !project.namespace && !isJiraIntegrationId(provider.id)) return;
|
|
652
|
+
return {
|
|
653
|
+
id: project.id,
|
|
654
|
+
name: project.name,
|
|
655
|
+
resourceId: project.resourceId,
|
|
656
|
+
resourceName: project.namespace ?? ""
|
|
652
657
|
};
|
|
653
658
|
}
|
|
659
|
+
function toIssueSyncedWith(syncedWith) {
|
|
660
|
+
return syncedWith.map((synced) => synced.owner != null ? {
|
|
661
|
+
provider: synced.service,
|
|
662
|
+
id: synced.id,
|
|
663
|
+
owner: synced.owner,
|
|
664
|
+
repo: synced.repo,
|
|
665
|
+
number: synced.number
|
|
666
|
+
} : {
|
|
667
|
+
provider: synced.service,
|
|
668
|
+
id: synced.id
|
|
669
|
+
});
|
|
670
|
+
}
|
|
654
671
|
function toIssueBodyField(field) {
|
|
655
672
|
return {
|
|
656
673
|
id: field.referenceName,
|
|
@@ -1027,12 +1044,7 @@ function fromProviderIssue(issue, integration, options) {
|
|
|
1027
1044
|
name: options.project.name,
|
|
1028
1045
|
resourceId: options.project.resourceId,
|
|
1029
1046
|
resourceName: options.project.resourceName
|
|
1030
|
-
} : issue.project
|
|
1031
|
-
id: issue.project.id,
|
|
1032
|
-
name: issue.project.name,
|
|
1033
|
-
resourceId: issue.project.resourceId,
|
|
1034
|
-
resourceName: issue.project.namespace
|
|
1035
|
-
} : void 0, identifier, issue.type ?? void 0, toIssueProviderState(issue.state), integration.id === "jira" ? "jira-wiki" : void 0, toIssueIterations(issue), options?.projection, issue.descriptionField != null ? toIssueBodyField(issue.descriptionField) : void 0, viewer?.viewer, viewer?.viewerUnresolved);
|
|
1047
|
+
} : toIssueProject(issue.project, integration), identifier, issue.type ?? void 0, toIssueProviderState(issue.state), integration.id === "jira" ? "jira-wiki" : void 0, toIssueIterations(issue), options?.projection, issue.descriptionField != null ? toIssueBodyField(issue.descriptionField) : void 0, viewer?.viewer, viewer?.viewerUnresolved, issue.syncedWith != null ? toIssueSyncedWith(issue.syncedWith) : void 0);
|
|
1036
1048
|
}
|
|
1037
1049
|
function toProviderPullRequestWithUniqueId(pr) {
|
|
1038
1050
|
const { reviews, mergeableState, ...providerPr } = toProviderPullRequest(pr);
|