mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-21 20:02:22 +02:00
feat: Pass tracing info with websocket (#9627)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -8,10 +8,10 @@
|
||||
*/
|
||||
import { Analytics } from '@hcengineering/analytics'
|
||||
import core, {
|
||||
PersonId,
|
||||
AttachedData,
|
||||
Doc,
|
||||
DocumentUpdate,
|
||||
PersonId,
|
||||
Ref,
|
||||
SortingOrder,
|
||||
Status,
|
||||
@@ -20,7 +20,9 @@ import core, {
|
||||
generateId,
|
||||
makeCollabId,
|
||||
makeCollabJsonId,
|
||||
makeDocCollabId
|
||||
makeDocCollabId,
|
||||
withContext,
|
||||
type MeasureContext
|
||||
} from '@hcengineering/core'
|
||||
import github, {
|
||||
DocSyncInfo,
|
||||
@@ -64,7 +66,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
return assignees
|
||||
}
|
||||
|
||||
@withContext('issues-handleEvent')
|
||||
async handleEvent<T = IssuesEvent | ProjectsV2ItemEvent>(
|
||||
ctx: MeasureContext,
|
||||
integration: IntegrationContainer,
|
||||
derivedClient: TxOperations,
|
||||
evt: T
|
||||
@@ -72,7 +76,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
await this.createPromise
|
||||
const event = evt as IssuesEvent | ProjectsV2ItemEvent
|
||||
|
||||
this.ctx.info('issue:handleEvent', {
|
||||
ctx.info('issue:handleEvent', {
|
||||
nodeId: (event as IssuesEvent).issue?.html_url ?? (event as ProjectsV2ItemEvent)?.projects_v2_item.node_id,
|
||||
action: event.action,
|
||||
login: event.sender.login,
|
||||
@@ -96,7 +100,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
const issueEvent = event as IssuesEvent
|
||||
const { project, repository } = await this.provider.getProjectAndRepository(issueEvent.repository.node_id)
|
||||
if (project === undefined || repository === undefined) {
|
||||
this.ctx.info('No project for repository', {
|
||||
ctx.info('No project for repository', {
|
||||
repository: issueEvent.repository.name,
|
||||
nodeId: issueEvent.repository.node_id,
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
@@ -107,12 +111,13 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
const urlId = issueEvent.issue.url
|
||||
|
||||
await syncRunner.exec(urlId, async () => {
|
||||
await this.processEvent(issueEvent, derivedClient, repository, integration, project)
|
||||
await this.processEvent(ctx, issueEvent, derivedClient, repository, integration, project)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private async processEvent (
|
||||
ctx: MeasureContext,
|
||||
event: IssuesEvent,
|
||||
derivedClient: TxOperations,
|
||||
repo: GithubIntegrationRepository,
|
||||
@@ -142,7 +147,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
externalData = response.repository.issue
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
this.ctx.error('Error', { err })
|
||||
ctx.error('Error', { err })
|
||||
|
||||
// We need to check if we do not have sync data, we need to create by html_url
|
||||
await this.createErrorSyncDataByUrl(
|
||||
@@ -197,6 +202,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
|
||||
await this.handleUpdate(
|
||||
ctx,
|
||||
externalData as IssueExternalData,
|
||||
derivedClient,
|
||||
update,
|
||||
@@ -216,7 +222,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
const update: IssueUpdate = {
|
||||
assignee: persons?.[0] ?? null
|
||||
}
|
||||
await this.handleUpdate(externalData as IssueExternalData, derivedClient, update, account, prj, false)
|
||||
await this.handleUpdate(ctx, externalData as IssueExternalData, derivedClient, update, account, prj, false)
|
||||
break
|
||||
}
|
||||
case 'closed':
|
||||
@@ -241,6 +247,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
)._id
|
||||
}
|
||||
await this.handleUpdate(
|
||||
ctx,
|
||||
externalData as IssueExternalData,
|
||||
derivedClient,
|
||||
update,
|
||||
@@ -294,7 +301,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
}
|
||||
|
||||
@withContext('issues-sync')
|
||||
async sync (
|
||||
ctx: MeasureContext,
|
||||
existing: Doc | undefined,
|
||||
info: DocSyncInfo,
|
||||
parent: DocSyncInfo | undefined,
|
||||
@@ -317,7 +326,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
if (info.repository == null) {
|
||||
// No need to sync if component it not yet set
|
||||
this.ctx.error('Not syncing repository === null', {
|
||||
ctx.error('Not syncing repository === null', {
|
||||
url: info.url,
|
||||
identifier: (existing as Issue).identifier
|
||||
})
|
||||
@@ -332,14 +341,14 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
if (info.external === undefined && existing !== undefined) {
|
||||
const repository = await this.provider.getRepositoryById(info.repository)
|
||||
if (repository === undefined) {
|
||||
this.ctx.error('Not syncing repository === undefined', {
|
||||
ctx.error('Not syncing repository === undefined', {
|
||||
url: info.url,
|
||||
identifier: (existing as Issue).identifier
|
||||
})
|
||||
return { needSync: githubSyncVersion }
|
||||
}
|
||||
|
||||
const description = await this.ctx.with(
|
||||
const description = await ctx.with(
|
||||
'query collaborative description',
|
||||
{},
|
||||
async () => {
|
||||
@@ -350,23 +359,28 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
{ log: true }
|
||||
)
|
||||
|
||||
this.ctx.info('create github issue', {
|
||||
ctx.info('create github issue', {
|
||||
title: (existing as Issue).title,
|
||||
number: (existing as Issue).number,
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
})
|
||||
const createdIssueData = await this.ctx.with(
|
||||
const createdIssueData = await ctx.with(
|
||||
'create github issue',
|
||||
{},
|
||||
async () => {
|
||||
this.createPromise = this.createGithubIssue(container, { ...(existing as Issue), description }, repository)
|
||||
this.createPromise = this.createGithubIssue(
|
||||
ctx,
|
||||
container,
|
||||
{ ...(existing as Issue), description },
|
||||
repository
|
||||
)
|
||||
return await this.createPromise
|
||||
},
|
||||
{ id: (existing as Issue).identifier, workspace: this.provider.getWorkspaceId() },
|
||||
{ log: true }
|
||||
)
|
||||
if (createdIssueData === undefined) {
|
||||
this.ctx.error('Error create issue', { url: info.url })
|
||||
ctx.error('Error create issue', { url: info.url })
|
||||
return { needSync: githubSyncVersion, error: 'Unknown error on create issue' }
|
||||
}
|
||||
issueExternal = createdIssueData
|
||||
@@ -397,7 +411,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
return { needSync: githubSyncVersion }
|
||||
}
|
||||
|
||||
const syncResult = await this.syncToTarget(container, existing, issueExternal, derivedClient, info)
|
||||
const syncResult = await this.syncToTarget(ctx, container, existing, issueExternal, derivedClient, info)
|
||||
|
||||
if (externalWasCreated && existing !== undefined) {
|
||||
// Create child documents
|
||||
@@ -412,7 +426,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
break
|
||||
}
|
||||
|
||||
await this.provider.doSyncFor(attachedDocs, container.project)
|
||||
await this.provider.doSyncFor(ctx, attachedDocs, container.project)
|
||||
for (const child of attachedDocs) {
|
||||
await derivedClient.update(child, { createId })
|
||||
}
|
||||
@@ -430,6 +444,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
|
||||
async syncToTarget (
|
||||
ctx: MeasureContext,
|
||||
container: ContainerFocus,
|
||||
existing: Doc | undefined,
|
||||
issueExternal: IssueExternalData,
|
||||
@@ -463,13 +478,13 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
// TODO: Use GithubProject configuration to specify target type for issues
|
||||
if (taskTypes.length === 0) {
|
||||
// Missing required task type
|
||||
this.ctx.error('Missing required task type', { identifier: (existing as Issue)?.identifier })
|
||||
ctx.error('Missing required task type', { identifier: (existing as Issue)?.identifier })
|
||||
return { needSync: githubSyncVersion }
|
||||
}
|
||||
|
||||
if (existing === undefined) {
|
||||
try {
|
||||
this.ctx.info('create platform issue', {
|
||||
ctx.info('create platform issue', {
|
||||
url: issueExternal.url,
|
||||
title: issueExternal.title,
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
@@ -483,7 +498,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
// No repository, it probable deleted
|
||||
return { needSync: githubSyncVersion }
|
||||
}
|
||||
await this.ctx.with(
|
||||
await ctx.with(
|
||||
'create platform issue',
|
||||
{},
|
||||
async () => {
|
||||
@@ -521,12 +536,12 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
this.ctx.error('Error', { err })
|
||||
ctx.error('Error', { err })
|
||||
return { needSync: githubSyncVersion, error: JSON.stringify(err) }
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
const description = await this.ctx.with(
|
||||
const description = await ctx.with(
|
||||
'query collaborative description',
|
||||
{},
|
||||
async () => {
|
||||
@@ -537,11 +552,12 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
{ log: true }
|
||||
)
|
||||
|
||||
const updateResult = await this.ctx.with(
|
||||
const updateResult = await ctx.with(
|
||||
'diff update',
|
||||
{},
|
||||
async () =>
|
||||
await this.handleDiffUpdate(
|
||||
ctx,
|
||||
container,
|
||||
{ ...(existing as any), description },
|
||||
info,
|
||||
@@ -560,15 +576,21 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
this.ctx.error('error sync', { err })
|
||||
ctx.error('error sync', { err })
|
||||
return { needSync: githubSyncVersion, error: JSON.stringify(err), external: issueExternal }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async afterSync (existing: Issue, update: DocumentUpdate<Doc>, account: PersonId): Promise<void> {}
|
||||
async afterSync (
|
||||
ctx: MeasureContext,
|
||||
existing: Issue,
|
||||
update: DocumentUpdate<Doc>,
|
||||
account: PersonId
|
||||
): Promise<void> {}
|
||||
|
||||
async performIssueFieldsUpdate (
|
||||
ctx: MeasureContext,
|
||||
info: DocSyncInfo,
|
||||
existing: WithMarkup<Issue>,
|
||||
platformUpdate: DocumentUpdate<Issue>,
|
||||
@@ -630,11 +652,11 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
|
||||
if (hasFieldStateChanges || body !== undefined) {
|
||||
if (body !== undefined && !isLocked) {
|
||||
await this.ctx.with(
|
||||
await ctx.with(
|
||||
'==> updateIssue',
|
||||
{},
|
||||
async () => {
|
||||
this.ctx.info('update fields', {
|
||||
ctx.info('update fields', {
|
||||
url: issueExternal.url,
|
||||
...issueUpdate,
|
||||
body,
|
||||
@@ -671,11 +693,11 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
)
|
||||
issueData.description = await this.provider.getMarkupSafe(container.container, body, this.stripGuestLink)
|
||||
} else if (hasFieldStateChanges) {
|
||||
await this.ctx.with(
|
||||
await ctx.with(
|
||||
'==> updateIssue',
|
||||
{},
|
||||
async () => {
|
||||
this.ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId() })
|
||||
ctx.info('update fields', { ...issueUpdate, workspace: this.provider.getWorkspaceId() })
|
||||
if (isGHWriteAllowed()) {
|
||||
const hasOtherChanges = Object.keys(issueUpdate).length > 0
|
||||
if (state === 'OPEN') {
|
||||
@@ -714,13 +736,14 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
|
||||
async createGithubIssue (
|
||||
ctx: MeasureContext,
|
||||
container: ContainerFocus,
|
||||
existing: WithMarkup<Issue>,
|
||||
repository: GithubIntegrationRepository
|
||||
): Promise<IssueExternalData | undefined> {
|
||||
const existingIssue = existing
|
||||
|
||||
const okit = (await this.provider.getOctokit(existingIssue.modifiedBy)) ?? container.container.octokit
|
||||
const okit = (await this.provider.getOctokit(ctx, existingIssue.modifiedBy)) ?? container.container.octokit
|
||||
|
||||
const repoId = repository.nodeId
|
||||
|
||||
@@ -760,8 +783,13 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
}
|
||||
|
||||
async deleteGithubDocument (container: ContainerFocus, account: PersonId, id: string): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(account)) ?? container.container.octokit
|
||||
async deleteGithubDocument (
|
||||
ctx: MeasureContext,
|
||||
container: ContainerFocus,
|
||||
account: PersonId,
|
||||
id: string
|
||||
): Promise<void> {
|
||||
const okit = (await this.provider.getOctokit(ctx, account)) ?? container.container.octokit
|
||||
|
||||
const q = `mutation deleteIssue($issueID: ID!) {
|
||||
deleteIssue(
|
||||
@@ -871,7 +899,9 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
|
||||
async fillBackChanges (update: DocumentUpdate<Issue>, existing: TGithubIssue, external: any): Promise<void> {}
|
||||
|
||||
@withContext('issues-externalSync')
|
||||
async externalSync (
|
||||
ctx: MeasureContext,
|
||||
integration: IntegrationContainer,
|
||||
derivedClient: TxOperations,
|
||||
kind: ExternalSyncField,
|
||||
@@ -897,7 +927,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
const idsp = idsPart.map((it) => `"${it}"`).join(', ')
|
||||
try {
|
||||
const response: any = await this.ctx.with(
|
||||
const response: any = await ctx.with(
|
||||
'graphql.listIssue',
|
||||
{},
|
||||
() =>
|
||||
@@ -919,19 +949,19 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
const issues: IssueExternalData[] = response.nodes
|
||||
|
||||
if (issues.some((issue) => issue.url === undefined && Object.keys(issue).length === 0)) {
|
||||
this.ctx.error('empty document content', {
|
||||
ctx.error('empty document content', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(response)
|
||||
})
|
||||
}
|
||||
|
||||
await this.syncIssues(tracker.class.Issue, repo, issues, derivedClient, docsPart)
|
||||
await this.syncIssues(ctx, tracker.class.Issue, repo, issues, derivedClient, docsPart)
|
||||
} catch (err: any) {
|
||||
if (partsize > 1) {
|
||||
partsize = 1
|
||||
allSyncDocs.push(...docsPart)
|
||||
this.ctx.warn('issue external retrieval switch to one by one mode', {
|
||||
ctx.warn('issue external retrieval switch to one by one mode', {
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
@@ -940,7 +970,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
// We need to update issue, since it is missing on external side.
|
||||
const syncDoc = syncDocs.find((it) => it.external.id === idsPart[0])
|
||||
if (syncDoc !== undefined) {
|
||||
this.ctx.warn('mark missing external PR', {
|
||||
ctx.warn('mark missing external PR', {
|
||||
errors: err.errors,
|
||||
msg: err.message,
|
||||
url: syncDoc.url,
|
||||
@@ -961,7 +991,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
for (const d of syncDocs) {
|
||||
if ((d.external as IssueExternalData).id == null) {
|
||||
this.ctx.error('failed to do external sync for', { objectClass: d.objectClass, _id: d._id })
|
||||
ctx.error('failed to do external sync for', { objectClass: d.objectClass, _id: d._id })
|
||||
// no external data for doc
|
||||
await derivedClient.update<DocSyncInfo>(d, {
|
||||
externalVersion: githubExternalSyncVersion
|
||||
@@ -971,15 +1001,17 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
this.provider.sync()
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
this.ctx.error('Error', { err })
|
||||
ctx.error('Error', { err })
|
||||
}
|
||||
}
|
||||
|
||||
repositoryDisabled (integration: IntegrationContainer, repo: GithubIntegrationRepository): void {
|
||||
repositoryDisabled (ctx: MeasureContext, integration: IntegrationContainer, repo: GithubIntegrationRepository): void {
|
||||
integration.synchronized.delete(`${repo._id}:issues`)
|
||||
}
|
||||
|
||||
@withContext('issues-externalFullSync')
|
||||
async externalFullSync (
|
||||
ctx: MeasureContext,
|
||||
integration: IntegrationContainer,
|
||||
derivedClient: TxOperations,
|
||||
projects: GithubProject[],
|
||||
@@ -1010,7 +1042,7 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
const since = await getSince(this.client, tracker.class.Issue, repo)
|
||||
|
||||
this.ctx.info('sync external issues', { repo: repo.name, since, workspace: this.provider.getWorkspaceId() })
|
||||
ctx.info('sync external issues', { repo: repo.name, since, workspace: this.provider.getWorkspaceId() })
|
||||
|
||||
const i = integration.octokit.graphql.paginate.iterator(
|
||||
`query listIssue($name: String!, $owner: String!, $since: DateTime!, $cursor: String) {
|
||||
@@ -1042,21 +1074,21 @@ export class IssueSyncManager extends IssueSyncManagerBase implements DocSyncMan
|
||||
}
|
||||
const issues: IssueExternalData[] = data.repository.issues.nodes
|
||||
if (issues.some((issue) => issue.url === undefined && Object.keys(issue).length === 0)) {
|
||||
this.ctx.error('empty document content', {
|
||||
ctx.error('empty document content', {
|
||||
repo: repo.name,
|
||||
workspace: this.provider.getWorkspaceId(),
|
||||
data: cutObjectArray(data)
|
||||
})
|
||||
}
|
||||
await this.syncIssues(tracker.class.Issue, repo, issues, derivedClient)
|
||||
await this.syncIssues(ctx, tracker.class.Issue, repo, issues, derivedClient)
|
||||
this.provider.sync()
|
||||
}
|
||||
} catch (err: any) {
|
||||
this.ctx.error('Error', { err })
|
||||
ctx.error('Error', { err })
|
||||
Analytics.handleError(err)
|
||||
}
|
||||
|
||||
this.ctx.info('sync external issues - done', {
|
||||
ctx.info('sync external issues - done', {
|
||||
repo: repo.name,
|
||||
since,
|
||||
workspace: this.provider.getWorkspaceId()
|
||||
|
||||
Reference in New Issue
Block a user