v3: new build system fixes (#1278)

* Support custom config file names & paths

* Fix entry point paths on windows

* Support custom conditions

Add support for custom conditions (for bundling and running), to support being able to import `ai/rsc` with the “react-server” condition.

- Fixed an issue where symlinking unresolvable externals after rebuilding caused the build to hang
- Fixed an issue with external not working with subpath exports (e.g. “ai” would not match “ai/rsc”)
- Protect better against build extensions breaking builds

* Add changeset

* Fix passing CLI process.env down to the task processes

* Remove unused import

* reviving the e2e CLI tests

* Another attempt at fixing windows

* yet another windows attempt (yawa)

* Output index child stdout and stderr (yawa)

* normalize import paths for windows

* Added some logging (yawa)

* normalize the loader path as well

* Added some logging to figure out why the entry points aren’t being found on windows

* Fix for entry point detection on windows

* Normalize runner import loader path

* Normalize import paths in dev and make sure rewritten build manifest paths are correct on windows as well

* Various cleanup after windows fixes

* Remove the webapp e2e for now

* Add node10 type resolution support for subpath exports (still does not actually import in Node 10 or Browserify/Parcel)

https://github.com/andrewbranch/example-subpath-exports-ts-compat

* init using templates again but downloaded from the repo this time

* Adding init schedule example

* Support for js init

* init now working with js

* Fix issues with links in terminals that don’t support them. Also skip update check of version starts with 0.0.0
This commit is contained in:
Eric Allam
2024-09-05 12:56:23 +01:00
committed by GitHub
parent 5231381717
commit f040417440
178 changed files with 4897 additions and 26523 deletions
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Fix entry point paths on windows
+5
View File
@@ -0,0 +1,5 @@
---
"trigger.dev": patch
---
Support custom config file names & paths
+6
View File
@@ -0,0 +1,6 @@
---
"trigger.dev": patch
"@trigger.dev/core": patch
---
Support for custom conditions
+5 -67
View File
@@ -9,12 +9,13 @@ on:
type: string
jobs:
cli-v3:
name: "🧪 CLI v3 tests"
name: "🧪 CLI v3 tests (${{ matrix.os }} - ${{ matrix.package-manager }})"
if: inputs.package == 'cli-v3' || inputs.package == ''
runs-on: buildjet-8vcpu-ubuntu-2204
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [buildjet-8vcpu-ubuntu-2204, windows-latest]
package-manager: ["npm", "pnpm", "yarn"]
steps:
- name: ⬇️ Checkout repo
@@ -46,71 +47,8 @@ jobs:
run: corepack enable
- name: Run E2E Tests
shell: bash
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
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME || vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN || vars.DOCKERHUB_TOKEN }}
LOG=debug PM=${{ matrix.package-manager }} pnpm --filter trigger.dev run test:e2e
- name: ⬇️ Checkout repo
uses: actions/checkout@v3
with:
fetch-depth: 0
submodules: recursive
- name: ⎔ Setup pnpm
uses: pnpm/action-setup@v4
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
- name: Install Playwright Browsers
run: npx playwright install --with-deps
- name: Run Playwright tests
run: |
# Setup environment variables
cp ./.env.example ./.env
cp ./references/nextjs-test/.env.example ./references/nextjs-test/.env.local
# Build packages
pnpm run build --filter @references/nextjs-test^...
cd apps/webapp && pnpm run build:server
cd ../..
pnpm --filter @trigger.dev/database generate
pnpm --filter @trigger.dev/otlp-importer generate
# Move trigger-cli bin to correct place
pnpm install --frozen-lockfile
# Execute tests
pnpm run docker
pnpm run db:migrate
pnpm run db:seed
pnpm run test:e2e
# Cleanup
pnpm run docker:stop
- name: Upload Playwright report
uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
+7 -7
View File
@@ -21,9 +21,15 @@ jobs:
uses: ./.github/workflows/unit-tests.yml
secrets: inherit
e2e:
uses: ./.github/workflows/e2e.yml
with:
package: cli-v3
secrets: inherit
preview-release:
name: Preview Release
needs: [typecheck, units]
needs: [typecheck, units, e2e]
if: |
github.repository == 'triggerdotdev/trigger.dev'
runs-on: buildjet-8vcpu-ubuntu-2204
@@ -52,9 +58,3 @@ jobs:
- name: ⚡ publish preview release
run: npx pkg-pr-new publish --no-template $(ls -d ./packages/*)
# e2e:
# uses: ./.github/workflows/e2e.yml
# with:
# package: webapp
# secrets: inherit
+4 -1
View File
@@ -29,4 +29,7 @@ jobs:
run: pnpm run generate
- name: 🔎 Type check
run: pnpm run typecheck --filter webapp
run: pnpm run typecheck
- name: 🔎 Check exports
run: pnpm run check-exports
+4 -2
View File
@@ -53,5 +53,7 @@ apps/**/public/build
/playwright/.cache/
.cosine
.trigger/
.tshy*
.trigger
.tshy*
.yarn
*.tsbuildinfo
+16
View File
@@ -29,6 +29,14 @@
"cwd": "${workspaceFolder}/references/job-catalog",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug V3 init CLI",
"command": "pnpm exec triggerdev init",
"cwd": "${workspaceFolder}/references/init-shell",
"sourceMaps": true
},
{
"type": "node-terminal",
"request": "launch",
@@ -76,6 +84,14 @@
"port": 9229,
"restart": true,
"skipFiles": ["<node_internals>/**"]
},
{
"type": "node-terminal",
"request": "launch",
"name": "Debug CLI e2e tests",
"command": "PM=yarn pnpm run test:e2e",
"cwd": "${workspaceFolder}/packages/cli-v3",
"sourceMaps": true
}
]
}
+2 -2
View File
@@ -71,12 +71,12 @@ import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "<project ref>",
build: {
externals: ["native-module"],
external: ["native-module"],
},
});
```
`externals` is an array of strings, where each string is the name of a dependency that should be made external. Glob expressions are also supported and use the [minimatch](https://github.com/isaacs/minimatch) matcher.
`external` is an array of strings, where each string is the name of a dependency that should be made external. Glob expressions are also supported and use the [minimatch](https://github.com/isaacs/minimatch) matcher.
### `additionalFiles`
+1
View File
@@ -28,6 +28,7 @@
"test": "turbo run test",
"test:dev": "turbo run test:dev",
"start": "turbo run start",
"check-exports": "turbo run check-exports",
"clean": "turbo run clean",
"clean:node_modules": "find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +",
"typecheck": "turbo run typecheck",
+23 -2
View File
@@ -33,12 +33,32 @@
"@triggerdotdev/source"
]
},
"typesVersions": {
"*": {
"extensions": [
"dist/commonjs/extensions/index.d.ts"
],
"extensions/core": [
"dist/commonjs/extensions/core.d.ts"
],
"extensions/prisma": [
"dist/commonjs/extensions/prisma.d.ts"
],
"extensions/audioWaveform": [
"dist/commonjs/extensions/audioWaveform.d.ts"
],
"extensions/typescript": [
"dist/commonjs/extensions/typescript.d.ts"
]
}
},
"scripts": {
"clean": "rimraf dist",
"build": "tshy && pnpm run update-version",
"dev": "tshy --watch",
"typecheck": "tsc --noEmit -p tsconfig.src.json",
"update-version": "tsx ../../scripts/updateVersion.ts"
"update-version": "tsx ../../scripts/updateVersion.ts",
"check-exports": "attw --pack ."
},
"dependencies": {
"@trigger.dev/core": "workspace:3.0.0-beta.56",
@@ -51,7 +71,8 @@
"tshy": "^3.0.2",
"typescript": "^5.5.4",
"tsx": "4.17.0",
"esbuild": "^0.23.0"
"esbuild": "^0.23.0",
"@arethetypeswrong/cli": "^0.15.4"
},
"engines": {
"node": ">=18.20.0"
File diff suppressed because one or more lines are too long
-222
View File
@@ -1,222 +0,0 @@
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, relative, resolve, sep } 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";
import { E2EJavascriptProject } from "./javascriptProject.js";
import { PackageManager } from "../src/utilities/getUserPackageManager.js";
type CompileOptions = {
outputMetafile?: string;
packageManager: PackageManager;
resolvedConfig: ReadConfigResult;
tempDir: string;
};
export async function compile(options: CompileOptions) {
if (options.resolvedConfig.status === "error") {
throw new Error("cannot resolve config");
}
const {
packageManager,
tempDir,
resolvedConfig: { config },
} = options;
const configPath =
options.resolvedConfig.status === "file" ? options.resolvedConfig.path : undefined;
const taskFiles = await gatherTaskFiles(config);
const workerFacade = readFileSync(resolve("./dist/workers/prod/worker-facade.js"), "utf-8");
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 e2eJsProject = new E2EJavascriptProject(config.projectDir, packageManager);
const directDependenciesMeta = await e2eJsProject.extractDirectDependenciesMeta();
const result = await build({
stdin: {
contents: workerContents,
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: resolve(config.projectDir, "out"),
footer: {
js: "process.exit();",
},
define: {
TRIGGER_API_URL: `"${config.triggerUrl}"`,
__PROJECT_CONFIG__: JSON.stringify(config),
},
plugins: [
mockServerOnlyPlugin(),
bundleDependenciesPlugin(
"workerFacade",
directDependenciesMeta,
config.dependenciesToBundle,
config.tsconfigPath
),
workerSetupImportConfigPlugin(configPath),
esbuildDecorators({
tsconfig: config.tsconfigPath,
tsx: true,
force: false,
}),
],
});
if (result.errors.length > 0) {
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"), "utf-8");
const entryPointResult = await build({
stdin: {
contents: entryPointContents,
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: resolve(config.projectDir, "out"),
define: {
__PROJECT_CONFIG__: JSON.stringify(config),
},
plugins: [
bundleDependenciesPlugin(
"entryPoint.ts",
directDependenciesMeta,
config.dependenciesToBundle,
config.tsconfigPath
),
],
});
if (entryPointResult.errors.length > 0) {
throw new Error("Build failed, aborting deployment");
}
if (options.outputMetafile) {
await writeJSONFile(
join(options.outputMetafile, "entry-point.json"),
entryPointResult.metafile
);
}
logger.debug(`Writing compiled files to ${tempDir}`);
// Get the metaOutput for the result build
const pathsToProjectDir = relative(
join(process.cwd(), "e2e", "fixtures"),
config.projectDir
).split(sep);
const metaOutput =
result.metafile!.outputs[
posix.join("e2e", "fixtures", ...pathsToProjectDir, "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("e2e", "fixtures", ...pathsToProjectDir, "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,
};
}
@@ -1,28 +0,0 @@
import { readFileSync } from "node:fs";
import { writeFile } from "node:fs/promises";
import { join, resolve } from "node:path";
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");
await writeFile(join(tempDir, "Containerfile"), containerFileContents);
}
-28
View File
@@ -1,28 +0,0 @@
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 { dependencies, 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 };
}
+282
View File
@@ -0,0 +1,282 @@
import { BuildManifest, WorkerManifest } from "@trigger.dev/core/v3/schemas";
import * as fs from "node:fs";
import { mkdir, rename, rm } from "node:fs/promises";
import * as path from "node:path";
import { rimraf } from "rimraf";
import { buildWorker, rewriteBuildManifestPaths } from "../src/build/buildWorker.js";
import { loadConfig } from "../src/config.js";
import { indexWorkerManifest } from "../src/indexing/indexWorkerManifest.js";
import { writeJSONFile } from "../src/utilities/fileSystem.js";
import { logger } from "../src/utilities/logger.js";
import { getTmpDir } from "../src/utilities/tempDirectories.js";
import { fixturesConfig, TestCase } from "./fixtures.js";
import { E2EOptions, E2EOptionsSchema } from "./schemas.js";
import { executeTestCaseRun, runTsc } from "./utils.js";
import { normalizeImportPath } from "../src/utilities/normalizeImportPath.js";
import { installFixtureDeps, LOCKFILES, PackageManager, parsePackageManager } from "./utils.js";
const TIMEOUT = 120_000;
interface E2EFixtureTest extends TestCase {
fixtureDir: string;
packageManager: PackageManager;
tempDir: string;
workspaceDir: string;
}
const testCases: TestCase[] = process.env.MOD
? fixturesConfig.filter(({ id }) => process.env.MOD === id)
: fixturesConfig;
let options: E2EOptions;
try {
options = E2EOptionsSchema.parse({
logLevel: process.env.LOG,
packageManager: process.env.PM,
});
} catch (e) {
options = {
logLevel: "log",
};
}
logger.loggerLevel = options.logLevel;
if (testCases.length === 0) {
if (process.env.MOD) {
throw new Error(`No test case found for ${process.env.MOD}`);
} else {
throw new Error("Nothing to test");
}
}
describe.concurrent("buildWorker", async () => {
beforeEach<E2EFixtureTest>(async ({ fixtureDir, skip, packageManager, workspaceDir }) => {
await rimraf(path.join(workspaceDir, "**/node_modules"), {
glob: true,
});
await rimraf(path.join(workspaceDir, ".yarn"), { glob: true });
if (
packageManager === "npm" &&
(fs.existsSync(path.resolve(path.join(workspaceDir, "yarn.lock"))) ||
fs.existsSync(path.resolve(path.join(workspaceDir, "yarn.lock.copy"))))
) {
// `npm ci` & `npm install` will update an existing yarn.lock
try {
await rename(
path.resolve(path.join(workspaceDir, "yarn.lock")),
path.resolve(path.join(workspaceDir, "yarn.lock.copy"))
);
} catch (e) {
await rename(
path.resolve(path.join(workspaceDir, "yarn.lock.copy")),
path.resolve(path.join(workspaceDir, "yarn.lock"))
);
}
}
if (
options.packageManager &&
!fs.existsSync(path.resolve(fixtureDir, LOCKFILES[options.packageManager]))
) {
skip();
}
await installFixtureDeps({ fixtureDir, packageManager, workspaceDir });
}, TIMEOUT);
afterEach<E2EFixtureTest>(async ({ packageManager, workspaceDir }) => {
if (packageManager === "npm") {
try {
await rename(
path.resolve(path.join(workspaceDir, "yarn.lock.copy")),
path.resolve(path.join(workspaceDir, "yarn.lock"))
);
} catch {}
}
vi.unstubAllEnvs();
});
for (let testCase of testCases) {
test.extend<E2EFixtureTest>({
...testCase,
fixtureDir: async ({ id }, use) =>
await use(path.resolve(path.join(process.cwd(), "e2e/fixtures", id))),
workspaceDir: async ({ fixtureDir, workspaceRelativeDir = "" }, use) =>
await use(path.resolve(path.join(fixtureDir, workspaceRelativeDir))),
packageManager: async ({ workspaceDir }, use) =>
await use(await parsePackageManager(options.packageManager, workspaceDir)),
tempDir: async ({ workspaceDir }, use) => {
const existingTempDir = path.resolve(path.join(workspaceDir, ".trigger"));
if (fs.existsSync(existingTempDir)) {
await rm(existingTempDir, { force: true, recursive: true });
}
await use(
(await mkdir(path.join(workspaceDir, ".trigger"), { recursive: true })) as string
);
},
})(
`fixture ${testCase.id}`,
{ timeout: TIMEOUT },
async ({
id,
tempDir,
tsconfig,
workspaceDir,
wantConfigInvalidError,
wantConfigNotFoundError,
wantBuildWorkerError,
wantIndexingError,
buildManifestMatcher,
workerManifestMatcher,
runs,
}) => {
let resolvedConfig: Awaited<ReturnType<typeof loadConfig>>;
const configExpect = expect(
(async () => {
resolvedConfig = await loadConfig({
cwd: workspaceDir,
});
})(),
wantConfigNotFoundError || wantConfigInvalidError
? "does not resolve config"
: "resolves config"
);
if (wantConfigNotFoundError) {
await configExpect.rejects.toThrowError();
return;
}
await configExpect.resolves.not.toThrowError();
if (wantConfigInvalidError) {
expect(resolvedConfig!).toBeUndefined();
return;
}
expect(resolvedConfig!).toBeTruthy();
if (tsconfig) {
const tscResult = await runTsc(workspaceDir, tsconfig);
expect(tscResult.success).toBe(true);
}
const destination = getTmpDir(workspaceDir, "build");
let buildManifest: BuildManifest;
const buildExpect = expect(
(async () => {
buildManifest = await buildWorker({
target: "deploy",
environment: "test",
destination: destination.path,
resolvedConfig: resolvedConfig!,
rewritePaths: false,
});
})(),
wantBuildWorkerError ? "does not build" : "builds"
);
if (wantBuildWorkerError) {
await buildExpect.rejects.toThrowError();
return;
}
await buildExpect.resolves.not.toThrowError();
if (buildManifestMatcher) {
expect(buildManifest!).toMatchObject(buildManifestMatcher);
} else {
expect(buildManifest!).toBeTruthy();
}
logger.debug("Build manifest", buildManifest!);
const rewrittenManifest = rewriteBuildManifestPaths(buildManifest!, destination.path);
expect(rewrittenManifest.loaderEntryPoint).toBe("/app/src/entryPoints/loader.mjs");
expect(rewrittenManifest.indexWorkerEntryPoint).toBe(
"/app/src/entryPoints/deploy-index-worker.mjs"
);
const stdout: string[] = [];
const stderr: string[] = [];
let workerManifest: WorkerManifest;
const indexExpect = expect(
(async () => {
workerManifest = await indexWorkerManifest({
runtime: buildManifest!.runtime,
indexWorkerPath: buildManifest!.indexWorkerEntryPoint,
buildManifestPath: path.join(destination.path, "build.json"),
nodeOptions: buildManifest!.loaderEntryPoint
? `--import=${normalizeImportPath(buildManifest!.loaderEntryPoint)}`
: undefined,
env: {},
otelHookExclude: buildManifest!.otelImportHook?.exclude,
otelHookInclude: buildManifest!.otelImportHook?.include,
handleStdout(data) {
stdout.push(data);
logger.debug("indexWorkerManifest handleStdout");
logger.debug(data);
},
handleStderr(data) {
if (!data.includes("DeprecationWarning")) {
stderr.push(data);
logger.debug("indexWorkerManifest handleStderr");
logger.debug(data);
}
},
});
})(),
wantIndexingError ? "does not index" : "indexes"
);
if (wantIndexingError) {
await indexExpect.rejects.toThrowError();
return;
}
await indexExpect.resolves.not.toThrowError();
if (workerManifestMatcher) {
expect(workerManifest!).toMatchObject(workerManifestMatcher);
} else {
expect(workerManifest!).toBeTruthy();
}
logger.debug("Worker manifest", workerManifest!);
if (runs && runs.length > 0) {
await writeJSONFile(path.join(destination.path, "index.json"), workerManifest!);
}
for (const taskRun of runs || []) {
const { result, totalDurationMs } = await executeTestCaseRun({
run: taskRun,
testCase,
destination: destination.path,
workerManifest: workerManifest!,
contentHash: buildManifest!.contentHash,
});
expect(result.ok).toBe(taskRun.result.ok);
if (taskRun.result.durationMs) {
expect(totalDurationMs).toBeGreaterThanOrEqual(taskRun.result.durationMs);
}
}
}
);
}
});
-72
View File
@@ -1,72 +0,0 @@
export interface TestCase {
resolveEnv?: { [key: string]: string };
id: string;
workspaceRelativeDir?: string;
skipTypecheck?: boolean;
wantConfigNotFoundError?: boolean;
wantConfigInvalidError?: boolean;
wantCompilationError?: boolean;
wantWorkerError?: boolean;
wantDependenciesError?: boolean;
wantInstallationError?: boolean;
}
export const fixturesConfig: TestCase[] = [
{
id: "compile-monorepo-packages",
skipTypecheck: true,
workspaceRelativeDir: "packages/trigger",
},
{
id: "compile-monorepo-packages-npm",
skipTypecheck: true,
workspaceRelativeDir: "packages/trigger",
},
{
id: "config-infisical-sdk",
skipTypecheck: true,
},
{
id: "config-invalid",
wantConfigInvalidError: true,
},
{
id: "config-not-found",
wantConfigNotFoundError: true,
},
{
id: "dep-to-add-scope-parsing",
skipTypecheck: true,
},
{
id: "lock-nested-peer-deps",
skipTypecheck: true,
resolveEnv: {
npm_config_legacy_peer_deps: "true",
},
},
{
id: "resolve-legacy-peer-deps",
skipTypecheck: true,
// Should fail with better error at resolve
wantWorkerError: true,
},
{
id: "resolve-trigger-deps",
skipTypecheck: true,
},
{
id: "server-only",
skipTypecheck: true,
},
{
id: "trigger-dir-missing",
skipTypecheck: true,
},
{
id: "trigger-dir-not-found",
skipTypecheck: true,
// Should fail way before
wantCompilationError: true,
},
];
+71
View File
@@ -0,0 +1,71 @@
import { BuildManifest, WorkerManifest } from "@trigger.dev/core/v3/schemas";
type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;
export interface TestCaseRun {
task: {
id: string;
filePath: string;
exportName: string;
};
payload: string;
payloadType?: string;
result: {
ok: boolean;
durationMs?: number;
};
}
export interface TestCase {
resolveEnv?: { [key: string]: string };
id: string;
workspaceRelativeDir?: string;
wantConfigNotFoundError?: boolean;
wantConfigInvalidError?: boolean;
wantBuildWorkerError?: boolean;
wantIndexingError?: boolean;
wantWorkerError?: boolean;
wantDependenciesError?: boolean;
wantInstallationError?: boolean;
buildManifestMatcher?: DeepPartial<BuildManifest>;
workerManifestMatcher?: DeepPartial<WorkerManifest>;
runs?: TestCaseRun[];
tsconfig?: string;
}
export const fixturesConfig: TestCase[] = [
{
id: "hello-world",
buildManifestMatcher: {
runtime: "node",
externals: [
{
name: "import-in-the-middle",
version: "1.11.0",
},
],
files: [{ entry: "src/trigger/helloWorld.ts" }],
},
workerManifestMatcher: {
tasks: [
{
id: "helloWorld",
filePath: "src/trigger/helloWorld.ts",
exportName: "helloWorld",
},
],
},
runs: [
{
task: { id: "helloWorld", filePath: "src/trigger/helloWorld.ts", exportName: "helloWorld" },
payload: "{}",
result: { ok: true, durationMs: 1000 },
},
],
tsconfig: "tsconfig.json",
},
];
-1
View File
@@ -1 +0,0 @@
.yarn
@@ -1,3 +0,0 @@
module.exports = {
MESSAGE: "Hello, World!",
};
@@ -1,4 +0,0 @@
{
"name": "@compile-monorepo-packages-npm/message",
"private": true
}
@@ -1,8 +0,0 @@
{
"name": "@compile-monorepo-packages-npm/trigger",
"private": true,
"dependencies": {
"@compile-monorepo-packages-npm/message": "*",
"@trigger.dev/sdk": "3.0.0-beta.40"
}
}
@@ -1,9 +0,0 @@
import { task } from "@trigger.dev/sdk/v3";
import { MESSAGE } from "@compile-monorepo-packages-npm/message";
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
console.log(MESSAGE, payload);
},
});
@@ -1,4 +0,0 @@
export const config = {
project: "compile-monorepo-packages",
triggerDirectories: ["./src"],
};
@@ -1,12 +0,0 @@
{
"name": "compile-monorepo-packages",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
},
"workspaces": [
"packages/*"
]
}
@@ -1,3 +0,0 @@
module.exports = {
MESSAGE: "Hello, World!",
};
@@ -1,4 +0,0 @@
{
"name": "@compile-monorepo-packages/message",
"private": true
}
@@ -1,8 +0,0 @@
{
"name": "@compile-monorepo-packages/trigger",
"private": true,
"dependencies": {
"@compile-monorepo-packages/message": "workspace:*",
"@trigger.dev/sdk": "3.0.0-beta.40"
}
}
@@ -1,9 +0,0 @@
import { task } from "@trigger.dev/sdk/v3";
import { MESSAGE } from "@compile-monorepo-packages/message";
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
console.log(MESSAGE, payload);
},
});
@@ -1,4 +0,0 @@
export const config = {
project: "compile-monorepo-packages",
triggerDirectories: ["./src"],
};
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
nodeLinker: node-modules
File diff suppressed because it is too large Load Diff
@@ -1,13 +0,0 @@
{
"name": "config-infisical-sdk",
"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"
}
}
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,9 +0,0 @@
import { InfisicalClient } from "@infisical/sdk";
export const config = async () => {
console.log("InfisicalClient", InfisicalClient);
return {
project: "config-infisical-sdk",
};
};
@@ -1,8 +0,0 @@
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
@@ -1 +0,0 @@
nodeLinker: node-modules
@@ -1,14 +0,0 @@
{
"name": "config-invalid",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "config-invalid",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
}
}
@@ -1,9 +0,0 @@
{
"name": "config-invalid",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
@@ -1,9 +0,0 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,4 +0,0 @@
export const config = {
// 'project' field is mandatory
triggerDirectories: [],
};
@@ -1,12 +0,0 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"config-invalid@workspace:.":
version: 0.0.0-use.local
resolution: "config-invalid@workspace:."
languageName: unknown
linkType: soft
@@ -1 +0,0 @@
nodeLinker: node-modules
@@ -1,14 +0,0 @@
{
"name": "config-not-found",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "config-not-found",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
}
}
@@ -1,9 +0,0 @@
{
"name": "config-not-found",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
@@ -1,9 +0,0 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,12 +0,0 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"config-not-found@workspace:.":
version: 0.0.0-use.local
resolution: "config-not-found@workspace:."
languageName: unknown
linkType: soft
File diff suppressed because it is too large Load Diff
@@ -1,13 +0,0 @@
{
"name": "dep-to-add-scope-parsing",
"description": "https://github.com/triggerdotdev/trigger.dev/commit/b8477ea2b08828e547885a6f2a14c15074852879",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
},
"workspaces": [
"packages/*"
]
}
@@ -1,3 +0,0 @@
module.exports = {
MESSAGE: "Hello, World!",
};
@@ -1,4 +0,0 @@
{
"name": "@dep-to-add-scope-parsing/dep-to-add",
"private": true
}
@@ -1,9 +0,0 @@
import { task } from "@trigger.dev/sdk/v3";
import { MESSAGE } from "@dep-to-add-scope-parsing/dep-to-add";
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
console.log(MESSAGE, payload);
},
});
@@ -1,8 +0,0 @@
{
"name": "@dep-to-add-scope-parsing/trigger",
"private": true,
"dependencies": {
"@dep-to-add-scope-parsing/dep-to-add": "*",
"@trigger.dev/sdk": "3.0.0-beta.37"
}
}
@@ -1,5 +0,0 @@
export const config = {
project: "dep-to-add-scope-parsing",
additionalPackages: ["@dep-to-add-scope-parsing/dep-to-add"],
triggerDirectories: ["./packages/trigger"],
};
@@ -1,5 +1,5 @@
{
"name": "compile-monorepo-packages-npm",
"name": "hello-world",
"private": true,
"packageManager": "yarn@4.2.2+sha256.1aa43a5304405be7a7cb9cb5de7b97de9c4e8ddd3273e4dad00d6ae3eb39f0ef",
"engines": {
@@ -8,5 +8,11 @@
},
"workspaces": [
"packages/*"
]
],
"dependencies": {
"@trigger.dev/sdk": "0.0.0-prerelease-20240825150620"
},
"devDependencies": {
"typescript": "5.5.4"
}
}
@@ -0,0 +1,10 @@
import { task } from "@trigger.dev/sdk/v3";
import { setTimeout } from "node:timers/promises";
export const helloWorld = task({
id: "helloWorld",
run: async () => {
await setTimeout(1000);
console.log("Hello, World!");
},
});
@@ -0,0 +1,6 @@
import { defineConfig } from "@trigger.dev/sdk/v3";
export default defineConfig({
project: "<fixture project>",
dirs: ["./src/trigger"],
});
@@ -0,0 +1,32 @@
{
"include": ["src/**/*.ts", "trigger.config.ts"],
"compilerOptions": {
"target": "es2022",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"moduleDetection": "force",
"verbatimModuleSyntax": false,
"jsx": "react",
"strict": true,
"alwaysStrict": true,
"strictPropertyInitialization": false,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noFallthroughCasesInSwitch": true,
"resolveJsonModule": true,
"removeComments": false,
"esModuleInterop": true,
"emitDecoratorMetadata": false,
"experimentalDecorators": false,
"downlevelIteration": true,
"isolatedModules": true,
"noUncheckedIndexedAccess": true,
"pretty": true
}
}
@@ -1 +0,0 @@
nodeLinker: node-modules
File diff suppressed because it is too large Load Diff
@@ -1,14 +0,0 @@
{
"name": "lock-nested-peer-deps",
"description": "nested peer dep resolved (installed), but legacy-peer-dep true when creating container lockfile. https://github.com/triggerdotdev/trigger.dev/commit/c092c0f9db70039e2f1bc495547a723c1f1a21cf",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
},
"dependencies": {
"@trigger.dev/sdk": "3.0.0-beta.40",
"react-dom": "18.3.1"
}
}
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,3 +0,0 @@
export const config = {
project: "lock-nested-peer-deps",
};
@@ -1,17 +0,0 @@
import { task } from "@trigger.dev/sdk/v3";
import { renderToPipeableStream } from "react-dom/server";
function App() {
return <div>Hello World</div>;
}
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
const stream = renderToPipeableStream(<App />, {
onShellReady() {
stream.pipe(payload);
},
});
},
});
File diff suppressed because it is too large Load Diff
@@ -1,4 +0,0 @@
# Configure npm to ignore peer deps upon install
legacy-peer-deps=true
# Configure pnpm to ignore peer deps upon install
auto-install-peers=false
@@ -1 +0,0 @@
nodeLinker: node-modules
File diff suppressed because it is too large Load Diff
@@ -1,16 +0,0 @@
{
"name": "resolve-legacy-peer-deps",
"description": "",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
},
"dependencies": {
"@trigger.dev/sdk": "3.0.0-beta.40"
},
"peerDependencies": {
"lodash": "4.17.21"
}
}
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,3 +0,0 @@
export const config = {
project: "resolve-legacy-peer-deps",
};
@@ -1,9 +0,0 @@
import { concat } from "lodash/array";
import { task } from "@trigger.dev/sdk/v3";
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
console.log(concat(["Hello"], "World!").join(", "), payload);
},
});
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
nodeLinker: node-modules
@@ -1,14 +0,0 @@
{
"name": "resolve-trigger-deps",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "resolve-trigger-deps",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
}
}
@@ -1,10 +0,0 @@
{
"name": "resolve-trigger-deps",
"description": "https://github.com/triggerdotdev/trigger.dev/commit/6406924b025de766af68dcceea04d26993211ed0",
"private": true,
"packageManager": "pnpm@8.15.5+sha256.4b4efa12490e5055d59b9b9fc9438b7d581a6b7af3b5675eb5c5f447cee1a589",
"engines": {
"pnpm": "8.15.5",
"yarn": "4.2.2"
}
}
@@ -1,9 +0,0 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
importers:
.: {}
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,4 +0,0 @@
export const config = {
project: "resolve-trigger-deps",
triggerDirectories: ["./trigger"],
};
@@ -1,8 +0,0 @@
import { task } from "@trigger.dev/sdk/v3";
export const helloWorldTask = task({
id: "hello-world",
run: async (payload) => {
console.log("Hello, World!", payload);
},
});
@@ -1,12 +0,0 @@
# This file is generated by running "yarn install" inside your project.
# Manual changes might be lost - proceed with caution!
__metadata:
version: 8
cacheKey: 10c0
"resolve-trigger-deps@workspace:.":
version: 0.0.0-use.local
resolution: "resolve-trigger-deps@workspace:."
languageName: unknown
linkType: soft
@@ -1 +0,0 @@
nodeLinker: node-modules
File diff suppressed because it is too large Load Diff
@@ -1,13 +0,0 @@
{
"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"
}
}
File diff suppressed because it is too large Load Diff
@@ -1 +0,0 @@
# https://github.com/pnpm/pnpm/issues/2412
@@ -1,4 +0,0 @@
export const config = {
project: "server-only",
triggerDirectories: ["./trigger"],
};
@@ -1,9 +0,0 @@
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

Some files were not shown because too many files have changed in this diff Show More