@sshkeda/task 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +131 -2
- package/package.json +41 -4
- package/src/index.ts +2 -0
- package/src/lib/errors/index.ts +15 -0
- package/src/lib/errors/internal/errors.ts +147 -0
- package/src/lib/kill-leftover-processes/index.ts +17 -0
- package/src/lib/kill-leftover-processes/internal/command-words.ts +16 -0
- package/src/lib/kill-leftover-processes/internal/find-process-ids.ts +36 -0
- package/src/lib/kill-leftover-processes/internal/kill-process-groups.ts +270 -0
- package/src/lib/kill-leftover-processes/internal/list-linux-processes-from-proc.ts +191 -0
- package/src/lib/kill-leftover-processes/internal/list-macos-processes-with-sysctl.ts +335 -0
- package/src/lib/kill-leftover-processes/internal/list-processes.ts +58 -0
- package/src/lib/kill-leftover-processes/internal/mark-run-processes.ts +367 -0
- package/src/lib/kill-leftover-processes/internal/process-cleanup-errors.ts +17 -0
- package/src/lib/kill-leftover-processes/internal/send-signal.ts +32 -0
- package/src/lib/kill-leftover-processes/internal/signal-run-processes.ts +48 -0
- package/src/lib/kill-leftover-processes/internal/started-process-groups.ts +107 -0
- package/src/lib/main-thread/index.ts +3 -0
- package/src/lib/main-thread/internal/listen-for-stop-requests.ts +102 -0
- package/src/lib/main-thread/internal/run-main-thread.ts +81 -0
- package/src/lib/main-thread/internal/run-root-task-fiber.ts +191 -0
- package/src/lib/main-thread/internal/stops-at-first-failure.ts +20 -0
- package/src/lib/main-thread/internal/trace-the-run.ts +107 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/index.ts +7 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/follow-imports-from-entry-files.ts +306 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/load-all-reporting-first-failure.ts +11 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/make-module-graph.ts +48 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/read-configured-loaders.ts +64 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/resolve-module-specifiers.ts +60 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/rewrite-worker-imports.ts +118 -0
- package/src/lib/main-thread/lib/find-code-each-task-depends-on/internal/worker-import-errors.ts +19 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/index.ts +7 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/internal/handle-worker-events.ts +348 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/internal/make-task-runs.ts +207 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/index.ts +1 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/await-within-counted-limit.ts +29 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/execute-task.ts +272 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/make-task-setup-clock.ts +129 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/lib/run-requested-task-once/internal/run-requested-tasks.ts +135 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/define-task-run-state.ts +288 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/make-stopwatch.ts +39 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/share-standard-input-with-root-task.ts +36 -0
- package/src/lib/main-thread/lib/run-tasks-on-workers/shared/stop-task.ts +166 -0
- package/src/lib/main-thread/lib/scan-module-source/index.ts +1 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/find-lexical-bindings.ts +154 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/find-task-declarations.ts +205 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/parse-module-text.ts +34 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/read-literal-string.ts +15 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/read-module-loads.ts +316 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/scan-module-text.ts +70 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/unwrap-type-assertions.ts +10 -0
- package/src/lib/main-thread/lib/scan-module-source/internal/visit-non-reference-identifiers.ts +21 -0
- package/src/lib/main-thread/shared/fail-run.ts +36 -0
- package/src/lib/main-thread/shared/find-failure-reason.ts +43 -0
- package/src/lib/main-thread/shared/find-package-directories.ts +34 -0
- package/src/lib/main-thread/shared/find-tasks-reachable-from-root-task-file.ts +246 -0
- package/src/lib/main-thread/shared/list-directory-paths-up-to-root.ts +13 -0
- package/src/lib/main-thread/shared/main-thread-errors.ts +373 -0
- package/src/lib/main-thread/shared/package-json-errors.ts +93 -0
- package/src/lib/main-thread/shared/provide-discovered-tasks.ts +26 -0
- package/src/lib/main-thread/shared/provide-process-groups.ts +63 -0
- package/src/lib/main-thread/shared/provide-run-root-task-config.ts +66 -0
- package/src/lib/main-thread/shared/provide-stop-state.ts +150 -0
- package/src/lib/main-thread/shared/provide-worker-pool.ts +607 -0
- package/src/lib/main-thread/shared/read-bare-package-name.ts +3 -0
- package/src/lib/main-thread/shared/read-package-json.ts +149 -0
- package/src/lib/main-thread/shared/report-task-failure.ts +31 -0
- package/src/lib/preload-rewritten-imports-into-each-worker/index.ts +5 -0
- package/src/lib/preload-rewritten-imports-into-each-worker/internal/load-rewritten-imports.ts +34 -0
- package/src/lib/supervise-the-run/index.ts +15 -0
- package/src/lib/supervise-the-run/internal/adopt-orphans-on-linux.ts +73 -0
- package/src/lib/supervise-the-run/internal/check-root-task-file.ts +8 -0
- package/src/lib/supervise-the-run/internal/report-ready.ts +12 -0
- package/src/lib/supervise-the-run/internal/share-process-groups.ts +25 -0
- package/src/lib/supervise-the-run/internal/start-watching-the-supervisor.ts +6 -0
- package/src/lib/supervise-the-run/internal/supervise-run.ts +155 -0
- package/src/lib/supervise-the-run/internal/talk-to-the-supervisor.ts +53 -0
- package/src/lib/supervise-the-run/internal/watch-the-supervisor.ts +61 -0
- package/src/lib/task/index.ts +5 -0
- package/src/lib/task/internal/make-tasks.ts +82 -0
- package/src/lib/task/internal/run-command.ts +194 -0
- package/src/lib/task/internal/run-root-task.ts +263 -0
- package/src/lib/task/internal/run-task-lists.ts +51 -0
- package/src/lib/task/internal/trust-output-mode-names.ts +18 -0
- package/src/lib/task/internal/trust-task-results.ts +35 -0
- package/src/lib/task/internal/use-task-services.ts +4 -0
- package/src/lib/worker-thread/index.ts +3 -0
- package/src/lib/worker-thread/internal/answer-main-thread-messages.ts +141 -0
- package/src/lib/worker-thread/internal/describe-task-body-result.ts +91 -0
- package/src/lib/worker-thread/internal/name-config-key-not-set.ts +57 -0
- package/src/lib/worker-thread/internal/run-task-body.ts +117 -0
- package/src/lib/worker-thread/internal/serve-on-the-parent-port.ts +63 -0
- package/src/lib/worker-thread/internal/start-worker-thread.ts +41 -0
- package/src/lib/worker-thread/lib/provide-task-services/index.ts +1 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/make-task-logger.ts +34 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/provide-task-services.ts +86 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/read-standard-input-from-main-thread.ts +58 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/resolve-paths-from-package-directory.ts +61 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/run-commands-in-package-directory.ts +24 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/spawn-commands-with-bun.ts +545 -0
- package/src/lib/worker-thread/lib/provide-task-services/internal/spawn-reported-process.ts +151 -0
- package/src/lib/worker-thread/shared/await-main-thread-answers.ts +76 -0
- package/src/lib/worker-thread/shared/decode-task-result-json.ts +114 -0
- package/src/lib/worker-thread/shared/define-task-body-record.ts +11 -0
- package/src/lib/worker-thread/shared/describe-issue-input.ts +52 -0
- package/src/lib/worker-thread/shared/plain-object.ts +8 -0
- package/src/lib/worker-thread/shared/provide-worker-state.ts +160 -0
- package/src/lib/worker-thread/shared/worker-thread-errors.ts +41 -0
- package/src/shared/attribute-reported-failures.ts +25 -0
- package/src/shared/claim-processes-to-report.ts +22 -0
- package/src/shared/command-errors.ts +44 -0
- package/src/shared/complete-discarded-calls-once-sent.ts +12 -0
- package/src/shared/cut-to-graphemes.ts +12 -0
- package/src/shared/environment-config-errors.ts +74 -0
- package/src/shared/error-fields.ts +13 -0
- package/src/shared/find-bun-loader-for-script.ts +32 -0
- package/src/shared/find-node-modules-package-directory.ts +35 -0
- package/src/shared/find-user-locations-in-stack-traces.ts +64 -0
- package/src/shared/format-error-lines.ts +53 -0
- package/src/shared/format-task-lines.ts +21 -0
- package/src/shared/hold-task-logs.ts +24 -0
- package/src/shared/invariant-errors.ts +28 -0
- package/src/shared/mark-task-worker-thread-contexts.ts +29 -0
- package/src/shared/module-graph-errors.ts +49 -0
- package/src/shared/name-config-key.ts +42 -0
- package/src/shared/names-from-package-json.ts +7 -0
- package/src/shared/print-to-standard-error.ts +48 -0
- package/src/shared/process-errors.ts +191 -0
- package/src/shared/read-environment-config.ts +239 -0
- package/src/shared/record-tasks-made.ts +10 -0
- package/src/shared/report-cause.ts +140 -0
- package/src/shared/report-errors.ts +121 -0
- package/src/shared/resolve-task-options.ts +20 -0
- package/src/shared/rpc.ts +161 -0
- package/src/shared/run-in-child-fiber-and-join.ts +16 -0
- package/src/shared/run-marker.ts +7 -0
- package/src/shared/save-standard-stream-flags.ts +57 -0
- package/src/shared/select-cause-reasons.ts +14 -0
- package/src/shared/signal-run-called-twice.ts +11 -0
- package/src/shared/standard-input-streams.ts +41 -0
- package/src/shared/stop-signals.ts +41 -0
- package/src/shared/task-errors.ts +224 -0
- package/src/shared/task-package.ts +5 -0
- package/src/shared/task-results.ts +55 -0
- package/src/shared/task-services.ts +30 -0
- package/src/shared/write-trace-file.ts +112 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Cause, Effect } from "effect";
|
|
2
|
+
|
|
3
|
+
import { StopState } from "./provide-stop-state.ts";
|
|
4
|
+
import { reportTaskFailure } from "./report-task-failure.ts";
|
|
5
|
+
|
|
6
|
+
export const failTask = Effect.fn("failTask")(function* (
|
|
7
|
+
failure: Effect.Success<StopState["Service"]["awaitFailure"]>,
|
|
8
|
+
markFailed: (taskName: string) => Effect.Effect<void>,
|
|
9
|
+
) {
|
|
10
|
+
if (failure.taskName === null) {
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
yield* markFailed(failure.taskName);
|
|
14
|
+
yield* reportTaskFailure(failure.taskName, Cause.fail(failure));
|
|
15
|
+
}, Effect.uninterruptible);
|
|
16
|
+
|
|
17
|
+
export const failRun = Effect.fn("failRun")(function* (
|
|
18
|
+
failure: Parameters<typeof failTask>[0],
|
|
19
|
+
markFailed: Parameters<typeof failTask>[1],
|
|
20
|
+
) {
|
|
21
|
+
if (yield* (yield* StopState).recordFirstFailure(failure)) {
|
|
22
|
+
yield* failTask(failure, markFailed);
|
|
23
|
+
}
|
|
24
|
+
}, Effect.uninterruptible);
|
|
25
|
+
|
|
26
|
+
export const failRunOnFailure =
|
|
27
|
+
(markFailed: Parameters<typeof failTask>[1]) =>
|
|
28
|
+
<Success, Failure extends Parameters<typeof failTask>[0], Services>(
|
|
29
|
+
effect: Effect.Effect<Success, Failure, Services>,
|
|
30
|
+
) =>
|
|
31
|
+
effect.pipe(
|
|
32
|
+
Effect.matchEffect({
|
|
33
|
+
onFailure: (failure) => failRun(failure, markFailed),
|
|
34
|
+
onSuccess: (success) => Effect.succeed(success),
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Cause, Schema } from "effect";
|
|
2
|
+
|
|
3
|
+
import { reportCause } from "../../../shared/report-cause.ts";
|
|
4
|
+
import { isAwaitedTaskFailed } from "../../../shared/task-errors.ts";
|
|
5
|
+
import { SettledTasksFailed } from "../../errors/index.ts";
|
|
6
|
+
import type { PrintableError } from "../../errors/index.ts";
|
|
7
|
+
import { UnawaitedTasksFailed } from "./main-thread-errors.ts";
|
|
8
|
+
|
|
9
|
+
const isFailureOfOtherTasks = Schema.is(Schema.Union([SettledTasksFailed, UnawaitedTasksFailed]));
|
|
10
|
+
|
|
11
|
+
const namesOfFailedTasksBehind = (reason: Cause.Reason<unknown>): readonly string[] => {
|
|
12
|
+
if (!Cause.isFailReason(reason)) {
|
|
13
|
+
return [];
|
|
14
|
+
}
|
|
15
|
+
if (isAwaitedTaskFailed(reason.error)) {
|
|
16
|
+
return [reason.error.awaitedTaskName];
|
|
17
|
+
}
|
|
18
|
+
return isFailureOfOtherTasks(reason.error) ? reason.error.failedTaskNames : [];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export const findFailureReason = (
|
|
22
|
+
runEndingCause: Cause.Cause<unknown>,
|
|
23
|
+
failureCauseByTaskName: ReadonlyMap<string, Cause.Cause<unknown>>,
|
|
24
|
+
): PrintableError | null => {
|
|
25
|
+
for (const reason of runEndingCause.reasons) {
|
|
26
|
+
if (Cause.isInterruptReason(reason)) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const failedTaskNames = namesOfFailedTasksBehind(reason);
|
|
30
|
+
if (failedTaskNames.length === 0) {
|
|
31
|
+
return reportCause(Cause.fromReasons([reason])).failures[0];
|
|
32
|
+
}
|
|
33
|
+
for (const failedTaskName of failedTaskNames) {
|
|
34
|
+
const failureCause = failureCauseByTaskName.get(failedTaskName);
|
|
35
|
+
const originalReason =
|
|
36
|
+
failureCause === undefined ? null : findFailureReason(failureCause, failureCauseByTaskName);
|
|
37
|
+
if (originalReason !== null) {
|
|
38
|
+
return originalReason;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Effect, FileSystem, Path } from "effect";
|
|
2
|
+
|
|
3
|
+
import { listDirectoryPathsUpToRoot } from "./list-directory-paths-up-to-root.ts";
|
|
4
|
+
import { MissingPackageJson } from "./main-thread-errors.ts";
|
|
5
|
+
import { PackageJsonSearchFailed } from "./package-json-errors.ts";
|
|
6
|
+
|
|
7
|
+
export const findPackageJsonDirectoryPath = Effect.fn("findPackageJsonDirectoryPath")(function* (
|
|
8
|
+
start: string,
|
|
9
|
+
) {
|
|
10
|
+
const fileSystem = yield* FileSystem.FileSystem;
|
|
11
|
+
const path = yield* Path.Path;
|
|
12
|
+
for (const searchDirectoryPath of listDirectoryPathsUpToRoot(path, start)) {
|
|
13
|
+
const packageJsonFilePath = `${searchDirectoryPath}/package.json`;
|
|
14
|
+
const packageJsonExists = yield* fileSystem
|
|
15
|
+
.exists(packageJsonFilePath)
|
|
16
|
+
.pipe(
|
|
17
|
+
Effect.mapError(
|
|
18
|
+
(cause) => new PackageJsonSearchFailed({ filePath: packageJsonFilePath, cause }),
|
|
19
|
+
),
|
|
20
|
+
);
|
|
21
|
+
if (packageJsonExists) {
|
|
22
|
+
return searchDirectoryPath;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export const requirePackageJsonDirectoryPath = (filePath: string) =>
|
|
29
|
+
Path.Path.use((path) => findPackageJsonDirectoryPath(path.dirname(filePath))).pipe(
|
|
30
|
+
Effect.filterOrFail(
|
|
31
|
+
(packageJsonDirectoryPath) => packageJsonDirectoryPath !== null,
|
|
32
|
+
() => new MissingPackageJson({ filePath }),
|
|
33
|
+
),
|
|
34
|
+
);
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { inspect } from "node:util";
|
|
2
|
+
|
|
3
|
+
import { Array as Arrays, Duration, Effect, Option, Path } from "effect";
|
|
4
|
+
|
|
5
|
+
import { makeNodeModulesPackageFinder } from "../../../shared/find-node-modules-package-directory.ts";
|
|
6
|
+
import { InternalInvariantBroken } from "../../../shared/invariant-errors.ts";
|
|
7
|
+
import { TASK_TRACE_LABEL_PREFIX } from "../../../shared/names-from-package-json.ts";
|
|
8
|
+
import { findTasksMadeWithName } from "../../../shared/record-tasks-made.ts";
|
|
9
|
+
import { STOP_GRACE_PERIOD } from "../../../shared/stop-signals.ts";
|
|
10
|
+
import { TaskModuleImportFailed, TaskSetupTimedOut } from "../../../shared/task-errors.ts";
|
|
11
|
+
import { ModuleGraph } from "../lib/find-code-each-task-depends-on/index.ts";
|
|
12
|
+
import { requirePackageJsonDirectoryPath } from "./find-package-directories.ts";
|
|
13
|
+
import {
|
|
14
|
+
BrokenTasksFound,
|
|
15
|
+
RootTaskNotMadeAtTopLevel,
|
|
16
|
+
TaskCleanupInvalid,
|
|
17
|
+
TaskFileImportsItself,
|
|
18
|
+
TaskMadeAgainInThread,
|
|
19
|
+
TaskMadeMoreThanOnce,
|
|
20
|
+
TaskNotMadeByImport,
|
|
21
|
+
TaskOptionsUnknown,
|
|
22
|
+
TaskTimeoutInvalid,
|
|
23
|
+
} from "./main-thread-errors.ts";
|
|
24
|
+
import type { TaskDefinitionViolation } from "./main-thread-errors.ts";
|
|
25
|
+
import { RunRootTaskConfig } from "./provide-run-root-task-config.ts";
|
|
26
|
+
|
|
27
|
+
const readTimeoutDuration = (input: Duration.Input) =>
|
|
28
|
+
Option.filter(Duration.fromInput(input), Duration.isPositive);
|
|
29
|
+
|
|
30
|
+
const readCleanupDuration = (input: Duration.Input) =>
|
|
31
|
+
Option.filter(
|
|
32
|
+
Duration.fromInput(input),
|
|
33
|
+
(duration) => Duration.isZero(duration) || Duration.isPositive(duration),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const findImportCycleThrough = (
|
|
37
|
+
reachable: Effect.Success<ReturnType<ModuleGraph["Service"]["findReachableModules"]>>,
|
|
38
|
+
taskFilePath: string,
|
|
39
|
+
) => {
|
|
40
|
+
const seenFilePaths = new Set([taskFilePath]);
|
|
41
|
+
const importPaths = [Arrays.of(taskFilePath)];
|
|
42
|
+
for (const importPath of importPaths) {
|
|
43
|
+
const importingFilePath = Arrays.lastNonEmpty(importPath);
|
|
44
|
+
const importingModule = reachable.get(importingFilePath);
|
|
45
|
+
if (importingModule === undefined) {
|
|
46
|
+
throw new InternalInvariantBroken({
|
|
47
|
+
area: "module graph",
|
|
48
|
+
invariant: `${importingFilePath} is among the modules reachable from the root task file`,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
for (const importedModule of importingModule.imports) {
|
|
52
|
+
if (importedModule.filePath === taskFilePath) {
|
|
53
|
+
return Arrays.append(importPath, taskFilePath);
|
|
54
|
+
}
|
|
55
|
+
if (!seenFilePaths.has(importedModule.filePath)) {
|
|
56
|
+
seenFilePaths.add(importedModule.filePath);
|
|
57
|
+
importPaths.push(Arrays.append(importPath, importedModule.filePath));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const findTaskFileImportCycles = (
|
|
65
|
+
reachable: Effect.Success<ReturnType<ModuleGraph["Service"]["findReachableModules"]>>,
|
|
66
|
+
) => {
|
|
67
|
+
const cycles: Arrays.NonEmptyArray<string>[] = [];
|
|
68
|
+
const filePathsInFoundCycles = new Set<string>();
|
|
69
|
+
for (const [filePath, module] of reachable) {
|
|
70
|
+
const isUncheckedTaskFile =
|
|
71
|
+
module.madeTasks.length > 0 && !filePathsInFoundCycles.has(filePath);
|
|
72
|
+
const cycle = isUncheckedTaskFile ? findImportCycleThrough(reachable, filePath) : null;
|
|
73
|
+
if (cycle !== null) {
|
|
74
|
+
cycles.push(cycle);
|
|
75
|
+
for (const filePathInCycle of cycle) {
|
|
76
|
+
filePathsInFoundCycles.add(filePathInCycle);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return cycles;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export const findTasksReachableFromRootTaskFile = Effect.fn("findTasksReachableFromRootTaskFile")(
|
|
84
|
+
function* () {
|
|
85
|
+
const path = yield* Path.Path;
|
|
86
|
+
const runRootTaskConfig = yield* RunRootTaskConfig;
|
|
87
|
+
const rootTask = runRootTaskConfig.rootTask;
|
|
88
|
+
const findNodeModulesPackageDirectoryPath = makeNodeModulesPackageFinder(
|
|
89
|
+
runRootTaskConfig.rootTaskPackageJsonDirectoryPath,
|
|
90
|
+
);
|
|
91
|
+
const moduleGraph = yield* ModuleGraph;
|
|
92
|
+
const reachable = yield* moduleGraph.findReachableModules(runRootTaskConfig.rootTaskFilePath);
|
|
93
|
+
const sitesMakingTask = new Map<
|
|
94
|
+
string,
|
|
95
|
+
Arrays.NonEmptyArray<{
|
|
96
|
+
readonly filePath: string;
|
|
97
|
+
readonly location: string;
|
|
98
|
+
}>
|
|
99
|
+
>();
|
|
100
|
+
for (const [taskFilePath, module] of reachable) {
|
|
101
|
+
for (const madeTask of module.madeTasks) {
|
|
102
|
+
sitesMakingTask.set(
|
|
103
|
+
madeTask.name,
|
|
104
|
+
Arrays.append(sitesMakingTask.get(madeTask.name) ?? [], {
|
|
105
|
+
filePath: taskFilePath,
|
|
106
|
+
location: `${taskFilePath}:${madeTask.line}`,
|
|
107
|
+
}),
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const importCycles = findTaskFileImportCycles(reachable).map(
|
|
113
|
+
(cycle) =>
|
|
114
|
+
new TaskFileImportsItself({
|
|
115
|
+
filePath: Arrays.headNonEmpty(cycle),
|
|
116
|
+
cycle: cycle.map((filePath) =>
|
|
117
|
+
path.relative(runRootTaskConfig.rootTaskPackageJsonDirectoryPath, filePath),
|
|
118
|
+
),
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
const violations: (typeof TaskDefinitionViolation.Type)[] = [...reachable.values()].flatMap(
|
|
122
|
+
(module) => module.refusals,
|
|
123
|
+
);
|
|
124
|
+
if (Arrays.isArrayNonEmpty(importCycles)) {
|
|
125
|
+
return yield* new BrokenTasksFound({
|
|
126
|
+
violations: Arrays.appendAll(violations, importCycles),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
for (const [taskFilePath, taskName] of new Map(
|
|
130
|
+
Array.from(sitesMakingTask, ([name, sites]) => [Arrays.headNonEmpty(sites).filePath, name]),
|
|
131
|
+
)) {
|
|
132
|
+
yield* Effect.tryPromise({
|
|
133
|
+
try: () => import(taskFilePath),
|
|
134
|
+
catch: (cause) => new TaskModuleImportFailed({ filePath: taskFilePath, cause }),
|
|
135
|
+
}).pipe(
|
|
136
|
+
Effect.timeoutOrElse({
|
|
137
|
+
duration: runRootTaskConfig.setupLimit,
|
|
138
|
+
orElse: () =>
|
|
139
|
+
Effect.fail(
|
|
140
|
+
new TaskSetupTimedOut({
|
|
141
|
+
taskName,
|
|
142
|
+
limitMilliseconds: Duration.toMillis(runRootTaskConfig.setupLimit),
|
|
143
|
+
unfinishedStep: `loading ${taskFilePath}`,
|
|
144
|
+
}),
|
|
145
|
+
),
|
|
146
|
+
}),
|
|
147
|
+
Effect.withSpan("import task file", {
|
|
148
|
+
attributes: {
|
|
149
|
+
[`${TASK_TRACE_LABEL_PREFIX}.file`]: path.relative(
|
|
150
|
+
runRootTaskConfig.rootTaskPackageJsonDirectoryPath,
|
|
151
|
+
taskFilePath,
|
|
152
|
+
),
|
|
153
|
+
},
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const discoveredTaskEntries = [];
|
|
159
|
+
for (const [taskName, sites] of sitesMakingTask) {
|
|
160
|
+
const [task, ...otherTasks] = findTasksMadeWithName(taskName);
|
|
161
|
+
const { filePath: taskFilePath, location } = Arrays.headNonEmpty(sites);
|
|
162
|
+
if (sites.length > 1) {
|
|
163
|
+
violations.push(
|
|
164
|
+
...sites.map(
|
|
165
|
+
(site) =>
|
|
166
|
+
new TaskMadeMoreThanOnce({
|
|
167
|
+
taskName,
|
|
168
|
+
location: site.location,
|
|
169
|
+
madeCount: sites.length,
|
|
170
|
+
}),
|
|
171
|
+
),
|
|
172
|
+
);
|
|
173
|
+
} else if (task === undefined) {
|
|
174
|
+
violations.push(new TaskNotMadeByImport({ taskName, filePath: taskFilePath }));
|
|
175
|
+
} else if (otherTasks.length > 0) {
|
|
176
|
+
violations.push(
|
|
177
|
+
new TaskMadeAgainInThread({
|
|
178
|
+
taskName,
|
|
179
|
+
filePath: taskFilePath,
|
|
180
|
+
madeCount: otherTasks.length + 1,
|
|
181
|
+
}),
|
|
182
|
+
);
|
|
183
|
+
} else {
|
|
184
|
+
const timeoutDuration =
|
|
185
|
+
task.options.timeout === null
|
|
186
|
+
? Option.some(null)
|
|
187
|
+
: readTimeoutDuration(task.options.timeout);
|
|
188
|
+
const cleanupDuration =
|
|
189
|
+
task.options.cleanup === null
|
|
190
|
+
? Option.some(STOP_GRACE_PERIOD)
|
|
191
|
+
: readCleanupDuration(task.options.cleanup);
|
|
192
|
+
if (Option.isNone(timeoutDuration)) {
|
|
193
|
+
violations.push(
|
|
194
|
+
new TaskTimeoutInvalid({ taskName, timeout: inspect(task.options.timeout) }),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (Option.isNone(cleanupDuration)) {
|
|
198
|
+
violations.push(
|
|
199
|
+
new TaskCleanupInvalid({ taskName, cleanup: inspect(task.options.cleanup) }),
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
if (Arrays.isReadonlyArrayNonEmpty(task.options.unknownOptionNames)) {
|
|
203
|
+
violations.push(
|
|
204
|
+
new TaskOptionsUnknown({
|
|
205
|
+
taskName,
|
|
206
|
+
location,
|
|
207
|
+
optionNames: task.options.unknownOptionNames,
|
|
208
|
+
}),
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
const isMissingDuration = Option.isNone(timeoutDuration) || Option.isNone(cleanupDuration);
|
|
212
|
+
if (isMissingDuration) {
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
const taskPackageJsonDirectoryPath =
|
|
216
|
+
findNodeModulesPackageDirectoryPath(taskFilePath) === null
|
|
217
|
+
? yield* requirePackageJsonDirectoryPath(taskFilePath)
|
|
218
|
+
: runRootTaskConfig.rootTaskPackageJsonDirectoryPath;
|
|
219
|
+
discoveredTaskEntries.push([
|
|
220
|
+
taskName,
|
|
221
|
+
{
|
|
222
|
+
definition: task,
|
|
223
|
+
filePath: taskFilePath,
|
|
224
|
+
packageJsonDirectoryPath: taskPackageJsonDirectoryPath,
|
|
225
|
+
timeoutDuration: timeoutDuration.value,
|
|
226
|
+
cleanupDuration: cleanupDuration.value,
|
|
227
|
+
},
|
|
228
|
+
] as const);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
const discoveredTasksByName = new Map(discoveredTaskEntries);
|
|
232
|
+
const isRootTaskNotMadeAtTopLevel =
|
|
233
|
+
!sitesMakingTask.has(rootTask.name) ||
|
|
234
|
+
!findTasksMadeWithName(rootTask.name).includes(rootTask);
|
|
235
|
+
if (isRootTaskNotMadeAtTopLevel) {
|
|
236
|
+
violations.push(
|
|
237
|
+
new RootTaskNotMadeAtTopLevel({ rootTaskFilePath: runRootTaskConfig.rootTaskFilePath }),
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
if (Arrays.isArrayNonEmpty(violations)) {
|
|
241
|
+
return yield* new BrokenTasksFound({ violations });
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
return discoveredTasksByName;
|
|
245
|
+
},
|
|
246
|
+
);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Path } from "effect";
|
|
2
|
+
|
|
3
|
+
export const listDirectoryPathsUpToRoot = function* (
|
|
4
|
+
path: Path.Path,
|
|
5
|
+
directoryPath: string,
|
|
6
|
+
): Generator<string, void, undefined> {
|
|
7
|
+
yield directoryPath;
|
|
8
|
+
const parentDirectoryPath = path.dirname(directoryPath);
|
|
9
|
+
if (parentDirectoryPath === directoryPath) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
yield* listDirectoryPathsUpToRoot(path, parentDirectoryPath);
|
|
13
|
+
};
|