Merge branch 'master' into budi-7754-make-our-helm-chart-work-out-of-the-box

This commit is contained in:
Sam Rose 2023-12-04 10:49:08 +00:00 committed by GitHub
commit 030cdba5d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 152 additions and 14 deletions

View File

@ -10,6 +10,7 @@ jobs:
steps: steps:
- uses: actions/stale@v8 - uses: actions/stale@v8
with: with:
days-before-stale: 330
operations-per-run: 1 operations-per-run: 1
# stale rules for PRs # stale rules for PRs
days-before-pr-stale: 7 days-before-pr-stale: 7

View File

@ -99,6 +99,8 @@ function updateContext(updates: ContextMap): ContextMap {
} }
async function newContext<T>(updates: ContextMap, task: () => T) { async function newContext<T>(updates: ContextMap, task: () => T) {
guardMigration()
// see if there already is a context setup // see if there already is a context setup
let context: ContextMap = updateContext(updates) let context: ContextMap = updateContext(updates)
return Context.run(context, task) return Context.run(context, task)
@ -145,23 +147,27 @@ export async function doInTenant<T>(
} }
export async function doInAppContext<T>( export async function doInAppContext<T>(
appId: string | null, appId: string,
task: () => T task: () => T
): Promise<T> { ): Promise<T> {
if (!appId && !env.isTest()) { return _doInAppContext(appId, task)
}
async function _doInAppContext<T>(
appId: string,
task: () => T,
extraContextSettings?: ContextMap
): Promise<T> {
if (!appId) {
throw new Error("appId is required") throw new Error("appId is required")
} }
let updates: ContextMap const tenantId = getTenantIDFromAppID(appId)
if (!appId) { const updates: ContextMap = { appId, ...extraContextSettings }
updates = { appId: "" } if (tenantId) {
} else { updates.tenantId = tenantId
const tenantId = getTenantIDFromAppID(appId)
updates = { appId }
if (tenantId) {
updates.tenantId = tenantId
}
} }
return newContext(updates, task) return newContext(updates, task)
} }
@ -182,6 +188,24 @@ export async function doInIdentityContext<T>(
return newContext(context, task) return newContext(context, task)
} }
function guardMigration() {
const context = Context.get()
if (context?.isMigrating) {
throw new Error(
"The context cannot be changed, a migration is currently running"
)
}
}
export async function doInAppMigrationContext<T>(
appId: string,
task: () => T
): Promise<T> {
return _doInAppContext(appId, task, {
isMigrating: true,
})
}
export function getIdentity(): IdentityContext | undefined { export function getIdentity(): IdentityContext | undefined {
try { try {
const context = Context.get() const context = Context.get()

View File

@ -1,6 +1,11 @@
import { testEnv } from "../../../tests/extra" import { testEnv } from "../../../tests/extra"
import * as context from "../" import * as context from "../"
import { DEFAULT_TENANT_ID } from "../../constants" import { DEFAULT_TENANT_ID } from "../../constants"
import { structures } from "../../../tests"
import { db } from "../.."
import Context from "../Context"
import { ContextMap } from "../types"
import { IdentityType } from "@budibase/types"
describe("context", () => { describe("context", () => {
describe("doInTenant", () => { describe("doInTenant", () => {
@ -144,4 +149,107 @@ describe("context", () => {
expect(isScim).toBe(false) expect(isScim).toBe(false)
}) })
}) })
describe("doInAppMigrationContext", () => {
it("the context is set correctly", async () => {
const appId = db.generateAppID()
await context.doInAppMigrationContext(appId, () => {
const context = Context.get()
const expected: ContextMap = {
appId,
isMigrating: true,
}
expect(context).toEqual(expected)
})
})
it("the context is set correctly when running in a tenant id", async () => {
const tenantId = structures.tenant.id()
const appId = db.generateAppID(tenantId)
await context.doInAppMigrationContext(appId, () => {
const context = Context.get()
const expected: ContextMap = {
appId,
isMigrating: true,
tenantId,
}
expect(context).toEqual(expected)
})
})
it("the context is not modified outside the delegate", async () => {
const appId = db.generateAppID()
expect(Context.get()).toBeUndefined()
await context.doInAppMigrationContext(appId, () => {
const context = Context.get()
const expected: ContextMap = {
appId,
isMigrating: true,
}
expect(context).toEqual(expected)
})
expect(Context.get()).toBeUndefined()
})
it.each([
[
"doInAppMigrationContext",
() => context.doInAppMigrationContext(db.generateAppID(), () => {}),
],
[
"doInAppContext",
() => context.doInAppContext(db.generateAppID(), () => {}),
],
[
"doInAutomationContext",
() =>
context.doInAutomationContext({
appId: db.generateAppID(),
automationId: structures.generator.guid(),
task: () => {},
}),
],
["doInContext", () => context.doInContext(db.generateAppID(), () => {})],
[
"doInEnvironmentContext",
() => context.doInEnvironmentContext({}, () => {}),
],
[
"doInIdentityContext",
() =>
context.doInIdentityContext(
{
account: undefined,
type: IdentityType.USER,
_id: structures.users.user()._id!,
},
() => {}
),
],
["doInScimContext", () => context.doInScimContext(() => {})],
[
"doInTenant",
() => context.doInTenant(structures.tenant.id(), () => {}),
],
])(
"a nested context.%s function cannot run",
async (_, otherContextCall: () => Promise<void>) => {
await expect(
context.doInAppMigrationContext(db.generateAppID(), async () => {
await otherContextCall()
})
).rejects.toThrowError(
"The context cannot be changed, a migration is currently running"
)
}
)
})
}) })

View File

@ -8,4 +8,5 @@ export type ContextMap = {
environmentVariables?: Record<string, string> environmentVariables?: Record<string, string>
isScim?: boolean isScim?: boolean
automationId?: string automationId?: string
isMigrating?: boolean
} }

View File

@ -137,6 +137,10 @@ class TestConfiguration {
} }
getAppId() { getAppId() {
if (!this.appId) {
throw "appId has not been initialised properly"
}
return this.appId return this.appId
} }
@ -510,7 +514,7 @@ class TestConfiguration {
// create dev app // create dev app
// clear any old app // clear any old app
this.appId = null this.appId = null
this.app = await context.doInAppContext(null, async () => { this.app = await context.doInTenant(this.tenantId!, async () => {
const app = await this._req( const app = await this._req(
{ name: appName }, { name: appName },
null, null,
@ -519,7 +523,7 @@ class TestConfiguration {
this.appId = app.appId! this.appId = app.appId!
return app return app
}) })
return await context.doInAppContext(this.appId, async () => { return await context.doInAppContext(this.getAppId(), async () => {
// create production app // create production app
this.prodApp = await this.publish() this.prodApp = await this.publish()
@ -817,7 +821,7 @@ class TestConfiguration {
} }
async getAutomationLogs() { async getAutomationLogs() {
return context.doInAppContext(this.appId, async () => { return context.doInAppContext(this.getAppId(), async () => {
const now = new Date() const now = new Date()
return await pro.sdk.automations.logs.logSearch({ return await pro.sdk.automations.logs.logSearch({
startDate: new Date(now.getTime() - 100000).toISOString(), startDate: new Date(now.getTime() - 100000).toISOString(),