mirror of
https://github.com/hcengineering/platform.git
synced 2026-08-23 04:42:22 +02:00
UBERF-7836: Fix github integeration (#6313)
Signed-off-by: Andrey Sobolev <haiodo@gmail.com>
This commit is contained in:
@@ -15,8 +15,8 @@ import core, {
|
||||
Ref,
|
||||
TxOperations
|
||||
} from '@hcengineering/core'
|
||||
import github, { GithubAuthentication, makeQuery } from '@hcengineering/github'
|
||||
import { MongoClientReference, getMongoClient } from '@hcengineering/mongo'
|
||||
import github, { GithubAuthentication, makeQuery, type GithubIntegration } from '@hcengineering/github'
|
||||
import { getMongoClient, MongoClientReference } from '@hcengineering/mongo'
|
||||
import { setMetadata } from '@hcengineering/platform'
|
||||
import { buildStorageFromConfig, storageConfigFromEnv } from '@hcengineering/server-storage'
|
||||
import serverToken, { generateToken } from '@hcengineering/server-token'
|
||||
@@ -199,9 +199,39 @@ export class PlatformWorker {
|
||||
installationId: number,
|
||||
accountId: Ref<Account>
|
||||
): Promise<void> {
|
||||
if (this.integrations.find((it) => it.installationId === installationId) != null) {
|
||||
const oldInstallation = this.integrations.find((it) => it.installationId === installationId)
|
||||
if (oldInstallation != null) {
|
||||
ctx.info('update integration', { workspace, installationId, accountId })
|
||||
// What to do with installation in different workspace?
|
||||
// Let's remove it and sync to new one.
|
||||
if (oldInstallation.workspace !== workspace) {
|
||||
//
|
||||
const oldWorkspace = oldInstallation.workspace
|
||||
|
||||
await this.integrationCollection.updateOne(
|
||||
{ installationId: oldInstallation.installationId },
|
||||
{ $set: { workspace } }
|
||||
)
|
||||
oldInstallation.workspace = workspace
|
||||
|
||||
const oldWorker = this.clients.get(oldWorkspace) as GithubWorker
|
||||
if (oldWorker !== undefined) {
|
||||
await this.removeInstallationFromWorkspace(oldWorker.client, installationId)
|
||||
await oldWorker.reloadRepositories(installationId)
|
||||
} else {
|
||||
let client: Client | undefined
|
||||
try {
|
||||
client = await createPlatformClient(oldWorkspace, config.ProductID, 30000)
|
||||
await this.removeInstallationFromWorkspace(oldWorker, installationId)
|
||||
await client.close()
|
||||
} catch (err: any) {
|
||||
ctx.error('failed to remove old installation from workspace', { workspace: oldWorkspace, installationId })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await this.updateInstallation(installationId)
|
||||
|
||||
const worker = this.clients.get(workspace) as GithubWorker
|
||||
await worker?.reloadRepositories(installationId)
|
||||
worker?.triggerUpdate()
|
||||
@@ -214,7 +244,9 @@ export class PlatformWorker {
|
||||
installationId,
|
||||
accountId
|
||||
}
|
||||
await ctx.withLog('add integration', { workspace, installationId, accountId }, async (ctx) => {
|
||||
ctx.info('add integration', { workspace, installationId, accountId })
|
||||
|
||||
await ctx.with('add integration', { workspace, installationId, accountId }, async (ctx) => {
|
||||
await this.integrationCollection.insertOne(record)
|
||||
this.integrations.push(record)
|
||||
})
|
||||
@@ -228,12 +260,43 @@ export class PlatformWorker {
|
||||
this.triggerCheckWorkspaces()
|
||||
}
|
||||
|
||||
private async removeInstallationFromWorkspace (client: Client, installationId: number): Promise<void> {
|
||||
const wsIntegerations = await client.findAll(github.class.GithubIntegration, { installationId })
|
||||
|
||||
for (const intValue of wsIntegerations) {
|
||||
const ops = new TxOperations(client, core.account.System)
|
||||
await ops.remove<GithubIntegration>(intValue)
|
||||
}
|
||||
}
|
||||
|
||||
async removeInstallation (ctx: MeasureContext, workspace: string, installationId: number): Promise<void> {
|
||||
const installation = this.installations.get(installationId)
|
||||
if (installation !== undefined) {
|
||||
await installation.octokit.rest.apps.deleteInstallation({
|
||||
installation_id: installationId
|
||||
})
|
||||
try {
|
||||
await installation.octokit.rest.apps.deleteInstallation({
|
||||
installation_id: installationId
|
||||
})
|
||||
} catch (err: any) {
|
||||
if (err.status !== 404) {
|
||||
// Already deleted.
|
||||
ctx.error('error from github api', { error: err })
|
||||
}
|
||||
await this.handleInstallationEventDelete(installationId)
|
||||
}
|
||||
// Let's check if workspace somehow still have installation and remove it
|
||||
const worker = this.clients.get(workspace) as GithubWorker
|
||||
if (worker !== undefined) {
|
||||
await GithubWorker.checkIntegrations(worker.client, this.installations)
|
||||
} else {
|
||||
let client: Client | undefined
|
||||
try {
|
||||
client = await createPlatformClient(workspace, config.ProductID, 30000)
|
||||
await GithubWorker.checkIntegrations(client, this.installations)
|
||||
await client.close()
|
||||
} catch (err: any) {
|
||||
ctx.error('failed to clean installation from workspace', { workspace, installationId })
|
||||
}
|
||||
}
|
||||
}
|
||||
this.triggerCheckWorkspaces()
|
||||
}
|
||||
@@ -578,6 +641,12 @@ export class PlatformWorker {
|
||||
const rateLimiter = new RateLimiter(5)
|
||||
let errors = 0
|
||||
let idx = 0
|
||||
const connecting = new Map<string, number>()
|
||||
const connectingInfo = setInterval(() => {
|
||||
for (const [c, d] of connecting.entries()) {
|
||||
this.ctx.info('connecting to workspace', { workspace: c, time: Date.now() - d })
|
||||
}
|
||||
}, 5000)
|
||||
for (const workspace of workspaces) {
|
||||
const widx = ++idx
|
||||
if (this.clients.has(workspace)) {
|
||||
@@ -607,8 +676,14 @@ export class PlatformWorker {
|
||||
errors++
|
||||
return
|
||||
}
|
||||
if (workspaceInfo?.disabled === true) {
|
||||
this.ctx.error('Workspace is disabled workspaceId', { workspace })
|
||||
return
|
||||
}
|
||||
const branding = Object.values(this.brandingMap).find((b) => b.key === workspaceInfo?.branding) ?? null
|
||||
const workerCtx = this.ctx.newChild('worker', { workspace: workspaceInfo.workspace }, {})
|
||||
|
||||
connecting.set(workspaceInfo.workspace, Date.now())
|
||||
workerCtx.info('************************* Register worker ************************* ', {
|
||||
workspaceId: workspaceInfo.workspaceId,
|
||||
workspace: workspaceInfo.workspace,
|
||||
@@ -658,6 +733,8 @@ export class PlatformWorker {
|
||||
this.ctx.info("Couldn't create WS worker", { workspace, error: e })
|
||||
console.error(e)
|
||||
errors++
|
||||
} finally {
|
||||
connecting.delete(workspaceInfo.workspace)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -667,6 +744,7 @@ export class PlatformWorker {
|
||||
Analytics.handleError(e)
|
||||
errors++
|
||||
}
|
||||
clearInterval(connectingInfo)
|
||||
// Close deleted workspaces
|
||||
for (const deleted of Array.from(toDelete.keys())) {
|
||||
const ws = this.clients.get(deleted)
|
||||
|
||||
@@ -73,13 +73,12 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
||||
app.post('/api/v1/installation', async (req, res) => {
|
||||
const payloadData: {
|
||||
installationId: number
|
||||
accountId: Ref<Account>
|
||||
token: string
|
||||
} = req.body
|
||||
try {
|
||||
const payloadData: {
|
||||
installationId: number
|
||||
accountId: Ref<Account>
|
||||
token: string
|
||||
} = req.body
|
||||
|
||||
const decodedToken = decodeToken(payloadData.token)
|
||||
ctx.info('/api/v1/installation', {
|
||||
email: decodedToken.email,
|
||||
@@ -87,6 +86,10 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
body: req.body
|
||||
})
|
||||
|
||||
ctx.info('map-installation', {
|
||||
workspace: decodedToken.workspace.name,
|
||||
installationid: payloadData.installationId
|
||||
})
|
||||
await ctx.withLog('map-installation', {}, async (ctx) => {
|
||||
await worker.mapInstallation(
|
||||
ctx,
|
||||
@@ -99,6 +102,12 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
res.json({})
|
||||
} catch (err: any) {
|
||||
Analytics.handleError(err)
|
||||
const tok = decodeToken(payloadData.token, false)
|
||||
ctx.error('failed to map-installation', {
|
||||
workspace: tok.workspace?.name,
|
||||
installationid: payloadData.installationId,
|
||||
email: tok?.email
|
||||
})
|
||||
res.status(401)
|
||||
res.json({ error: err.message })
|
||||
}
|
||||
@@ -121,7 +130,12 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
} = JSON.parse(atob(payloadData.state))
|
||||
|
||||
const decodedToken = decodeToken(decodedData.token)
|
||||
|
||||
ctx.info('request github access-token', {
|
||||
workspace: decodedToken.workspace.name,
|
||||
accountId: payloadData.accountId,
|
||||
code: payloadData.code,
|
||||
state: payloadData.state
|
||||
})
|
||||
await ctx.withLog('request-github-access-token', {}, async (ctx) => {
|
||||
await worker.requestGithubAccessToken({
|
||||
workspace: decodedToken.workspace.name,
|
||||
@@ -154,7 +168,11 @@ export async function start (ctx: MeasureContext, brandingMap: BrandingMap): Pro
|
||||
body: req.body
|
||||
})
|
||||
|
||||
await ctx.withLog('map-installation', {}, async (ctx) => {
|
||||
ctx.info('remove-installation', {
|
||||
workspace: decodedToken.workspace.name,
|
||||
installationId: payloadData.installationId
|
||||
})
|
||||
await ctx.withLog('remove-installation', {}, async (ctx) => {
|
||||
await worker.removeInstallation(ctx, decodedToken.workspace.name, payloadData.installationId)
|
||||
})
|
||||
res.status(200)
|
||||
|
||||
@@ -624,7 +624,7 @@ export class GithubWorker implements IntegrationManager {
|
||||
return statuses.filter((it) => allowedTypes.has(it._id))
|
||||
}
|
||||
|
||||
async init (): Promise<boolean> {
|
||||
async init (): Promise<void> {
|
||||
this.registerNotifyHandler()
|
||||
|
||||
await this.queryAccounts()
|
||||
@@ -692,7 +692,6 @@ export class GithubWorker implements IntegrationManager {
|
||||
this.triggerRequests = 1
|
||||
this.updateRequests = 1
|
||||
this.syncPromise = this.syncAndWait()
|
||||
return true
|
||||
}
|
||||
|
||||
projects: GithubProject[] = []
|
||||
@@ -1504,9 +1503,8 @@ export class GithubWorker implements IntegrationManager {
|
||||
branding
|
||||
)
|
||||
ctx.info('Init worker', { workspace: workspace.workspaceUrl, workspaceId: workspace.workspaceName })
|
||||
if (await worker.init()) {
|
||||
return worker
|
||||
}
|
||||
void worker.init()
|
||||
return worker
|
||||
} catch (err: any) {
|
||||
ctx.error('timeout during to connect', { workspace, error: err })
|
||||
await client?.close()
|
||||
|
||||
Reference in New Issue
Block a user