v3 CLI compiling E2E test suite (#1135)
* Boilerplate server-only use case * wip: integration suite instrumentation setup * Working poc testing compileProject * Add pnpm script to run e2e tests only * Use vitest globals * Remove commented line * Remove useless export * Add modifier to test only one fixture project * Handle package manager and log level choice * Update server-only example * Setup / teardown + split compile for package manager capabilities * Ignore yarn files * Fix issue with corepack, store version in engines field * Rename test file * Fix npm updates yarn.lock * Move typecheking in a dedicated test * Stop bundling the compile command to allow for more granular testing * Put config resolving in separate test * Add no-config test case and add test case expected errors configuration * Add wantCompilationError option * Add dependencies handling * Use packageManager passed as option to resolve required deps * Remove unused guard clauses * Add postinstall & hash handling step * Add worker start test * Handle yarn.lock copy renaming on sigterm and sigkill * Update vitest and use concurrent option * Add a readme file * Add CI workflow * Fix handle cli deps * Run cli v3 e2e tests on publish action * Increase timeout on deps resolving step * Add changeset * Remove .pnp.cjs as we use yarn with nodeLinker node-modules * Add missing .yarnrc.yml file * No need to build CLI to run E2E tests * Remove bun.lockb files * Update beige-pears-explode.md --------- Co-authored-by: Eric Allam <eallam@icloud.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"trigger.dev": patch
|
||||
---
|
||||
|
||||
Add an e2e suite to test compiling with v3 CLI.
|
||||
@@ -1,9 +1,53 @@
|
||||
name: "🧪 E2E Tests"
|
||||
name: "E2E"
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
package:
|
||||
description: The identifier of the job to run
|
||||
default: webapp
|
||||
required: false
|
||||
type: string
|
||||
jobs:
|
||||
e2e:
|
||||
name: "🧪 E2E Tests"
|
||||
cli-v3:
|
||||
name: "🧪 CLI v3 tests"
|
||||
if: inputs.package == 'cli-v3' || inputs.package == ''
|
||||
runs-on: buildjet-8vcpu-ubuntu-2204
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
package-manager: ["npm", "pnpm", "yarn"]
|
||||
steps:
|
||||
- name: ⬇️ Checkout repo
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: ⎔ Setup pnpm
|
||||
uses: pnpm/action-setup@v2.2.4
|
||||
with:
|
||||
version: 8.15.5
|
||||
|
||||
- name: ⎔ Setup node
|
||||
uses: buildjet/setup-node@v3
|
||||
with:
|
||||
node-version: 20.11.1
|
||||
cache: "pnpm"
|
||||
|
||||
- name: 📥 Download deps
|
||||
run: pnpm install --frozen-lockfile --filter trigger.dev...
|
||||
|
||||
- name: 🔧 Build v3 cli monorepo dependencies
|
||||
run: pnpm run build --filter trigger.dev^...
|
||||
|
||||
- name: 🔧 Build worker template files
|
||||
run: pnpm --filter trigger.dev run build:workers
|
||||
|
||||
- name: Run E2E Tests
|
||||
run: |
|
||||
PM=${{ matrix.package-manager }} pnpm --filter trigger.dev run test:e2e
|
||||
webapp:
|
||||
name: "🧪 Webapp tests"
|
||||
if: inputs.package == 'webapp' || inputs.package == ''
|
||||
runs-on: buildjet-16vcpu-ubuntu-2204
|
||||
steps:
|
||||
- name: 🐳 Login to Docker Hub
|
||||
|
||||
@@ -29,4 +29,6 @@ jobs:
|
||||
|
||||
# e2e:
|
||||
# uses: ./.github/workflows/e2e.yml
|
||||
# with:
|
||||
# package: webapp
|
||||
# secrets: inherit
|
||||
|
||||
@@ -49,9 +49,11 @@ jobs:
|
||||
uses: ./.github/workflows/unit-tests.yml
|
||||
secrets: inherit
|
||||
|
||||
# e2e:
|
||||
# uses: ./.github/workflows/e2e.yml
|
||||
# secrets: inherit
|
||||
e2e:
|
||||
uses: ./.github/workflows/e2e.yml
|
||||
with:
|
||||
package: cli-v3
|
||||
secrets: inherit
|
||||
|
||||
publish:
|
||||
needs: [typecheck, units]
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
# Trigger.dev CLI E2E suite
|
||||
|
||||
E2E test suite for the Trigger.dev v3 CLI.
|
||||
|
||||
Note: this only works with Trigger.dev v3 projects and later. There is no E2E test suite for the [@trigger.dev/cli](https://www.npmjs.com/package/@trigger.dev/cli) package yet.
|
||||
|
||||
Trigger.dev is an open source platform that makes it easy to create event-driven background tasks directly in your existing project.
|
||||
|
||||
## Description
|
||||
|
||||
This suite aims to test the outputs fo the `triggerdev deploy` command.
|
||||
To do so, it runs the deploy code against fixture projects that are located under `packages/cli-v3/e2e/fixtures/`.
|
||||
Those fixtures reproduce minimal project structure and contents, in order to reproduce known bugs and run fast.
|
||||
|
||||
**Notes**
|
||||
- The suite uses vitest
|
||||
- Everything happens locally
|
||||
- There is no login required
|
||||
- There is not real project reference needed
|
||||
- No docker image is created or built, instead, the bundled worker file is started with node directly inside the vitest process
|
||||
|
||||
## Usage
|
||||
|
||||
If you have not done it yet, build the CLI:
|
||||
|
||||
```sh
|
||||
pnpm run build --filter trigger.dev
|
||||
```
|
||||
|
||||
Then, run the v3 CLI E2E test suite:
|
||||
|
||||
```sh
|
||||
pnpm --filter trigger.dev run test:e2e
|
||||
```
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ---------------------------------------------------------------------------- |
|
||||
| `MOD=<fixture-name>` | The name of any folder directly nested under `packages/cli-v3/e2e/fixtures/` |
|
||||
| `PM=<package-manager>` | The package manager to use. One of `npm`, `pnpm`, `yarn`. Defaults to `npm` |
|
||||
|
||||
Example:
|
||||
|
||||
```sh
|
||||
MOD=server-only PM=yarn pnpm --filter trigger.dev run test:e2e
|
||||
```
|
||||
|
||||
This will run the test suite for the `server-only` fixture using `yarn` to install and resolve dependencies.
|
||||
|
||||
## Debugging
|
||||
|
||||
When debugging an issue with the `triggerdev deploy` or `triggerdev dev` command, it is recommended to reproduce it with a minimal project fixture in the e2e suite.
|
||||
Check [Adding a fixture](#adding-a-fixture) for more information.
|
||||
|
||||
Then run:
|
||||
|
||||
```sh
|
||||
MOD=<fixture-name> pnpm run test:e2e
|
||||
```
|
||||
|
||||
This will test your fixture project, and generate outputs in the `packages/cli-v3/e2e/fixtures/<fixture-name>/.trigger` folder, so you can easily debug.
|
||||
|
||||
## Adding a fixture
|
||||
|
||||
1. Create a new `packages/cli-v3/e2e/fixtures/<fixture-name>` folder.
|
||||
|
||||
It will hold the project to test.
|
||||
|
||||
2. Add a `package.json` file in your `packages/cli-v3/e2e/fixtures/<fixture-name>` folder.
|
||||
|
||||
Use the following template:
|
||||
|
||||
```json package.json
|
||||
{
|
||||
"name": "<fixture-name>",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"pnpm": "8.15.5",
|
||||
"yarn": "4.2.2"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.5"
|
||||
}
|
||||
```
|
||||
|
||||
> The `engines` field is used to store the versions of pnpm and yarn to use when running the suite.
|
||||
|
||||
3. Add an empty `pnpm-workspace.yaml` in your `packages/cli-v3/e2e/fixtures/<fixture-name>` folder.
|
||||
|
||||
This is necessary to prevent the Trigger.dev monorepo from handling this project.
|
||||
Please check https://github.com/pnpm/pnpm/issues/2412 for more inforation.
|
||||
|
||||
4. Add an empty `yarn.lock` in your fixture folder.
|
||||
|
||||
This is necessary to allow to use `yarn` without having a warning on the current project being a `pnpm` project.
|
||||
|
||||
5. Install the fixture dependencies and generate lockfiles.
|
||||
|
||||
Like you would in any project.
|
||||
E.g. if your fixture contains a trigger task that uses the `jsdom` library:
|
||||
|
||||
```sh
|
||||
cd packages/cli-v3/e2e/fixtures/<fixture-name>
|
||||
corepack use pnpm@8.15.5
|
||||
pnpm install jsdom
|
||||
```
|
||||
|
||||
> This will update the `package.json` and generate the `pnpm-lock.yaml` file.
|
||||
|
||||
6. To run the test suite against multiple package manager, we need to generate the other lockfiles.
|
||||
|
||||
```sh
|
||||
cd packages/cli-v3/e2e/fixtures/<fixture-name>
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
rm -rf node_modules
|
||||
corepack use yarn # will update the yarn lockfile
|
||||
```
|
||||
|
||||
> Do it in this order, otherwise `npm install` will update the existing `yarn.lock` file with legacy version 1.
|
||||
|
||||
7. Create a new `packages/cli-v3/e2e/fixtures/trigger` folder, and create a trigger task in it.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```javascript
|
||||
import { task } from "@trigger.dev/sdk/v3";
|
||||
|
||||
export const helloWorldTask = task({
|
||||
id: "hello-world",
|
||||
run: async (payload) => {
|
||||
console.log("Hello, World!", payload);
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
8. Add a trigger configuration file.
|
||||
|
||||
The configuration file is mandatory here, the E2E suite does not execute `trigger.dev` commands.
|
||||
|
||||
```javascript
|
||||
export const config = {
|
||||
project: "<fixture-name>",
|
||||
triggerDirectories: ["./trigger"],
|
||||
};
|
||||
```
|
||||
|
||||
> The project reference can be anything here, as the suite runs locally without connecting to the platform.
|
||||
|
||||
9. Commit your changes.
|
||||
|
||||
10. Add your fixture test configuration in `testCases.json`.
|
||||
|
||||
```json testCases.json
|
||||
[
|
||||
...
|
||||
{
|
||||
"name": "<fixture-name>",
|
||||
},
|
||||
...
|
||||
]
|
||||
```
|
||||
|
||||
You can configure your test case by adding other properties to the JSON object. Here is the `TestCase` type for reference:
|
||||
|
||||
```typescript
|
||||
type TestCase = {
|
||||
name: string;
|
||||
skipTypecheck?: boolean;
|
||||
wantConfigNotFoundError?: boolean;
|
||||
wantBadConfigError?: boolean;
|
||||
wantCompilationError?: boolean;
|
||||
wantWorkerError?: boolean;
|
||||
wantDependenciesError?: boolean;
|
||||
wantInstallationError?: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
> You might expect a specific error at a specific test, so use those configuration option at your discretion.
|
||||
@@ -0,0 +1,243 @@
|
||||
import { esbuildDecorators } from "@anatine/esbuild-decorators";
|
||||
import { build } from "esbuild";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { basename, join, posix, resolve } from "node:path";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
import {
|
||||
bundleDependenciesPlugin,
|
||||
mockServerOnlyPlugin,
|
||||
workerSetupImportConfigPlugin,
|
||||
} from "../src/utilities/build.js";
|
||||
import { ReadConfigResult } from "../src/utilities/configFiles.js";
|
||||
import { writeJSONFile } from "../src/utilities/fileSystem.js";
|
||||
import { logger } from "../src/utilities/logger.js";
|
||||
import { createTaskFileImports, gatherTaskFiles } from "../src/utilities/taskFiles.js";
|
||||
import { escapeImportPath } from "../src/utilities/windows.js";
|
||||
|
||||
type CompileOptions = {
|
||||
outputMetafile?: string;
|
||||
resolvedConfig: ReadConfigResult;
|
||||
tempDir: string;
|
||||
};
|
||||
|
||||
export async function compile(options: CompileOptions) {
|
||||
if (options.resolvedConfig.status === "error") {
|
||||
throw new Error("cannot resolve config");
|
||||
}
|
||||
|
||||
const {
|
||||
tempDir,
|
||||
resolvedConfig: { config },
|
||||
} = options;
|
||||
const configPath =
|
||||
options.resolvedConfig.status === "file" ? options.resolvedConfig.path : undefined;
|
||||
|
||||
// COPIED FROM compileProject()
|
||||
// const compileSpinner = spinner();
|
||||
// compileSpinner.start(`Building project in ${config.projectDir}`);
|
||||
|
||||
const taskFiles = await gatherTaskFiles(config);
|
||||
const workerFacade = readFileSync(
|
||||
resolve("./dist/workers/prod/worker-facade.js"),
|
||||
// join(cliRootPath(), "workers", "prod", "worker-facade.js"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
// const workerSetupPath = join(cliRootPath(), "workers", "prod", "worker-setup.js");
|
||||
const workerSetupPath = resolve("./dist/workers/prod/worker-setup.js");
|
||||
|
||||
let workerContents = workerFacade
|
||||
.replace("__TASKS__", createTaskFileImports(taskFiles))
|
||||
.replace(
|
||||
"__WORKER_SETUP__",
|
||||
`import { tracingSDK, otelTracer, otelLogger } from "${escapeImportPath(workerSetupPath)}";`
|
||||
);
|
||||
|
||||
if (configPath) {
|
||||
logger.debug("Importing project config from", { configPath });
|
||||
|
||||
workerContents = workerContents.replace(
|
||||
"__IMPORTED_PROJECT_CONFIG__",
|
||||
`import * as importedConfigExports from "${escapeImportPath(
|
||||
configPath
|
||||
)}"; const importedConfig = importedConfigExports.config; const handleError = importedConfigExports.handleError;`
|
||||
);
|
||||
} else {
|
||||
workerContents = workerContents.replace(
|
||||
"__IMPORTED_PROJECT_CONFIG__",
|
||||
`const importedConfig = undefined; const handleError = undefined;`
|
||||
);
|
||||
}
|
||||
|
||||
const result = await build({
|
||||
stdin: {
|
||||
contents: workerContents,
|
||||
// resolveDir: process.cwd(),
|
||||
resolveDir: config.projectDir,
|
||||
sourcefile: "__entryPoint.ts",
|
||||
},
|
||||
bundle: true,
|
||||
metafile: true,
|
||||
write: false,
|
||||
minify: false,
|
||||
sourcemap: "external", // does not set the //# sourceMappingURL= comment in the file, we handle it ourselves
|
||||
logLevel: "error",
|
||||
platform: "node",
|
||||
format: "cjs", // This is needed to support opentelemetry instrumentation that uses module patching
|
||||
target: ["node18", "es2020"],
|
||||
// outdir: "out",
|
||||
outdir: resolve(config.projectDir, "out"),
|
||||
// banner: {
|
||||
// js: `process.on("uncaughtException", function(error, origin) { if (error instanceof Error) { process.send && process.send({ type: "EVENT", message: { type: "UNCAUGHT_EXCEPTION", payload: { error: { name: error.name, message: error.message, stack: error.stack }, origin }, version: "v1" } }); } else { process.send && process.send({ type: "EVENT", message: { type: "UNCAUGHT_EXCEPTION", payload: { error: { name: "Error", message: typeof error === "string" ? error : JSON.stringify(error) }, origin }, version: "v1" } }); } });`,
|
||||
// },
|
||||
footer: {
|
||||
js: "process.exit();",
|
||||
},
|
||||
define: {
|
||||
TRIGGER_API_URL: `"${config.triggerUrl}"`,
|
||||
__PROJECT_CONFIG__: JSON.stringify(config),
|
||||
},
|
||||
plugins: [
|
||||
mockServerOnlyPlugin(),
|
||||
bundleDependenciesPlugin("workerFacade", config.dependenciesToBundle, config.tsconfigPath),
|
||||
workerSetupImportConfigPlugin(configPath),
|
||||
esbuildDecorators({
|
||||
tsconfig: config.tsconfigPath,
|
||||
tsx: true,
|
||||
force: false,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
if (result.errors.length > 0) {
|
||||
// compileSpinner.stop("Build failed, aborting deployment");
|
||||
|
||||
// span.setAttributes({
|
||||
// "build.workerErrors": result.errors.map(
|
||||
// (error) => `Error: ${error.text} at ${error.location?.file}`
|
||||
// ),
|
||||
// });
|
||||
|
||||
throw new Error("Build failed, aborting deployment");
|
||||
}
|
||||
|
||||
if (options.outputMetafile) {
|
||||
await writeJSONFile(join(options.outputMetafile, "worker.json"), result.metafile);
|
||||
}
|
||||
|
||||
const entryPointContents = readFileSync(
|
||||
resolve("./dist/workers/prod/entry-point.js"),
|
||||
// join(cliRootPath(), "workers", "prod", "entry-point.js"),
|
||||
"utf-8"
|
||||
);
|
||||
|
||||
const entryPointResult = await build({
|
||||
stdin: {
|
||||
contents: entryPointContents,
|
||||
// resolveDir: process.cwd(),
|
||||
resolveDir: config.projectDir,
|
||||
sourcefile: "index.ts",
|
||||
},
|
||||
bundle: true,
|
||||
metafile: true,
|
||||
write: false,
|
||||
minify: false,
|
||||
sourcemap: false,
|
||||
logLevel: "error",
|
||||
platform: "node",
|
||||
packages: "external",
|
||||
format: "cjs", // This is needed to support opentelemetry instrumentation that uses module patching
|
||||
target: ["node18", "es2020"],
|
||||
// outdir: "out",
|
||||
outdir: resolve(config.projectDir, "out"),
|
||||
define: {
|
||||
__PROJECT_CONFIG__: JSON.stringify(config),
|
||||
},
|
||||
plugins: [
|
||||
bundleDependenciesPlugin("entryPoint.ts", config.dependenciesToBundle, config.tsconfigPath),
|
||||
],
|
||||
});
|
||||
|
||||
if (entryPointResult.errors.length > 0) {
|
||||
// compileSpinner.stop("Build failed, aborting deployment");
|
||||
|
||||
// span.setAttributes({
|
||||
// "build.entryPointErrors": entryPointResult.errors.map(
|
||||
// (error) => `Error: ${error.text} at ${error.location?.file}`
|
||||
// ),
|
||||
// });
|
||||
|
||||
throw new Error("Build failed, aborting deployment");
|
||||
}
|
||||
|
||||
if (options.outputMetafile) {
|
||||
await writeJSONFile(
|
||||
join(options.outputMetafile, "entry-point.json"),
|
||||
entryPointResult.metafile
|
||||
);
|
||||
}
|
||||
|
||||
// Create a tmp directory to store the build
|
||||
// const tempDir = await createTempDir();
|
||||
|
||||
logger.debug(`Writing compiled files to ${tempDir}`);
|
||||
|
||||
// Get the metaOutput for the result build
|
||||
// const metaOutput = result.metafile!.outputs[posix.join("out", "stdin.js")];
|
||||
const metaOutput =
|
||||
result.metafile!.outputs[
|
||||
posix.join("e2e", "fixtures", basename(config.projectDir), "out", "stdin.js")
|
||||
];
|
||||
|
||||
invariant(metaOutput, "Meta output for the result build is missing");
|
||||
|
||||
// Get the metaOutput for the entryPoint build
|
||||
// const entryPointMetaOutput =
|
||||
// entryPointResult.metafile!.outputs[posix.join("out", "stdin.js")];
|
||||
const entryPointMetaOutput =
|
||||
entryPointResult.metafile!.outputs[
|
||||
posix.join("e2e", "fixtures", basename(config.projectDir), "out", "stdin.js")
|
||||
];
|
||||
|
||||
invariant(entryPointMetaOutput, "Meta output for the entryPoint build is missing");
|
||||
|
||||
// Get the outputFile and the sourceMapFile for the result build
|
||||
const workerOutputFile = result.outputFiles.find(
|
||||
(file) => file.path === join(config.projectDir, "out", "stdin.js")
|
||||
);
|
||||
|
||||
invariant(workerOutputFile, "Output file for the result build is missing");
|
||||
|
||||
const workerSourcemapFile = result.outputFiles.find(
|
||||
(file) => file.path === join(config.projectDir, "out", "stdin.js.map")
|
||||
);
|
||||
|
||||
invariant(workerSourcemapFile, "Sourcemap file for the result build is missing");
|
||||
|
||||
// Get the outputFile for the entryPoint build
|
||||
|
||||
const entryPointOutputFile = entryPointResult.outputFiles.find(
|
||||
(file) => file.path === join(config.projectDir, "out", "stdin.js")
|
||||
);
|
||||
|
||||
invariant(entryPointOutputFile, "Output file for the entryPoint build is missing");
|
||||
|
||||
// Save the result outputFile to /tmp/dir/worker.js (and make sure to map the sourceMap to the correct location in the file)
|
||||
await writeFile(
|
||||
join(tempDir, "worker.js"),
|
||||
`${workerOutputFile.text}\n//# sourceMappingURL=worker.js.map`
|
||||
);
|
||||
// Save the sourceMapFile to /tmp/dir/worker.js.map
|
||||
await writeFile(join(tempDir, "worker.js.map"), workerSourcemapFile.text);
|
||||
// Save the entryPoint outputFile to /tmp/dir/index.js
|
||||
await writeFile(join(tempDir, "index.js"), entryPointOutputFile.text);
|
||||
|
||||
return {
|
||||
workerMetaOutput: metaOutput,
|
||||
workerOutputFile,
|
||||
entryPointMetaOutput,
|
||||
entryPointOutputFile,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { writeFile } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
import { cliRootPath } from "../src/utilities/resolveInternalFilePath";
|
||||
import { ReadConfigResult } from "../src/utilities/configFiles";
|
||||
|
||||
type CreateContainerFileOptions = {
|
||||
resolvedConfig: ReadConfigResult;
|
||||
tempDir: string;
|
||||
};
|
||||
|
||||
export async function createContainerFile(options: CreateContainerFileOptions) {
|
||||
if (options.resolvedConfig.status === "error") {
|
||||
throw new Error("cannot resolve config");
|
||||
}
|
||||
const {
|
||||
resolvedConfig: { config },
|
||||
tempDir,
|
||||
} = options;
|
||||
|
||||
// COPIED FROM compileProject()
|
||||
// Write the Containerfile to /mpt / dir / Containerfile;
|
||||
// const containerFilePath = join(cliRootPath(), "Containerfile.prod");
|
||||
const containerFilePath = resolve("./src/Containerfile.prod");
|
||||
|
||||
let containerFileContents = readFileSync(containerFilePath, "utf-8");
|
||||
|
||||
if (config.postInstall) {
|
||||
containerFileContents = containerFileContents.replace(
|
||||
"__POST_INSTALL__",
|
||||
`RUN ${config.postInstall}`
|
||||
);
|
||||
} else {
|
||||
containerFileContents = containerFileContents.replace("__POST_INSTALL__", "");
|
||||
}
|
||||
|
||||
await writeFile(join(tempDir, "Containerfile"), containerFileContents);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import { OutputFile } from "esbuild";
|
||||
|
||||
type CreateDeployHashOptions = {
|
||||
dependencies: { [k: string]: string };
|
||||
entryPointOutputFile: OutputFile;
|
||||
workerOutputFile: OutputFile;
|
||||
};
|
||||
|
||||
export async function createDeployHash(options: CreateDeployHashOptions) {
|
||||
const { entryPointOutputFile, workerOutputFile } = options;
|
||||
|
||||
// COPIED FROM compileProject()
|
||||
const contentHasher = createHash("sha256");
|
||||
contentHasher.update(Buffer.from(entryPointOutputFile.text));
|
||||
contentHasher.update(Buffer.from(workerOutputFile.text));
|
||||
contentHasher.update(Buffer.from(JSON.stringify(dependencies)));
|
||||
|
||||
const contentHash = contentHasher.digest("hex");
|
||||
|
||||
// span.setAttributes({
|
||||
// contentHash: contentHash,
|
||||
// });
|
||||
|
||||
// span.end();
|
||||
|
||||
return { contentHash };
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
.yarn
|
||||
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "server-only",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@infisical/sdk": "^2.2.3",
|
||||
"@trigger.dev/sdk": "3.0.0-beta.33"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
|
||||
"engines": {
|
||||
"pnpm": "8.15.5",
|
||||
"yarn": "4.2.2"
|
||||
}
|
||||
}
|
||||
+1373
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
# https://github.com/pnpm/pnpm/issues/2412
|
||||
@@ -0,0 +1,4 @@
|
||||
export const config = {
|
||||
project: "infisical-sdk",
|
||||
dependenciesToBundle: ["@infisical/sdk", "@infisical/sdk-darwin-arm64"],
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import { task } from "@trigger.dev/sdk/v3";
|
||||
import { LogLevel } from "@infisical/sdk";
|
||||
|
||||
export const helloWorldTask = task({
|
||||
id: "hello-world",
|
||||
run: async (payload) => {
|
||||
console.log("Hello, World!", payload, LogLevel.Debug);
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "no-config",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "no-config",
|
||||
"engines": {
|
||||
"pnpm": "8.15.5",
|
||||
"yarn": "4.2.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "no-config",
|
||||
"private": true,
|
||||
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
|
||||
"engines": {
|
||||
"pnpm": "8.15.5",
|
||||
"yarn": "4.2.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
lockfileVersion: '6.0'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
importers:
|
||||
|
||||
.: {}
|
||||
@@ -0,0 +1 @@
|
||||
# https://github.com/pnpm/pnpm/issues/2412
|
||||
@@ -0,0 +1,12 @@
|
||||
# This file is generated by running "yarn install" inside your project.
|
||||
# Manual changes might be lost - proceed with caution!
|
||||
|
||||
__metadata:
|
||||
version: 8
|
||||
cacheKey: 10c0
|
||||
|
||||
"no-config@workspace:.":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "no-config@workspace:."
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
+2141
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "server-only",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@trigger.dev/sdk": "3.0.0-beta.33",
|
||||
"server-only": "^0.0.1"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
|
||||
"engines": {
|
||||
"pnpm": "8.15.5",
|
||||
"yarn": "4.2.2"
|
||||
}
|
||||
}
|
||||
+1251
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1 @@
|
||||
# https://github.com/pnpm/pnpm/issues/2412
|
||||
@@ -0,0 +1,4 @@
|
||||
export const config = {
|
||||
project: "server-only",
|
||||
triggerDirectories: ["./trigger"],
|
||||
};
|
||||
@@ -0,0 +1,9 @@
|
||||
import "server-only";
|
||||
import { task } from "@trigger.dev/sdk/v3";
|
||||
|
||||
export const helloWorldTask = task({
|
||||
id: "hello-world",
|
||||
run: async (payload) => {
|
||||
console.log("Hello, World!", payload);
|
||||
},
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,114 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { log } from "@clack/prompts";
|
||||
import { Metafile } from "esbuild";
|
||||
import { join } from "node:path";
|
||||
import terminalLink from "terminal-link";
|
||||
|
||||
import { SkipLoggingError } from "../src/cli/common.js";
|
||||
import {
|
||||
copyAdditionalFiles,
|
||||
resolveDependencies,
|
||||
resolveRequiredDependencies,
|
||||
} from "../src/commands/deploy.js";
|
||||
import { ReadConfigResult } from "../src/utilities/configFiles.js";
|
||||
import { writeJSONFile } from "../src/utilities/fileSystem.js";
|
||||
import { PackageManager } from "../src/utilities/getUserPackageManager.js";
|
||||
import { JavascriptProject } from "../src/utilities/javascriptProject.js";
|
||||
import { logger } from "../src/utilities/logger.js";
|
||||
|
||||
type HandleDependenciesOptions = {
|
||||
entryPointMetaOutput: Metafile["outputs"]["out/stdin.js"];
|
||||
metaOutput: Metafile["outputs"]["out/stdin.js"];
|
||||
packageManager: PackageManager;
|
||||
resolvedConfig: ReadConfigResult;
|
||||
tempDir: string;
|
||||
};
|
||||
|
||||
class JavascriptProjectLocal extends JavascriptProject {
|
||||
constructor(
|
||||
projectPath: string,
|
||||
private overridenPackageManager: PackageManager
|
||||
) {
|
||||
super(projectPath);
|
||||
}
|
||||
|
||||
async getPackageManager(): Promise<PackageManager> {
|
||||
return Promise.resolve(this.overridenPackageManager);
|
||||
}
|
||||
}
|
||||
|
||||
export async function handleDependencies(options: HandleDependenciesOptions) {
|
||||
if (options.resolvedConfig.status === "error") {
|
||||
throw new Error("cannot resolve config");
|
||||
}
|
||||
const {
|
||||
entryPointMetaOutput,
|
||||
metaOutput,
|
||||
packageManager,
|
||||
resolvedConfig: { config },
|
||||
tempDir,
|
||||
} = options;
|
||||
|
||||
// COPIED FROM compileProject()
|
||||
logger.debug("Getting the imports for the worker and entryPoint builds", {
|
||||
workerImports: metaOutput.imports,
|
||||
entryPointImports: entryPointMetaOutput.imports,
|
||||
});
|
||||
|
||||
// Get all the required dependencies from the metaOutputs and save them to /tmp/dir/package.json
|
||||
const allImports = [...metaOutput.imports, ...entryPointMetaOutput.imports];
|
||||
|
||||
// const javascriptProject = new JavascriptProject(config.projectDir);
|
||||
const javascriptProject = new JavascriptProjectLocal(config.projectDir, packageManager);
|
||||
|
||||
const dependencies = await resolveRequiredDependencies(allImports, config, javascriptProject);
|
||||
|
||||
logger.debug("gatherRequiredDependencies()", { dependencies });
|
||||
|
||||
const packageJsonContents = {
|
||||
name: "trigger-worker",
|
||||
version: "0.0.0",
|
||||
description: "",
|
||||
dependencies,
|
||||
scripts: {
|
||||
...javascriptProject.scripts,
|
||||
},
|
||||
};
|
||||
|
||||
// span.setAttributes({
|
||||
// ...flattenAttributes(packageJsonContents, "packageJson.contents"),
|
||||
// });
|
||||
|
||||
await writeJSONFile(join(tempDir, "package.json"), packageJsonContents);
|
||||
|
||||
const copyResult = await copyAdditionalFiles(config, tempDir);
|
||||
|
||||
if (!copyResult.ok) {
|
||||
// compileSpinner.stop("Project built with warnings");
|
||||
|
||||
log.warn(
|
||||
`No additionalFiles matches for:\n\n${copyResult.noMatches
|
||||
.map((glob) => `- "${glob}"`)
|
||||
.join("\n")}\n\nIf this is unexpected you should check your ${terminalLink(
|
||||
"glob patterns",
|
||||
"https://github.com/isaacs/node-glob?tab=readme-ov-file#glob-primer"
|
||||
)} are valid.`
|
||||
);
|
||||
}
|
||||
// } else {
|
||||
// compileSpinner.stop("Project built successfully");
|
||||
// }
|
||||
|
||||
const resolvingDependenciesResult = await resolveDependencies(
|
||||
tempDir,
|
||||
packageJsonContents,
|
||||
config
|
||||
);
|
||||
|
||||
if (!resolvingDependenciesResult) {
|
||||
throw new SkipLoggingError("Failed to resolve dependencies");
|
||||
}
|
||||
|
||||
return { dependencies };
|
||||
}
|
||||
@@ -0,0 +1,343 @@
|
||||
import { execa, execaNode } from "execa";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { mkdir, rename, rm } from "node:fs/promises";
|
||||
import { join, resolve } from "node:path";
|
||||
|
||||
import { typecheckProject } from "../src/commands/deploy";
|
||||
import { readConfig, ReadConfigFileResult } from "../src/utilities/configFiles";
|
||||
import { PackageManager } from "../src/utilities/getUserPackageManager";
|
||||
import { logger } from "../src/utilities/logger";
|
||||
import { compile } from "./compile";
|
||||
import { createContainerFile } from "./createContainerFile";
|
||||
import { createDeployHash } from "./createDeployHash";
|
||||
import { handleDependencies } from "./handleDependencies";
|
||||
import { Loglevel, LogLevelSchema, PackageManagerSchema } from "./schemas";
|
||||
import allTestCases from "./testCases.json";
|
||||
|
||||
type TestCase = {
|
||||
name: string;
|
||||
skipTypecheck?: boolean;
|
||||
wantConfigNotFoundError?: boolean;
|
||||
wantBadConfigError?: boolean;
|
||||
wantCompilationError?: boolean;
|
||||
wantWorkerError?: boolean;
|
||||
wantDependenciesError?: boolean;
|
||||
wantInstallationError?: boolean;
|
||||
};
|
||||
|
||||
const testCases: TestCase[] = process.env.MOD
|
||||
? allTestCases.filter(({ name }) => process.env.MOD === name)
|
||||
: allTestCases;
|
||||
|
||||
let logLevel: Loglevel = "log";
|
||||
let packageManager: PackageManager = "npm";
|
||||
|
||||
try {
|
||||
logLevel = LogLevelSchema.parse(process.env.LOG);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.log("Using default log level 'log'");
|
||||
}
|
||||
|
||||
logger.loggerLevel = logLevel;
|
||||
|
||||
try {
|
||||
packageManager = PackageManagerSchema.parse(process.env.PM);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
console.log("Using default package manager 'npm'");
|
||||
}
|
||||
|
||||
if (testCases.length > 0) {
|
||||
console.log(`Using ${packageManager}`);
|
||||
|
||||
describe.each(testCases)(
|
||||
"fixture $name",
|
||||
async ({
|
||||
name,
|
||||
skipTypecheck,
|
||||
wantConfigNotFoundError,
|
||||
wantBadConfigError,
|
||||
wantCompilationError,
|
||||
wantWorkerError,
|
||||
wantDependenciesError,
|
||||
wantInstallationError,
|
||||
}: TestCase) => {
|
||||
const fixtureDir = resolve(join(process.cwd(), "e2e/fixtures", name));
|
||||
|
||||
beforeAll(async () => {
|
||||
await rm(resolve(join(fixtureDir, ".trigger")), { force: true, recursive: true });
|
||||
await rm(resolve(join(fixtureDir, "node_modules")), { force: true, recursive: true });
|
||||
if (packageManager === "npm") {
|
||||
// `npm ci` & `npm install` will update an existing yarn.lock
|
||||
try {
|
||||
await rename(
|
||||
resolve(join(fixtureDir, "yarn.lock")),
|
||||
resolve(join(fixtureDir, "yarn.lock.copy"))
|
||||
);
|
||||
} catch (e) {
|
||||
await rename(
|
||||
resolve(join(fixtureDir, "yarn.lock.copy")),
|
||||
resolve(join(fixtureDir, "yarn.lock"))
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
if (packageManager === "npm") {
|
||||
try {
|
||||
await rename(
|
||||
resolve(join(fixtureDir, "yarn.lock.copy")),
|
||||
resolve(join(fixtureDir, "yarn.lock"))
|
||||
);
|
||||
} catch {}
|
||||
}
|
||||
});
|
||||
|
||||
test(
|
||||
"installs",
|
||||
async () => {
|
||||
await expect(
|
||||
(async () => {
|
||||
if (["pnpm", "yarn"].includes(packageManager)) {
|
||||
const buffer = readFileSync(resolve(join(fixtureDir, "package.json")), "utf8");
|
||||
const pkgJSON = JSON.parse(buffer.toString());
|
||||
const version = pkgJSON.engines[packageManager];
|
||||
console.log(
|
||||
`Detected ${packageManager}@${version} from package.json 'engines' field`
|
||||
);
|
||||
const { stdout, stderr } = await execa(
|
||||
"corepack",
|
||||
["use", `${packageManager}@${version}`],
|
||||
{
|
||||
cwd: fixtureDir,
|
||||
}
|
||||
);
|
||||
console.log(stdout);
|
||||
if (stderr) console.error(stderr);
|
||||
} else {
|
||||
const { stdout, stderr } = await execa(
|
||||
packageManager,
|
||||
installArgs(packageManager),
|
||||
{
|
||||
cwd: fixtureDir,
|
||||
}
|
||||
);
|
||||
console.log(stdout);
|
||||
if (stderr) console.error(stderr);
|
||||
}
|
||||
})()
|
||||
).resolves.not.toThrowError();
|
||||
},
|
||||
{ timeout: 60_000 }
|
||||
);
|
||||
|
||||
test(
|
||||
wantConfigNotFoundError || wantBadConfigError
|
||||
? "does not resolve config"
|
||||
: "resolves config",
|
||||
async () => {
|
||||
const expectation = expect(
|
||||
(async () => {
|
||||
global.resolvedConfig = await readConfig(fixtureDir, { cwd: fixtureDir });
|
||||
})()
|
||||
);
|
||||
if (wantConfigNotFoundError) {
|
||||
await expectation.rejects.toThrowError();
|
||||
} else {
|
||||
await expectation.resolves.not.toThrowError();
|
||||
}
|
||||
|
||||
if (wantBadConfigError) {
|
||||
expect(global.resolvedConfig).toBe("error");
|
||||
} else {
|
||||
expect(global.resolvedConfig).not.toBe("error");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
describe.skipIf(wantConfigNotFoundError || wantBadConfigError)("with resolved config", () => {
|
||||
beforeAll(async () => {
|
||||
global.tempDir = await mkdir(
|
||||
join((global.resolvedConfig as ReadConfigFileResult).config.projectDir, ".trigger"),
|
||||
{ recursive: true }
|
||||
);
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
delete global.tempDir;
|
||||
delete global.resolvedConfig;
|
||||
});
|
||||
|
||||
test.skipIf(skipTypecheck).concurrent("typechecks", async () => {
|
||||
await expect(
|
||||
(async () =>
|
||||
await typecheckProject((global.resolvedConfig as ReadConfigFileResult).config))()
|
||||
).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
test.concurrent(
|
||||
wantCompilationError ? "does not compile" : "compiles",
|
||||
async () => {
|
||||
const expectation = expect(
|
||||
(async () => {
|
||||
const {
|
||||
workerMetaOutput,
|
||||
workerOutputFile,
|
||||
entryPointMetaOutput,
|
||||
entryPointOutputFile,
|
||||
} = await compile({
|
||||
resolvedConfig: global.resolvedConfig!,
|
||||
tempDir: global.tempDir!,
|
||||
});
|
||||
global.entryPointMetaOutput = entryPointMetaOutput;
|
||||
global.entryPointOutputFile = entryPointOutputFile;
|
||||
global.workerMetaOutput = workerMetaOutput;
|
||||
global.workerOutputFile = workerOutputFile;
|
||||
})()
|
||||
);
|
||||
|
||||
if (wantCompilationError) {
|
||||
await expectation.rejects.toThrowError();
|
||||
} else {
|
||||
await expectation.resolves.not.toThrowError();
|
||||
}
|
||||
},
|
||||
{ timeout: 60_000 }
|
||||
);
|
||||
|
||||
describe.skipIf(wantCompilationError)("with successful compilation", () => {
|
||||
afterAll(() => {
|
||||
delete global.entryPointMetaOutput;
|
||||
delete global.entryPointOutputFile;
|
||||
delete global.workerMetaOutput;
|
||||
delete global.workerOutputFile;
|
||||
});
|
||||
|
||||
test(
|
||||
wantDependenciesError ? "does not resolve dependencies" : "resolves dependencies",
|
||||
async () => {
|
||||
const expectation = expect(
|
||||
(async () => {
|
||||
const { dependencies } = await handleDependencies({
|
||||
entryPointMetaOutput: global.entryPointMetaOutput!,
|
||||
metaOutput: global.workerMetaOutput!,
|
||||
resolvedConfig: global.resolvedConfig!,
|
||||
tempDir: global.tempDir!,
|
||||
packageManager,
|
||||
});
|
||||
global.dependencies = dependencies;
|
||||
})()
|
||||
);
|
||||
|
||||
if (wantDependenciesError) {
|
||||
await expectation.rejects.toThrowError();
|
||||
} else {
|
||||
await expectation.resolves.not.toThrowError();
|
||||
}
|
||||
},
|
||||
{ timeout: 120_000 }
|
||||
);
|
||||
|
||||
describe.skipIf(wantDependenciesError)("with resolved dependencies", () => {
|
||||
afterAll(() => {
|
||||
delete global.dependencies;
|
||||
});
|
||||
|
||||
test.concurrent("copies postinstall command into Containerfile.prod", async () => {
|
||||
await expect(
|
||||
(async () => {
|
||||
await createContainerFile({
|
||||
resolvedConfig: global.resolvedConfig!,
|
||||
tempDir: global.tempDir!,
|
||||
});
|
||||
})()
|
||||
).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
test.concurrent("creates deploy hash", async () => {
|
||||
await expect(
|
||||
(async () => {
|
||||
await createDeployHash({
|
||||
dependencies: global.dependencies!,
|
||||
entryPointOutputFile: global.entryPointOutputFile!,
|
||||
workerOutputFile: global.workerOutputFile!,
|
||||
});
|
||||
})()
|
||||
).resolves.not.toThrowError();
|
||||
});
|
||||
|
||||
describe("with Containerfile ready", () => {
|
||||
test(
|
||||
"installs dependencies",
|
||||
async () => {
|
||||
const expectation = expect(
|
||||
(async () => {
|
||||
const { stdout, stderr } = await execa(
|
||||
"npm",
|
||||
["ci", "--no-audit", "--no-fund"],
|
||||
{
|
||||
cwd: resolve(join(fixtureDir, ".trigger")),
|
||||
}
|
||||
);
|
||||
console.log(stdout);
|
||||
if (stderr) console.error(stderr);
|
||||
})()
|
||||
);
|
||||
|
||||
if (wantInstallationError) {
|
||||
await expectation.rejects.toThrowError();
|
||||
} else {
|
||||
await expectation.resolves.not.toThrowError();
|
||||
}
|
||||
},
|
||||
{ timeout: 60_000 }
|
||||
);
|
||||
|
||||
test(
|
||||
wantWorkerError ? "'node worker.js' fails" : "'node worker.js' succeeds",
|
||||
async () => {
|
||||
const expectation = expect(
|
||||
(async () => {
|
||||
const { stdout, stderr } = await execaNode("worker.js", {
|
||||
cwd: resolve(join(fixtureDir, ".trigger")),
|
||||
});
|
||||
console.log(stdout);
|
||||
if (stderr) console.error(stderr);
|
||||
})()
|
||||
);
|
||||
|
||||
if (wantWorkerError) {
|
||||
await expectation.rejects.toThrowError();
|
||||
} else {
|
||||
await expectation.resolves.not.toThrowError();
|
||||
}
|
||||
},
|
||||
{ timeout: 60_000 }
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
} else if (process.env.MOD) {
|
||||
throw new Error(`Unknown fixture '${process.env.MOD}'`);
|
||||
} else {
|
||||
throw new Error("Nothing to test");
|
||||
}
|
||||
|
||||
function installArgs(packageManager: string) {
|
||||
switch (packageManager) {
|
||||
case "bun":
|
||||
return ["install", "--frozen-lockfile"];
|
||||
case "pnpm":
|
||||
case "yarn":
|
||||
throw new Error("pnpm and yarn must install using `corepack use`");
|
||||
case "npm":
|
||||
return ["ci", "--no-audit"];
|
||||
default:
|
||||
throw new Error(`Unknown package manager '${packageManager}'`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { z } from "zod";
|
||||
|
||||
export const LogLevelSchema = z
|
||||
.enum(["debug", "info", "log", "warn", "error", "none"])
|
||||
.default("log");
|
||||
export type Loglevel = z.infer<typeof LogLevelSchema>;
|
||||
export const PackageManagerSchema = z.enum(["npm", "pnpm", "yarn"]).default("npm");
|
||||
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"name": "no-config",
|
||||
"wantConfigNotFoundError": true
|
||||
},
|
||||
{
|
||||
"name": "server-only",
|
||||
"skipTypecheck": true
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,9 @@
|
||||
import { configDefaults, defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
setupFiles: ["e2e/vitest.d.ts"],
|
||||
globals: true,
|
||||
exclude: [...configDefaults.exclude, "src/**/*"],
|
||||
},
|
||||
});
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
import { Metafile, OutputFile } from "esbuild";
|
||||
|
||||
import { ReadConfigResult } from "../src/utilities/configFiles";
|
||||
|
||||
declare global {
|
||||
var dependencies: { [k: string]: string } | undefined;
|
||||
var entryPointMetaOutput: Metafile["outputs"]["out/stdin.js"] | undefined;
|
||||
var entryPointOutputFile: OutputFile | undefined;
|
||||
var resolvedConfig: ReadConfigResult | undefined;
|
||||
var tempDir: string | undefined;
|
||||
var workerMetaOutput: Metafile["outputs"]["out/stdin.js"] | undefined;
|
||||
var workerOutputFile: OutputFile | undefined;
|
||||
}
|
||||
@@ -53,7 +53,7 @@
|
||||
"tsup": "^8.0.1",
|
||||
"type-fest": "^3.6.0",
|
||||
"typescript": "^5.3.3",
|
||||
"vitest": "^0.34.4",
|
||||
"vitest": "^1.6.0",
|
||||
"xdg-app-paths": "^8.3.0"
|
||||
},
|
||||
"scripts": {
|
||||
@@ -68,7 +68,8 @@
|
||||
"dev:test": "nodemon -w src/Containerfile.prod -x npm run build:prod-containerfile",
|
||||
"clean": "rimraf dist",
|
||||
"start": "node dist/index.js",
|
||||
"test": "vitest"
|
||||
"test": "vitest",
|
||||
"test:e2e": "vitest --run -c e2e/vite.config.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@anatine/esbuild-decorators": "^0.2.19",
|
||||
@@ -131,4 +132,4 @@
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1105,7 +1105,7 @@ async function compileProject(
|
||||
return await tracer.startActiveSpan("compileProject", async (span) => {
|
||||
try {
|
||||
if (!options.skipTypecheck) {
|
||||
const typecheck = await typecheckProject(config, options);
|
||||
const typecheck = await typecheckProject(config);
|
||||
|
||||
if (!typecheck) {
|
||||
throw new Error("Typecheck failed, aborting deployment");
|
||||
@@ -1353,8 +1353,7 @@ async function compileProject(
|
||||
const resolvingDependenciesResult = await resolveDependencies(
|
||||
tempDir,
|
||||
packageJsonContents,
|
||||
config,
|
||||
options
|
||||
config
|
||||
);
|
||||
|
||||
if (!resolvingDependenciesResult) {
|
||||
@@ -1491,11 +1490,10 @@ async function resolveEnvironmentVariables(
|
||||
// in the `.trigger/cache` directory. If the package-lock.json is found, we'll write it to the project directory
|
||||
// If the package-lock.json is not found, we will run `npm install --package-lock-only` and then write the package-lock.json
|
||||
// to the project directory, and finally we'll write the digest to the `.trigger/cache` directory with the contents of the package-lock.json
|
||||
async function resolveDependencies(
|
||||
export async function resolveDependencies(
|
||||
projectDir: string,
|
||||
packageJsonContents: any,
|
||||
config: ResolvedConfig,
|
||||
options: DeployCommandOptions
|
||||
config: ResolvedConfig
|
||||
) {
|
||||
return await tracer.startActiveSpan("resolveDependencies", async (span) => {
|
||||
const resolvingDepsSpinner = spinner();
|
||||
@@ -1633,7 +1631,7 @@ async function resolveDependencies(
|
||||
});
|
||||
}
|
||||
|
||||
async function typecheckProject(config: ResolvedConfig, options: DeployCommandOptions) {
|
||||
export async function typecheckProject(config: ResolvedConfig) {
|
||||
return await tracer.startActiveSpan("typecheckProject", async (span) => {
|
||||
try {
|
||||
const typecheckSpinner = spinner();
|
||||
@@ -1686,7 +1684,7 @@ async function typecheckProject(config: ResolvedConfig, options: DeployCommandOp
|
||||
|
||||
// Returns the dependencies that are required by the output that are found in output and the CLI package dependencies
|
||||
// Returns the dependency names and the version to use (taken from the CLI deps package.json)
|
||||
async function resolveRequiredDependencies(
|
||||
export async function resolveRequiredDependencies(
|
||||
imports: Metafile["outputs"][string]["imports"],
|
||||
config: ResolvedConfig,
|
||||
project: JavascriptProject
|
||||
@@ -1814,7 +1812,7 @@ type AdditionalFilesReturn =
|
||||
noMatches: string[];
|
||||
};
|
||||
|
||||
async function copyAdditionalFiles(
|
||||
export async function copyAdditionalFiles(
|
||||
config: ResolvedConfig,
|
||||
tempDir: string
|
||||
): Promise<AdditionalFilesReturn> {
|
||||
|
||||
@@ -115,15 +115,18 @@ async function findFilePath(dir: string, fileName: string): Promise<string | und
|
||||
export type ReadConfigOptions = {
|
||||
projectRef?: string;
|
||||
configFile?: string;
|
||||
cwd?: string;
|
||||
};
|
||||
|
||||
export type ReadConfigFileResult = {
|
||||
status: "file";
|
||||
config: ResolvedConfig;
|
||||
path: string;
|
||||
module?: any;
|
||||
};
|
||||
|
||||
export type ReadConfigResult =
|
||||
| {
|
||||
status: "file";
|
||||
config: ResolvedConfig;
|
||||
path: string;
|
||||
module?: any;
|
||||
}
|
||||
| ReadConfigFileResult
|
||||
| {
|
||||
status: "in-memory";
|
||||
config: ResolvedConfig;
|
||||
@@ -137,7 +140,7 @@ export async function readConfig(
|
||||
dir: string,
|
||||
options?: ReadConfigOptions
|
||||
): Promise<ReadConfigResult> {
|
||||
const absoluteDir = path.resolve(process.cwd(), dir);
|
||||
const absoluteDir = path.resolve(options?.cwd || process.cwd(), dir);
|
||||
|
||||
const configPath = await getConfigPath(dir, options?.configFile);
|
||||
|
||||
@@ -226,7 +229,7 @@ export async function resolveConfig(path: string, config: Config): Promise<Resol
|
||||
config.triggerDirectories = await findTriggerDirectories(path);
|
||||
}
|
||||
|
||||
config.triggerDirectories = resolveTriggerDirectories(config.triggerDirectories);
|
||||
config.triggerDirectories = resolveTriggerDirectories(path, config.triggerDirectories);
|
||||
|
||||
logger.debug("Resolved trigger directories", { triggerDirectories: config.triggerDirectories });
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ async function gatherTaskFilesFromDir(
|
||||
return taskFiles;
|
||||
}
|
||||
|
||||
export function resolveTriggerDirectories(dirs: string[]): string[] {
|
||||
return dirs.map((dir) => resolve(dir));
|
||||
export function resolveTriggerDirectories(projectDir: string, dirs: string[]): string[] {
|
||||
return dirs.map((dir) => resolve(projectDir, dir));
|
||||
}
|
||||
|
||||
const IGNORED_DIRS = ["node_modules", ".git", "dist", "build"];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// See: https://www.totaltypescript.com/tsconfig-cheat-sheet
|
||||
{
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx"],
|
||||
"include": ["./src/**/*.ts", "./src/**/*.tsx", "./e2e/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
@@ -30,5 +30,5 @@
|
||||
"@trigger.dev/core-apps/*": ["../core-apps/src/*"]
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
"exclude": ["node_modules", "./e2e/fixtures"]
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { defineConfig } from 'vitest/config';
|
||||
import { configDefaults, defineConfig } from "vitest/config";
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
globals: true
|
||||
globals: true,
|
||||
exclude: [...configDefaults.exclude, "e2e/**/*"],
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
Generated
+155
-3
@@ -1707,8 +1707,8 @@ importers:
|
||||
specifier: ^3.6.0
|
||||
version: 3.13.0
|
||||
vitest:
|
||||
specifier: ^0.34.4
|
||||
version: 0.34.4
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0(@types/node@18.17.1)
|
||||
xdg-app-paths:
|
||||
specifier: ^8.3.0
|
||||
version: 8.3.0
|
||||
@@ -17063,6 +17063,14 @@ packages:
|
||||
chai: 4.4.1
|
||||
dev: true
|
||||
|
||||
/@vitest/expect@1.6.0:
|
||||
resolution: {integrity: sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==}
|
||||
dependencies:
|
||||
'@vitest/spy': 1.6.0
|
||||
'@vitest/utils': 1.6.0
|
||||
chai: 4.4.1
|
||||
dev: true
|
||||
|
||||
/@vitest/runner@0.28.5:
|
||||
resolution: {integrity: sha512-NKkHtLB+FGjpp5KmneQjTcPLWPTDfB7ie+MmF1PnUBf/tGe2OjGxWyB62ySYZ25EYp9krR5Bw0YPLS/VWh1QiA==}
|
||||
dependencies:
|
||||
@@ -17086,6 +17094,14 @@ packages:
|
||||
pathe: 1.1.1
|
||||
dev: true
|
||||
|
||||
/@vitest/runner@1.6.0:
|
||||
resolution: {integrity: sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==}
|
||||
dependencies:
|
||||
'@vitest/utils': 1.6.0
|
||||
p-limit: 5.0.0
|
||||
pathe: 1.1.1
|
||||
dev: true
|
||||
|
||||
/@vitest/snapshot@0.34.4:
|
||||
resolution: {integrity: sha512-GCsh4coc3YUSL/o+BPUo7lHQbzpdttTxL6f4q0jRx2qVGoYz/cyTRDJHbnwks6TILi6560bVWoBpYC10PuTLHw==}
|
||||
dependencies:
|
||||
@@ -17101,6 +17117,14 @@ packages:
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/@vitest/snapshot@1.6.0:
|
||||
resolution: {integrity: sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==}
|
||||
dependencies:
|
||||
magic-string: 0.30.8
|
||||
pathe: 1.1.1
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/@vitest/spy@0.28.5:
|
||||
resolution: {integrity: sha512-7if6rsHQr9zbmvxN7h+gGh2L9eIIErgf8nSKYDlg07HHimCxp4H6I/X/DPXktVPPLQfiZ1Cw2cbDIx9fSqDjGw==}
|
||||
dependencies:
|
||||
@@ -17118,6 +17142,12 @@ packages:
|
||||
tinyspy: 2.2.1
|
||||
dev: true
|
||||
|
||||
/@vitest/spy@1.6.0:
|
||||
resolution: {integrity: sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==}
|
||||
dependencies:
|
||||
tinyspy: 2.2.1
|
||||
dev: true
|
||||
|
||||
/@vitest/utils@0.28.5:
|
||||
resolution: {integrity: sha512-UyZdYwdULlOa4LTUSwZ+Paz7nBHGTT72jKwdFSV4IjHF1xsokp+CabMdhjvVhYwkLfO88ylJT46YMilnkSARZA==}
|
||||
dependencies:
|
||||
@@ -17144,6 +17174,15 @@ packages:
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/@vitest/utils@1.6.0:
|
||||
resolution: {integrity: sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==}
|
||||
dependencies:
|
||||
diff-sequences: 29.6.3
|
||||
estree-walker: 3.0.3
|
||||
loupe: 2.3.7
|
||||
pretty-format: 29.7.0
|
||||
dev: true
|
||||
|
||||
/@web3-storage/multipart-parser@1.0.0:
|
||||
resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==}
|
||||
|
||||
@@ -18793,7 +18832,7 @@ packages:
|
||||
check-error: 1.0.3
|
||||
deep-eql: 4.1.3
|
||||
get-func-name: 2.0.2
|
||||
loupe: 2.3.6
|
||||
loupe: 2.3.7
|
||||
pathval: 1.1.1
|
||||
type-detect: 4.0.8
|
||||
dev: true
|
||||
@@ -35212,6 +35251,27 @@ packages:
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vite-node@1.6.0(@types/node@18.17.1):
|
||||
resolution: {integrity: sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
vite: 5.2.7(@types/node@18.17.1)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vite-tsconfig-paths@4.0.5:
|
||||
resolution: {integrity: sha512-/L/eHwySFYjwxoYt1WRJniuK/jPv+WGwgRGBYx3leciR5wBeqntQpUE6Js6+TJemChc+ter7fDBKieyEWDx4yQ==}
|
||||
dependencies:
|
||||
@@ -35433,6 +35493,42 @@ packages:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vite@5.2.7(@types/node@18.17.1):
|
||||
resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
less: '*'
|
||||
lightningcss: ^1.21.0
|
||||
sass: '*'
|
||||
stylus: '*'
|
||||
sugarss: '*'
|
||||
terser: ^5.4.0
|
||||
peerDependenciesMeta:
|
||||
'@types/node':
|
||||
optional: true
|
||||
less:
|
||||
optional: true
|
||||
lightningcss:
|
||||
optional: true
|
||||
sass:
|
||||
optional: true
|
||||
stylus:
|
||||
optional: true
|
||||
sugarss:
|
||||
optional: true
|
||||
terser:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 18.17.1
|
||||
esbuild: 0.20.2
|
||||
postcss: 8.4.38
|
||||
rollup: 4.13.2
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
dev: true
|
||||
|
||||
/vitefu@0.2.4(vite@4.4.9):
|
||||
resolution: {integrity: sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==}
|
||||
peerDependencies:
|
||||
@@ -35619,6 +35715,62 @@ packages:
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vitest@1.6.0(@types/node@18.17.1):
|
||||
resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==}
|
||||
engines: {node: ^18.0.0 || >=20.0.0}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@edge-runtime/vm': '*'
|
||||
'@types/node': ^18.0.0 || >=20.0.0
|
||||
'@vitest/browser': 1.6.0
|
||||
'@vitest/ui': 1.6.0
|
||||
happy-dom: '*'
|
||||
jsdom: '*'
|
||||
peerDependenciesMeta:
|
||||
'@edge-runtime/vm':
|
||||
optional: true
|
||||
'@types/node':
|
||||
optional: true
|
||||
'@vitest/browser':
|
||||
optional: true
|
||||
'@vitest/ui':
|
||||
optional: true
|
||||
happy-dom:
|
||||
optional: true
|
||||
jsdom:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@types/node': 18.17.1
|
||||
'@vitest/expect': 1.6.0
|
||||
'@vitest/runner': 1.6.0
|
||||
'@vitest/snapshot': 1.6.0
|
||||
'@vitest/spy': 1.6.0
|
||||
'@vitest/utils': 1.6.0
|
||||
acorn-walk: 8.3.2
|
||||
chai: 4.4.1
|
||||
debug: 4.3.4(supports-color@8.1.1)
|
||||
execa: 8.0.1
|
||||
local-pkg: 0.5.0
|
||||
magic-string: 0.30.8
|
||||
pathe: 1.1.1
|
||||
picocolors: 1.0.0
|
||||
std-env: 3.7.0
|
||||
strip-literal: 2.1.0
|
||||
tinybench: 2.6.0
|
||||
tinypool: 0.8.3
|
||||
vite: 5.2.7(@types/node@18.17.1)
|
||||
vite-node: 1.6.0(@types/node@18.17.1)
|
||||
why-is-node-running: 2.2.2
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
- sass
|
||||
- stylus
|
||||
- sugarss
|
||||
- supports-color
|
||||
- terser
|
||||
dev: true
|
||||
|
||||
/vscode-oniguruma@1.7.0:
|
||||
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ packages:
|
||||
- "docs"
|
||||
- "perf"
|
||||
- "runtime_tests"
|
||||
- "!packages/cli-v3/e2e/**"
|
||||
|
||||
Reference in New Issue
Block a user