UBERF-10494: Allow to reintegrate same project again

Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
Andrey Sobolev 2025-05-05 19:10:13 +07:00
parent b368e5522a
commit 7d54bbff4a
No known key found for this signature in database
GPG Key ID: BD80F68D68D8F7F2
6 changed files with 47 additions and 30 deletions

View File

@ -13,12 +13,18 @@
showPopup showPopup
} from '@hcengineering/ui' } from '@hcengineering/ui'
import DropdownLabelsPopup from '@hcengineering/ui/src/components/DropdownLabelsPopup.svelte' import DropdownLabelsPopup from '@hcengineering/ui/src/components/DropdownLabelsPopup.svelte'
import { GithubIntegration, GithubIntegrationRepository, githubPullRequestStates } from '@hcengineering/github' import {
GithubIntegration,
GithubIntegrationRepository,
githubPullRequestStates,
type GithubProject
} from '@hcengineering/github'
import github from '../plugin' import github from '../plugin'
export let integration: WithLookup<GithubIntegration> export let integration: WithLookup<GithubIntegration>
export let repository: GithubIntegrationRepository export let repository: GithubIntegrationRepository
export let projects: Project[] = [] export let projects: Project[] = []
export let orphanProjects: GithubProject[] = []
/** /**
* @public * @public
@ -112,16 +118,23 @@
const githubProject = client.getHierarchy().as(projectInst, github.mixin.GithubProject) const githubProject = client.getHierarchy().as(projectInst, github.mixin.GithubProject)
void getClient().update(githubProject, { if (githubProject.integration !== integration._id) {
await getClient().update(githubProject, {
integration: integration._id
})
}
await getClient().update(githubProject, {
$push: { repositories: repository._id } $push: { repositories: repository._id }
}) })
void getClient().update(repository, { githubProject: githubProject._id, enabled: true }) await getClient().update(repository, { githubProject: githubProject._id, enabled: true })
} }
$: allowedProjects = projects.filter( $: allowedProjects = projects
(it) => .filter(
(client.getHierarchy().asIf(it, github.mixin.GithubProject)?.integration ?? integration._id) === integration._id (it) =>
) (client.getHierarchy().asIf(it, github.mixin.GithubProject)?.integration ?? integration._id) === integration._id
)
.concat(orphanProjects)
async function selectProject (event: MouseEvent): Promise<void> { async function selectProject (event: MouseEvent): Promise<void> {
showPopup( showPopup(
DropdownLabelsPopup, DropdownLabelsPopup,

View File

@ -1,11 +1,11 @@
<script lang="ts"> <script lang="ts">
import GithubRepositories from './GithubRepositories.svelte' import GithubRepositories from './GithubRepositories.svelte'
import { WithLookup } from '@hcengineering/core' import { toIdMap, WithLookup } from '@hcengineering/core'
import { GithubIntegration } from '@hcengineering/github'
import { getClient } from '@hcengineering/presentation' import { getClient } from '@hcengineering/presentation'
import { Project } from '@hcengineering/tracker' import { Project } from '@hcengineering/tracker'
import { Scroller } from '@hcengineering/ui' import { Scroller } from '@hcengineering/ui'
import { GithubIntegration } from '@hcengineering/github'
import github from '../plugin' import github from '../plugin'
export let integrations: WithLookup<GithubIntegration>[] = [] export let integrations: WithLookup<GithubIntegration>[] = []
@ -14,6 +14,10 @@
const client = getClient() const client = getClient()
$: githubProjects = client.getHierarchy().asIfArray(projects, github.mixin.GithubProject) $: githubProjects = client.getHierarchy().asIfArray(projects, github.mixin.GithubProject)
$: integerationsMap = toIdMap(integrations)
$: orphanProjects = githubProjects.filter((it) => !integerationsMap.has(it.integration))
</script> </script>
{#if integrations.length > 0} {#if integrations.length > 0}
@ -23,7 +27,7 @@
{@const giprj = githubProjects.filter((it) => it.integration === gi._id)} {@const giprj = githubProjects.filter((it) => it.integration === gi._id)}
<div class="flex flex-col mb-4"> <div class="flex flex-col mb-4">
<!-- svelte-ignore a11y-missing-attribute --> <!-- svelte-ignore a11y-missing-attribute -->
<GithubRepositories integration={gi} giProjects={giprj} {projects} /> <GithubRepositories integration={gi} giProjects={giprj} {projects} {orphanProjects} />
</div> </div>
{/each} {/each}
</div> </div>

View File

@ -26,11 +26,11 @@
import ConnectProject from './ConnectProject.svelte' import ConnectProject from './ConnectProject.svelte'
import { githubLanguageColors } from './languageColors' import { githubLanguageColors } from './languageColors'
import { sendGHServiceRequest } from './utils' import { sendGHServiceRequest } from './utils'
import { BackgroundColor } from '@hcengineering/text'
export let integration: WithLookup<GithubIntegration> export let integration: WithLookup<GithubIntegration>
export let projects: Project[] = [] export let projects: Project[] = []
export let giProjects: GithubProject[] = [] export let giProjects: GithubProject[] = []
export let orphanProjects: GithubProject[] = []
const client = getClient() const client = getClient()
@ -235,7 +235,7 @@
/> />
</div> </div>
{:else} {:else}
<ConnectProject {integration} {repository} {projects} /> <ConnectProject {integration} {repository} {projects} {orphanProjects} />
{/if} {/if}
</div> </div>
</div> </div>

View File

@ -528,7 +528,7 @@ export class CommentSyncManager implements DocSyncManager {
} }
const syncInfo = await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, { const syncInfo = await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, {
space: repo.githubProject, space: repo.githubProject,
repository: repo._id, // repository: repo._id, // If we skip repository, we will find orphaned comments, so we could connect them on.
objectClass: chunter.class.ChatMessage, objectClass: chunter.class.ChatMessage,
url: { $in: comments.map((it) => (it.url ?? '').toLowerCase()) } url: { $in: comments.map((it) => (it.url ?? '').toLowerCase()) }
}) })
@ -550,14 +550,19 @@ export class CommentSyncManager implements DocSyncManager {
lastModified lastModified
}) })
} else { } else {
if (!deepEqual(existing.external, comment) || existing.externalVersion !== githubExternalSyncVersion) { if (
!deepEqual(existing.external, comment) ||
existing.externalVersion !== githubExternalSyncVersion ||
existing.repository !== repo._id
) {
await derivedClient.diffUpdate( await derivedClient.diffUpdate(
existing, existing,
{ {
needSync: '', needSync: '',
external: comment, external: comment,
externalVersion: githubExternalSyncVersion, externalVersion: githubExternalSyncVersion,
lastModified lastModified,
repository: repo._id
}, },
lastModified lastModified
) )

View File

@ -1087,7 +1087,7 @@ export abstract class IssueSyncManagerBase {
const update: IssueUpdate = {} const update: IssueUpdate = {}
const du: DocumentUpdate<DocSyncInfo> = {} const du: DocumentUpdate<DocSyncInfo> = {}
const account = (await this.provider.getAccount(issueExternal.author))?._id ?? core.account.System const account = (await this.provider.getAccount(issueExternal.author)) ?? core.account.System
const container = await this.provider.getContainer(info.space) const container = await this.provider.getContainer(info.space)
if (container == null) { if (container == null) {
@ -1114,17 +1114,10 @@ export abstract class IssueSyncManagerBase {
} }
if (!deepEqual(previousExternal.assignees, issueExternal.assignees)) { if (!deepEqual(previousExternal.assignees, issueExternal.assignees)) {
const assignees = await this.getAssignees(issueExternal) const assignees = await this.getAssignees(issueExternal)
update.assignee = assignees?.[0]?.person ?? null update.assignee = assignees?.[0] ?? null
} }
if (Object.keys(update).length > 0) { if (Object.keys(update).length > 0) {
await this.handleUpdate( await this.handleUpdate(issueExternal, derivedClient, update, account, container.project, false)
issueExternal,
derivedClient,
update,
account,
container.project,
false
)
} }
} }
@ -1142,7 +1135,7 @@ export abstract class IssueSyncManagerBase {
syncDocs ?? syncDocs ??
(await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, { (await this.client.findAll<DocSyncInfo>(github.class.DocSyncInfo, {
space: repo.githubProject, space: repo.githubProject,
repository: repo._id, // repository: repo._id, // If we skip repository, we will find orphaned issues, so we could connect them on.
objectClass: _class, objectClass: _class,
url: { $in: issues.map((it) => (it.url ?? '').toLowerCase()) } url: { $in: issues.map((it) => (it.url ?? '').toLowerCase()) }
})) }))
@ -1176,15 +1169,15 @@ export abstract class IssueSyncManagerBase {
if (syncDocs !== undefined) { if (syncDocs !== undefined) {
syncDocs = syncDocs.filter((it) => it._id !== existing._id) syncDocs = syncDocs.filter((it) => it._id !== existing._id)
} }
const externalEqual = deepEqual(existing.external, issue) const externalEqual = deepEqual(existing.external, issue) && existing.repository === repo._id
if (!externalEqual || existing.externalVersion !== githubExternalSyncVersion) { if (!externalEqual || existing.externalVersion !== githubExternalSyncVersion) {
this.ctx.info('Update sync doc(extarnal changes)', { this.ctx.info('Update sync doc(extarnal changes)', {
url: issue.url, url: issue.url,
workspace: this.provider.getWorkspaceId() workspace: this.provider.getWorkspaceId()
}) })
if (existing.needSync === githubSyncVersion) { if (existing.needSync === githubSyncVersion || existing.repository !== repo._id) {
// Sync external if and only if no changes from platform. // Sync external if and only if no changes from platform or we do resync from github.
// We need to apply changes from Github, while service was offline. // We need to apply changes from Github, while service was offline.
await this.performDocumentExternalSync(this.ctx, existing, existing.external, issue, derivedClient) await this.performDocumentExternalSync(this.ctx, existing, existing.external, issue, derivedClient)
} }
@ -1197,6 +1190,7 @@ export abstract class IssueSyncManagerBase {
externalVersion: githubExternalSyncVersion, externalVersion: githubExternalSyncVersion,
derivedVersion: '', // Clear derived state to recalculate it. derivedVersion: '', // Clear derived state to recalculate it.
externalVersionSince: '', externalVersionSince: '',
repository: repo._id,
lastModified: new Date(issue.updatedAt).getTime() lastModified: new Date(issue.updatedAt).getTime()
}, },
Date.now() Date.now()

View File

@ -370,12 +370,13 @@ export async function syncDerivedDocuments<T extends { url: string }> (
}) })
} else { } else {
processed.add(existing._id) processed.add(existing._id)
if (!deepEqual(existing.external, r)) { if (!deepEqual(existing.external, r) || existing.repository !== repo._id) {
// Only update if had changes. // Only update if had changes.
await derivedClient.update(existing, { await derivedClient.update(existing, {
external: r, external: r,
needSync: '', // We need to check if we had any changes. needSync: '', // We need to check if we had any changes.
derivedVersion: '', derivedVersion: '',
repository: repo._id,
externalVersion: githubExternalSyncVersion, externalVersion: githubExternalSyncVersion,
lastModified: new Date(r.updatedAt ?? r.createdAt).getTime(), lastModified: new Date(r.updatedAt ?? r.createdAt).getTime(),
...extra ...extra