Skip to content

Commit 58fc445

Browse files
authored
UBERF-10471: Fix Github miss status updates and allow to re-integrate existing repos (#8842)
Signed-off-by: Andrey Sobolev <[email protected]>
1 parent 4007537 commit 58fc445

File tree

6 files changed

+99
-19
lines changed

6 files changed

+99
-19
lines changed

services/github/github-resources/src/components/ConnectProject.svelte

+20-7
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,18 @@
1313
showPopup
1414
} from '@hcengineering/ui'
1515
import DropdownLabelsPopup from '@hcengineering/ui/src/components/DropdownLabelsPopup.svelte'
16-
import { GithubIntegration, GithubIntegrationRepository, githubPullRequestStates } from '@hcengineering/github'
16+
import {
17+
GithubIntegration,
18+
GithubIntegrationRepository,
19+
githubPullRequestStates,
20+
type GithubProject
21+
} from '@hcengineering/github'
1722
import github from '../plugin'
1823
1924
export let integration: WithLookup<GithubIntegration>
2025
export let repository: GithubIntegrationRepository
2126
export let projects: Project[] = []
27+
export let orphanProjects: GithubProject[] = []
2228
2329
/**
2430
* @public
@@ -112,16 +118,23 @@
112118
113119
const githubProject = client.getHierarchy().as(projectInst, github.mixin.GithubProject)
114120
115-
void getClient().update(githubProject, {
121+
if (githubProject.integration !== integration._id) {
122+
await getClient().update(githubProject, {
123+
integration: integration._id
124+
})
125+
}
126+
await getClient().update(githubProject, {
116127
$push: { repositories: repository._id }
117128
})
118-
void getClient().update(repository, { githubProject: githubProject._id, enabled: true })
129+
await getClient().update(repository, { githubProject: githubProject._id, enabled: true })
119130
}
120131
121-
$: allowedProjects = projects.filter(
122-
(it) =>
123-
(client.getHierarchy().asIf(it, github.mixin.GithubProject)?.integration ?? integration._id) === integration._id
124-
)
132+
$: allowedProjects = projects
133+
.filter(
134+
(it) =>
135+
(client.getHierarchy().asIf(it, github.mixin.GithubProject)?.integration ?? integration._id) === integration._id
136+
)
137+
.concat(orphanProjects)
125138
async function selectProject (event: MouseEvent): Promise<void> {
126139
showPopup(
127140
DropdownLabelsPopup,

services/github/github-resources/src/components/GithubIntegerations.svelte

+7-3
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<script lang="ts">
22
import GithubRepositories from './GithubRepositories.svelte'
33
4-
import { WithLookup } from '@hcengineering/core'
4+
import { toIdMap, WithLookup } from '@hcengineering/core'
5+
import { GithubIntegration } from '@hcengineering/github'
56
import { getClient } from '@hcengineering/presentation'
67
import { Project } from '@hcengineering/tracker'
78
import { Scroller } from '@hcengineering/ui'
8-
import { GithubIntegration } from '@hcengineering/github'
99
import github from '../plugin'
1010
1111
export let integrations: WithLookup<GithubIntegration>[] = []
@@ -14,6 +14,10 @@
1414
const client = getClient()
1515
1616
$: githubProjects = client.getHierarchy().asIfArray(projects, github.mixin.GithubProject)
17+
18+
$: integerationsMap = toIdMap(integrations)
19+
20+
$: orphanProjects = githubProjects.filter((it) => !integerationsMap.has(it.integration))
1721
</script>
1822

1923
{#if integrations.length > 0}
@@ -23,7 +27,7 @@
2327
{@const giprj = githubProjects.filter((it) => it.integration === gi._id)}
2428
<div class="flex flex-col mb-4">
2529
<!-- svelte-ignore a11y-missing-attribute -->
26-
<GithubRepositories integration={gi} giProjects={giprj} {projects} />
30+
<GithubRepositories integration={gi} giProjects={giprj} {projects} {orphanProjects} />
2731
</div>
2832
{/each}
2933
</div>

services/github/github-resources/src/components/GithubRepositories.svelte

+2-2
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
import ConnectProject from './ConnectProject.svelte'
2727
import { githubLanguageColors } from './languageColors'
2828
import { sendGHServiceRequest } from './utils'
29-
import { BackgroundColor } from '@hcengineering/text'
3029
3130
export let integration: WithLookup<GithubIntegration>
3231
export let projects: Project[] = []
3332
export let giProjects: GithubProject[] = []
33+
export let orphanProjects: GithubProject[] = []
3434
3535
const client = getClient()
3636
@@ -235,7 +235,7 @@
235235
/>
236236
</div>
237237
{:else}
238-
<ConnectProject {integration} {repository} {projects} />
238+
<ConnectProject {integration} {repository} {projects} {orphanProjects} />
239239
{/if}
240240
</div>
241241
</div>

services/github/pod-github/src/sync/comments.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,7 @@ export class CommentSyncManager implements DocSyncManager {
528528
}
529529
const syncInfo = await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, {
530530
space: repo.githubProject,
531-
repository: repo._id,
531+
// repository: repo._id, // If we skip repository, we will find orphaned comments, so we could connect them on.
532532
objectClass: chunter.class.ChatMessage,
533533
url: { $in: comments.map((it) => (it.url ?? '').toLowerCase()) }
534534
})
@@ -550,14 +550,19 @@ export class CommentSyncManager implements DocSyncManager {
550550
lastModified
551551
})
552552
} else {
553-
if (!deepEqual(existing.external, comment) || existing.externalVersion !== githubExternalSyncVersion) {
553+
if (
554+
!deepEqual(existing.external, comment) ||
555+
existing.externalVersion !== githubExternalSyncVersion ||
556+
existing.repository !== repo._id
557+
) {
554558
await derivedClient.diffUpdate(
555559
existing,
556560
{
557561
needSync: '',
558562
external: comment,
559563
externalVersion: githubExternalSyncVersion,
560-
lastModified
564+
lastModified,
565+
repository: repo._id
561566
},
562567
lastModified
563568
)

services/github/pod-github/src/sync/issueBase.ts

+60-3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ import {
6969
errorToObj,
7070
getCreateStatus,
7171
getType,
72+
guessStatus,
7273
isGHWriteAllowed
7374
} from './utils'
7475

@@ -1075,6 +1076,51 @@ export abstract class IssueSyncManagerBase {
10751076
return issueUpdate
10761077
}
10771078

1079+
async performDocumentExternalSync (
1080+
ctx: MeasureContext,
1081+
info: DocSyncInfo,
1082+
previousExternal: IssueExternalData,
1083+
issueExternal: IssueExternalData,
1084+
derivedClient: TxOperations
1085+
): Promise<void> {
1086+
// TODO: Since Github integeration need to be re-written to use cards, so this is quick fix to not loose data in case of external sync while service was offline.
1087+
1088+
const update: IssueUpdate = {}
1089+
const du: DocumentUpdate<DocSyncInfo> = {}
1090+
const account = (await this.provider.getAccount(issueExternal.author)) ?? core.account.System
1091+
1092+
const container = await this.provider.getContainer(info.space)
1093+
if (container == null) {
1094+
return
1095+
}
1096+
const type = await this.provider.getTaskTypeOf(container.project.type, tracker.class.Issue)
1097+
const statuses = await this.provider.getStatuses(type?._id)
1098+
1099+
if (previousExternal.state !== issueExternal.state) {
1100+
update.status = (
1101+
await guessStatus({ state: issueExternal.state, stateReason: issueExternal.stateReason }, statuses)
1102+
)._id
1103+
}
1104+
if (previousExternal.title !== issueExternal.title) {
1105+
update.title = issueExternal.title
1106+
}
1107+
if (previousExternal.body !== issueExternal.body) {
1108+
update.description = await this.provider.getMarkupSafe(
1109+
container.container,
1110+
issueExternal.body,
1111+
this.stripGuestLink
1112+
)
1113+
du.markdown = await this.provider.getMarkdown(update.description)
1114+
}
1115+
if (!deepEqual(previousExternal.assignees, issueExternal.assignees)) {
1116+
const assignees = await this.getAssignees(issueExternal)
1117+
update.assignee = assignees?.[0] ?? null
1118+
}
1119+
if (Object.keys(update).length > 0) {
1120+
await this.handleUpdate(issueExternal, derivedClient, update, account, container.project, false)
1121+
}
1122+
}
1123+
10781124
async syncIssues (
10791125
_class: Ref<Class<Doc>>,
10801126
repo: GithubIntegrationRepository,
@@ -1089,7 +1135,7 @@ export abstract class IssueSyncManagerBase {
10891135
syncDocs ??
10901136
(await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, {
10911137
space: repo.githubProject,
1092-
repository: repo._id,
1138+
// repository: repo._id, // If we skip repository, we will find orphaned issues, so we could connect them on.
10931139
objectClass: _class,
10941140
url: { $in: issues.map((it) => (it.url ?? '').toLowerCase()) }
10951141
}))
@@ -1123,9 +1169,19 @@ export abstract class IssueSyncManagerBase {
11231169
if (syncDocs !== undefined) {
11241170
syncDocs = syncDocs.filter((it) => it._id !== existing._id)
11251171
}
1126-
const externalEqual = deepEqual(existing.external, issue)
1172+
const externalEqual = deepEqual(existing.external, issue) && existing.repository === repo._id
11271173
if (!externalEqual || existing.externalVersion !== githubExternalSyncVersion) {
1128-
this.ctx.info('Update sync doc', { url: issue.url, workspace: this.provider.getWorkspaceId() })
1174+
this.ctx.info('Update sync doc(extarnal changes)', {
1175+
url: issue.url,
1176+
workspace: this.provider.getWorkspaceId()
1177+
})
1178+
1179+
if (existing.needSync === githubSyncVersion || existing.repository !== repo._id) {
1180+
// Sync external if and only if no changes from platform or we do resync from github.
1181+
// We need to apply changes from Github, while service was offline.
1182+
await this.performDocumentExternalSync(this.ctx, existing, existing.external, issue, derivedClient)
1183+
}
1184+
11291185
await ops.diffUpdate(
11301186
existing,
11311187
{
@@ -1134,6 +1190,7 @@ export abstract class IssueSyncManagerBase {
11341190
externalVersion: githubExternalSyncVersion,
11351191
derivedVersion: '', // Clear derived state to recalculate it.
11361192
externalVersionSince: '',
1193+
repository: repo._id,
11371194
lastModified: new Date(issue.updatedAt).getTime()
11381195
},
11391196
Date.now()

services/github/pod-github/src/sync/utils.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -370,12 +370,13 @@ export async function syncDerivedDocuments<T extends { url: string }> (
370370
})
371371
} else {
372372
processed.add(existing._id)
373-
if (!deepEqual(existing.external, r)) {
373+
if (!deepEqual(existing.external, r) || existing.repository !== repo._id) {
374374
// Only update if had changes.
375375
await derivedClient.update(existing, {
376376
external: r,
377377
needSync: '', // We need to check if we had any changes.
378378
derivedVersion: '',
379+
repository: repo._id,
379380
externalVersion: githubExternalSyncVersion,
380381
lastModified: new Date(r.updatedAt ?? r.createdAt).getTime(),
381382
...extra

0 commit comments

Comments
 (0)