diff --git a/.gitignore b/.gitignore index b68ddd975f..32d1416f4a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ bb-airgapped.tar.gz packages/server/build/oldClientVersions/**/* packages/builder/src/components/deploy/clientVersions.json +packages/server/src/integrations/tests/utils/*.lock + # Logs logs *.log diff --git a/packages/backend-core/src/environment.ts b/packages/backend-core/src/environment.ts index 0c7f84220b..e58660a889 100644 --- a/packages/backend-core/src/environment.ts +++ b/packages/backend-core/src/environment.ts @@ -93,15 +93,21 @@ function isApps() { return environment.SERVICE_TYPE === ServiceType.APPS } +function isQA() { + return environment.BUDIBASE_ENVIRONMENT === "QA" +} + const environment = { isTest, isJest, isDev, isWorker, isApps, + isQA, isProd: () => { return !isDev() }, + BUDIBASE_ENVIRONMENT: process.env.BUDIBASE_ENVIRONMENT, JS_BCRYPT: process.env.JS_BCRYPT, JWT_SECRET: process.env.JWT_SECRET, JWT_SECRET_FALLBACK: process.env.JWT_SECRET_FALLBACK, diff --git a/packages/backend-core/src/queue/inMemoryQueue.ts b/packages/backend-core/src/queue/inMemoryQueue.ts index 333accc985..62b971f9f5 100644 --- a/packages/backend-core/src/queue/inMemoryQueue.ts +++ b/packages/backend-core/src/queue/inMemoryQueue.ts @@ -63,12 +63,12 @@ class InMemoryQueue implements Partial { * Same callback API as Bull, each callback passed to this will consume messages as they are * available. Please note this is a queue service, not a notification service, so each * consumer will receive different messages. - * @param func The callback function which will return a "Job", the same * as the Bull API, within this job the property "data" contains the JSON message. Please * note this is incredibly limited compared to Bull as in reality the Job would contain * a lot more information about the queue and current status of Bull cluster. */ - async process(func: any) { + async process(concurrencyOrFunc: number | any, func?: any) { + func = typeof concurrencyOrFunc === "number" ? func : concurrencyOrFunc this._emitter.on("message", async () => { if (this._messages.length <= 0) { return diff --git a/packages/backend-core/src/tenancy/db.ts b/packages/backend-core/src/tenancy/db.ts index 10477a8579..f2e4705fa8 100644 --- a/packages/backend-core/src/tenancy/db.ts +++ b/packages/backend-core/src/tenancy/db.ts @@ -1,6 +1,16 @@ import { getDB } from "../db/db" import { getGlobalDBName } from "../context" +import { TenantInfo } from "@budibase/types" export function getTenantDB(tenantId: string) { return getDB(getGlobalDBName(tenantId)) } + +export async function saveTenantInfo(tenantInfo: TenantInfo) { + const db = getTenantDB(tenantInfo.tenantId) + // save the tenant info to db + return await db.put({ + _id: "tenant_info", + ...tenantInfo, + }) +} diff --git a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte index 71de1716f2..fa6f477ed9 100644 --- a/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte +++ b/packages/builder/src/components/design/settings/controls/DataSourceSelect/DataSourceCategory.svelte @@ -29,7 +29,7 @@ on:click={() => onSelect(data)} > - {data.label} + {data.datasource?.name ? `${data.datasource.name} - ` : ""}{data.label} ds._id === m.sourceId || m.datasourceId + ), })) $: viewsV1 = $viewsStore.list.map(view => ({ ...view, diff --git a/packages/server/specs/openapi.json b/packages/server/specs/openapi.json index 7d07b424f0..b21554505b 100644 --- a/packages/server/specs/openapi.json +++ b/packages/server/specs/openapi.json @@ -860,8 +860,10 @@ "json", "internal", "barcodeqr", + "signature_single", "bigint", - "bb_reference" + "bb_reference", + "bb_reference_single" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1067,8 +1069,10 @@ "json", "internal", "barcodeqr", + "signature_single", "bigint", - "bb_reference" + "bb_reference", + "bb_reference_single" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, @@ -1285,8 +1289,10 @@ "json", "internal", "barcodeqr", + "signature_single", "bigint", - "bb_reference" + "bb_reference", + "bb_reference_single" ], "description": "Defines the type of the column, most explain themselves, a link column is a relationship." }, diff --git a/packages/server/specs/openapi.yaml b/packages/server/specs/openapi.yaml index 3a798c424b..6a2ae89c61 100644 --- a/packages/server/specs/openapi.yaml +++ b/packages/server/specs/openapi.yaml @@ -782,8 +782,10 @@ components: - json - internal - barcodeqr + - signature_single - bigint - bb_reference + - bb_reference_single description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -948,8 +950,10 @@ components: - json - internal - barcodeqr + - signature_single - bigint - bb_reference + - bb_reference_single description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: @@ -1121,8 +1125,10 @@ components: - json - internal - barcodeqr + - signature_single - bigint - bb_reference + - bb_reference_single description: Defines the type of the column, most explain themselves, a link column is a relationship. constraints: diff --git a/packages/server/src/appMigrations/appMigrationMetadata.ts b/packages/server/src/appMigrations/appMigrationMetadata.ts index d87ddff3ef..971dde1e7a 100644 --- a/packages/server/src/appMigrations/appMigrationMetadata.ts +++ b/packages/server/src/appMigrations/appMigrationMetadata.ts @@ -1,4 +1,4 @@ -import { Duration, cache, context, db, env } from "@budibase/backend-core" +import { Duration, cache, db, env } from "@budibase/backend-core" import { Database, DocumentType, Document } from "@budibase/types" export interface AppMigrationDoc extends Document { @@ -25,8 +25,8 @@ export async function getAppMigrationVersion(appId: string): Promise { let metadata: AppMigrationDoc | undefined = await cache.get(cacheKey) - // We don't want to cache in dev, in order to be able to tweak it - if (metadata && !env.isDev()) { + // We don't want to cache in dev or QA in order to be able to tweak it + if (metadata && !env.isDev() && !env.isQA()) { return metadata.version } @@ -42,7 +42,10 @@ export async function getAppMigrationVersion(appId: string): Promise { version = "" } - await cache.store(cacheKey, version, EXPIRY_SECONDS) + // only cache if we have a valid version + if (version) { + await cache.store(cacheKey, version, EXPIRY_SECONDS) + } return version } @@ -54,8 +57,7 @@ export async function updateAppMigrationMetadata({ appId: string version: string }): Promise { - const db = context.getAppDB() - + const appDb = db.getDB(appId) let appMigrationDoc: AppMigrationDoc try { @@ -70,7 +72,7 @@ export async function updateAppMigrationMetadata({ version: "", history: {}, } - await db.put(appMigrationDoc) + await appDb.put(appMigrationDoc) appMigrationDoc = await getFromDB(appId) } @@ -82,7 +84,7 @@ export async function updateAppMigrationMetadata({ [version]: { runAt: new Date().toISOString() }, }, } - await db.put(updatedMigrationDoc) + await appDb.put(updatedMigrationDoc) const cacheKey = getCacheKey(appId) diff --git a/packages/server/src/appMigrations/index.ts b/packages/server/src/appMigrations/index.ts index 0440580d18..de15666215 100644 --- a/packages/server/src/appMigrations/index.ts +++ b/packages/server/src/appMigrations/index.ts @@ -16,7 +16,10 @@ export type AppMigration = { export function getLatestEnabledMigrationId(migrations?: AppMigration[]) { let latestMigrationId: string | undefined - for (let migration of migrations || MIGRATIONS) { + if (!migrations) { + migrations = MIGRATIONS + } + for (let migration of migrations) { // if a migration is disabled, all migrations after it are disabled if (migration.disabled) { break @@ -35,8 +38,14 @@ export async function checkMissingMigrations( next: Next, appId: string ) { - const currentVersion = await getAppMigrationVersion(appId) const latestMigration = getLatestEnabledMigrationId() + + // no migrations set - edge case, don't try to do anything + if (!latestMigration) { + return next() + } + + const currentVersion = await getAppMigrationVersion(appId) const queue = getAppMigrationQueue() if ( diff --git a/packages/server/src/appMigrations/migrationsProcessor.ts b/packages/server/src/appMigrations/migrationsProcessor.ts index 0337fc09f4..1441388564 100644 --- a/packages/server/src/appMigrations/migrationsProcessor.ts +++ b/packages/server/src/appMigrations/migrationsProcessor.ts @@ -13,8 +13,8 @@ export async function processMigrations( ) { console.log(`Processing app migration for "${appId}"`) try { - // have to wrap in context, this gets the tenant from the app ID - await context.doInAppContext(appId, async () => { + // first step - setup full context - tenancy, app and guards + await context.doInAppMigrationContext(appId, async () => { console.log(`Acquiring app migration lock for "${appId}"`) await locks.doWithLock( { @@ -23,48 +23,45 @@ export async function processMigrations( resource: appId, }, async () => { - await context.doInAppMigrationContext(appId, async () => { - console.log(`Lock acquired starting app migration for "${appId}"`) - let currentVersion = await getAppMigrationVersion(appId) + console.log(`Lock acquired starting app migration for "${appId}"`) + let currentVersion = await getAppMigrationVersion(appId) - const pendingMigrations = migrations - .filter(m => m.id > currentVersion) - .sort((a, b) => a.id.localeCompare(b.id)) + const pendingMigrations = migrations + .filter(m => m.id > currentVersion) + .sort((a, b) => a.id.localeCompare(b.id)) - const migrationIds = migrations.map(m => m.id).sort() - console.log( - `App migrations to run for "${appId}" - ${migrationIds.join(",")}` - ) + const migrationIds = migrations.map(m => m.id).sort() + console.log( + `App migrations to run for "${appId}" - ${migrationIds.join(",")}` + ) - let index = 0 - for (const { id, func } of pendingMigrations) { - const expectedMigration = - migrationIds[migrationIds.indexOf(currentVersion) + 1] + let index = 0 + for (const { id, func } of pendingMigrations) { + const expectedMigration = + migrationIds[migrationIds.indexOf(currentVersion) + 1] - if (expectedMigration !== id) { - throw new Error( - `Migration ${id} could not run, update for "${id}" is running but ${expectedMigration} is expected` - ) - } - - const counter = `(${++index}/${pendingMigrations.length})` - console.info(`Running migration ${id}... ${counter}`, { - migrationId: id, - appId, - }) - await func() - await updateAppMigrationMetadata({ - appId, - version: id, - }) - currentVersion = id + if (expectedMigration !== id) { + throw new Error( + `Migration ${id} could not run, update for "${id}" is running but ${expectedMigration} is expected` + ) } - }) + + const counter = `(${++index}/${pendingMigrations.length})` + console.info(`Running migration ${id}... ${counter}`, { + migrationId: id, + appId, + }) + await func() + await updateAppMigrationMetadata({ + appId, + version: id, + }) + currentVersion = id + } } ) - - console.log(`App migration for "${appId}" processed`) }) + console.log(`App migration for "${appId}" processed`) } catch (err) { logging.logAlert("Failed to run app migration", err) throw err diff --git a/packages/server/src/appMigrations/queue.ts b/packages/server/src/appMigrations/queue.ts index 5c932bcb7f..e2bc4406f1 100644 --- a/packages/server/src/appMigrations/queue.ts +++ b/packages/server/src/appMigrations/queue.ts @@ -2,9 +2,10 @@ import { queue, logging } from "@budibase/backend-core" import { Job } from "bull" import { MIGRATIONS } from "./migrations" import { processMigrations } from "./migrationsProcessor" -import { apiEnabled } from "../features" -const MAX_ATTEMPTS = 1 +const MAX_ATTEMPTS = 3 +// max number of migrations to run at same time, per node +const MIGRATION_CONCURRENCY = 5 export type AppMigrationJob = { appId: string @@ -13,10 +14,6 @@ export type AppMigrationJob = { let appMigrationQueue: queue.Queue | undefined export function init() { - // only run app migrations in main API services - if (!apiEnabled()) { - return - } appMigrationQueue = queue.createQueue( queue.JobQueue.APP_MIGRATION, { @@ -34,10 +31,10 @@ export function init() { } ) - return appMigrationQueue.process(processMessage) + return appMigrationQueue.process(MIGRATION_CONCURRENCY, processMessage) } -async function processMessage(job: Job) { +async function processMessage(job: Job) { const { appId } = job.data await processMigrations(appId, MIGRATIONS) diff --git a/packages/server/src/integrations/tests/utils/index.ts b/packages/server/src/integrations/tests/utils/index.ts index a54d0ac1a7..64617461bb 100644 --- a/packages/server/src/integrations/tests/utils/index.ts +++ b/packages/server/src/integrations/tests/utils/index.ts @@ -4,8 +4,9 @@ import * as mongodb from "./mongodb" import * as mysql from "./mysql" import * as mssql from "./mssql" import * as mariadb from "./mariadb" -import { GenericContainer } from "testcontainers" +import { GenericContainer, StartedTestContainer } from "testcontainers" import { testContainerUtils } from "@budibase/backend-core/tests" +import cloneDeep from "lodash/cloneDeep" export type DatasourceProvider = () => Promise @@ -65,9 +66,39 @@ export async function rawQuery(ds: Datasource, sql: string): Promise { } export async function startContainer(container: GenericContainer) { - container = container.withReuse().withLabels({ "com.budibase": "true" }) + const imageName = (container as any).imageName.string as string + const key = imageName.replaceAll("/", "-").replaceAll(":", "-") - const startedContainer = await container.start() + container = container + .withReuse() + .withLabels({ "com.budibase": "true" }) + .withName(key) + + let startedContainer: StartedTestContainer | undefined = undefined + let lastError = undefined + for (let i = 0; i < 10; i++) { + try { + // container.start() is not an idempotent operation, calling `start` + // modifies the internal state of a GenericContainer instance such that + // the hash it uses to determine reuse changes. We need to clone the + // container before calling start to ensure that we're using the same + // reuse hash every time. + const containerCopy = cloneDeep(container) + startedContainer = await containerCopy.start() + lastError = undefined + break + } catch (e: any) { + lastError = e + await new Promise(resolve => setTimeout(resolve, 1000)) + } + } + + if (!startedContainer) { + if (lastError) { + throw lastError + } + throw new Error(`failed to start container: ${imageName}`) + } const info = testContainerUtils.getContainerById(startedContainer.getId()) if (!info) { diff --git a/packages/server/src/integrations/tests/utils/mssql.ts b/packages/server/src/integrations/tests/utils/mssql.ts index 647f461272..57c5fe8049 100644 --- a/packages/server/src/integrations/tests/utils/mssql.ts +++ b/packages/server/src/integrations/tests/utils/mssql.ts @@ -29,6 +29,9 @@ export async function getDatasource(): Promise { } const port = (await ports).find(x => x.container === 1433)?.host + if (!port) { + throw new Error("SQL Server port not found") + } const datasource: Datasource = { type: "datasource_plus", diff --git a/packages/server/src/integrations/tests/utils/mysql.ts b/packages/server/src/integrations/tests/utils/mysql.ts index a78833e1de..560d6bb2d4 100644 --- a/packages/server/src/integrations/tests/utils/mysql.ts +++ b/packages/server/src/integrations/tests/utils/mysql.ts @@ -38,6 +38,9 @@ export async function getDatasource(): Promise { } const port = (await ports).find(x => x.container === 3306)?.host + if (!port) { + throw new Error("MySQL port not found") + } const datasource: Datasource = { type: "datasource_plus", diff --git a/packages/server/src/integrations/tests/utils/postgres.ts b/packages/server/src/integrations/tests/utils/postgres.ts index 4191b107e9..8c0cd886e8 100644 --- a/packages/server/src/integrations/tests/utils/postgres.ts +++ b/packages/server/src/integrations/tests/utils/postgres.ts @@ -21,6 +21,9 @@ export async function getDatasource(): Promise { } const port = (await ports).find(x => x.container === 5432)?.host + if (!port) { + throw new Error("Postgres port not found") + } const datasource: Datasource = { type: "datasource_plus", diff --git a/packages/server/src/startup/index.ts b/packages/server/src/startup/index.ts index 750acdb0aa..0e08075698 100644 --- a/packages/server/src/startup/index.ts +++ b/packages/server/src/startup/index.ts @@ -20,7 +20,7 @@ import * as pro from "@budibase/pro" import * as api from "../api" import sdk from "../sdk" import { initialise as initialiseWebsockets } from "../websockets" -import { automationsEnabled, printFeatures } from "../features" +import { apiEnabled, automationsEnabled, printFeatures } from "../features" import * as jsRunner from "../jsRunner" import Koa from "koa" import { Server } from "http" @@ -70,6 +70,9 @@ export async function startup( return } printFeatures() + if (env.BUDIBASE_ENVIRONMENT) { + console.log(`service running environment: "${env.BUDIBASE_ENVIRONMENT}"`) + } STARTUP_RAN = true if (app && server && !env.CLUSTER_MODE) { console.log(`Budibase running on ${JSON.stringify(server.address())}`) @@ -115,10 +118,13 @@ export async function startup( // configure events to use the pro audit log write // can't integrate directly into backend-core due to cyclic issues queuePromises.push(events.processors.init(pro.sdk.auditLogs.write)) - queuePromises.push(appMigrations.init()) + // app migrations and automations on other service if (automationsEnabled()) { queuePromises.push(automations.init()) } + if (apiEnabled()) { + queuePromises.push(appMigrations.init()) + } queuePromises.push(initPro()) if (app) { // bring routes online as final step once everything ready diff --git a/packages/types/src/documents/global/index.ts b/packages/types/src/documents/global/index.ts index b728439dd6..6784f2638c 100644 --- a/packages/types/src/documents/global/index.ts +++ b/packages/types/src/documents/global/index.ts @@ -7,3 +7,4 @@ export * from "./schedule" export * from "./templates" export * from "./environmentVariables" export * from "./auditLogs" +export * from "./tenantInfo" diff --git a/packages/types/src/documents/global/tenantInfo.ts b/packages/types/src/documents/global/tenantInfo.ts new file mode 100644 index 0000000000..2fa8f4ad96 --- /dev/null +++ b/packages/types/src/documents/global/tenantInfo.ts @@ -0,0 +1,13 @@ +import { Document } from "../document" + +export interface TenantInfo extends Document { + owner: { + email: string + password?: string + ssoId?: string + givenName?: string + familyName?: string + budibaseUserId?: string + } + tenantId: string +} diff --git a/packages/worker/src/api/controllers/global/tenant.ts b/packages/worker/src/api/controllers/global/tenant.ts new file mode 100644 index 0000000000..1e86fb8246 --- /dev/null +++ b/packages/worker/src/api/controllers/global/tenant.ts @@ -0,0 +1,10 @@ +import { tenancy } from "@budibase/backend-core" +import { TenantInfo, Ctx } from "@budibase/types" + +export const save = async (ctx: Ctx) => { + const response = await tenancy.saveTenantInfo(ctx.request.body) + ctx.body = { + _id: response.id, + _rev: response.rev, + } +} diff --git a/packages/worker/src/api/index.ts b/packages/worker/src/api/index.ts index 82495df4ee..feec8b4de1 100644 --- a/packages/worker/src/api/index.ts +++ b/packages/worker/src/api/index.ts @@ -76,6 +76,10 @@ const PUBLIC_ENDPOINTS = [ route: "/api/global/users/invite", method: "GET", }, + { + route: "/api/global/tenant", + method: "POST", + }, ] const NO_TENANCY_ENDPOINTS = [ @@ -121,6 +125,10 @@ const NO_TENANCY_ENDPOINTS = [ route: "/api/global/users/invite/:code", method: "GET", }, + { + route: "/api/global/tenant", + method: "POST", + }, ] // most public endpoints are gets, but some are posts diff --git a/packages/worker/src/api/routes/global/tenant.ts b/packages/worker/src/api/routes/global/tenant.ts new file mode 100644 index 0000000000..7179532cde --- /dev/null +++ b/packages/worker/src/api/routes/global/tenant.ts @@ -0,0 +1,33 @@ +import Router from "@koa/router" +import Joi from "joi" +import { auth } from "@budibase/backend-core" +import * as controller from "../../controllers/global/tenant" +import cloudRestricted from "../../../middleware/cloudRestricted" + +const router: Router = new Router() +const OPTIONAL_STRING = Joi.string().optional().allow(null).allow("") + +function buildTenantInfoValidation() { + return auth.joiValidator.body( + Joi.object({ + owner: Joi.object({ + email: Joi.string().required(), + password: OPTIONAL_STRING, + ssoId: OPTIONAL_STRING, + givenName: OPTIONAL_STRING, + familyName: OPTIONAL_STRING, + budibaseUserId: OPTIONAL_STRING, + }).required(), + tenantId: Joi.string().required(), + }).required() + ) +} + +router.post( + "/api/global/tenant", + cloudRestricted, + buildTenantInfoValidation(), + controller.save +) + +export default router diff --git a/packages/worker/src/api/routes/global/tests/tenant.spec.ts b/packages/worker/src/api/routes/global/tests/tenant.spec.ts new file mode 100644 index 0000000000..36036eceee --- /dev/null +++ b/packages/worker/src/api/routes/global/tests/tenant.spec.ts @@ -0,0 +1,47 @@ +import { TenantInfo } from "@budibase/types" +import { TestConfiguration } from "../../../../tests" +import { tenancy as _tenancy } from "@budibase/backend-core" + +const tenancy = jest.mocked(_tenancy) + +describe("/api/global/tenant", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + describe("POST /api/global/tenant", () => { + it("should save the tenantInfo", async () => { + tenancy.saveTenantInfo = jest.fn().mockImplementation(async () => ({ + id: "DOC_ID", + ok: true, + rev: "DOC_REV", + })) + const tenantInfo: TenantInfo = { + owner: { + email: "test@example.com", + password: "PASSWORD", + ssoId: "SSO_ID", + givenName: "Jane", + familyName: "Doe", + budibaseUserId: "USER_ID", + }, + tenantId: "tenant123", + } + const response = await config.api.tenants.saveTenantInfo(tenantInfo) + + expect(_tenancy.saveTenantInfo).toHaveBeenCalledTimes(1) + expect(_tenancy.saveTenantInfo).toHaveBeenCalledWith(tenantInfo) + expect(response.text).toEqual('{"_id":"DOC_ID","_rev":"DOC_REV"}') + }) + }) +}) diff --git a/packages/worker/src/api/routes/index.ts b/packages/worker/src/api/routes/index.ts index e6cacf110f..2eb4b5cd5d 100644 --- a/packages/worker/src/api/routes/index.ts +++ b/packages/worker/src/api/routes/index.ts @@ -1,6 +1,7 @@ import Router from "@koa/router" import { api as pro } from "@budibase/pro" import userRoutes from "./global/users" +import tenantRoutes from "./global/tenant" import configRoutes from "./global/configs" import workspaceRoutes from "./global/workspaces" import templateRoutes from "./global/templates" @@ -40,6 +41,7 @@ export const routes: Router[] = [ accountRoutes, restoreRoutes, eventRoutes, + tenantRoutes, pro.scim, ] diff --git a/packages/worker/src/environment.ts b/packages/worker/src/environment.ts index f6b3701be1..d642d50846 100644 --- a/packages/worker/src/environment.ts +++ b/packages/worker/src/environment.ts @@ -47,6 +47,7 @@ const environment = { SMTP_FALLBACK_ENABLED: process.env.SMTP_FALLBACK_ENABLED, DISABLE_DEVELOPER_LICENSE: process.env.DISABLE_DEVELOPER_LICENSE, SQS_SEARCH_ENABLE: process.env.SQS_SEARCH_ENABLE, + BUDIBASE_ENVIRONMENT: process.env.BUDIBASE_ENVIRONMENT, // smtp SMTP_USER: process.env.SMTP_USER, SMTP_PASSWORD: process.env.SMTP_PASSWORD, diff --git a/packages/worker/src/index.ts b/packages/worker/src/index.ts index 4e770c6ecb..85e5d6ad2e 100644 --- a/packages/worker/src/index.ts +++ b/packages/worker/src/index.ts @@ -88,7 +88,11 @@ const shutdown = () => { } export default server.listen(parseInt(env.PORT || "4002"), async () => { - console.log(`Worker running on ${JSON.stringify(server.address())}`) + let startupLog = `Worker running on ${JSON.stringify(server.address())}` + if (env.BUDIBASE_ENVIRONMENT) { + startupLog = `${startupLog} - environment: "${env.BUDIBASE_ENVIRONMENT}"` + } + console.log(startupLog) await initPro() await redis.clients.init() cache.docWritethrough.init() diff --git a/packages/worker/src/tests/api/tenants.ts b/packages/worker/src/tests/api/tenants.ts index 16f970915a..c404b8ad58 100644 --- a/packages/worker/src/tests/api/tenants.ts +++ b/packages/worker/src/tests/api/tenants.ts @@ -1,3 +1,4 @@ +import { TenantInfo } from "@budibase/types" import TestConfiguration from "../TestConfiguration" import { TestAPI, TestAPIOpts } from "./base" @@ -14,4 +15,12 @@ export class TenantAPI extends TestAPI { .set(opts?.headers) .expect(opts?.status ? opts.status : 204) } + + saveTenantInfo = (tenantInfo: TenantInfo) => { + return this.request + .post("/api/global/tenant") + .set(this.config.internalAPIHeaders()) + .send(tenantInfo) + .expect(200) + } } diff --git a/yarn.lock b/yarn.lock index 5297fe0cad..e0e1229fbf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3483,10 +3483,10 @@ dependencies: lodash "^4.17.21" -"@koa/cors@^3.1.0": - version "3.4.3" - resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.4.3.tgz#d669ee6e8d6e4f0ec4a7a7b0a17e7a3ed3752ebb" - integrity sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw== +"@koa/cors@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-5.0.0.tgz#0029b5f057fa0d0ae0e37dd2c89ece315a0daffd" + integrity sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw== dependencies: vary "^1.1.2" @@ -5797,10 +5797,10 @@ "@types/koa-compose" "*" "@types/node" "*" -"@types/koa__cors@^3.1.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.3.1.tgz#0ec7543c4c620fd23451bfdd3e21b9a6aadedccd" - integrity sha512-aFGYhTFW7651KhmZZ05VG0QZJre7QxBxDj2LF1lf6GA/wSXEfKVAJxiQQWzRV4ZoMzQIO8vJBXKsUcRuvYK9qw== +"@types/koa__cors@^5.0.0": + version "5.0.0" + resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-5.0.0.tgz#74567a045b599266e2cd3940cef96cedecc2ef1f" + integrity sha512-LCk/n25Obq5qlernGOK/2LUwa/2YJb2lxHUkkvYFDOpLXlVI6tKcdfCHRBQnOY4LwH6el5WOLs6PD/a8Uzau6g== dependencies: "@types/koa" "*" @@ -16299,10 +16299,10 @@ node-source-walk@^5.0.0: dependencies: "@babel/parser" "^7.0.0" -nodemailer@6.7.2: - version "6.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" - integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== +nodemailer@6.9.13: + version "6.9.13" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6" + integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA== nodemailer@6.9.9: version "6.9.9"