diff --git a/.github/workflows/action.yml b/.github/workflows/action.yml index 742e5fe6d5..ce7763cbdd 100644 --- a/.github/workflows/action.yml +++ b/.github/workflows/action.yml @@ -36,7 +36,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Assert changed diff --git a/.github/workflows/docs-freshness-check.yml b/.github/workflows/docs-freshness-check.yml index 0f10237c39..e5c6ff5fef 100644 --- a/.github/workflows/docs-freshness-check.yml +++ b/.github/workflows/docs-freshness-check.yml @@ -24,7 +24,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Install dependencies diff --git a/.github/workflows/docs-test.yml b/.github/workflows/docs-test.yml index 0c2e9678ab..76805e6338 100644 --- a/.github/workflows/docs-test.yml +++ b/.github/workflows/docs-test.yml @@ -1,5 +1,5 @@ name: Documentation Tests -on: +on: pull_request: paths: - www/** @@ -22,7 +22,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "18" + node-version: 20 cache: "yarn" - name: Install dependencies @@ -44,7 +44,7 @@ jobs: # TODO change once we have actual URLs NEXT_PUBLIC_RESOURCES_URL: "http://example.com" NEXT_PUBLIC_USER_GUIDE_URL: "http://example.com" - + vale-book: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -75,7 +75,7 @@ jobs: # an error state - name: Get PR files number working-directory: www/utils/packages/scripts - run: 'yarn check:pr-files-count ${{ github.ref_name }}' + run: "yarn check:pr-files-count ${{ github.ref_name }}" id: pr-files - name: Get Directories to Scan @@ -90,13 +90,13 @@ jobs: with: files: ${{ steps.directories.outputs.LIST }} fail_on_error: true - vale_flags: '--minAlertLevel=error' + vale_flags: "--minAlertLevel=error" reporter: github-pr-check token: ${{ github.token }} filter_mode: nofilter env: REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} - + vale-resources: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -127,7 +127,7 @@ jobs: # an error state - name: Get PR files number working-directory: www/utils/packages/scripts - run: 'yarn check:pr-files-count ${{ github.ref_name }}' + run: "yarn check:pr-files-count ${{ github.ref_name }}" id: pr-files - name: Get Directories to Scan @@ -141,13 +141,13 @@ jobs: with: files: ${{ steps.directories.outputs.LIST }} fail_on_error: true - vale_flags: '--minAlertLevel=error' + vale_flags: "--minAlertLevel=error" reporter: github-pr-check token: ${{ github.token }} filter_mode: nofilter env: REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} - + vale-user-guide: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -178,7 +178,7 @@ jobs: # an error state - name: Get PR files number working-directory: www/utils/packages/scripts - run: 'yarn check:pr-files-count ${{ github.ref_name }}' + run: "yarn check:pr-files-count ${{ github.ref_name }}" id: pr-files - name: Get Directories to Scan @@ -192,13 +192,13 @@ jobs: with: files: ${{ steps.directories.outputs.LIST }} fail_on_error: true - vale_flags: '--minAlertLevel=error' + vale_flags: "--minAlertLevel=error" reporter: github-pr-check token: ${{ github.token }} filter_mode: nofilter env: REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} - + vale-ui: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -229,7 +229,7 @@ jobs: # an error state - name: Get PR files number working-directory: www/utils/packages/scripts - run: 'yarn check:pr-files-count ${{ github.ref_name }}' + run: "yarn check:pr-files-count ${{ github.ref_name }}" id: pr-files - name: Get Directories to Scan @@ -244,13 +244,13 @@ jobs: with: files: ${{ steps.directories.outputs.LIST }} fail_on_error: true - vale_flags: '--minAlertLevel=error' + vale_flags: "--minAlertLevel=error" reporter: github-pr-check token: ${{ github.token }} filter_mode: nofilter env: REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} - + vale-api: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -281,7 +281,7 @@ jobs: # an error state - name: Get PR files number working-directory: www/utils/packages/scripts - run: 'yarn check:pr-files-count ${{ github.ref_name }}' + run: "yarn check:pr-files-count ${{ github.ref_name }}" id: pr-files - name: Get Directories to Scan @@ -296,13 +296,13 @@ jobs: with: files: ${{ steps.directories.outputs.LIST }} fail_on_error: true - vale_flags: '--minAlertLevel=error' + vale_flags: "--minAlertLevel=error" reporter: github-pr-check token: ${{ github.token }} filter_mode: diff_context env: REVIEWDOG_GITHUB_API_TOKEN: ${{ github.token }} - + content-eslint: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -324,7 +324,7 @@ jobs: - name: Run Eslint working-directory: www run: yarn lint:content - + code-docs-eslint: if: ${{ startsWith(github.head_ref, 'docs/') }} runs-on: ubuntu-latest @@ -352,4 +352,4 @@ jobs: - name: Run Eslint working-directory: www - run: yarn lint \ No newline at end of file + run: yarn lint diff --git a/.github/workflows/generate-docblocks-reference.yml b/.github/workflows/generate-docblocks-reference.yml index 685f6481dd..c818864651 100644 --- a/.github/workflows/generate-docblocks-reference.yml +++ b/.github/workflows/generate-docblocks-reference.yml @@ -9,9 +9,9 @@ on: workflow_dispatch: inputs: referenceName: - description: 'Reference to Generate. Use either `all` or a name of a config file in `www/utils/packages/typedoc-config` such as `product`.' + description: "Reference to Generate. Use either `all` or a name of a config file in `www/utils/packages/typedoc-config` such as `product`." required: false - default: 'all' + default: "all" jobs: references: @@ -31,7 +31,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Install dependencies @@ -83,4 +83,4 @@ jobs: add-paths: www/apps/resources/references/** branch: "docs/generate-reference" branch-suffix: "timestamp" - body: ${{ steps.pr-message.outputs.body }} \ No newline at end of file + body: ${{ steps.pr-message.outputs.body }} diff --git a/.github/workflows/generate-docblocks.yml b/.github/workflows/generate-docblocks.yml index 00d52671bf..a0f36ae7db 100644 --- a/.github/workflows/generate-docblocks.yml +++ b/.github/workflows/generate-docblocks.yml @@ -14,10 +14,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@v3 - - name: Setup Node.js 18 + - name: Setup Node.js 20 uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 20 - name: Install Dependencies run: yarn @@ -70,10 +70,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@v3 - - name: Setup Node.js 18 + - name: Setup Node.js 20 uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 20 - name: Install Dependencies run: yarn diff --git a/.github/workflows/generate-public-references.yml b/.github/workflows/generate-public-references.yml index 9e3138d22c..5d0787a877 100644 --- a/.github/workflows/generate-public-references.yml +++ b/.github/workflows/generate-public-references.yml @@ -3,9 +3,9 @@ on: workflow_dispatch: inputs: referenceName: - description: 'Reference to Generate. Use either `all` to generate all references, `api` to generate the API reference, or `ui` to generate UI reference.' + description: "Reference to Generate. Use either `all` to generate all references, `api` to generate the API reference, or `ui` to generate UI reference." required: false - default: 'all' + default: "all" release: types: [published] @@ -28,7 +28,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Install dependencies @@ -78,7 +78,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Install dependencies @@ -114,4 +114,4 @@ jobs: labels: "type: chore" add-paths: www/apps/ui/src/specs branch: "docs/generate-ui-ref" - branch-suffix: "timestamp" \ No newline at end of file + branch-suffix: "timestamp" diff --git a/.github/workflows/release-notifications.yml b/.github/workflows/release-notifications.yml index 1551a3c4c0..533f339f64 100644 --- a/.github/workflows/release-notifications.yml +++ b/.github/workflows/release-notifications.yml @@ -20,7 +20,7 @@ jobs: - name: Setup Node.js environment uses: actions/setup-node@v3 with: - node-version: "16.10.0" + node-version: 20 cache: "yarn" - name: Post to Slack channel diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 034018f968..ced86aaa60 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,10 +15,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@v3 - - name: Setup Node.js 16 + - name: Setup Node.js 20 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 20 - name: Creating .npmrc run: | @@ -37,4 +37,4 @@ jobs: - name: Create Release Pull Request uses: changesets/action@v1 env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/snapshot-this.yml b/.github/workflows/snapshot-this.yml index 6cc1eef8a2..d11ed0be8e 100644 --- a/.github/workflows/snapshot-this.yml +++ b/.github/workflows/snapshot-this.yml @@ -12,7 +12,7 @@ jobs: snapshot: name: Snapshot Release if: | - github.event.issue.pull_request && + github.event.issue.pull_request && github.event.comment.body == '/snapshot-this' runs-on: ubuntu-latest steps: @@ -79,7 +79,7 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 20 cache: "yarn" - name: Install dependencies @@ -120,7 +120,7 @@ jobs: '```sh\n' + `yarn add ${tag}\n` + '```' - )).join('\n') + + )).join('\n') + `\n\n> Latest commit: ${context.sha}` ) diff --git a/.github/workflows/test-cli-with-database.yml b/.github/workflows/test-cli-with-database.yml index 73b3132150..0cbeaa5049 100644 --- a/.github/workflows/test-cli-with-database.yml +++ b/.github/workflows/test-cli-with-database.yml @@ -1,82 +1,82 @@ name: CLI Pipeline on: - pull_request: + pull_request: jobs: - test-cli-with-database: - env: - NODE_ENV: CI - REDIS_URL: redis://localhost:6379 - DATABASE_URL: "postgres://postgres:postgres@localhost/cli-test" - POSTGRES_URL: "postgres://postgres:postgres@localhost/cli-test" - services: - redis: - image: redis - options: >- - --health-cmd "redis-cli ping" - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 6379:6379 + test-cli-with-database: + env: + NODE_ENV: CI + REDIS_URL: redis://localhost:6379 + DATABASE_URL: "postgres://postgres:postgres@localhost/cli-test" + POSTGRES_URL: "postgres://postgres:postgres@localhost/cli-test" + services: + redis: + image: redis + options: >- + --health-cmd "redis-cli ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 6379:6379 - postgres: - image: postgres - env: - POSTGRES_PASSWORD: postgres - POSTGRES_USER: postgres - POSTGRES_DB: cli-test - options: >- - --health-cmd pg_isready - --health-interval 10s - --health-timeout 5s - --health-retries 5 - ports: - - 5432:5432 + postgres: + image: postgres + env: + POSTGRES_PASSWORD: postgres + POSTGRES_USER: postgres + POSTGRES_DB: cli-test + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + ports: + - 5432:5432 - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v3 - with: - fetch-depth: 0 + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 - - name: Setup development server - uses: ./.github/actions/setup-server - with: - cache-extension: "cli-test" - node-version: 18 + - name: Setup development server + uses: ./.github/actions/setup-server + with: + cache-extension: "cli-test" + node-version: 20 - - name: Install Medusa cli - run: npm i -g @medusajs/medusa-cli@preview + - name: Install Medusa cli + run: npm i -g @medusajs/medusa-cli@preview - - name: Create Medusa project - run: | - medusa new cli-test --skip-db --v2 --branch feat/v2-ci - working-directory: .. + - name: Create Medusa project + run: | + medusa new cli-test --skip-db --v2 --branch feat/v2-ci + working-directory: .. - - name: run medusa dev - run: medusa-dev --force-install - working-directory: ../cli-test + - name: run medusa dev + run: medusa-dev --force-install + working-directory: ../cli-test - - name: Run migrations - run: medusa migrations run - working-directory: ../cli-test + - name: Run migrations + run: medusa migrations run + working-directory: ../cli-test - - name: Create admin user - run: medusa user -e test@test.com -p password -i admin_123 - working-directory: ../cli-test + - name: Create admin user + run: medusa user -e test@test.com -p password -i admin_123 + working-directory: ../cli-test - - name: Run development server - run: medusa develop & - working-directory: ../cli-test + - name: Run development server + run: medusa develop & + working-directory: ../cli-test - - name: Testing development server - uses: ./.github/actions/test-server + - name: Testing development server + uses: ./.github/actions/test-server - - name: Starting medusa - run: medusa start & - working-directory: ../cli-test + - name: Starting medusa + run: medusa start & + working-directory: ../cli-test - - name: Testing server - uses: ./.github/actions/test-server + - name: Testing server + uses: ./.github/actions/test-server diff --git a/.github/workflows/trigger-release.yml b/.github/workflows/trigger-release.yml index cfd6cc1af7..d2ea23c5b5 100644 --- a/.github/workflows/trigger-release.yml +++ b/.github/workflows/trigger-release.yml @@ -5,14 +5,14 @@ on: inputs: version: type: choice - default: 'preview' + default: "preview" description: What tag do you want to release? required: true - options: - - preview - - next - - snapshot - - canary + options: + - preview + - next + - snapshot + - canary branches: - develop paths-ignore: @@ -32,10 +32,10 @@ jobs: - name: Checkout Repo uses: actions/checkout@v3 - - name: Setup Node.js 16.x + - name: Setup Node.js 20 uses: actions/setup-node@v3 with: - node-version: 16.x + node-version: 20 - name: Creating .npmrc run: | @@ -44,8 +44,8 @@ jobs: EOF env: NPM_TOKEN: ${{ secrets.NPM_TOKEN }} - - - name: Configure npm node prepend + + - name: Configure npm node prepend run: npm config set scripts-prepend-node-path auto - name: Install Dependencies @@ -61,6 +61,6 @@ jobs: - name: Build all packages run: yarn build - + - name: Publish packages under next tag run: yarn changeset publish --no-git-tags --snapshot --tag ${{ github.event.inputs.version || 'preview' }} diff --git a/packages/core/medusa-test-utils/src/medusa-test-runner-utils/bootstrap-app.ts b/packages/core/medusa-test-utils/src/medusa-test-runner-utils/bootstrap-app.ts index 707a58e821..e922ec0066 100644 --- a/packages/core/medusa-test-utils/src/medusa-test-runner-utils/bootstrap-app.ts +++ b/packages/core/medusa-test-utils/src/medusa-test-runner-utils/bootstrap-app.ts @@ -1,7 +1,7 @@ import express from "express" import getPort from "get-port" import { resolve } from "path" -import { isObject, promiseAll } from "@medusajs/utils" +import { isObject, promiseAll, GracefulShutdownServer } from "@medusajs/utils" import { MedusaContainer } from "@medusajs/types" async function bootstrapApp({ @@ -52,7 +52,7 @@ export async function startApp({ let expressServer const shutdown = async () => { - await promiseAll([expressServer.shutdown(), medusaShutdown()]) + await promiseAll([expressServer?.shutdown(), medusaShutdown()]) if (typeof global !== "undefined" && global?.gc) { global.gc() @@ -77,10 +77,6 @@ export async function startApp({ }) // TODO: fix that once we find the appropriate place to put this util - const { - GracefulShutdownServer, - } = require("@medusajs/medusa/dist/utils/graceful-shutdown-server") - expressServer = GracefulShutdownServer.create(server) }) } diff --git a/packages/core/utils/package.json b/packages/core/utils/package.json index c7e6c05f8b..f7ee4ec6fb 100644 --- a/packages/core/utils/package.json +++ b/packages/core/utils/package.json @@ -36,6 +36,7 @@ "@mikro-orm/postgresql": "5.9.7", "awilix": "^8.0.1", "bignumber.js": "^9.1.2", + "dotenv": "^16.4.5", "knex": "2.4.2", "ulid": "^2.3.0" }, diff --git a/packages/medusa/src/utils/__tests__/graceful-shutdown-server.ts b/packages/core/utils/src/common/__tests__/graceful-shutdown-server.ts similarity index 100% rename from packages/medusa/src/utils/__tests__/graceful-shutdown-server.ts rename to packages/core/utils/src/common/__tests__/graceful-shutdown-server.ts diff --git a/packages/core/utils/src/common/__tests__/load-env.spec.ts b/packages/core/utils/src/common/__tests__/load-env.spec.ts new file mode 100644 index 0000000000..21f6dd75e0 --- /dev/null +++ b/packages/core/utils/src/common/__tests__/load-env.spec.ts @@ -0,0 +1,40 @@ +import { join } from "path" +import { FileSystem } from "../file-system" +import { loadEnv } from "../load-env" + +const filesystem = new FileSystem(join(__dirname, "tmp")) + +describe("loadEnv", function () { + afterEach(async () => { + await filesystem.cleanup() + delete process.env.MEDUSA_VERSION + delete process.env.MEDUSA_DEV_VERSION + delete process.env.MEDUSA_TEST_VERSION + delete process.env.MEDUSA_STAGING_VERSION + delete process.env.MEDUSA_PRODUCTION_VERSION + }) + + it("should load .env file when in unknown environment", async function () { + await filesystem.create(".env", "MEDUSA_VERSION=1.0") + loadEnv("", filesystem.basePath) + + expect(process.env.MEDUSA_VERSION).toEqual("1.0") + }) + + it("should load .env file for known environments", async function () { + await filesystem.create(".env", "MEDUSA_DEV_VERSION=1.0") + await filesystem.create(".env.test", "MEDUSA_TEST_VERSION=1.0") + await filesystem.create(".env.staging", "MEDUSA_STAGING_VERSION=1.0") + await filesystem.create(".env.production", "MEDUSA_PRODUCTION_VERSION=1.0") + + loadEnv("development", filesystem.basePath) + loadEnv("test", filesystem.basePath) + loadEnv("staging", filesystem.basePath) + loadEnv("production", filesystem.basePath) + + expect(process.env.MEDUSA_DEV_VERSION).toEqual("1.0") + expect(process.env.MEDUSA_TEST_VERSION).toEqual("1.0") + expect(process.env.MEDUSA_STAGING_VERSION).toEqual("1.0") + expect(process.env.MEDUSA_PRODUCTION_VERSION).toEqual("1.0") + }) +}) diff --git a/packages/core/utils/src/common/file-system.ts b/packages/core/utils/src/common/file-system.ts new file mode 100644 index 0000000000..6a83ba0643 --- /dev/null +++ b/packages/core/utils/src/common/file-system.ts @@ -0,0 +1,159 @@ +import { dirname, join } from "path" +import { + promises, + constants, + type Dirent, + type RmOptions, + type StatOptions, + type WriteFileOptions, + type MakeDirectoryOptions, +} from "fs" + +const { rm, stat, mkdir, access, readdir, readFile, writeFile } = promises + +export type JSONFileOptions = WriteFileOptions & { + spaces?: number | string + replacer?: (this: any, key: string, value: any) => any +} + +/** + * File system abstraction to create and cleanup files during + * tests + */ +export class FileSystem { + constructor(public basePath: string) {} + + private makePath(filePath: string) { + return join(this.basePath, filePath) + } + + /** + * Cleanup directory + */ + async cleanup(options?: RmOptions) { + return rm(this.basePath, { + recursive: true, + maxRetries: 10, + force: true, + ...options, + }) + } + + /** + * Creates a directory inside the root of the filesystem + * path. You may use this method to create nested + * directories as well. + */ + mkdir(dirPath: string, options?: MakeDirectoryOptions) { + return mkdir(this.makePath(dirPath), { recursive: true, ...options }) + } + + /** + * Create a new file + */ + async create(filePath: string, contents: string, options?: WriteFileOptions) { + const absolutePath = this.makePath(filePath) + await mkdir(dirname(absolutePath), { recursive: true }) + return writeFile(this.makePath(filePath), contents, options) + } + + /** + * Remove a file + */ + async remove(filePath: string, options?: RmOptions) { + return rm(this.makePath(filePath), { + recursive: true, + force: true, + maxRetries: 2, + ...options, + }) + } + + /** + * Check if the root of the filesystem exists + */ + async rootExists() { + try { + await access(this.basePath, constants.F_OK) + return true + } catch (error) { + if (error.code === "ENOENT") { + return false + } + throw error + } + } + + /** + * Check if a file exists + */ + async exists(filePath: string) { + try { + await access(this.makePath(filePath), constants.F_OK) + return true + } catch (error) { + if (error.code === "ENOENT") { + return false + } + throw error + } + } + + /** + * Returns file contents + */ + async contents(filePath: string) { + return readFile(this.makePath(filePath), "utf-8") + } + + /** + * Dumps file contents to the stdout + */ + async dump(filePath: string) { + console.log("------------------------------------------------------------") + console.log(`file path => "${filePath}"`) + console.log(`contents => "${await this.contents(filePath)}"`) + } + + /** + * Returns stats for a file + */ + async stats(filePath: string, options?: StatOptions) { + return stat(this.makePath(filePath), options) + } + + /** + * Recursively reads files from a given directory + */ + readDir(dirPath?: string): Promise { + const location = dirPath ? this.makePath(dirPath) : this.basePath + return readdir(location, { + recursive: true, + withFileTypes: true, + }) + } + + /** + * Create a json file + */ + async createJson(filePath: string, contents: any, options?: JSONFileOptions) { + if (options && typeof options === "object") { + const { replacer, spaces, ...rest } = options + return this.create( + filePath, + JSON.stringify(contents, replacer, spaces), + rest + ) + } + + return this.create(filePath, JSON.stringify(contents), options) + } + + /** + * Read and parse a json file + */ + async contentsJson(filePath: string) { + const contents = await readFile(this.makePath(filePath), "utf-8") + return JSON.parse(contents) + } +} diff --git a/packages/medusa/src/utils/graceful-shutdown-server.ts b/packages/core/utils/src/common/graceful-shutdown-server.ts similarity index 100% rename from packages/medusa/src/utils/graceful-shutdown-server.ts rename to packages/core/utils/src/common/graceful-shutdown-server.ts diff --git a/packages/core/utils/src/common/index.ts b/packages/core/utils/src/common/index.ts index ecd8c2fca8..8d89b4496a 100644 --- a/packages/core/utils/src/common/index.ts +++ b/packages/core/utils/src/common/index.ts @@ -61,3 +61,6 @@ export * from "./to-handle" export * from "./validate-handle" export * from "./parse-cors-origins" export * from "./build-regexp-if-valid" +export * from "./load-env" +export * from "./file-system" +export * from "./graceful-shutdown-server" diff --git a/packages/core/utils/src/common/load-env.ts b/packages/core/utils/src/common/load-env.ts new file mode 100644 index 0000000000..7e191405f2 --- /dev/null +++ b/packages/core/utils/src/common/load-env.ts @@ -0,0 +1,24 @@ +import dotenv from "dotenv" +import { join } from "path" +const KNOWN_ENVIRONMENTS = ["staging", "production", "test"] + +/** + * Loads ".env" file based upon the environment in which the + * app is running. + * + * - Loads ".env" file by default. + * - Loads ".env.staging" when "environment=staging". + * - Loads ".env.production" when "environment=production". + * - Loads ".env.test" when "environment=test". + * + * This method does not return any value and updates the "process.env" + * object instead. + */ +export function loadEnv(environment: string, envDir: string) { + const fileToLoad = KNOWN_ENVIRONMENTS.includes(environment) + ? `.env.${environment}` + : ".env" + try { + dotenv.config({ path: join(envDir, fileToLoad) }) + } catch {} +} diff --git a/packages/medusa/src/commands/start-cluster.ts b/packages/medusa/src/commands/start-cluster.ts index 08285ae95c..7e09597849 100644 --- a/packages/medusa/src/commands/start-cluster.ts +++ b/packages/medusa/src/commands/start-cluster.ts @@ -3,14 +3,13 @@ import "regenerator-runtime/runtime" import cluster from "cluster" import express from "express" -import { GracefulShutdownServer } from "../utils" import { track } from "medusa-telemetry" import { scheduleJob } from "node-schedule" import os from "os" import loaders from "../loaders" import Logger from "../loaders/logger" -import { isPresent } from "@medusajs/utils" +import { isPresent, GracefulShutdownServer } from "@medusajs/utils" const EVERY_SIXTH_HOUR = "0 */6 * * *" const CRON_SCHEDULE = EVERY_SIXTH_HOUR diff --git a/packages/medusa/src/commands/start.ts b/packages/medusa/src/commands/start.ts index 310fcda2b6..e9057a1738 100644 --- a/packages/medusa/src/commands/start.ts +++ b/packages/medusa/src/commands/start.ts @@ -2,12 +2,12 @@ import "core-js/stable" import "regenerator-runtime/runtime" import express from "express" -import { GracefulShutdownServer } from "../utils" import { track } from "medusa-telemetry" import { scheduleJob } from "node-schedule" import loaders from "../loaders" import Logger from "../loaders/logger" +import { GracefulShutdownServer } from "@medusajs/utils" const EVERY_SIXTH_HOUR = "0 */6 * * *" const CRON_SCHEDULE = EVERY_SIXTH_HOUR diff --git a/packages/medusa/src/loaders/__tests__/feature-flags.spec.ts b/packages/medusa/src/loaders/__tests__/feature-flags.spec.ts index 500f571b80..1561e1632d 100644 --- a/packages/medusa/src/loaders/__tests__/feature-flags.spec.ts +++ b/packages/medusa/src/loaders/__tests__/feature-flags.spec.ts @@ -1,13 +1,8 @@ -import { mkdirSync, rmSync, writeFileSync } from "fs" -import { resolve } from "path" +import { join } from "path" +import { FileSystem } from "@medusajs/utils" import loadFeatureFlags from "../feature-flags" - -const distTestTargetDirectorPath = resolve(__dirname, "__ff-test__") - -const getFolderTestTargetDirectoryPath = (folderName: string): string => { - return resolve(distTestTargetDirectorPath, folderName) -} +const filesystem = new FileSystem(join(__dirname, "__ff-test__")) const buildFeatureFlag = ( key: string, @@ -28,60 +23,42 @@ const buildFeatureFlag = ( describe("feature flags", () => { const OLD_ENV = { ...process.env } - beforeEach(() => { + beforeEach(async () => { jest.resetModules() jest.clearAllMocks() process.env = { ...OLD_ENV } - - rmSync(distTestTargetDirectorPath, { recursive: true, force: true }) - - mkdirSync(getFolderTestTargetDirectoryPath("project"), { - mode: "777", - recursive: true, - }) - - mkdirSync(getFolderTestTargetDirectoryPath("flags"), { - mode: "777", - recursive: true, - }) + await filesystem.cleanup() }) - afterAll(() => { + afterAll(async () => { process.env = OLD_ENV - rmSync(distTestTargetDirectorPath, { recursive: true, force: true }) + await filesystem.cleanup() }) it("should load the flag from project", async () => { - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-1.js"), - buildFeatureFlag("flag-1", true) - ) + await filesystem.create("flags/flag-1.js", buildFeatureFlag("flag-1", true)) - const flags = await loadFeatureFlags( + const flags = loadFeatureFlags( { featureFlags: { flag_1: false } }, undefined, - getFolderTestTargetDirectoryPath("flags") + join(filesystem.basePath, "flags") ) expect(flags.isFeatureEnabled("flag_1")).toEqual(false) }) it("should load a nested + simple flag from project", async () => { - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "test.js"), - buildFeatureFlag("test", false) - ) - - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "simpletest.js"), + await filesystem.create("flags/test.js", buildFeatureFlag("test", false)) + await filesystem.create( + "flags/simpletest.js", buildFeatureFlag("simpletest", false) ) - const flags = await loadFeatureFlags( + const flags = loadFeatureFlags( { featureFlags: { test: { nested: true }, simpletest: true } }, undefined, - getFolderTestTargetDirectoryPath("flags") + join(filesystem.basePath, "flags") ) expect(flags.isFeatureEnabled({ test: "nested" })).toEqual(true) @@ -89,15 +66,15 @@ describe("feature flags", () => { }) it("should load the default feature flags", async () => { - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-1.js"), - buildFeatureFlag("flag-1", true) + await filesystem.create( + "flags/flag-1.js", + buildFeatureFlag("flag-1", false) ) - const flags = await loadFeatureFlags( + const flags = loadFeatureFlags( {}, undefined, - getFolderTestTargetDirectoryPath("flags") + join(filesystem.basePath, "flags") ) expect(flags.isFeatureEnabled("flag_1")).toEqual(true) @@ -106,15 +83,14 @@ describe("feature flags", () => { it("should load the flag from env", async () => { process.env.MEDUSA_FF_FLAG_1 = "false" - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-1.js"), - buildFeatureFlag("flag-1", true) + await filesystem.create( + "flags/flag-1.js", + buildFeatureFlag("flag-1", false) ) - - const flags = await loadFeatureFlags( + const flags = loadFeatureFlags( {}, undefined, - getFolderTestTargetDirectoryPath("flags") + join(filesystem.basePath, "flags") ) expect(flags.isFeatureEnabled("flag_1")).toEqual(false) @@ -122,26 +98,23 @@ describe("feature flags", () => { it("should load mix of flags", async () => { process.env.MEDUSA_FF_FLAG_3 = "false" - - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-1.js"), - buildFeatureFlag("flag-1", true) + await filesystem.create( + "flags/flag-1.js", + buildFeatureFlag("flag-1", false) + ) + await filesystem.create( + "flags/flag-2.js", + buildFeatureFlag("flag-2", false) + ) + await filesystem.create( + "flags/flag-3.js", + buildFeatureFlag("flag-3", false) ) - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-2.js"), - buildFeatureFlag("flag-2", true) - ) - - writeFileSync( - resolve(getFolderTestTargetDirectoryPath("flags"), "flag-3.js"), - buildFeatureFlag("flag-3", true) - ) - - const flags = await loadFeatureFlags( + const flags = loadFeatureFlags( { featureFlags: { flag_2: false } }, undefined, - getFolderTestTargetDirectoryPath("flags") + join(filesystem.basePath, "flags") ) expect(flags.isFeatureEnabled("flag_1")).toEqual(true) diff --git a/packages/medusa/src/utils/index.ts b/packages/medusa/src/utils/index.ts index a4b68e6e12..13545c3094 100644 --- a/packages/medusa/src/utils/index.ts +++ b/packages/medusa/src/utils/index.ts @@ -3,4 +3,3 @@ export * from "./exception-formatter" export * from "./middlewares" export * from "./omit-deep" export * from "./remove-undefined-properties" -export * from "./graceful-shutdown-server" diff --git a/yarn.lock b/yarn.lock index 82d6f1a150..54649dfda7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6178,6 +6178,7 @@ __metadata: awilix: ^8.0.1 bignumber.js: ^9.1.2 cross-env: ^5.2.1 + dotenv: ^16.4.5 express: ^4.18.2 jest: ^29.6.3 knex: 2.4.2