diff --git a/.github/workflows/budibase_ci.yml b/.github/workflows/budibase_ci.yml index b644a6bdb9..9509a22e99 100644 --- a/.github/workflows/budibase_ci.yml +++ b/.github/workflows/budibase_ci.yml @@ -159,7 +159,7 @@ jobs: run: | cd qa-core yarn setup - yarn test:ci + yarn serve:test:self:ci env: BB_ADMIN_USER_EMAIL: admin BB_ADMIN_USER_PASSWORD: admin diff --git a/.github/workflows/release-develop.yml b/.github/workflows/release-develop.yml index a7bf041eb5..61cb283e28 100644 --- a/.github/workflows/release-develop.yml +++ b/.github/workflows/release-develop.yml @@ -6,7 +6,7 @@ concurrency: on: push: tags: - - v*-alpha.* + - "*-alpha.*" workflow_dispatch: env: diff --git a/.github/workflows/release-master.yml b/.github/workflows/release-master.yml index 9a86f50c04..7f8b8f1d55 100644 --- a/.github/workflows/release-master.yml +++ b/.github/workflows/release-master.yml @@ -6,9 +6,9 @@ concurrency: on: push: tags: - - "v[0-9]+.[0-9]+.[0-9]+" + - "[0-9]+.[0-9]+.[0-9]+" # Exclude all pre-releases - - "!v*[0-9]+.[0-9]+.[0-9]+-*" + - "!*[0-9]+.[0-9]+.[0-9]+-*" env: # Posthog token used by ui at build time @@ -98,7 +98,7 @@ jobs: git fetch mkdir sync echo "Packaging chart to sync dir" - helm package charts/budibase --version 0.0.0-master --app-version v"$RELEASE_VERSION" --destination sync + helm package charts/budibase --version 0.0.0-master --app-version "$RELEASE_VERSION" --destination sync echo "Packaging successful" git checkout gh-pages echo "Indexing helm repo" diff --git a/.github/workflows/release-selfhost.yml b/.github/workflows/release-selfhost.yml index f4524e99dc..39ee812726 100644 --- a/.github/workflows/release-selfhost.yml +++ b/.github/workflows/release-selfhost.yml @@ -43,7 +43,7 @@ jobs: run: | docker login -u $DOCKER_USER -p $DOCKER_PASSWORD - release_tag=v${{ env.RELEASE_VERSION }} + release_tag=${{ env.RELEASE_VERSION }} # Pull apps and worker images docker pull budibase/apps:$release_tag @@ -108,8 +108,8 @@ jobs: - name: Perform Github Release uses: softprops/action-gh-release@v1 with: - name: v${{ env.RELEASE_VERSION }} - tag_name: v${{ env.RELEASE_VERSION }} + name: ${{ env.RELEASE_VERSION }} + tag_name: ${{ env.RELEASE_VERSION }} generate_release_notes: true files: | packages/cli/build/cli-win.exe diff --git a/.github/workflows/release-singleimage.yml b/.github/workflows/release-singleimage.yml index 5408b48ef8..92f21bd649 100644 --- a/.github/workflows/release-singleimage.yml +++ b/.github/workflows/release-singleimage.yml @@ -71,7 +71,7 @@ jobs: context: . push: true platforms: linux/amd64,linux/arm64 - tags: budibase/budibase,budibase/budibase:v${{ env.RELEASE_VERSION }} + tags: budibase/budibase,budibase/budibase:${{ env.RELEASE_VERSION }} file: ./hosting/single/Dockerfile - name: Tag and release Budibase Azure App Service docker image uses: docker/build-push-action@v2 @@ -80,5 +80,5 @@ jobs: push: true platforms: linux/amd64 build-args: TARGETBUILD=aas - tags: budibase/budibase-aas,budibase/budibase-aas:v${{ env.RELEASE_VERSION }} + tags: budibase/budibase-aas,budibase/budibase-aas:${{ env.RELEASE_VERSION }} file: ./hosting/single/Dockerfile diff --git a/charts/budibase/values.yaml b/charts/budibase/values.yaml index 2d89e81b7f..74e4c52654 100644 --- a/charts/budibase/values.yaml +++ b/charts/budibase/values.yaml @@ -209,7 +209,7 @@ services: # Override values in couchDB subchart couchdb: ## clusterSize is the initial size of the CouchDB cluster. - clusterSize: 3 + clusterSize: 1 allowAdminParty: false # Secret Management diff --git a/lerna.json b/lerna.json index a2456706d1..f9c639e296 100644 --- a/lerna.json +++ b/lerna.json @@ -1,5 +1,5 @@ { - "version": "2.8.12-alpha.5", + "version": "2.8.16-alpha.4", "npmClient": "yarn", "packages": [ "packages/*" diff --git a/packages/backend-core/src/constants/misc.ts b/packages/backend-core/src/constants/misc.ts index ba2533cf4a..0c68798164 100644 --- a/packages/backend-core/src/constants/misc.ts +++ b/packages/backend-core/src/constants/misc.ts @@ -20,6 +20,8 @@ export enum Header { TYPE = "x-budibase-type", PREVIEW_ROLE = "x-budibase-role", TENANT_ID = "x-budibase-tenant-id", + VERIFICATION_CODE = "x-budibase-verification-code", + RETURN_VERIFICATION_CODE = "x-budibase-return-verification-code", TOKEN = "x-budibase-token", CSRF_TOKEN = "x-csrf-token", CORRELATION_ID = "x-budibase-correlation-id", diff --git a/packages/backend-core/src/logging/index.ts b/packages/backend-core/src/logging/index.ts index f7e1c4fa41..0824fa681b 100644 --- a/packages/backend-core/src/logging/index.ts +++ b/packages/backend-core/src/logging/index.ts @@ -2,6 +2,3 @@ export * as correlation from "./correlation/correlation" export { logger } from "./pino/logger" export * from "./alerts" export * as system from "./system" - -// turn off or on context logging i.e. tenantId, appId etc -export let LOG_CONTEXT = true diff --git a/packages/backend-core/src/logging/pino/logger.ts b/packages/backend-core/src/logging/pino/logger.ts index 0b130068f3..f2024db72b 100644 --- a/packages/backend-core/src/logging/pino/logger.ts +++ b/packages/backend-core/src/logging/pino/logger.ts @@ -2,11 +2,9 @@ import pino, { LoggerOptions } from "pino" import pinoPretty from "pino-pretty" import { IdentityType } from "@budibase/types" - import env from "../../environment" import * as context from "../../context" import * as correlation from "../correlation" -import { LOG_CONTEXT } from "../index" import { localFileDestination } from "../system" @@ -93,15 +91,13 @@ if (!env.DISABLE_PINO_LOGGER) { let contextObject = {} - if (LOG_CONTEXT) { - contextObject = { - tenantId: getTenantId(), - appId: getAppId(), - automationId: getAutomationId(), - identityId: identity?._id, - identityType: identity?.type, - correlationId: correlation.getId(), - } + contextObject = { + tenantId: getTenantId(), + appId: getAppId(), + automationId: getAutomationId(), + identityId: identity?._id, + identityType: identity?.type, + correlationId: correlation.getId(), } const mergingObject: any = { diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte index 823dcc432b..cece075860 100644 --- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte +++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte @@ -15,6 +15,7 @@ Icon, Checkbox, DatePicker, + Detail, } from "@budibase/bbui" import CreateWebhookModal from "components/automation/Shared/CreateWebhookModal.svelte" import { automationStore, selectedAutomation } from "builderStore" @@ -32,7 +33,7 @@ import CodeEditor from "components/common/CodeEditor/CodeEditor.svelte" import { bindingsToCompletions, - jsAutocomplete, + hbAutocomplete, EditorModes, } from "components/common/CodeEditor" import FilterDrawer from "components/design/settings/controls/FilterEditor/FilterDrawer.svelte" @@ -55,6 +56,7 @@ let drawer let fillWidth = true let inputData + let codeBindingOpen = false $: filters = lookForFilters(schemaProperties) || [] $: tempFilters = filters @@ -70,6 +72,13 @@ $: queryLimit = tableId?.includes("datasource") ? "∞" : "1000" $: isTrigger = block?.type === "TRIGGER" $: isUpdateRow = stepId === ActionStepID.UPDATE_ROW + $: codeMode = + stepId === "EXECUTE_BASH" ? EditorModes.Handlebars : EditorModes.JS + + $: stepCompletions = + codeMode === EditorModes.Handlebars + ? [hbAutocomplete([...bindingsToCompletions(bindings, codeMode)])] + : [] /** * TODO - Remove after November 2023 @@ -489,6 +498,18 @@ /> {:else if value.customType === "code"} + {#if codeMode == EditorModes.JS} + (codeBindingOpen = !codeBindingOpen)} + quiet + icon={codeBindingOpen ? "ChevronDown" : "ChevronRight"} + > + Bindings + + {#if codeBindingOpen} +
{JSON.stringify(bindings, null, 2)}
+ {/if} + {/if} { @@ -496,19 +517,22 @@ onChange({ detail: e.detail }, key) inputData[key] = e.detail }} - completions={[ - jsAutocomplete([ - ...bindingsToCompletions(bindings, EditorModes.JS), - ]), - ]} - mode={EditorModes.JS} + completions={stepCompletions} + mode={codeMode} + autocompleteEnabled={codeMode != EditorModes.JS} height={500} />
- -
-
Add available bindings by typing $
-
+ {#if codeMode == EditorModes.Handlebars} + +
+
+ Add available bindings by typing + }} + +
+
+ {/if}
{:else if value.customType === "loopOption"} diff --git a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte index e68d3fd842..74f160710f 100644 --- a/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte +++ b/packages/builder/src/components/common/CodeEditor/CodeEditor.svelte @@ -51,6 +51,7 @@ export let mode = EditorModes.Handlebars export let value = "" export let placeholder = null + export let autocompleteEnabled = true // Export a function to expose caret position export const getCaretPosition = () => { @@ -150,12 +151,6 @@ syntaxHighlighting(oneDarkHighlightStyle, { fallback: true }), highlightActiveLineGutter(), highlightSpecialChars(), - autocompletion({ - override: [...completions], - closeOnBlur: true, - icons: false, - optionClass: () => "autocomplete-option", - }), EditorView.lineWrapping, EditorView.updateListener.of(v => { const docStr = v.state.doc?.toString() @@ -178,11 +173,16 @@ const buildExtensions = base => { const complete = [...base] - if (mode.name == "javascript") { - complete.push(javascript()) - complete.push(highlightWhitespace()) - complete.push(lineNumbers()) - complete.push(foldGutter()) + + if (autocompleteEnabled) { + complete.push( + autocompletion({ + override: [...completions], + closeOnBlur: true, + icons: false, + optionClass: () => "autocomplete-option", + }) + ) complete.push( EditorView.inputHandler.of((view, from, to, insert) => { if (insert === "$") { @@ -212,6 +212,13 @@ ) } + if (mode.name == "javascript") { + complete.push(javascript()) + complete.push(highlightWhitespace()) + complete.push(lineNumbers()) + complete.push(foldGutter()) + } + if (placeholder) { complete.push(placeholderFn(placeholder)) } diff --git a/packages/builder/src/components/portal/onboarding/TourPopover.svelte b/packages/builder/src/components/portal/onboarding/TourPopover.svelte index d4958b386e..d959a6ef95 100644 --- a/packages/builder/src/components/portal/onboarding/TourPopover.svelte +++ b/packages/builder/src/components/portal/onboarding/TourPopover.svelte @@ -1,5 +1,5 @@ diff --git a/packages/client/src/components/app/blocks/CardsBlock.svelte b/packages/client/src/components/app/blocks/CardsBlock.svelte index bbe54867ee..3e48247f92 100644 --- a/packages/client/src/components/app/blocks/CardsBlock.svelte +++ b/packages/client/src/components/app/blocks/CardsBlock.svelte @@ -126,7 +126,7 @@ order={1} > {#if enrichedSearchColumns?.length} - {#each enrichedSearchColumns as column, idx} + {#each enrichedSearchColumns as column, idx (column.name)} {#if enrichedSearchColumns?.length} - {#each enrichedSearchColumns as column, idx} + {#each enrichedSearchColumns as column, idx (column.name)} { actions.slice(i + 1), newContext ) - resolve(await next()) + resolve(typeof next === "function" ? await next() : true) } else { resolve(false) } diff --git a/packages/pro b/packages/pro index 9c564edb37..4d9840700e 160000 --- a/packages/pro +++ b/packages/pro @@ -1 +1 @@ -Subproject commit 9c564edb37cb619cb5971e10c4317fa6e7c5bb00 +Subproject commit 4d9840700e7684581c39965b7cb6a2b2428c477c diff --git a/packages/server/src/api/controllers/query/index.ts b/packages/server/src/api/controllers/query/index.ts index 4c1cad6b5b..11ad25f037 100644 --- a/packages/server/src/api/controllers/query/index.ts +++ b/packages/server/src/api/controllers/query/index.ts @@ -157,7 +157,7 @@ export async function preview(ctx: any) { } const runFn = () => Runner.run(inputs) - const { rows, keys, info, extra } = await quotas.addQuery(runFn, { + const { rows, keys, info, extra } = await quotas.addQuery(runFn, { datasourceId: datasource._id, }) const schemaFields: any = {} @@ -246,9 +246,12 @@ async function execute( } const runFn = () => Runner.run(inputs) - const { rows, pagination, extra, info } = await quotas.addQuery(runFn, { - datasourceId: datasource._id, - }) + const { rows, pagination, extra, info } = await quotas.addQuery( + runFn, + { + datasourceId: datasource._id, + } + ) // remove the raw from execution incase transformer being used to hide data if (extra?.raw) { delete extra.raw diff --git a/packages/server/src/api/controllers/row/index.ts b/packages/server/src/api/controllers/row/index.ts index 21b2792139..a1f5664754 100644 --- a/packages/server/src/api/controllers/row/index.ts +++ b/packages/server/src/api/controllers/row/index.ts @@ -27,7 +27,7 @@ export async function patch(ctx: any): Promise { return save(ctx) } try { - const { row, table } = await quotas.addQuery( + const { row, table } = await quotas.addQuery( () => pickApi(tableId).patch(ctx), { datasourceId: tableId, @@ -121,7 +121,7 @@ export async function destroy(ctx: any) { ctx.request.body.rows = rowDeletes } - let { rows } = await quotas.addQuery( + let { rows } = await quotas.addQuery( () => pickApi(tableId).bulkDestroy(ctx), { datasourceId: tableId, @@ -134,7 +134,7 @@ export async function destroy(ctx: any) { gridSocket?.emitRowDeletion(ctx, row._id) } } else { - let resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), { + let resp = await quotas.addQuery(() => pickApi(tableId).destroy(ctx), { datasourceId: tableId, }) await quotas.removeRow() diff --git a/packages/types/src/api/account/accounts.ts b/packages/types/src/api/account/accounts.ts index 9191babc86..bb3419c5d1 100644 --- a/packages/types/src/api/account/accounts.ts +++ b/packages/types/src/api/account/accounts.ts @@ -1,3 +1,4 @@ +import { Account } from "../../documents" import { Hosting } from "../../sdk" export interface CreateAccountRequest { @@ -11,3 +12,11 @@ export interface CreateAccountRequest { name?: string password: string } + +export interface SearchAccountsRequest { + // one or the other - not both + email?: string + tenantId?: string +} + +export type SearchAccountsResponse = Account[] diff --git a/qa-core/jest.config.ts b/qa-core/jest.config.ts index de63f9074b..eb942eca97 100644 --- a/qa-core/jest.config.ts +++ b/qa-core/jest.config.ts @@ -5,6 +5,9 @@ const config: Config.InitialOptions = { setupFiles: ["./src/jest/jestSetup.ts"], setupFilesAfterEnv: ["./src/jest/jest.extends.ts"], testEnvironment: "node", + transform: { + "^.+\\.ts?$": "@swc/jest", + }, globalSetup: "./src/jest/globalSetup.ts", globalTeardown: "./src/jest/globalTeardown.ts", moduleNameMapper: { diff --git a/qa-core/package.json b/qa-core/package.json index 13f2e80332..710e0b6a3b 100644 --- a/qa-core/package.json +++ b/qa-core/package.json @@ -15,8 +15,10 @@ "test:watch": "yarn run test --watch", "test:debug": "DEBUG=1 yarn run test", "test:notify": "node scripts/testResultsWebhook", - "test:smoke": "yarn run test --testPathIgnorePatterns=/.+\\.integration\\.spec\\.ts", - "test:ci": "start-server-and-test dev:built http://localhost:4001/health test:smoke", + "test:cloud:prod": "yarn run test --testPathIgnorePatterns=\\.integration\\.", + "test:cloud:qa": "yarn run test", + "test:self:ci": "yarn run test --testPathIgnorePatterns=\\.integration\\. \\.cloud\\.", + "serve:test:self:ci": "start-server-and-test dev:built http://localhost:4001/health test:self:ci", "serve": "start-server-and-test dev:built http://localhost:4001/health", "dev:built": "cd ../ && yarn dev:built" }, @@ -30,6 +32,8 @@ "jest": "29.0.0", "prettier": "2.7.1", "start-server-and-test": "1.14.0", + "@swc/core": "^1.3.25", + "@swc/jest": "^0.2.24", "timekeeper": "2.2.0", "ts-jest": "29.0.0", "ts-node": "10.8.1", diff --git a/qa-core/scripts/createEnv.js b/qa-core/scripts/createEnv.js index e5ab783735..64b9664049 100644 --- a/qa-core/scripts/createEnv.js +++ b/qa-core/scripts/createEnv.js @@ -12,6 +12,8 @@ function init() { BB_ADMIN_USER_EMAIL: "admin", BB_ADMIN_USER_PASSWORD: "admin", LOG_LEVEL: "info", + JEST_TIMEOUT: "60000", + DISABLE_PINO_LOGGER: "1", } let envFile = "" Object.keys(envFileJson).forEach(key => { diff --git a/qa-core/src/account-api/api/AccountInternalAPI.ts b/qa-core/src/account-api/api/AccountInternalAPI.ts index a5abdcbccd..3813ad2c9e 100644 --- a/qa-core/src/account-api/api/AccountInternalAPI.ts +++ b/qa-core/src/account-api/api/AccountInternalAPI.ts @@ -1,15 +1,17 @@ import AccountInternalAPIClient from "./AccountInternalAPIClient" -import { AccountAPI, LicenseAPI } from "./apis" +import { AccountAPI, LicenseAPI, AuthAPI } from "./apis" import { State } from "../../types" export default class AccountInternalAPI { client: AccountInternalAPIClient + auth: AuthAPI accounts: AccountAPI licenses: LicenseAPI constructor(state: State) { this.client = new AccountInternalAPIClient(state) + this.auth = new AuthAPI(this.client) this.accounts = new AccountAPI(this.client) this.licenses = new LicenseAPI(this.client) } diff --git a/qa-core/src/account-api/api/AccountInternalAPIClient.ts b/qa-core/src/account-api/api/AccountInternalAPIClient.ts index 85807fd87a..1b73f51320 100644 --- a/qa-core/src/account-api/api/AccountInternalAPIClient.ts +++ b/qa-core/src/account-api/api/AccountInternalAPIClient.ts @@ -1,6 +1,8 @@ +import { Response } from "node-fetch" import env from "../../environment" import fetch, { HeadersInit } from "node-fetch" import { State } from "../../types" +import { Header } from "@budibase/backend-core" type APIMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" @@ -28,7 +30,7 @@ export default class AccountInternalAPIClient { apiCall = (method: APIMethod) => - async (url = "", options: ApiOptions = {}) => { + async (url = "", options: ApiOptions = {}): Promise<[Response, any]> => { const requestOptions = { method, body: JSON.stringify(options.body), @@ -46,7 +48,7 @@ export default class AccountInternalAPIClient { if (options.internal) { requestOptions.headers = { ...requestOptions.headers, - ...{ "x-budibase-api-key": env.ACCOUNT_PORTAL_API_KEY }, + ...{ [Header.API_KEY]: env.ACCOUNT_PORTAL_API_KEY }, } } diff --git a/qa-core/src/account-api/api/apis/AccountAPI.ts b/qa-core/src/account-api/api/apis/AccountAPI.ts index fc6f6caecb..33e64da7ad 100644 --- a/qa-core/src/account-api/api/apis/AccountAPI.ts +++ b/qa-core/src/account-api/api/apis/AccountAPI.ts @@ -1,75 +1,117 @@ import { Response } from "node-fetch" -import { Account, CreateAccountRequest } from "@budibase/types" +import { + Account, + CreateAccountRequest, + SearchAccountsRequest, + SearchAccountsResponse, +} from "@budibase/types" import AccountInternalAPIClient from "../AccountInternalAPIClient" import { APIRequestOpts } from "../../../types" +import { Header } from "@budibase/backend-core" +import BaseAPI from "./BaseAPI" -export default class AccountAPI { +export default class AccountAPI extends BaseAPI { client: AccountInternalAPIClient constructor(client: AccountInternalAPIClient) { + super() this.client = client } - async validateEmail( - email: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( - `/api/accounts/validate/email`, - { + async validateEmail(email: string, opts: APIRequestOpts = { status: 200 }) { + return this.doRequest(() => { + return this.client.post(`/api/accounts/validate/email`, { body: { email }, - } - ) - if (opts.doExpect) { - expect(response).toHaveStatusCode(200) - } - return response + }) + }, opts) } async validateTenantId( tenantId: string, - opts: APIRequestOpts = { doExpect: true } - ): Promise { - const [response, json] = await this.client.post( - `/api/accounts/validate/tenantId`, - { + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post(`/api/accounts/validate/tenantId`, { body: { tenantId }, - } - ) - if (opts.doExpect) { - expect(response).toHaveStatusCode(200) - } - return response + }) + }, opts) } async create( body: CreateAccountRequest, - opts: APIRequestOpts = { doExpect: true } + opts: APIRequestOpts & { autoVerify: boolean } = { + status: 201, + autoVerify: false, + } ): Promise<[Response, Account]> { - const headers = { - "no-verify": "1", - } - const [response, json] = await this.client.post(`/api/accounts`, { - body, - headers, - }) - if (opts.doExpect) { - expect(response).toHaveStatusCode(201) - } - return [response, json] + return this.doRequest(() => { + const headers = { + "no-verify": opts.autoVerify ? "1" : "0", + } + return this.client.post(`/api/accounts`, { + body, + headers, + }) + }, opts) } - async delete(accountID: string) { - const [response, json] = await this.client.del( - `/api/accounts/${accountID}`, - { + async delete(accountID: string, opts: APIRequestOpts = { status: 204 }) { + return this.doRequest(() => { + return this.client.del(`/api/accounts/${accountID}`, { internal: true, + }) + }, opts) + } + + async deleteCurrentAccount(opts: APIRequestOpts = { status: 204 }) { + return this.doRequest(() => { + return this.client.del(`/api/accounts`) + }, opts) + } + + async verifyAccount( + verificationCode: string, + opts: APIRequestOpts = { status: 200 } + ) { + return this.doRequest(() => { + return this.client.post(`/api/accounts/verify`, { + body: { verificationCode }, + }) + }, opts) + } + + async sendVerificationEmail( + email: string, + opts: APIRequestOpts = { status: 200 } + ): Promise<[Response, string]> { + return this.doRequest(async () => { + const [response] = await this.client.post(`/api/accounts/verify/send`, { + body: { email }, + headers: { + [Header.RETURN_VERIFICATION_CODE]: "1", + }, + }) + const code = response.headers.get(Header.VERIFICATION_CODE) + return [response, code] + }, opts) + } + + async search( + searchType: string, + search: "email" | "tenantId", + opts: APIRequestOpts = { status: 200 } + ): Promise<[Response, SearchAccountsResponse]> { + return this.doRequest(() => { + let body: SearchAccountsRequest = {} + if (search === "email") { + body.email = searchType + } else if (search === "tenantId") { + body.tenantId = searchType } - ) - // can't use expect here due to use in global teardown - if (response.status !== 204) { - throw new Error(`Could not delete accountId=${accountID}`) - } - return response + return this.client.post(`/api/accounts/search`, { + body, + internal: true, + }) + }, opts) } } diff --git a/qa-core/src/account-api/api/apis/AuthAPI.ts b/qa-core/src/account-api/api/apis/AuthAPI.ts new file mode 100644 index 0000000000..50345c891b --- /dev/null +++ b/qa-core/src/account-api/api/apis/AuthAPI.ts @@ -0,0 +1,30 @@ +import { Response } from "node-fetch" +import AccountInternalAPIClient from "../AccountInternalAPIClient" +import { APIRequestOpts } from "../../../types" +import BaseAPI from "./BaseAPI" + +export default class AuthAPI extends BaseAPI { + client: AccountInternalAPIClient + + constructor(client: AccountInternalAPIClient) { + super() + this.client = client + } + + async login( + email: string, + password: string, + opts: APIRequestOpts = { doExpect: true, status: 200 } + ): Promise<[Response, string]> { + return this.doRequest(async () => { + const [res] = await this.client.post(`/api/auth/login`, { + body: { + email: email, + password: password, + }, + }) + const cookie = res.headers.get("set-cookie") + return [res, cookie] + }, opts) + } +} diff --git a/qa-core/src/account-api/api/apis/BaseAPI.ts b/qa-core/src/account-api/api/apis/BaseAPI.ts new file mode 100644 index 0000000000..ed5d261e9e --- /dev/null +++ b/qa-core/src/account-api/api/apis/BaseAPI.ts @@ -0,0 +1,20 @@ +import { Response } from "node-fetch" +import { APIRequestOpts } from "../../../types" + +export default class BaseAPI { + async doRequest( + request: () => Promise<[Response, any]>, + opts: APIRequestOpts + ): Promise<[Response, any]> { + const [response, body] = await request() + + // do expect on by default + if (opts.doExpect === undefined) { + opts.doExpect = true + } + if (opts.doExpect && opts.status) { + expect(response).toHaveStatusCode(opts.status) + } + return [response, body] + } +} diff --git a/qa-core/src/account-api/api/apis/LicenseAPI.ts b/qa-core/src/account-api/api/apis/LicenseAPI.ts index e0601fe127..f0398ade95 100644 --- a/qa-core/src/account-api/api/apis/LicenseAPI.ts +++ b/qa-core/src/account-api/api/apis/LicenseAPI.ts @@ -1,31 +1,27 @@ import AccountInternalAPIClient from "../AccountInternalAPIClient" import { Account, UpdateLicenseRequest } from "@budibase/types" import { Response } from "node-fetch" +import BaseAPI from "./BaseAPI" +import { APIRequestOpts } from "../../../types" -export default class LicenseAPI { +export default class LicenseAPI extends BaseAPI { client: AccountInternalAPIClient constructor(client: AccountInternalAPIClient) { + super() this.client = client } async updateLicense( accountId: string, - body: UpdateLicenseRequest + body: UpdateLicenseRequest, + opts: APIRequestOpts = { status: 200 } ): Promise<[Response, Account]> { - const [response, json] = await this.client.put( - `/api/accounts/${accountId}/license`, - { + return this.doRequest(() => { + return this.client.put(`/api/accounts/${accountId}/license`, { body, internal: true, - } - ) - - if (response.status !== 200) { - throw new Error( - `Could not update license for accountId=${accountId}: ${response.status}` - ) - } - return [response, json] + }) + }, opts) } } diff --git a/qa-core/src/account-api/api/apis/index.ts b/qa-core/src/account-api/api/apis/index.ts index b8a1dc7b4a..1137ac3e36 100644 --- a/qa-core/src/account-api/api/apis/index.ts +++ b/qa-core/src/account-api/api/apis/index.ts @@ -1,2 +1,3 @@ +export { default as AuthAPI } from "./AuthAPI" export { default as AccountAPI } from "./AccountAPI" export { default as LicenseAPI } from "./LicenseAPI" diff --git a/qa-core/src/account-api/config/TestConfiguration.ts b/qa-core/src/account-api/config/TestConfiguration.ts new file mode 100644 index 0000000000..66adb85ca2 --- /dev/null +++ b/qa-core/src/account-api/config/TestConfiguration.ts @@ -0,0 +1,29 @@ +import { AccountInternalAPI } from "../api" +import { BudibaseTestConfiguration } from "../../shared" + +export default class TestConfiguration extends BudibaseTestConfiguration { + // apis + api: AccountInternalAPI + + context: T + + constructor() { + super() + this.api = new AccountInternalAPI(this.state) + this.context = {} + } + + async beforeAll() { + await super.beforeAll() + await this.setApiKey() + } + + async afterAll() { + await super.afterAll() + } + + async setApiKey() { + const apiKeyResponse = await this.internalApi.self.getApiKey() + this.state.apiKey = apiKeyResponse.apiKey + } +} diff --git a/qa-core/src/account-api/fixtures/accounts.ts b/qa-core/src/account-api/fixtures/accounts.ts new file mode 100644 index 0000000000..62c84f3647 --- /dev/null +++ b/qa-core/src/account-api/fixtures/accounts.ts @@ -0,0 +1,21 @@ +import { generator } from "../../shared" +import { Hosting, CreateAccountRequest } from "@budibase/types" + +// TODO: Refactor me to central location +export const generateAccount = (): CreateAccountRequest => { + const uuid = generator.guid() + + const email = `${uuid}@budibase.com` + const tenant = `tenant${uuid.replace(/-/g, "")}` + + return { + email, + hosting: Hosting.CLOUD, + name: email, + password: uuid, + profession: "software_engineer", + size: "10+", + tenantId: tenant, + tenantName: tenant, + } +} diff --git a/qa-core/src/account-api/fixtures/index.ts b/qa-core/src/account-api/fixtures/index.ts new file mode 100644 index 0000000000..952f4a8cc8 --- /dev/null +++ b/qa-core/src/account-api/fixtures/index.ts @@ -0,0 +1 @@ +export * as accounts from "./accounts" diff --git a/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts b/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts new file mode 100644 index 0000000000..fc5eb57de7 --- /dev/null +++ b/qa-core/src/account-api/tests/accounts/accounts.cloud.internal.spec.ts @@ -0,0 +1,29 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { generator } from "../../../shared" + +describe("Account Internal Operations", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("performs account deletion by ID", async () => { + // Deleting by unknown id doesn't work + const accountId = generator.string() + await config.api.accounts.delete(accountId, { status: 404 }) + + // Create new account + const [_, account] = await config.api.accounts.create({ + ...fixtures.accounts.generateAccount(), + }) + + // New account can be deleted + await config.api.accounts.delete(account.accountId) + }) +}) diff --git a/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts b/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts new file mode 100644 index 0000000000..e3a4d4eacf --- /dev/null +++ b/qa-core/src/account-api/tests/accounts/accounts.cloud.spec.ts @@ -0,0 +1,92 @@ +import TestConfiguration from "../../config/TestConfiguration" +import * as fixtures from "../../fixtures" +import { generator } from "../../../shared" + +describe("Accounts", () => { + const config = new TestConfiguration() + + beforeAll(async () => { + await config.beforeAll() + }) + + afterAll(async () => { + await config.afterAll() + }) + + it("performs signup and deletion flow", async () => { + await config.doInNewState(async () => { + // Create account + const createAccountRequest = fixtures.accounts.generateAccount() + const email = createAccountRequest.email + const tenantId = createAccountRequest.tenantId + + // Validation - email and tenant ID allowed + await config.api.accounts.validateEmail(email) + await config.api.accounts.validateTenantId(tenantId) + + // Create unverified account + await config.api.accounts.create(createAccountRequest) + + // Validation - email and tenant ID no longer valid + await config.api.accounts.validateEmail(email, { status: 400 }) + await config.api.accounts.validateTenantId(tenantId, { status: 400 }) + + // Attempt to log in using unverified account + await config.loginAsAccount(createAccountRequest, { status: 400 }) + + // Re-send verification email to get access to code + const [_, code] = await config.accountsApi.accounts.sendVerificationEmail( + email + ) + + // Send the verification request + await config.accountsApi.accounts.verifyAccount(code!) + + // Can now log in to the account + await config.loginAsAccount(createAccountRequest) + + // Delete account + await config.api.accounts.deleteCurrentAccount() + + // Can't log in + await config.loginAsAccount(createAccountRequest, { status: 403 }) + }) + }) + + describe("Searching accounts", () => { + it("search by tenant ID", async () => { + const tenantId = generator.string() + + // Empty result + const [_, emptyBody] = await config.api.accounts.search( + tenantId, + "tenantId" + ) + expect(emptyBody.length).toBe(0) + + // Hit result + const [hitRes, hitBody] = await config.api.accounts.search( + config.state.tenantId!, + "tenantId" + ) + expect(hitBody.length).toBe(1) + expect(hitBody[0].tenantId).toBe(config.state.tenantId) + }) + + it("searches by email", async () => { + const email = generator.email() + + // Empty result + const [_, emptyBody] = await config.api.accounts.search(email, "email") + expect(emptyBody.length).toBe(0) + + // Hit result + const [hitRes, hitBody] = await config.api.accounts.search( + config.state.email!, + "email" + ) + expect(hitBody.length).toBe(1) + expect(hitBody[0].email).toBe(config.state.email) + }) + }) +}) diff --git a/qa-core/src/jest/globalSetup.ts b/qa-core/src/jest/globalSetup.ts index 040a65ecef..103126d74c 100644 --- a/qa-core/src/jest/globalSetup.ts +++ b/qa-core/src/jest/globalSetup.ts @@ -1,5 +1,4 @@ -process.env.DISABLE_PINO_LOGGER = "1" -import { DEFAULT_TENANT_ID, logging } from "@budibase/backend-core" +import { DEFAULT_TENANT_ID } from "@budibase/backend-core" import { AccountInternalAPI } from "../account-api" import * as fixtures from "../internal-api/fixtures" import { BudibaseInternalAPI } from "../internal-api" @@ -7,10 +6,6 @@ import { Account, CreateAccountRequest, Feature } from "@budibase/types" import env from "../environment" import { APIRequestOpts } from "../types" -// turn off or on context logging i.e. tenantId, appId etc -// it's not applicable for the qa run -logging.LOG_CONTEXT = false - const accountsApi = new AccountInternalAPI({}) const internalApi = new BudibaseInternalAPI({}) @@ -23,7 +18,10 @@ async function createAccount(): Promise<[CreateAccountRequest, Account]> { const account = fixtures.accounts.generateAccount() await accountsApi.accounts.validateEmail(account.email, API_OPTS) await accountsApi.accounts.validateTenantId(account.tenantId, API_OPTS) - const [res, newAccount] = await accountsApi.accounts.create(account, API_OPTS) + const [res, newAccount] = await accountsApi.accounts.create(account, { + ...API_OPTS, + autoVerify: true, + }) await updateLicense(newAccount.accountId) return [account, newAccount] } @@ -31,25 +29,34 @@ async function createAccount(): Promise<[CreateAccountRequest, Account]> { const UNLIMITED = { value: -1 } async function updateLicense(accountId: string) { - await accountsApi.licenses.updateLicense(accountId, { - overrides: { - // add all features - features: Object.values(Feature), - quotas: { - usage: { - monthly: { - automations: UNLIMITED, - }, - static: { - rows: UNLIMITED, - users: UNLIMITED, - userGroups: UNLIMITED, - plugins: UNLIMITED, + const [response] = await accountsApi.licenses.updateLicense( + accountId, + { + overrides: { + // add all features + features: Object.values(Feature), + quotas: { + usage: { + monthly: { + automations: UNLIMITED, + }, + static: { + rows: UNLIMITED, + users: UNLIMITED, + userGroups: UNLIMITED, + plugins: UNLIMITED, + }, }, }, }, }, - }) + { doExpect: false } + ) + if (response.status !== 200) { + throw new Error( + `Could not update license for accountId=${accountId}: ${response.status}` + ) + } } async function loginAsAdmin() { @@ -68,8 +75,7 @@ async function loginAsAdmin() { } async function loginAsAccount(account: CreateAccountRequest) { - const [res, cookie] = await internalApi.auth.login( - account.tenantId, + const [res, cookie] = await accountsApi.auth.login( account.email, account.password, API_OPTS @@ -90,6 +96,8 @@ async function setup() { // @ts-ignore global.qa.tenantId = account.tenantId // @ts-ignore + global.qa.email = account.email + // @ts-ignore global.qa.accountId = newAccount.accountId await loginAsAccount(account) } else { diff --git a/qa-core/src/jest/globalTeardown.ts b/qa-core/src/jest/globalTeardown.ts index 52696a72f8..ff3fea7b7c 100644 --- a/qa-core/src/jest/globalTeardown.ts +++ b/qa-core/src/jest/globalTeardown.ts @@ -10,8 +10,13 @@ const API_OPTS: APIRequestOpts = { doExpect: false } async function deleteAccount() { // @ts-ignore const accountID = global.qa.accountId - // can't run 'expect' blocks in teardown - await accountsApi.accounts.delete(accountID) + + const [response] = await accountsApi.accounts.delete(accountID, { + doExpect: false, + }) + if (response.status !== 204) { + throw new Error(`status: ${response.status} not equal to expected: 201`) + } } async function teardown() { diff --git a/qa-core/src/jest/jestSetup.ts b/qa-core/src/jest/jestSetup.ts index 6c60845c87..928e547337 100644 --- a/qa-core/src/jest/jestSetup.ts +++ b/qa-core/src/jest/jestSetup.ts @@ -1,5 +1,3 @@ -import { logging } from "@budibase/backend-core" -logging.LOG_CONTEXT = false - -jest.retryTimes(2) -jest.setTimeout(60000) +const envTimeout = process.env.JEST_TIMEOUT +const timeout = envTimeout && parseInt(envTimeout) +jest.setTimeout(timeout || 60000) diff --git a/qa-core/src/shared/BudibaseTestConfiguration.ts b/qa-core/src/shared/BudibaseTestConfiguration.ts index 12a0f16138..18b7c89ec8 100644 --- a/qa-core/src/shared/BudibaseTestConfiguration.ts +++ b/qa-core/src/shared/BudibaseTestConfiguration.ts @@ -1,7 +1,8 @@ import { BudibaseInternalAPI } from "../internal-api" import { AccountInternalAPI } from "../account-api" -import { CreateAppRequest, State } from "../types" +import { APIRequestOpts, CreateAppRequest, State } from "../types" import * as fixtures from "../internal-api/fixtures" +import { CreateAccountRequest } from "@budibase/types" export default class BudibaseTestConfiguration { // apis @@ -23,6 +24,8 @@ export default class BudibaseTestConfiguration { // @ts-ignore this.state.tenantId = global.qa.tenantId // @ts-ignore + this.state.email = global.qa.email + // @ts-ignore this.state.cookie = global.qa.authCookie } @@ -40,10 +43,49 @@ export default class BudibaseTestConfiguration { // AUTH + async doInNewState(task: () => Promise) { + return this.doWithState(task, {}) + } + + async doWithState(task: () => Promise, state: State) { + const original = { ...this.state } + + // override the state + this.state.apiKey = state.apiKey + this.state.appId = state.appId + this.state.cookie = state.cookie + this.state.tableId = state.tableId + this.state.tenantId = state.tenantId + this.state.email = state.email + + await task() + + // restore the state + this.state.apiKey = original.apiKey + this.state.appId = original.appId + this.state.cookie = original.cookie + this.state.tableId = original.tableId + this.state.tenantId = original.tenantId + this.state.email = original.email + } + + async loginAsAccount( + account: CreateAccountRequest, + opts: APIRequestOpts = {} + ) { + const [_, cookie] = await this.accountsApi.auth.login( + account.email, + account.password, + opts + ) + this.state.cookie = cookie + } + async login(email: string, password: string, tenantId?: string) { if (!tenantId && this.state.tenantId) { tenantId = this.state.tenantId - } else { + } + if (!tenantId) { throw new Error("Could not determine tenant id") } const [res, cookie] = await this.internalApi.auth.login( diff --git a/qa-core/src/types/api.ts b/qa-core/src/types/api.ts index c94150d3eb..3d52445280 100644 --- a/qa-core/src/types/api.ts +++ b/qa-core/src/types/api.ts @@ -1,5 +1,6 @@ export interface APIRequestOpts { // in some cases we need to bypass the expect assertion in an api call // e.g. during global setup where jest is not available - doExpect: boolean + doExpect?: boolean + status?: number } diff --git a/qa-core/src/types/state.ts b/qa-core/src/types/state.ts index 0da471e090..8fab3998ce 100644 --- a/qa-core/src/types/state.ts +++ b/qa-core/src/types/state.ts @@ -4,4 +4,5 @@ export interface State { cookie?: string tableId?: string tenantId?: string + email?: string } diff --git a/qa-core/yarn.lock b/qa-core/yarn.lock index a2cfae27a9..a423e45b21 100644 --- a/qa-core/yarn.lock +++ b/qa-core/yarn.lock @@ -455,6 +455,13 @@ slash "^3.0.0" strip-ansi "^6.0.0" +"@jest/create-cache-key-function@^27.4.2": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-27.5.1.tgz#7448fae15602ea95c828f5eceed35c202a820b31" + integrity sha512-dmH1yW+makpTSURTy8VzdUwFnfQh1G8R+DxO2Ho2FFmBbKFEVm+3jWdvFhE2VqB/LATCTokkP0dotjyQyw5/AQ== + dependencies: + "@jest/types" "^27.5.1" + "@jest/environment@^29.5.0": version "29.5.0" resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz" @@ -589,6 +596,17 @@ slash "^3.0.0" write-file-atomic "^4.0.2" +"@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@jest/types@^29.0.0", "@jest/types@^29.5.0": version "29.5.0" resolved "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz" @@ -738,6 +756,80 @@ dependencies: "@sinonjs/commons" "^2.0.0" +"@swc/core-darwin-arm64@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.70.tgz#056ac6899e22cb7f7be21388d4d938ca5123a72b" + integrity sha512-31+mcl0dgdRHvZRjhLOK9V6B+qJ7nxDZYINr9pBlqGWxknz37Vld5KK19Kpr79r0dXUZvaaelLjCnJk9dA2PcQ== + +"@swc/core-darwin-x64@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.3.70.tgz#3945814de6fadbee5b46cb2a3422353acb420c5c" + integrity sha512-GMFJ65E18zQC80t0os+TZvI+8lbRuitncWVge/RXmXbVLPRcdykP4EJ87cqzcG5Ah0z18/E0T+ixD6jHRisrYQ== + +"@swc/core-linux-arm-gnueabihf@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.70.tgz#7960e54ede1af75a7ef99ee53febf37fea6269a8" + integrity sha512-wjhCwS8LCiAq2VedF1b4Bryyw68xZnfMED4pLRazAl8BaUlDFANfRBORNunxlfHQj4V3x39IaiLgCZRHMdzXBg== + +"@swc/core-linux-arm64-gnu@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.70.tgz#df9654e5040bbeb1619739756a7f50100e38ace8" + integrity sha512-9D/Rx67cAOnMiexvCqARxvhj7coRajTp5HlJHuf+rfwMqI2hLhpO9/pBMQxBUAWxODO/ksQ/OF+GJRjmtWw/2A== + +"@swc/core-linux-arm64-musl@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.70.tgz#2c2aab5a136c7eb409ddc9cdc4f947a68fd74493" + integrity sha512-gkjxBio7XD+1GlQVVyPP/qeFkLu83VhRHXaUrkNYpr5UZG9zZurBERT9nkS6Y+ouYh+Q9xmw57aIyd2KvD2zqQ== + +"@swc/core-linux-x64-gnu@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.70.tgz#774351532b154ed36a5c6d14b647e7a8ab510028" + integrity sha512-/nCly+V4xfMVwfEUoLLAukxUSot/RcSzsf6GdsGTjFcrp5sZIntAjokYRytm3VT1c2TK321AfBorsi9R5w8Y7Q== + +"@swc/core-linux-x64-musl@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.70.tgz#c0b1b4ad5f4ef187eaa093589a4933ecb6836546" + integrity sha512-HoOsPJbt361KGKaivAK0qIiYARkhzlxeAfvF5NlnKxkIMOZpQ46Lwj3tR0VWohKbrhS+cYKFlVuDi5XnDkx0XA== + +"@swc/core-win32-arm64-msvc@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.70.tgz#8640267ce3959db0e7e682103677a5e0500b5ea7" + integrity sha512-hm4IBK/IaRil+aj1cWU6f0GyAdHpw/Jr5nyFYLM2c/tt7w2t5hgb8NjzM2iM84lOClrig1fG6edj2vCF1dFzNQ== + +"@swc/core-win32-ia32-msvc@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.70.tgz#f95d5656622f5a963bc0125da9fda84cf40faa8d" + integrity sha512-5cgKUKIT/9Fp5fCA+zIjYCQ4dSvjFYOeWGZR3QiTXGkC4bGa1Ji9SEPyeIAX0iruUnKjYaZB9RvHK2tNn7RLrQ== + +"@swc/core-win32-x64-msvc@1.3.70": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.70.tgz#5b3acddb96fdf60df089b837061915cb4be94eaa" + integrity sha512-LE8lW46+TQBzVkn2mHBlk8DIElPIZ2dO5P8AbJiARNBAnlqQWu67l9gWM89UiZ2l33J2cI37pHzON3tKnT8f9g== + +"@swc/core@^1.3.25": + version "1.3.70" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.3.70.tgz#f5ddc6fe6add7a99f5b94d2214ad0d8527d11479" + integrity sha512-LWVWlEDLlOD25PvA2NEz41UzdwXnlDyBiZbe69s3zM0DfCPwZXLUm79uSqH9ItsOjTrXSL5/1+XUL6C/BZwChA== + optionalDependencies: + "@swc/core-darwin-arm64" "1.3.70" + "@swc/core-darwin-x64" "1.3.70" + "@swc/core-linux-arm-gnueabihf" "1.3.70" + "@swc/core-linux-arm64-gnu" "1.3.70" + "@swc/core-linux-arm64-musl" "1.3.70" + "@swc/core-linux-x64-gnu" "1.3.70" + "@swc/core-linux-x64-musl" "1.3.70" + "@swc/core-win32-arm64-msvc" "1.3.70" + "@swc/core-win32-ia32-msvc" "1.3.70" + "@swc/core-win32-x64-msvc" "1.3.70" + +"@swc/jest@^0.2.24": + version "0.2.26" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.26.tgz#6ef2d6d31869e3aaddc132603bc21f2e4c57cc5d" + integrity sha512-7lAi7q7ShTO3E5Gt1Xqf3pIhRbERxR1DUxvtVa9WKzIB+HGQ7wZP5sYx86zqnaEoKKGhmOoZ7gyW0IRu8Br5+A== + dependencies: + "@jest/create-cache-key-function" "^27.4.2" + jsonc-parser "^3.2.0" + "@techpass/passport-openidconnect@0.3.2": version "0.3.2" resolved "https://registry.npmjs.org/@techpass/passport-openidconnect/-/passport-openidconnect-0.3.2.tgz" @@ -885,6 +977,13 @@ resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== +"@types/yargs@^16.0.0": + version "16.0.5" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" + integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== + dependencies: + "@types/yargs-parser" "*" + "@types/yargs@^17.0.8": version "17.0.22" resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.22.tgz" @@ -2866,6 +2965,11 @@ json5@^2.2.1, json5@^2.2.2: resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonc-parser@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" + integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== + jsonwebtoken@9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz" diff --git a/scripts/versionCommit.sh b/scripts/versionCommit.sh index 71c931d736..86db0136e7 100755 --- a/scripts/versionCommit.sh +++ b/scripts/versionCommit.sh @@ -13,6 +13,6 @@ node ./bumpVersion.js $1 NEW_VERSION=$(node -p "require('../lerna.json').version") git add ../lerna.json git commit -m "Bump version to $NEW_VERSION" -git tag v$NEW_VERSION +git tag $NEW_VERSION git push git push --tags \ No newline at end of file