From 96eb77f54766a0018573ad8f024b53464aa136aa Mon Sep 17 00:00:00 2001 From: DarkSky Date: Mon, 18 Nov 2024 16:41:05 +0800 Subject: [PATCH 1/7] feat: cron job for copilot test --- .github/actions/deploy/deploy.mjs | 4 + .../graphql/templates/copilot-secret.yaml | 2 + .../graphql/templates/copilot-test.yaml | 66 +++++++++++ .github/workflows/deploy.yml | 3 + packages/backend/server/package.json | 11 +- .../server/scripts/copilot-cron-test.js | 99 ++++++++++++++++ .../backend/server/tests/ava.docker.config.js | 9 ++ .../server/tests/copilot-provider.e2e.ts | 112 +++++++++++++++--- .../backend/server/tests/tsconfig.docker.json | 20 ++++ .../backend/server/tests/user/user.e2e.ts | 3 +- packages/backend/server/tests/utils/blobs.ts | 31 ++++- packages/backend/server/tests/utils/common.ts | 38 +++++- .../backend/server/tests/utils/copilot.ts | 11 +- packages/backend/server/tests/utils/invite.ts | 16 +-- packages/backend/server/tests/utils/user.ts | 14 +-- packages/backend/server/tests/utils/utils.ts | 34 ------ .../backend/server/tests/utils/workspace.ts | 16 +-- yarn.lock | 54 ++++++++- 18 files changed, 448 insertions(+), 95 deletions(-) create mode 100644 .github/helm/affine/charts/graphql/templates/copilot-test.yaml create mode 100644 packages/backend/server/scripts/copilot-cron-test.js create mode 100644 packages/backend/server/tests/ava.docker.config.js create mode 100644 packages/backend/server/tests/tsconfig.docker.json diff --git a/.github/actions/deploy/deploy.mjs b/.github/actions/deploy/deploy.mjs index e5a35a18bf070..114198f190b5f 100644 --- a/.github/actions/deploy/deploy.mjs +++ b/.github/actions/deploy/deploy.mjs @@ -19,6 +19,8 @@ const { COPILOT_FAL_API_KEY, COPILOT_PERPLEXITY_API_KEY, COPILOT_UNSPLASH_API_KEY, + SLACK_BOT_TOKEN, + RELEASE_SLACK_CHNNEL_ID, MAILER_SENDER, MAILER_USER, MAILER_PASSWORD, @@ -150,6 +152,8 @@ const createHelmCommand = ({ isDryRun }) => { `--set-string graphql.app.copilot.fal.key="${COPILOT_FAL_API_KEY}"`, `--set-string graphql.app.copilot.perplexity.key="${COPILOT_PERPLEXITY_API_KEY}"`, `--set-string graphql.app.copilot.unsplash.key="${COPILOT_UNSPLASH_API_KEY}"`, + `--set-string graphql.app.copilot.slack.botToken="${SLACK_BOT_TOKEN}"`, + `--set-string graphql.app.copilot.slack.channelId="${RELEASE_SLACK_CHNNEL_ID}"`, `--set-string graphql.app.mailer.sender="${MAILER_SENDER}"`, `--set-string graphql.app.mailer.user="${MAILER_USER}"`, `--set-string graphql.app.mailer.password="${MAILER_PASSWORD}"`, diff --git a/.github/helm/affine/charts/graphql/templates/copilot-secret.yaml b/.github/helm/affine/charts/graphql/templates/copilot-secret.yaml index 5e08f72619559..1199fcdb2f227 100644 --- a/.github/helm/affine/charts/graphql/templates/copilot-secret.yaml +++ b/.github/helm/affine/charts/graphql/templates/copilot-secret.yaml @@ -9,4 +9,6 @@ data: falSecret: {{ .Values.app.copilot.fal.key | b64enc }} perplexitySecret: {{ .Values.app.copilot.perplexity.key | b64enc }} unsplashSecret: {{ .Values.app.copilot.unsplash.key | b64enc }} + slackBotToken: {{ .Values.app.copilot.slack.botToken | b64enc }} + slackChannelId: {{ .Values.app.copilot.slack.channelId | b64enc }} {{- end }} diff --git a/.github/helm/affine/charts/graphql/templates/copilot-test.yaml b/.github/helm/affine/charts/graphql/templates/copilot-test.yaml new file mode 100644 index 0000000000000..64fa3c1754ede --- /dev/null +++ b/.github/helm/affine/charts/graphql/templates/copilot-test.yaml @@ -0,0 +1,66 @@ +{{ if .Values.app.copilot.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "graphql.fullname" . }}-copilot-test + labels: + {{- include "graphql.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": post-install,post-upgrade + "helm.sh/hook-weight": "1" + "helm.sh/hook-delete-policy": before-hook-creation +spec: + schedule: "0 8 * * *" + jobTemplate: + spec: + template: + spec: + serviceAccountName: {{ include "graphql.serviceAccountName" . }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + command: ["yarn", "test:copilot:e2e:cron"] + env: + - name: AFFINE_ENV + value: "{{ .Release.Namespace }}" + - name: SLACK_BOT_TOKEN + valueFrom: + secretKeyRef: + name: "{{ .Values.app.copilot.secretName }}" + key: slackBotToken + - name: CHANNEL_ID + valueFrom: + secretKeyRef: + name: "{{ .Values.app.copilot.secretName }}" + key: slackChannelId + - name: COPILOT_E2E_ENDPOINT + value: "http://{{ include "graphql.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:3000" + - name: DATABASE_PASSWORD + valueFrom: + secretKeyRef: + name: pg-postgresql + key: postgres-password + - name: DATABASE_URL + value: postgres://{{ .Values.global.database.user }}:$(DATABASE_PASSWORD)@{{ .Values.global.database.url }}:{{ .Values.global.database.port }}/{{ .Values.global.database.name }} + - name: COPILOT_OPENAI_API_KEY + valueFrom: + secretKeyRef: + name: "{{ .Values.app.copilot.secretName }}" + key: openaiSecret + - name: COPILOT_FAL_API_KEY + valueFrom: + secretKeyRef: + name: "{{ .Values.app.copilot.secretName }}" + key: falSecret + - name: COPILOT_UNSPLASH_API_KEY + valueFrom: + secretKeyRef: + name: "{{ .Values.app.copilot.secretName }}" + key: unsplashSecret + resources: + requests: + cpu: '100m' + memory: '200Mi' + restartPolicy: Never + backoffLimit: 1 +{{ end }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 95b3067851d9c..28686dd2c5400 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -100,6 +100,9 @@ jobs: COPILOT_FAL_API_KEY: ${{ secrets.COPILOT_FAL_API_KEY }} COPILOT_PERPLEXITY_API_KEY: ${{ secrets.COPILOT_PERPLEXITY_API_KEY }} COPILOT_UNSPLASH_API_KEY: ${{ secrets.COPILOT_UNSPLASH_API_KEY }} + # used for slack notifications + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + RELEASE_SLACK_CHNNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} METRICS_CUSTOMER_IO_TOKEN: ${{ secrets.METRICS_CUSTOMER_IO_TOKEN }} MAILER_SENDER: ${{ secrets.OAUTH_EMAIL_SENDER }} MAILER_USER: ${{ secrets.OAUTH_EMAIL_LOGIN }} diff --git a/packages/backend/server/package.json b/packages/backend/server/package.json index edc2b48af2668..1c2f46142266f 100644 --- a/packages/backend/server/package.json +++ b/packages/backend/server/package.json @@ -16,6 +16,7 @@ "test:coverage": "c8 ava --concurrency 1 --serial", "test:copilot:e2e:coverage": "c8 ava --timeout=5m \"tests/**/copilot-*.e2e.ts\"", "test:copilot:spec:coverage": "c8 ava --timeout=5m \"tests/**/copilot-*.spec.ts\"", + "test:copilot:e2e:cron": "node ./scripts/copilot-cron-test.js", "data-migration": "cross-env NODE_ENV=script r ./src/data/index.ts", "predeploy": "yarn prisma migrate deploy && NODE_ENV=script node --import ./scripts/register.js ./dist/data/index.js run", "postinstall": "prisma generate" @@ -58,7 +59,9 @@ "@opentelemetry/semantic-conventions": "^1.28.0", "@prisma/client": "^5.22.0", "@prisma/instrumentation": "^5.22.0", + "@slack/web-api": "^7.3.4", "@socket.io/redis-adapter": "^8.3.0", + "ava": "^6.1.2", "cookie-parser": "^1.4.7", "dotenv": "^16.4.7", "eventsource-parser": "^3.0.0", @@ -71,8 +74,10 @@ "html-validate": "^9.0.0", "ioredis": "^5.4.1", "is-mobile": "^5.0.0", + "jsx-slack": "^6.1.1", "keyv": "^5.2.2", "lodash-es": "^4.17.21", + "marked": "^15.0.0", "mixpanel": "^0.18.0", "mustache": "^4.2.0", "nanoid": "^5.0.9", @@ -89,6 +94,8 @@ "ses": "^1.10.0", "socket.io": "^4.8.1", "stripe": "^17.4.0", + "supertest": "^7.0.0", + "tap-parser": "^18.0.0", "ts-node": "^10.9.2", "typescript": "^5.7.2", "winston": "^3.17.0", @@ -112,12 +119,10 @@ "@types/on-headers": "^1.0.3", "@types/sinon": "^17.0.3", "@types/supertest": "^6.0.2", - "ava": "^6.2.0", "c8": "^10.1.3", "cross-env": "^7.0.3", "nodemon": "^3.1.7", - "sinon": "^19.0.2", - "supertest": "^7.0.0" + "sinon": "^19.0.2" }, "ava": { "timeout": "1m", diff --git a/packages/backend/server/scripts/copilot-cron-test.js b/packages/backend/server/scripts/copilot-cron-test.js new file mode 100644 index 0000000000000..915b68bd79d13 --- /dev/null +++ b/packages/backend/server/scripts/copilot-cron-test.js @@ -0,0 +1,99 @@ +// start process + +import { spawn } from 'node:child_process'; + +import { WebClient } from '@slack/web-api'; +import { jsxslack } from 'jsx-slack'; +import { marked, Renderer } from 'marked'; +import { Parser } from 'tap-parser'; + +async function runTest() { + const tester = new Promise(resolve => { + const test = spawn( + 'npx', + [ + 'ava', + '--config', + 'tests/ava.docker.config.js', + 'tests/**/copilot-*.e2e.ts', + '--tap', + ], + { env: { ...process.env, NODE_NO_WARNINGS: 1 } } + ); + + const parser = new Parser(); + test.stdout.on('data', data => { + console.log(data.toString()); + parser.write(data); + }); + + test.on('close', _ => { + const failures = parser?.failures.filter(f => !!f.fullname); + const timeouts = parser?.failures.filter(f => !f.fullname); + const result = [ + `${parser.results.pass} passed`, + `${parser.results.fail - timeouts.length} failed`, + `${timeouts.length} timeouts`, + `${parser.results.skip} skipped`, + ]; + const report = [ + `Test finished with ${result.join(', ')}.`, + failures?.length > 0 + ? `Failed tests: \n\n${failures.map(failure => `- ${failure.fullname}`).join('\n')}` + : '', + ]; + resolve(report.join('\n\n')); + }); + }); + + try { + return await tester; + } catch (e) { + return e.message; + } +} + +function render(markdown) { + const rendered = marked(markdown, { + renderer: new (class CustomRenderer extends Renderer { + heading({ tokens }) { + return ` + +
${tokens[0].text}
+ +
`; + } + + paragraph({ tokens }) { + return `

${tokens[0].text}

`; + } + + list(token) { + return `
${super.list(token)}
`; + } + + hr() { + return ``; + } + })(), + }); + return jsxslack([`${rendered}`]); +} + +async function main() { + const { CHANNEL_ID, SLACK_BOT_TOKEN, AFFINE_ENV } = process.env; + + const report = await runTest(); + const blocks = render( + [`# AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, report].join('\n\n') + ); + const { ok } = await new WebClient(SLACK_BOT_TOKEN).chat.postMessage({ + channel: CHANNEL_ID, + text: `AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, + blocks, + }); + + console.assert(ok, 'Failed to send a message to Slack'); +} + +await main(); diff --git a/packages/backend/server/tests/ava.docker.config.js b/packages/backend/server/tests/ava.docker.config.js new file mode 100644 index 0000000000000..832ff81f3b290 --- /dev/null +++ b/packages/backend/server/tests/ava.docker.config.js @@ -0,0 +1,9 @@ +import packageJson from '../package.json' with { type: 'json' }; + +export default { + ...packageJson.ava, + environmentVariables: { + ...packageJson.ava.environmentVariables, + TS_NODE_PROJECT: './tests/tsconfig.docker.json', + }, +}; diff --git a/packages/backend/server/tests/copilot-provider.e2e.ts b/packages/backend/server/tests/copilot-provider.e2e.ts index 530db68d3e8e1..ae10f645e0ab9 100644 --- a/packages/backend/server/tests/copilot-provider.e2e.ts +++ b/packages/backend/server/tests/copilot-provider.e2e.ts @@ -1,10 +1,10 @@ -import { randomUUID } from 'node:crypto'; +import { randomInt, randomUUID } from 'node:crypto'; -import { createRandomAIUser } from '@affine-test/kit/utils/cloud'; +import { hash } from '@node-rs/argon2'; import type { ExecutionContext, TestFn } from 'ava'; import ava from 'ava'; +import { z } from 'zod'; -import { createWorkspace } from './utils'; import { chatWithImages, chatWithText, @@ -15,6 +15,7 @@ import { ProviderWorkflowTestCase, sse2array, } from './utils/copilot'; +import { createWorkspace } from './utils/workspace'; type Tester = { app: any; @@ -47,20 +48,14 @@ const runIfCopilotConfigured = test.macro( } ); -export const runPrisma = async ( +const runPrisma = async ( cb: ( prisma: InstanceType< - // eslint-disable-next-line @typescript-eslint/consistent-type-imports - typeof import('../../../../packages/backend/server/node_modules/@prisma/client').PrismaClient + typeof import('../node_modules/@prisma/client').PrismaClient > ) => Promise ): Promise => { - const { - PrismaClient, - // eslint-disable-next-line @typescript-eslint/no-var-requires - } = await import( - '../../../../packages/backend/server/node_modules/@prisma/client' - ); + const { PrismaClient } = await import('../node_modules/@prisma/client'); const client = new PrismaClient(); await client.$connect(); try { @@ -70,14 +65,99 @@ export const runPrisma = async ( } }; +const cloudUserSchema = z.object({ + id: z.string(), + name: z.string(), + email: z.string().email(), + password: z.string(), +}); + +function randomName() { + return Array.from({ length: 10 }, () => + String.fromCharCode(randomInt(65, 90)) + ) + .join('') + .toLowerCase(); +} + +async function createRandomAIUser(): Promise<{ + name: string; + email: string; + password: string; + id: string; + sessionId: string; +}> { + const name = randomName(); + const email = `${name}@affine.fail`; + const user = { name, email, password: '123456' }; + const result = await runPrisma(async client => { + const freeFeatureId = await client.feature + .findFirst({ + where: { feature: 'free_plan_v1' }, + select: { id: true }, + orderBy: { version: 'desc' }, + }) + .then(f => f!.id); + const aiFeatureId = await client.feature + .findFirst({ + where: { feature: 'unlimited_copilot' }, + select: { id: true }, + orderBy: { version: 'desc' }, + }) + .then(f => f!.id); + + const { id: userId } = await client.user.create({ + data: { + ...user, + emailVerifiedAt: new Date(), + password: await hash(user.password), + features: { + create: [ + { + reason: 'created by test case', + activated: true, + featureId: freeFeatureId, + }, + { + reason: 'created by test case', + activated: true, + featureId: aiFeatureId, + }, + ], + }, + }, + }); + + const { id: sessionId } = await client.session.create({ data: {} }); + await client.userSession.create({ + data: { + sessionId, + userId, + // half an hour + expiresAt: new Date(Date.now() + 60 * 30 * 1000), + }, + }); + + return await client.user + .findUnique({ + where: { + email: user.email, + }, + }) + .then(r => ({ ...r, sessionId })); + }); + cloudUserSchema.parse(result); + return { + ...result, + password: user.password, + } as any; +} + test.before(async t => { if (!isCopilotConfigured) return; const { endpoint } = e2eConfig; - const { email, sessionId: token } = await createRandomAIUser( - 'affine.fail', - runPrisma - ); + const { email, sessionId: token } = await createRandomAIUser(); const app = { getHttpServer: () => endpoint } as any; const { id } = await createWorkspace(app, token); diff --git a/packages/backend/server/tests/tsconfig.docker.json b/packages/backend/server/tests/tsconfig.docker.json new file mode 100644 index 0000000000000..023ed91e8add1 --- /dev/null +++ b/packages/backend/server/tests/tsconfig.docker.json @@ -0,0 +1,20 @@ +{ + "compilerOptions": { + "target": "ES2022", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "rootDir": ".", + "outDir": "../lib/tests", + "verbatimModuleSyntax": false, + "tsBuildInfoFile": "../lib/tests/.tsbuildinfo" + }, + "include": [".", "utils"], + "exclude": [], + "ts-node": { + "esm": true, + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "Node" + } + } +} diff --git a/packages/backend/server/tests/user/user.e2e.ts b/packages/backend/server/tests/user/user.e2e.ts index ae3b430d0a534..e8a0691b402af 100644 --- a/packages/backend/server/tests/user/user.e2e.ts +++ b/packages/backend/server/tests/user/user.e2e.ts @@ -5,7 +5,8 @@ import request from 'supertest'; import { AppModule } from '../../src/app.module'; import { AuthService, CurrentUser } from '../../src/core/auth'; -import { createTestingApp, gql, internalSignIn } from '../utils'; +import { createTestingApp, internalSignIn } from '../utils'; +import { gql } from '../utils/common'; const test = ava as TestFn<{ app: INestApplication; diff --git a/packages/backend/server/tests/utils/blobs.ts b/packages/backend/server/tests/utils/blobs.ts index f6832c41c401d..845ade0fef8b3 100644 --- a/packages/backend/server/tests/utils/blobs.ts +++ b/packages/backend/server/tests/utils/blobs.ts @@ -1,7 +1,7 @@ import type { INestApplication } from '@nestjs/common'; import request from 'supertest'; -import { gql } from './common'; +import { gqlEndpoint } from './common'; export async function listBlobs( app: INestApplication, @@ -9,7 +9,7 @@ export async function listBlobs( workspaceId: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -29,7 +29,7 @@ export async function getWorkspaceBlobsSize( workspaceId: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .send({ query: ` @@ -49,7 +49,7 @@ export async function collectAllBlobSizes( token: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .send({ query: ` @@ -66,6 +66,27 @@ export async function collectAllBlobSizes( return res.body.data.currentUser.quotaUsage.storageQuota; } +export async function checkBlobSize( + app: INestApplication, + token: string, + workspaceId: string, + size: number +): Promise { + const res = await request(app.getHttpServer()) + .post(gqlEndpoint) + .auth(token, { type: 'bearer' }) + .send({ + query: `query checkBlobSize($workspaceId: String!, $size: SafeInt!) { + checkBlobSize(workspaceId: $workspaceId, size: $size) { + size + } + }`, + variables: { workspaceId, size }, + }) + .expect(200); + return res.body.data.checkBlobSize.size; +} + export async function setBlob( app: INestApplication, token: string, @@ -73,7 +94,7 @@ export async function setBlob( buffer: Buffer ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .field( diff --git a/packages/backend/server/tests/utils/common.ts b/packages/backend/server/tests/utils/common.ts index 772922367612e..d8e27f72cc99f 100644 --- a/packages/backend/server/tests/utils/common.ts +++ b/packages/backend/server/tests/utils/common.ts @@ -1 +1,37 @@ -export const gql = '/graphql'; +import { INestApplication } from '@nestjs/common'; +import type { Response } from 'supertest'; +import supertest from 'supertest'; + +export function handleGraphQLError(resp: Response) { + const { errors } = resp.body; + if (errors) { + const cause = errors[0]; + const stacktrace = cause.extensions?.stacktrace; + throw new Error( + stacktrace + ? Array.isArray(stacktrace) + ? stacktrace.join('\n') + : String(stacktrace) + : cause.message, + cause + ); + } +} + +export const gqlEndpoint = '/graphql'; + +export function gql(app: INestApplication, query?: string) { + const req = supertest(app.getHttpServer()) + .post(gqlEndpoint) + .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }); + + if (query) { + return req.send({ query }); + } + + return req; +} + +export async function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/packages/backend/server/tests/utils/copilot.ts b/packages/backend/server/tests/utils/copilot.ts index de01ad0328a07..f506603573588 100644 --- a/packages/backend/server/tests/utils/copilot.ts +++ b/packages/backend/server/tests/utils/copilot.ts @@ -27,8 +27,7 @@ import { WorkflowNodeType, WorkflowParams, } from '../../src/plugins/copilot/workflow/types'; -import { gql } from './common'; -import { handleGraphQLError, sleep } from './utils'; +import { gqlEndpoint, handleGraphQLError, sleep } from './common'; // @ts-expect-error no error export class MockCopilotTestProvider @@ -167,7 +166,7 @@ export async function createCopilotSession( promptName: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -219,7 +218,7 @@ export async function forkCopilotSession( latestMessageId: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -249,7 +248,7 @@ export async function createCopilotMessage( params?: Record ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -403,7 +402,7 @@ export async function getHistories( } ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ diff --git a/packages/backend/server/tests/utils/invite.ts b/packages/backend/server/tests/utils/invite.ts index 4d99d1fc90bf1..332ec9e1570e0 100644 --- a/packages/backend/server/tests/utils/invite.ts +++ b/packages/backend/server/tests/utils/invite.ts @@ -2,7 +2,7 @@ import type { INestApplication } from '@nestjs/common'; import request from 'supertest'; import type { InvitationType } from '../../src/core/workspaces'; -import { gql } from './common'; +import { gqlEndpoint } from './common'; export async function inviteUser( app: INestApplication, @@ -12,7 +12,7 @@ export async function inviteUser( sendInviteMail = false ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -37,7 +37,7 @@ export async function inviteUsers( sendInviteMail = false ): Promise> { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -98,7 +98,7 @@ export async function createInviteLink( expireTime: 'OneDay' | 'ThreeDays' | 'OneWeek' | 'OneMonth' ): Promise<{ link: string; expireTime: string }> { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -149,7 +149,7 @@ export async function acceptInviteById( token: string = '' ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .auth(token, { type: 'bearer' }) .send({ @@ -201,7 +201,7 @@ export async function leaveWorkspace( sendLeaveMail = false ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -225,7 +225,7 @@ export async function revokeUser( userId: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -250,7 +250,7 @@ export async function getInviteInfo( inviteId: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ diff --git a/packages/backend/server/tests/utils/user.ts b/packages/backend/server/tests/utils/user.ts index 79b793a87394f..2a5eb438b67a2 100644 --- a/packages/backend/server/tests/utils/user.ts +++ b/packages/backend/server/tests/utils/user.ts @@ -8,7 +8,7 @@ import { } from '../../src/core/auth'; import { sessionUser } from '../../src/core/auth/service'; import { UserService, type UserType } from '../../src/core/user'; -import { gql } from './common'; +import { gqlEndpoint } from './common'; export type UserAuthedType = UserType & { token: ClientTokenType }; @@ -68,7 +68,7 @@ export async function signUp( export async function currentUser(app: INestApplication, token: string) { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -92,7 +92,7 @@ export async function sendChangeEmail( callbackUrl: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -114,7 +114,7 @@ export async function sendSetPasswordEmail( callbackUrl: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -136,7 +136,7 @@ export async function changePassword( password: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ query: ` @@ -158,7 +158,7 @@ export async function sendVerifyChangeEmail( callbackUrl: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -180,7 +180,7 @@ export async function changeEmail( email: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(userToken, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ diff --git a/packages/backend/server/tests/utils/utils.ts b/packages/backend/server/tests/utils/utils.ts index 71a11489b0743..ef2baed9fef7b 100644 --- a/packages/backend/server/tests/utils/utils.ts +++ b/packages/backend/server/tests/utils/utils.ts @@ -5,8 +5,6 @@ import { Test, TestingModuleBuilder } from '@nestjs/testing'; import { PrismaClient } from '@prisma/client'; import cookieParser from 'cookie-parser'; import graphqlUploadExpress from 'graphql-upload/graphqlUploadExpress.mjs'; -import type { Response } from 'supertest'; -import supertest from 'supertest'; import { AppModule, FunctionalityModules } from '../../src/app.module'; import { GlobalExceptionFilter, Runtime } from '../../src/base'; @@ -156,35 +154,3 @@ export async function createTestingApp(moduleDef: TestingModuleMeatdata = {}) { app, }; } - -export function handleGraphQLError(resp: Response) { - const { errors } = resp.body; - if (errors) { - const cause = errors[0]; - const stacktrace = cause.extensions?.stacktrace; - throw new Error( - stacktrace - ? Array.isArray(stacktrace) - ? stacktrace.join('\n') - : String(stacktrace) - : cause.message, - cause - ); - } -} - -export function gql(app: INestApplication, query?: string) { - const req = supertest(app.getHttpServer()) - .post('/graphql') - .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }); - - if (query) { - return req.send({ query }); - } - - return req; -} - -export async function sleep(ms: number) { - return new Promise(resolve => setTimeout(resolve, ms)); -} diff --git a/packages/backend/server/tests/utils/workspace.ts b/packages/backend/server/tests/utils/workspace.ts index 8fcdde1553afa..23bc9c1c46b84 100644 --- a/packages/backend/server/tests/utils/workspace.ts +++ b/packages/backend/server/tests/utils/workspace.ts @@ -2,7 +2,7 @@ import type { INestApplication } from '@nestjs/common'; import request from 'supertest'; import type { WorkspaceType } from '../../src/core/workspaces'; -import { gql } from './common'; +import { gqlEndpoint } from './common'; import { PermissionEnum } from './utils'; export async function createWorkspace( @@ -10,7 +10,7 @@ export async function createWorkspace( token: string ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .field( @@ -37,7 +37,7 @@ export async function getWorkspacePublicPages( workspaceId: string ) { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -64,7 +64,7 @@ export async function getWorkspace( take = 8 ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -87,7 +87,7 @@ export async function updateWorkspace( isPublic: boolean ): Promise { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -110,7 +110,7 @@ export async function publishPage( pageId: string ) { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -134,7 +134,7 @@ export async function revokePublicPage( pageId: string ) { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ @@ -160,7 +160,7 @@ export async function grantMember( permission: PermissionEnum ) { const res = await request(app.getHttpServer()) - .post(gql) + .post(gqlEndpoint) .auth(token, { type: 'bearer' }) .set({ 'x-request-id': 'test', 'x-operation-name': 'test' }) .send({ diff --git a/yarn.lock b/yarn.lock index 401df040e98e2..bf25b76411af9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -790,6 +790,7 @@ __metadata: "@opentelemetry/semantic-conventions": "npm:^1.28.0" "@prisma/client": "npm:^5.22.0" "@prisma/instrumentation": "npm:^5.22.0" + "@slack/web-api": "npm:^7.3.4" "@socket.io/redis-adapter": "npm:^8.3.0" "@types/cookie-parser": "npm:^1.4.8" "@types/express": "npm:^4.17.21" @@ -803,7 +804,7 @@ __metadata: "@types/on-headers": "npm:^1.0.3" "@types/sinon": "npm:^17.0.3" "@types/supertest": "npm:^6.0.2" - ava: "npm:^6.2.0" + ava: "npm:^6.1.2" c8: "npm:^10.1.3" cookie-parser: "npm:^1.4.7" cross-env: "npm:^7.0.3" @@ -818,8 +819,10 @@ __metadata: html-validate: "npm:^9.0.0" ioredis: "npm:^5.4.1" is-mobile: "npm:^5.0.0" + jsx-slack: "npm:^6.1.1" keyv: "npm:^5.2.2" lodash-es: "npm:^4.17.21" + marked: "npm:^15.0.0" mixpanel: "npm:^0.18.0" mustache: "npm:^4.2.0" nanoid: "npm:^5.0.9" @@ -839,6 +842,7 @@ __metadata: socket.io: "npm:^4.8.1" stripe: "npm:^17.4.0" supertest: "npm:^7.0.0" + tap-parser: "npm:^18.0.0" ts-node: "npm:^10.9.2" typescript: "npm:^5.7.2" winston: "npm:^3.17.0" @@ -12643,7 +12647,7 @@ __metadata: languageName: node linkType: hard -"@slack/web-api@npm:^7.8.0": +"@slack/web-api@npm:^7.3.4, @slack/web-api@npm:^7.8.0": version: 7.8.0 resolution: "@slack/web-api@npm:7.8.0" dependencies: @@ -16686,7 +16690,7 @@ __metadata: languageName: node linkType: hard -"ava@npm:^6.2.0": +"ava@npm:^6.1.2, ava@npm:^6.2.0": version: 6.2.0 resolution: "ava@npm:6.2.0" dependencies: @@ -21152,6 +21156,13 @@ __metadata: languageName: node linkType: hard +"events-to-array@npm:^2.0.3": + version: 2.0.3 + resolution: "events-to-array@npm:2.0.3" + checksum: 10/d392eb0013013c3dfa66710a017902760edb2a588f6b1a3f1c92219563ba1c24bcb99c48e3754423a3538ebfd70318c3536d30bfd80c00e7fec77fdd088540d0 + languageName: node + linkType: hard + "events@npm:^3.2.0": version: 3.3.0 resolution: "events@npm:3.3.0" @@ -24760,7 +24771,7 @@ __metadata: languageName: node linkType: hard -"jsx-slack@npm:^6.1.2": +"jsx-slack@npm:^6.1.1, jsx-slack@npm:^6.1.2": version: 6.1.2 resolution: "jsx-slack@npm:6.1.2" dependencies: @@ -25757,7 +25768,7 @@ __metadata: languageName: node linkType: hard -"marked@npm:^15.0.3": +"marked@npm:^15.0.0, marked@npm:^15.0.3": version: 15.0.6 resolution: "marked@npm:15.0.6" bin: @@ -32562,6 +32573,28 @@ __metadata: languageName: node linkType: hard +"tap-parser@npm:^18.0.0": + version: 18.0.0 + resolution: "tap-parser@npm:18.0.0" + dependencies: + events-to-array: "npm:^2.0.3" + tap-yaml: "npm:4.0.0" + bin: + tap-parser: bin/cmd.cjs + checksum: 10/6e13dc475bfdc880307cc935b9917d43255f7e2b0902d171b7f51b41b029aae9dce5b8683aa48170bb720819b3551d793663c0a11f0660ef78d4a0fe87228ad0 + languageName: node + linkType: hard + +"tap-yaml@npm:4.0.0": + version: 4.0.0 + resolution: "tap-yaml@npm:4.0.0" + dependencies: + yaml: "npm:^2.4.1" + yaml-types: "npm:^0.4.0" + checksum: 10/21d3a27328aa419bb90249357689446488351d350a4ba56c5b1afce9dfe33f60db49014170ea7d16eb90381d3f9f31b59d9637bda632e55167f33c834eb02171 + languageName: node + linkType: hard + "tapable@npm:^2.0.0, tapable@npm:^2.1.1, tapable@npm:^2.2.0, tapable@npm:^2.2.1": version: 2.2.1 resolution: "tapable@npm:2.2.1" @@ -35006,6 +35039,15 @@ __metadata: languageName: node linkType: hard +"yaml-types@npm:^0.4.0": + version: 0.4.0 + resolution: "yaml-types@npm:0.4.0" + peerDependencies: + yaml: ^2.3.0 + checksum: 10/8a3cd3a0420d5d09981e3e1add46d7482336531e3bdc02192d26caa915c7d0795ad28dd8766e357234d6bfa3a2bd986687f967079e47aecfd4b191250f041cec + languageName: node + linkType: hard + "yaml@npm:^1.10.0": version: 1.10.2 resolution: "yaml@npm:1.10.2" @@ -35013,7 +35055,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.3.1, yaml@npm:^2.3.4, yaml@npm:^2.6.1, yaml@npm:~2.6.1": +"yaml@npm:^2.3.1, yaml@npm:^2.3.4, yaml@npm:^2.4.1, yaml@npm:^2.6.1, yaml@npm:~2.6.1": version: 2.6.1 resolution: "yaml@npm:2.6.1" bin: From 376052269b7111a97d8f8d2920e282fa4a389125 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 13 Dec 2024 16:13:24 +0800 Subject: [PATCH 2/7] fix: merge error --- packages/backend/server/tests/utils/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/backend/server/tests/utils/index.ts b/packages/backend/server/tests/utils/index.ts index 92904d3c35d7e..6755347ca7824 100644 --- a/packages/backend/server/tests/utils/index.ts +++ b/packages/backend/server/tests/utils/index.ts @@ -1,4 +1,5 @@ export * from './blobs'; +export * from './common'; export * from './invite'; export * from './user'; export * from './utils'; From e211872f8d69f86149b776ec8ee077fc864b3cfe Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 13 Dec 2024 17:20:15 +0800 Subject: [PATCH 3/7] feat: add more detail for slack report --- tools/copilot-result/index.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/copilot-result/index.js b/tools/copilot-result/index.js index 77d8e26bcc17a..c25501448dc09 100644 --- a/tools/copilot-result/index.js +++ b/tools/copilot-result/index.js @@ -2,8 +2,16 @@ import { WebClient } from '@slack/web-api'; import { render } from './markdown.js'; -const { CHANNEL_ID, SLACK_BOT_TOKEN, COPILOT_RESULT, BRANCH_SHA, BRANCH_NAME } = - process.env; +const { + CHANNEL_ID, + SLACK_BOT_TOKEN, + COPILOT_RESULT, + BRANCH_SHA, + BRANCH_NAME, + GITHUB_SERVER_URL, + GITHUB_REPOSITORY, + GITHUB_RUN_ID, +} = process.env; const { ok } = await new WebClient(SLACK_BOT_TOKEN).chat.postMessage({ channel: CHANNEL_ID, @@ -11,7 +19,8 @@ const { ok } = await new WebClient(SLACK_BOT_TOKEN).chat.postMessage({ blocks: render( `# AFFiNE Copilot Test ${COPILOT_RESULT} -- [${BRANCH_NAME?.replace('refs/heads/', '') || BRANCH_SHA}](https://github.com/toeverything/AFFiNE/commit/${BRANCH_SHA}) +- Branch: [${BRANCH_NAME?.replace('refs/heads/', '') || BRANCH_SHA}](https://github.com/toeverything/AFFiNE/commit/${BRANCH_SHA}) +- Job: [${GITHUB_RUN_ID}](${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}) ` ), }); From 20a3e3b65a85d60fd82809fc7685dad6c0b127ec Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 13 Dec 2024 17:24:08 +0800 Subject: [PATCH 4/7] fix: env typo --- .github/actions/deploy/deploy.mjs | 4 ++-- .github/workflows/copilot-test.yml | 6 +++--- .github/workflows/deploy.yml | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/actions/deploy/deploy.mjs b/.github/actions/deploy/deploy.mjs index 114198f190b5f..f371bfa573c17 100644 --- a/.github/actions/deploy/deploy.mjs +++ b/.github/actions/deploy/deploy.mjs @@ -20,7 +20,7 @@ const { COPILOT_PERPLEXITY_API_KEY, COPILOT_UNSPLASH_API_KEY, SLACK_BOT_TOKEN, - RELEASE_SLACK_CHNNEL_ID, + RELEASE_SLACK_CHANNEL_ID, MAILER_SENDER, MAILER_USER, MAILER_PASSWORD, @@ -153,7 +153,7 @@ const createHelmCommand = ({ isDryRun }) => { `--set-string graphql.app.copilot.perplexity.key="${COPILOT_PERPLEXITY_API_KEY}"`, `--set-string graphql.app.copilot.unsplash.key="${COPILOT_UNSPLASH_API_KEY}"`, `--set-string graphql.app.copilot.slack.botToken="${SLACK_BOT_TOKEN}"`, - `--set-string graphql.app.copilot.slack.channelId="${RELEASE_SLACK_CHNNEL_ID}"`, + `--set-string graphql.app.copilot.slack.channelId="${RELEASE_SLACK_CHANNEL_ID}"`, `--set-string graphql.app.mailer.sender="${MAILER_SENDER}"`, `--set-string graphql.app.mailer.user="${MAILER_USER}"`, `--set-string graphql.app.mailer.password="${MAILER_PASSWORD}"`, diff --git a/.github/workflows/copilot-test.yml b/.github/workflows/copilot-test.yml index a1cbbee9752f0..8bec387068c8a 100644 --- a/.github/workflows/copilot-test.yml +++ b/.github/workflows/copilot-test.yml @@ -181,7 +181,7 @@ jobs: if: ${{ always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} run: node ./tools/copilot-result/index.js env: - CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} BRANCH_SHA: ${{ github.sha }} BRANCH_NAME: ${{ github.ref }} @@ -191,7 +191,7 @@ jobs: if: ${{ always() && contains(needs.*.result, 'failure') }} run: node ./tools/copilot-result/index.js env: - CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} BRANCH_SHA: ${{ github.sha }} BRANCH_NAME: ${{ github.ref }} @@ -201,7 +201,7 @@ jobs: if: ${{ always() && contains(needs.*.result, 'cancelled') && !contains(needs.*.result, 'failure') }} run: node ./tools/copilot-result/index.js env: - CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} BRANCH_SHA: ${{ github.sha }} BRANCH_NAME: ${{ github.ref }} diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 28686dd2c5400..b8aa4d5da5d05 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -102,7 +102,7 @@ jobs: COPILOT_UNSPLASH_API_KEY: ${{ secrets.COPILOT_UNSPLASH_API_KEY }} # used for slack notifications SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} - RELEASE_SLACK_CHNNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + RELEASE_SLACK_CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} METRICS_CUSTOMER_IO_TOKEN: ${{ secrets.METRICS_CUSTOMER_IO_TOKEN }} MAILER_SENDER: ${{ secrets.OAUTH_EMAIL_SENDER }} MAILER_USER: ${{ secrets.OAUTH_EMAIL_LOGIN }} @@ -165,7 +165,7 @@ jobs: if: ${{ always() && !contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') }} run: node ./tools/changelog/index.js env: - CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + CHANNEL_ID: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} DEPLOYED_URL: ${{ steps.set_info.outputs.deployed_url }} PREV_VERSION: ${{ needs.output-prev-version.outputs.prev }} @@ -181,7 +181,7 @@ jobs: method: chat.postMessage token: ${{ secrets.SLACK_BOT_TOKEN }} payload: | - channel: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + channel: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} text: "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Backend deploy failed `${{ github.event.inputs.flavor }}`>" blocks: - type: section @@ -196,7 +196,7 @@ jobs: token: ${{ secrets.SLACK_BOT_TOKEN }} method: chat.postMessage payload: | - channel: ${{ secrets.RELEASE_SLACK_CHNNEL_ID }} + channel: ${{ secrets.RELEASE_SLACK_CHANNEL_ID }} text: "<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Backend deploy cancelled `${{ github.event.inputs.flavor }}`>" blocks: - type: section From be661a783fc01af82cd87dc578e16f3d12e0c732 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Fri, 13 Dec 2024 17:28:37 +0800 Subject: [PATCH 5/7] chore: remove outdated api --- packages/backend/server/tests/utils/blobs.ts | 21 -------------------- 1 file changed, 21 deletions(-) diff --git a/packages/backend/server/tests/utils/blobs.ts b/packages/backend/server/tests/utils/blobs.ts index 845ade0fef8b3..4fd302be738a1 100644 --- a/packages/backend/server/tests/utils/blobs.ts +++ b/packages/backend/server/tests/utils/blobs.ts @@ -66,27 +66,6 @@ export async function collectAllBlobSizes( return res.body.data.currentUser.quotaUsage.storageQuota; } -export async function checkBlobSize( - app: INestApplication, - token: string, - workspaceId: string, - size: number -): Promise { - const res = await request(app.getHttpServer()) - .post(gqlEndpoint) - .auth(token, { type: 'bearer' }) - .send({ - query: `query checkBlobSize($workspaceId: String!, $size: SafeInt!) { - checkBlobSize(workspaceId: $workspaceId, size: $size) { - size - } - }`, - variables: { workspaceId, size }, - }) - .expect(200); - return res.body.data.checkBlobSize.size; -} - export async function setBlob( app: INestApplication, token: string, From 3e25df978651b5503df36f2aa596e3e5a780e706 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Thu, 2 Jan 2025 16:55:52 +0800 Subject: [PATCH 6/7] chore: use tla --- .../server/scripts/copilot-cron-test.js | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/packages/backend/server/scripts/copilot-cron-test.js b/packages/backend/server/scripts/copilot-cron-test.js index 915b68bd79d13..c5332f8cb3cbd 100644 --- a/packages/backend/server/scripts/copilot-cron-test.js +++ b/packages/backend/server/scripts/copilot-cron-test.js @@ -80,20 +80,16 @@ function render(markdown) { return jsxslack([`${rendered}`]); } -async function main() { - const { CHANNEL_ID, SLACK_BOT_TOKEN, AFFINE_ENV } = process.env; +const { CHANNEL_ID, SLACK_BOT_TOKEN, AFFINE_ENV } = process.env; - const report = await runTest(); - const blocks = render( - [`# AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, report].join('\n\n') - ); - const { ok } = await new WebClient(SLACK_BOT_TOKEN).chat.postMessage({ - channel: CHANNEL_ID, - text: `AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, - blocks, - }); - - console.assert(ok, 'Failed to send a message to Slack'); -} +const report = await runTest(); +const blocks = render( + [`# AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, report].join('\n\n') +); +const { ok } = await new WebClient(SLACK_BOT_TOKEN).chat.postMessage({ + channel: CHANNEL_ID, + text: `AFFiNE Copilot Test ${AFFINE_ENV} Env Test Result`, + blocks, +}); -await main(); +console.assert(ok, 'Failed to send a message to Slack'); From 387cc02e3fffbc5f1166c5465f13bec7ad6e4464 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Thu, 2 Jan 2025 23:16:33 +0800 Subject: [PATCH 7/7] fix: ava ts loader --- packages/backend/server/tests/ava.docker.config.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/backend/server/tests/ava.docker.config.js b/packages/backend/server/tests/ava.docker.config.js index 832ff81f3b290..08a05f011401f 100644 --- a/packages/backend/server/tests/ava.docker.config.js +++ b/packages/backend/server/tests/ava.docker.config.js @@ -2,6 +2,12 @@ import packageJson from '../package.json' with { type: 'json' }; export default { ...packageJson.ava, + nodeArguments: [ + '--trace-sigint', + '--loader', + 'ts-node/esm/transpile-only.mjs', + '--es-module-specifier-resolution=node', + ], environmentVariables: { ...packageJson.ava.environmentVariables, TS_NODE_PROJECT: './tests/tsconfig.docker.json',