@savvy-web/silk-effects 3.3.1 → 4.0.1
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/changesets/changelog/getReleaseLine.js +1 -1
- package/changesets/constants.js +0 -18
- package/changesets/index.js +10 -24
- package/changesets/schemas/changeset.js +8 -4
- package/changesets/schemas/dependency-table.js +15 -4
- package/changesets/schemas/git.js +7 -2
- package/changesets/schemas/github.js +4 -4
- package/changesets/schemas/options.js +3 -3
- package/changesets/schemas/package-scope.js +2 -5
- package/changesets/schemas/primitives.js +2 -2
- package/changesets/schemas/release-plan.js +12 -8
- package/changesets/schemas/version-files.js +4 -4
- package/changesets/services/branch-analyzer.js +60 -191
- package/changesets/services/changelog.js +2 -15
- package/changesets/services/config-inspector.js +109 -75
- package/changesets/services/deps-regen.js +58 -32
- package/changesets/services/github.js +3 -16
- package/changesets/services/maintenance-reason.js +5 -1
- package/changesets/services/markdown.js +3 -16
- package/changesets/services/release-planner.js +4 -13
- package/changesets/utils/commit-parser.js +0 -18
- package/changesets/utils/dep-diff.js +0 -27
- package/changesets/utils/git.js +15 -50
- package/changesets/utils/issue-refs.js +0 -13
- package/changesets/utils/logger.js +0 -13
- package/changesets/utils/markdown-link.js +0 -14
- package/changesets/utils/publishability.js +11 -24
- package/changesets/utils/strip-frontmatter.js +0 -19
- package/changesets/utils/version-files.js +85 -51
- package/commitlint/config/schema.js +9 -5
- package/commitlint/detection/scopes.js +2 -7
- package/commitlint/formatter/messages.js +0 -5
- package/commitlint/hook/diagnostics/branch.js +12 -12
- package/commitlint/hook/diagnostics/open-issues.js +13 -7
- package/commitlint/hook/diagnostics/signing.js +30 -37
- package/commitlint/hook/envelope.js +2 -8
- package/commitlint/hook/silence-logger.js +14 -12
- package/index.d.ts +897 -932
- package/lint/cli/templates/markdownlint.gen.js +0 -9
- package/lint/handlers/PnpmWorkspace.js +26 -12
- package/lint/utils/Filter.js +0 -13
- package/lint/utils/Workspace.js +10 -6
- package/package.json +11 -10
- package/repos/index.js +3 -5
- package/repos/schemas/manifest.js +7 -13
- package/repos/schemas/reports.js +5 -1
- package/repos/services/config-store.js +6 -10
- package/repos/services/manager.js +52 -112
- package/schemas/CommentStyle.js +1 -1
- package/schemas/ResolvedTool.js +52 -17
- package/schemas/SectionBlock.js +1 -1
- package/schemas/SectionDefinition.js +2 -2
- package/schemas/TagStrategySchemas.js +1 -1
- package/schemas/ToolDefinition.js +1 -1
- package/schemas/ToolResults.js +1 -1
- package/schemas/VersioningSchemas.js +28 -9
- package/schemas/WorkspaceAnalysisSchemas.js +27 -17
- package/services/BiomeSchemaSync.js +7 -8
- package/services/ChangesetConfig.js +2 -2
- package/services/ChangesetConfigReader.js +7 -8
- package/services/ConfigDiscovery.js +5 -6
- package/services/ManagedSection.js +3 -4
- package/services/SilkPublishability.js +38 -15
- package/services/SilkWorkspaceAnalyzer.js +7 -9
- package/services/TagStrategy.js +3 -3
- package/services/ToolDiscovery.js +22 -21
- package/services/VersioningStrategy.js +2 -2
- package/tsdoc-metadata.json +1 -1
- package/turbo/schemas/DryRun.js +8 -14
- package/turbo/schemas/results.js +8 -8
- package/turbo/services/TurboInspector.js +30 -23
- package/utils/ToolCommand.js +38 -12
|
@@ -5,9 +5,8 @@ import { WorkspaceAnalysisError } from "../errors/WorkspaceAnalysisError.js";
|
|
|
5
5
|
import { AnalyzedWorkspace, WorkspaceAnalysis } from "../schemas/WorkspaceAnalysisSchemas.js";
|
|
6
6
|
import { TagStrategy } from "./TagStrategy.js";
|
|
7
7
|
import { VersioningStrategy } from "./VersioningStrategy.js";
|
|
8
|
-
import { Context, Effect, Layer, Option } from "effect";
|
|
9
|
-
import {
|
|
10
|
-
import { PackageManagerDetector, TopologicalSorter, WorkspaceDiscovery } from "workspaces-effect";
|
|
8
|
+
import { Context, Effect, FileSystem, Layer, Option } from "effect";
|
|
9
|
+
import { DependencyGraph, PackageManagerDetector, WorkspaceDiscovery } from "@effected/workspaces";
|
|
11
10
|
|
|
12
11
|
//#region src/services/SilkWorkspaceAnalyzer.ts
|
|
13
12
|
/**
|
|
@@ -37,7 +36,7 @@ import { PackageManagerDetector, TopologicalSorter, WorkspaceDiscovery } from "w
|
|
|
37
36
|
* @since 0.2.0
|
|
38
37
|
* @public
|
|
39
38
|
*/
|
|
40
|
-
var SilkWorkspaceAnalyzer = class extends Context.
|
|
39
|
+
var SilkWorkspaceAnalyzer = class extends Context.Service()("@savvy-web/silk-effects/SilkWorkspaceAnalyzer") {};
|
|
41
40
|
/**
|
|
42
41
|
* Read the raw package.json from disk as an untyped record.
|
|
43
42
|
*
|
|
@@ -115,7 +114,6 @@ function computeReleaseStatus(pkgName, isPrivate, isPublishable, config) {
|
|
|
115
114
|
const SilkWorkspaceAnalyzerLive = Layer.effect(SilkWorkspaceAnalyzer, Effect.gen(function* () {
|
|
116
115
|
const fs = yield* FileSystem.FileSystem;
|
|
117
116
|
const discovery = yield* WorkspaceDiscovery;
|
|
118
|
-
const sorter = yield* TopologicalSorter;
|
|
119
117
|
const pmDetector = yield* PackageManagerDetector;
|
|
120
118
|
const configReader = yield* ChangesetConfigReader;
|
|
121
119
|
const versioningStrategy = yield* VersioningStrategy;
|
|
@@ -125,11 +123,11 @@ const SilkWorkspaceAnalyzerLive = Layer.effect(SilkWorkspaceAnalyzer, Effect.gen
|
|
|
125
123
|
root,
|
|
126
124
|
reason: `Package manager detection failed: ${String(err)}`
|
|
127
125
|
})));
|
|
128
|
-
const packages = yield* discovery.listPackages(
|
|
126
|
+
const packages = yield* discovery.listPackages().pipe(Effect.mapError((err) => new WorkspaceAnalysisError({
|
|
129
127
|
root,
|
|
130
128
|
reason: `Workspace discovery failed: ${String(err)}`
|
|
131
129
|
})));
|
|
132
|
-
const topoOrder = yield*
|
|
130
|
+
const topoOrder = yield* DependencyGraph.make({ packages }).sort().pipe(Effect.mapError((err) => new WorkspaceAnalysisError({
|
|
133
131
|
root,
|
|
134
132
|
reason: `Cyclic dependency detected: ${String(err)}`
|
|
135
133
|
})));
|
|
@@ -199,8 +197,8 @@ const SilkWorkspaceAnalyzerLive = Layer.effect(SilkWorkspaceAnalyzer, Effect.gen
|
|
|
199
197
|
root,
|
|
200
198
|
runtime: pm.runtime,
|
|
201
199
|
packageManager: {
|
|
202
|
-
type: pm.
|
|
203
|
-
version: pm.version
|
|
200
|
+
type: pm.name,
|
|
201
|
+
...Option.isSome(pm.version) ? { version: pm.version.value } : {}
|
|
204
202
|
},
|
|
205
203
|
workspaces: analyzedWorkspaces,
|
|
206
204
|
changesetConfig,
|
package/services/TagStrategy.js
CHANGED
|
@@ -25,7 +25,7 @@ import { Context, Effect, Layer } from "effect";
|
|
|
25
25
|
* @since 0.1.0
|
|
26
26
|
* @public
|
|
27
27
|
*/
|
|
28
|
-
var TagStrategy = class extends Context.
|
|
28
|
+
var TagStrategy = class extends Context.Service()("@savvy-web/silk-effects/TagStrategy") {};
|
|
29
29
|
/**
|
|
30
30
|
* Live implementation of {@link TagStrategy} with no external dependencies.
|
|
31
31
|
*
|
|
@@ -35,7 +35,7 @@ var TagStrategy = class extends Context.Tag("@savvy-web/silk-effects/TagStrategy
|
|
|
35
35
|
* @since 0.1.0
|
|
36
36
|
* @public
|
|
37
37
|
*/
|
|
38
|
-
const TagStrategyLive = Layer.succeed(TagStrategy,
|
|
38
|
+
const TagStrategyLive = Layer.succeed(TagStrategy, {
|
|
39
39
|
determine: (versioningResult) => {
|
|
40
40
|
if (versioningResult.type === "independent") return Effect.succeed("scoped");
|
|
41
41
|
return Effect.succeed("single");
|
|
@@ -50,7 +50,7 @@ const TagStrategyLive = Layer.succeed(TagStrategy, TagStrategy.of({
|
|
|
50
50
|
if (name.startsWith("@")) return Effect.succeed(`${name}@${version}`);
|
|
51
51
|
return Effect.succeed(`${name}@${version}`);
|
|
52
52
|
}
|
|
53
|
-
})
|
|
53
|
+
});
|
|
54
54
|
|
|
55
55
|
//#endregion
|
|
56
56
|
export { TagStrategy, TagStrategyLive };
|
|
@@ -2,8 +2,8 @@ import { ToolNotFoundError } from "../errors/ToolNotFoundError.js";
|
|
|
2
2
|
import { ToolResolutionError } from "../errors/ToolResolutionError.js";
|
|
3
3
|
import { ResolvedTool } from "../schemas/ResolvedTool.js";
|
|
4
4
|
import { Context, Effect, Layer, Option, Ref } from "effect";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
5
|
+
import { PackageManagerDetector, WorkspaceRoot } from "@effected/workspaces";
|
|
6
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
7
7
|
|
|
8
8
|
//#region src/services/ToolDiscovery.ts
|
|
9
9
|
/**
|
|
@@ -21,7 +21,7 @@ import { PackageManagerDetector, WorkspaceRoot } from "workspaces-effect";
|
|
|
21
21
|
* );
|
|
22
22
|
* }).pipe(
|
|
23
23
|
* Effect.provide(ToolDiscoveryLive),
|
|
24
|
-
* Effect.provide(
|
|
24
|
+
* Effect.provide(NodeServices.layer),
|
|
25
25
|
* )
|
|
26
26
|
* );
|
|
27
27
|
* ```
|
|
@@ -29,7 +29,7 @@ import { PackageManagerDetector, WorkspaceRoot } from "workspaces-effect";
|
|
|
29
29
|
* @since 0.2.0
|
|
30
30
|
* @public
|
|
31
31
|
*/
|
|
32
|
-
var ToolDiscovery = class extends Context.
|
|
32
|
+
var ToolDiscovery = class extends Context.Service()("@savvy-web/silk-effects/ToolDiscovery") {};
|
|
33
33
|
/**
|
|
34
34
|
* Build the PM exec prefix for running a local binary.
|
|
35
35
|
*/
|
|
@@ -62,14 +62,14 @@ function pmExecArgs(pmType, name) {
|
|
|
62
62
|
/**
|
|
63
63
|
* Run a command and return its stdout, or `Option.none()` on failure.
|
|
64
64
|
*/
|
|
65
|
-
function tryString(cmd) {
|
|
66
|
-
return
|
|
65
|
+
function tryString(spawner, cmd) {
|
|
66
|
+
return spawner.string(cmd).pipe(Effect.map((s) => Option.some(s.trim())), Effect.catch(() => Effect.succeed(Option.none())));
|
|
67
67
|
}
|
|
68
68
|
/**
|
|
69
69
|
* Run a command and return true if it succeeds (exit code 0).
|
|
70
70
|
*/
|
|
71
|
-
function tryExists(cmd) {
|
|
72
|
-
return
|
|
71
|
+
function tryExists(spawner, cmd) {
|
|
72
|
+
return spawner.exitCode(cmd).pipe(Effect.map((code) => code === 0), Effect.catch(() => Effect.succeed(false)));
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Extract version from command output using a VersionExtractor.
|
|
@@ -98,45 +98,46 @@ function extractVersion(output, extractor) {
|
|
|
98
98
|
* Live implementation of {@link ToolDiscovery}.
|
|
99
99
|
*
|
|
100
100
|
* @remarks
|
|
101
|
-
* Requires `
|
|
102
|
-
*
|
|
101
|
+
* Requires `ChildProcessSpawner` from `effect/unstable/process` (provide
|
|
102
|
+
* `NodeServices.layer` at the app edge), plus `PackageManagerDetector`
|
|
103
|
+
* and `WorkspaceRoot` from `@effected/workspaces`.
|
|
103
104
|
*
|
|
104
105
|
* @since 0.2.0
|
|
105
106
|
* @public
|
|
106
107
|
*/
|
|
107
108
|
const ToolDiscoveryLive = Layer.effect(ToolDiscovery, Effect.gen(function* () {
|
|
108
|
-
const
|
|
109
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
109
110
|
const wsRoot = yield* WorkspaceRoot;
|
|
110
111
|
const pmDetector = yield* PackageManagerDetector;
|
|
111
112
|
const cache = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
112
113
|
const resolve = (definition) => Effect.gen(function* () {
|
|
113
114
|
const hit = (yield* Ref.get(cache)).get(definition.name);
|
|
114
115
|
if (hit) return hit;
|
|
115
|
-
const root = yield* wsRoot.find(process.cwd()).pipe(Effect.
|
|
116
|
+
const root = yield* wsRoot.find(process.cwd()).pipe(Effect.catch(() => Effect.fail(new ToolResolutionError({
|
|
116
117
|
name: definition.name,
|
|
117
118
|
reason: "Could not find workspace root"
|
|
118
119
|
}))));
|
|
119
|
-
const pmType = (yield* pmDetector.detect(root).pipe(Effect.
|
|
120
|
+
const pmType = (yield* pmDetector.detect(root).pipe(Effect.catch(() => Effect.fail(new ToolResolutionError({
|
|
120
121
|
name: definition.name,
|
|
121
122
|
reason: "Could not detect package manager"
|
|
122
|
-
}))))).
|
|
123
|
-
const globalExists = yield*
|
|
123
|
+
}))))).name;
|
|
124
|
+
const globalExists = yield* tryExists(spawner, ChildProcess.make("sh", ["-c", `command -v ${definition.name}`]));
|
|
124
125
|
let globalVersion = Option.none();
|
|
125
126
|
if (globalExists && definition.versionExtractor._tag !== "None") {
|
|
126
127
|
const flag = definition.versionExtractor.flag;
|
|
127
|
-
globalVersion = extractVersion(yield*
|
|
128
|
+
globalVersion = extractVersion(yield* tryString(spawner, ChildProcess.make(definition.name, [flag])), definition.versionExtractor);
|
|
128
129
|
}
|
|
129
130
|
let localExists = false;
|
|
130
131
|
let localVersion = Option.none();
|
|
131
132
|
const [pmBin, ...pmArgs] = pmExecArgs(pmType, definition.name);
|
|
132
133
|
if (definition.versionExtractor._tag !== "None") {
|
|
133
134
|
const flag = definition.versionExtractor.flag;
|
|
134
|
-
const localOutput = yield*
|
|
135
|
+
const localOutput = yield* tryString(spawner, ChildProcess.make(pmBin, [...pmArgs, flag]));
|
|
135
136
|
if (Option.isSome(localOutput)) {
|
|
136
137
|
localExists = true;
|
|
137
138
|
localVersion = extractVersion(localOutput, definition.versionExtractor);
|
|
138
139
|
}
|
|
139
|
-
} else localExists = yield*
|
|
140
|
+
} else localExists = yield* tryExists(spawner, ChildProcess.make(pmBin, [...pmArgs, "--version"]));
|
|
140
141
|
if (!globalExists && !localExists) return yield* Effect.fail(new ToolResolutionError({
|
|
141
142
|
name: definition.name,
|
|
142
143
|
reason: "Tool not found globally or locally"
|
|
@@ -209,15 +210,15 @@ const ToolDiscoveryLive = Layer.effect(ToolDiscovery, Effect.gen(function* () {
|
|
|
209
210
|
reason: message ?? err.reason
|
|
210
211
|
})));
|
|
211
212
|
const isAvailable = (definition) => Effect.gen(function* () {
|
|
212
|
-
if (yield*
|
|
213
|
+
if (yield* tryExists(spawner, ChildProcess.make("sh", ["-c", `command -v ${definition.name}`]))) return true;
|
|
213
214
|
const rootResult = yield* wsRoot.find(process.cwd()).pipe(Effect.option);
|
|
214
215
|
if (Option.isNone(rootResult)) return false;
|
|
215
216
|
const pmResult = yield* pmDetector.detect(rootResult.value).pipe(Effect.option);
|
|
216
217
|
if (Option.isNone(pmResult)) return false;
|
|
217
|
-
const pmType = pmResult.value.
|
|
218
|
+
const pmType = pmResult.value.name;
|
|
218
219
|
const probeFlag = definition.versionExtractor._tag !== "None" ? definition.versionExtractor.flag : "--version";
|
|
219
220
|
const [pmBin, ...pmArgs] = pmExecArgs(pmType, definition.name);
|
|
220
|
-
return yield*
|
|
221
|
+
return yield* tryExists(spawner, ChildProcess.make(pmBin, [...pmArgs, probeFlag]));
|
|
221
222
|
});
|
|
222
223
|
return {
|
|
223
224
|
resolve,
|
|
@@ -19,7 +19,7 @@ import { Context, Effect, Layer } from "effect";
|
|
|
19
19
|
* }).pipe(
|
|
20
20
|
* Effect.provide(VersioningStrategyLive),
|
|
21
21
|
* Effect.provide(ChangesetConfigReaderLive),
|
|
22
|
-
* Effect.provide(
|
|
22
|
+
* Effect.provide(NodeServices.layer),
|
|
23
23
|
* )
|
|
24
24
|
* );
|
|
25
25
|
* ```
|
|
@@ -27,7 +27,7 @@ import { Context, Effect, Layer } from "effect";
|
|
|
27
27
|
* @since 0.1.0
|
|
28
28
|
* @public
|
|
29
29
|
*/
|
|
30
|
-
var VersioningStrategy = class extends Context.
|
|
30
|
+
var VersioningStrategy = class extends Context.Service()("@savvy-web/silk-effects/VersioningStrategy") {};
|
|
31
31
|
/**
|
|
32
32
|
* Live implementation of {@link VersioningStrategy}.
|
|
33
33
|
*
|
package/tsdoc-metadata.json
CHANGED
package/turbo/schemas/DryRun.js
CHANGED
|
@@ -5,9 +5,9 @@ import { Schema } from "effect";
|
|
|
5
5
|
const TurboCache = Schema.Struct({
|
|
6
6
|
local: Schema.Boolean,
|
|
7
7
|
remote: Schema.Boolean,
|
|
8
|
-
status: Schema.
|
|
8
|
+
status: Schema.Literals(["HIT", "MISS"]),
|
|
9
9
|
timeSaved: Schema.Number
|
|
10
|
-
}).
|
|
10
|
+
}).annotate({ identifier: "TurboCache" });
|
|
11
11
|
/** turbo's environment-variable contribution block (per-task and global). */
|
|
12
12
|
const TurboEnvVars = Schema.Struct({
|
|
13
13
|
specified: Schema.Struct({
|
|
@@ -17,7 +17,7 @@ const TurboEnvVars = Schema.Struct({
|
|
|
17
17
|
configured: Schema.Array(Schema.String),
|
|
18
18
|
inferred: Schema.Array(Schema.String),
|
|
19
19
|
passthrough: Schema.NullOr(Schema.Array(Schema.String))
|
|
20
|
-
}).
|
|
20
|
+
}).annotate({ identifier: "TurboEnvVars" });
|
|
21
21
|
/** A single task entry from `turbo run <task> --dry=json`. */
|
|
22
22
|
const TurboDryTask = Schema.Struct({
|
|
23
23
|
taskId: Schema.String,
|
|
@@ -25,33 +25,27 @@ const TurboDryTask = Schema.Struct({
|
|
|
25
25
|
package: Schema.String,
|
|
26
26
|
directory: Schema.String,
|
|
27
27
|
hash: Schema.String,
|
|
28
|
-
inputs: Schema.Record(
|
|
29
|
-
key: Schema.String,
|
|
30
|
-
value: Schema.String
|
|
31
|
-
}),
|
|
28
|
+
inputs: Schema.Record(Schema.String, Schema.String),
|
|
32
29
|
hashOfExternalDependencies: Schema.String,
|
|
33
30
|
cache: TurboCache,
|
|
34
31
|
dependencies: Schema.Array(Schema.String),
|
|
35
32
|
dependents: Schema.Array(Schema.String),
|
|
36
33
|
environmentVariables: TurboEnvVars
|
|
37
|
-
}).
|
|
34
|
+
}).annotate({ identifier: "TurboDryTask" });
|
|
38
35
|
/** The `globalCacheInputs` block — the components of the global hash. */
|
|
39
36
|
const TurboGlobalCacheInputs = Schema.Struct({
|
|
40
37
|
rootKey: Schema.String,
|
|
41
|
-
files: Schema.Record(
|
|
42
|
-
key: Schema.String,
|
|
43
|
-
value: Schema.String
|
|
44
|
-
}),
|
|
38
|
+
files: Schema.Record(Schema.String, Schema.String),
|
|
45
39
|
hashOfExternalDependencies: Schema.String,
|
|
46
40
|
hashOfInternalDependencies: Schema.String,
|
|
47
41
|
environmentVariables: TurboEnvVars
|
|
48
|
-
}).
|
|
42
|
+
}).annotate({ identifier: "TurboGlobalCacheInputs" });
|
|
49
43
|
/** The subset of `turbo run <task> --dry=json` the Turbo namespace reads. */
|
|
50
44
|
const TurboDryRun = Schema.Struct({
|
|
51
45
|
turboVersion: Schema.String,
|
|
52
46
|
globalCacheInputs: TurboGlobalCacheInputs,
|
|
53
47
|
tasks: Schema.Array(TurboDryTask)
|
|
54
|
-
}).
|
|
48
|
+
}).annotate({ identifier: "TurboDryRun" });
|
|
55
49
|
|
|
56
50
|
//#endregion
|
|
57
51
|
export { TurboCache, TurboDryRun, TurboDryTask, TurboEnvVars, TurboGlobalCacheInputs };
|
package/turbo/schemas/results.js
CHANGED
|
@@ -6,9 +6,9 @@ const PackageCacheStatus = Schema.Struct({
|
|
|
6
6
|
package: Schema.String,
|
|
7
7
|
taskId: Schema.String,
|
|
8
8
|
hash: Schema.String,
|
|
9
|
-
status: Schema.
|
|
9
|
+
status: Schema.Literals(["HIT", "MISS"]),
|
|
10
10
|
timeSaved: Schema.Number
|
|
11
|
-
}).
|
|
11
|
+
}).annotate({ identifier: "PackageCacheStatus" });
|
|
12
12
|
/** The hash-contributor breakdown explaining a single MISS. */
|
|
13
13
|
const MissExplanation = Schema.Struct({
|
|
14
14
|
package: Schema.String,
|
|
@@ -18,7 +18,7 @@ const MissExplanation = Schema.Struct({
|
|
|
18
18
|
hashedEnvVars: Schema.Array(Schema.String),
|
|
19
19
|
externalDependenciesHash: Schema.String,
|
|
20
20
|
dependsOn: Schema.Array(Schema.String)
|
|
21
|
-
}).
|
|
21
|
+
}).annotate({ identifier: "MissExplanation" });
|
|
22
22
|
/** Global-hash component summary (every task inherits this). */
|
|
23
23
|
const GlobalHashSummary = Schema.Struct({
|
|
24
24
|
rootKey: Schema.String,
|
|
@@ -26,7 +26,7 @@ const GlobalHashSummary = Schema.Struct({
|
|
|
26
26
|
externalDependenciesHash: Schema.String,
|
|
27
27
|
internalDependenciesHash: Schema.String,
|
|
28
28
|
globalEnvVars: Schema.Array(Schema.String)
|
|
29
|
-
}).
|
|
29
|
+
}).annotate({ identifier: "GlobalHashSummary" });
|
|
30
30
|
/** Result of `TurboInspector.diagnoseCache`. */
|
|
31
31
|
const CacheDiagnosis = Schema.Struct({
|
|
32
32
|
task: Schema.String,
|
|
@@ -36,26 +36,26 @@ const CacheDiagnosis = Schema.Struct({
|
|
|
36
36
|
statuses: Schema.Array(PackageCacheStatus),
|
|
37
37
|
explanations: Schema.Array(MissExplanation),
|
|
38
38
|
global: GlobalHashSummary
|
|
39
|
-
}).
|
|
39
|
+
}).annotate({ identifier: "CacheDiagnosis" });
|
|
40
40
|
/** One node in the task graph. */
|
|
41
41
|
const GraphNode = Schema.Struct({
|
|
42
42
|
taskId: Schema.String,
|
|
43
43
|
package: Schema.String,
|
|
44
44
|
dependsOn: Schema.Array(Schema.String)
|
|
45
|
-
}).
|
|
45
|
+
}).annotate({ identifier: "GraphNode" });
|
|
46
46
|
/** Result of `TurboInspector.taskGraph`. */
|
|
47
47
|
const TaskGraphResult = Schema.Struct({
|
|
48
48
|
task: Schema.optional(Schema.String),
|
|
49
49
|
nodeCount: Schema.Number,
|
|
50
50
|
nodes: Schema.Array(GraphNode),
|
|
51
51
|
criticalPath: Schema.Array(Schema.String)
|
|
52
|
-
}).
|
|
52
|
+
}).annotate({ identifier: "TaskGraphResult" });
|
|
53
53
|
/** Result of `TurboInspector.affected`. */
|
|
54
54
|
const AffectedResult = Schema.Struct({
|
|
55
55
|
base: Schema.String,
|
|
56
56
|
packages: Schema.Array(Schema.String),
|
|
57
57
|
dependents: Schema.Array(Schema.String)
|
|
58
|
-
}).
|
|
58
|
+
}).annotate({ identifier: "AffectedResult" });
|
|
59
59
|
|
|
60
60
|
//#endregion
|
|
61
61
|
export { AffectedResult, CacheDiagnosis, GlobalHashSummary, GraphNode, MissExplanation, PackageCacheStatus, TaskGraphResult };
|
|
@@ -3,8 +3,9 @@ import { ToolDiscovery } from "../../services/ToolDiscovery.js";
|
|
|
3
3
|
import { TurboDigest } from "../digest.js";
|
|
4
4
|
import { DryRunParseError, NotATurboRepoError, TurboExecError, TurboNotInstalledError } from "../errors.js";
|
|
5
5
|
import { TurboDryRun } from "../schemas/DryRun.js";
|
|
6
|
-
import { Context, Effect, Layer, Schema } from "effect";
|
|
7
|
-
import {
|
|
6
|
+
import { Context, Effect, FileSystem, Layer, Schema } from "effect";
|
|
7
|
+
import { Git } from "@effected/git";
|
|
8
|
+
import { ChildProcessSpawner } from "effect/unstable/process";
|
|
8
9
|
|
|
9
10
|
//#region src/turbo/services/TurboInspector.ts
|
|
10
11
|
/**
|
|
@@ -18,7 +19,7 @@ import { Command, CommandExecutor, FileSystem } from "@effect/platform";
|
|
|
18
19
|
*
|
|
19
20
|
* @since 0.7.0
|
|
20
21
|
*/
|
|
21
|
-
var TurboInspector = class extends Context.
|
|
22
|
+
var TurboInspector = class extends Context.Service()("@savvy-web/silk-effects/TurboInspector") {};
|
|
22
23
|
const TURBO = ToolDefinition.make({ name: "turbo" });
|
|
23
24
|
/** Default task used by {@link TurboInspector.taskGraph} and {@link TurboInspector.affected}. */
|
|
24
25
|
const DEFAULT_BUILD_TASK = "build:dev";
|
|
@@ -29,41 +30,51 @@ const DEFAULT_AFFECTED_BASE = "main";
|
|
|
29
30
|
*
|
|
30
31
|
* @remarks
|
|
31
32
|
* Requires {@link ToolDiscovery} to resolve the `turbo` binary, plus
|
|
32
|
-
* `
|
|
33
|
-
*
|
|
34
|
-
* discharged onto each command
|
|
35
|
-
* the public method effects at
|
|
33
|
+
* `ChildProcessSpawner` and `FileSystem` from core (provide `NodeServices.layer`
|
|
34
|
+
* at the app edge) and `Git` from `@effected/git`. Mirrors `ToolDiscoveryLive`:
|
|
35
|
+
* the spawner is captured at layer construction and discharged onto each command
|
|
36
|
+
* effect with `Effect.provideService`, keeping the public method effects at
|
|
37
|
+
* `R = never`.
|
|
36
38
|
*
|
|
37
39
|
* @since 0.7.0
|
|
38
40
|
*/
|
|
39
41
|
const TurboInspectorLive = Layer.effect(TurboInspector, Effect.gen(function* () {
|
|
40
42
|
const discovery = yield* ToolDiscovery;
|
|
41
|
-
const
|
|
43
|
+
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
|
|
42
44
|
const fs = yield* FileSystem.FileSystem;
|
|
45
|
+
const git = yield* Git;
|
|
43
46
|
const runTurbo = (cwd, args, env) => discovery.require(TURBO).pipe(Effect.mapError((e) => new TurboNotInstalledError({ reason: e.reason })), Effect.flatMap((resolved) => {
|
|
44
47
|
const command = resolved.exec(...args).workingDirectory(cwd);
|
|
45
|
-
return Effect.provideService((env ? command.env(env) : command).string(),
|
|
48
|
+
return Effect.provideService((env ? command.env(env) : command).string(), ChildProcessSpawner.ChildProcessSpawner, spawner).pipe(Effect.mapError((e) => new TurboExecError({
|
|
46
49
|
args: [...args],
|
|
47
50
|
reason: String(e)
|
|
48
51
|
})));
|
|
49
52
|
}));
|
|
50
|
-
/**
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
})
|
|
55
|
-
|
|
53
|
+
/** The paths changed between `base` and HEAD, via `@effected/git`. */
|
|
54
|
+
const changedPaths = (cwd, base) => git.changedFiles(cwd, {
|
|
55
|
+
base,
|
|
56
|
+
head: "HEAD"
|
|
57
|
+
}).pipe(Effect.mapError((e) => new TurboExecError({
|
|
58
|
+
args: [
|
|
59
|
+
"git",
|
|
60
|
+
"diff",
|
|
61
|
+
"--name-only",
|
|
62
|
+
`${base}...HEAD`
|
|
63
|
+
],
|
|
64
|
+
reason: e.message
|
|
65
|
+
})));
|
|
66
|
+
const ensureTurboRepo = (cwd) => fs.exists(`${cwd}/turbo.json`).pipe(Effect.catch(() => Effect.succeed(false)), Effect.flatMap((ok) => ok ? Effect.void : Effect.fail(new NotATurboRepoError({ cwd }))));
|
|
56
67
|
const dryRun = (task, cwd, args, env) => ensureTurboRepo(cwd).pipe(Effect.flatMap(() => runTurbo(cwd, args, env)), Effect.flatMap((stdout) => Effect.try({
|
|
57
68
|
try: () => JSON.parse(stdout),
|
|
58
69
|
catch: (e) => new DryRunParseError({
|
|
59
70
|
task,
|
|
60
71
|
reason: `invalid JSON: ${String(e)}`
|
|
61
72
|
})
|
|
62
|
-
})), Effect.flatMap((json) => Schema.
|
|
73
|
+
})), Effect.flatMap((json) => Schema.decodeUnknownEffect(TurboDryRun)(json).pipe(Effect.mapError((e) => new DryRunParseError({
|
|
63
74
|
task,
|
|
64
75
|
reason: String(e)
|
|
65
76
|
})))));
|
|
66
|
-
return
|
|
77
|
+
return {
|
|
67
78
|
diagnoseCache: (task, cwd) => dryRun(task, cwd, [
|
|
68
79
|
"run",
|
|
69
80
|
task,
|
|
@@ -80,11 +91,7 @@ const TurboInspectorLive = Layer.effect(TurboInspector, Effect.gen(function* ()
|
|
|
80
91
|
affected: (cwd, base) => {
|
|
81
92
|
const ref = base ?? DEFAULT_AFFECTED_BASE;
|
|
82
93
|
return Effect.all({
|
|
83
|
-
changedFiles:
|
|
84
|
-
"diff",
|
|
85
|
-
"--name-only",
|
|
86
|
-
`${ref}...HEAD`
|
|
87
|
-
]),
|
|
94
|
+
changedFiles: changedPaths(cwd, ref),
|
|
88
95
|
dry: dryRun(`${DEFAULT_BUILD_TASK} --affected`, cwd, [
|
|
89
96
|
"run",
|
|
90
97
|
DEFAULT_BUILD_TASK,
|
|
@@ -93,7 +100,7 @@ const TurboInspectorLive = Layer.effect(TurboInspector, Effect.gen(function* ()
|
|
|
93
100
|
], { TURBO_SCM_BASE: ref })
|
|
94
101
|
}).pipe(Effect.map(({ changedFiles, dry }) => TurboDigest.affected(ref, changedFiles, dry)));
|
|
95
102
|
}
|
|
96
|
-
}
|
|
103
|
+
};
|
|
97
104
|
}));
|
|
98
105
|
|
|
99
106
|
//#endregion
|
package/utils/ToolCommand.js
CHANGED
|
@@ -1,10 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Effect, Stream } from "effect";
|
|
2
|
+
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";
|
|
2
3
|
|
|
3
4
|
//#region src/utils/ToolCommand.ts
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
+
* Rebuild a command with patched options.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* @remarks
|
|
9
|
+
* `ChildProcess.Command` values are pure data, but core only ships setters for
|
|
10
|
+
* `cwd` and `env`. This helper rebuilds a `StandardCommand` with merged
|
|
11
|
+
* options, recursing into both sides of a `PipedCommand` the same way
|
|
12
|
+
* `ChildProcess.setCwd` does.
|
|
13
|
+
*/
|
|
14
|
+
const patchOptions = (command, patch) => {
|
|
15
|
+
switch (command._tag) {
|
|
16
|
+
case "StandardCommand": return ChildProcess.make(command.command, command.args, patch(command.options));
|
|
17
|
+
case "PipedCommand": return ChildProcess.pipeTo(patchOptions(command.left, patch), patchOptions(command.right, patch), command.options);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Wraps `effect/unstable/process` `ChildProcess.Command` with instance method ergonomics.
|
|
22
|
+
*
|
|
23
|
+
* Use `yield* cmd.string()` instead of resolving the `ChildProcessSpawner` service by hand.
|
|
8
24
|
*
|
|
9
25
|
* @since 0.2.0
|
|
10
26
|
* @public
|
|
@@ -14,26 +30,36 @@ var ToolCommand = class ToolCommand {
|
|
|
14
30
|
constructor(command) {
|
|
15
31
|
this.command = command;
|
|
16
32
|
}
|
|
17
|
-
string(
|
|
18
|
-
return
|
|
33
|
+
string() {
|
|
34
|
+
return Effect.flatMap(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.string(this.command));
|
|
19
35
|
}
|
|
20
36
|
exitCode() {
|
|
21
|
-
return
|
|
37
|
+
return Effect.flatMap(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.exitCode(this.command));
|
|
22
38
|
}
|
|
23
|
-
lines(
|
|
24
|
-
return
|
|
39
|
+
lines() {
|
|
40
|
+
return Effect.flatMap(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.lines(this.command));
|
|
25
41
|
}
|
|
26
42
|
stream() {
|
|
27
|
-
return
|
|
43
|
+
return Stream.unwrap(Effect.map(ChildProcessSpawner.ChildProcessSpawner, (spawner) => spawner.streamString(this.command)));
|
|
28
44
|
}
|
|
29
45
|
env(environment) {
|
|
30
|
-
return new ToolCommand(
|
|
46
|
+
return new ToolCommand(patchOptions(this.command, (options) => ({
|
|
47
|
+
...options,
|
|
48
|
+
env: {
|
|
49
|
+
...options.env,
|
|
50
|
+
...environment
|
|
51
|
+
},
|
|
52
|
+
extendEnv: true
|
|
53
|
+
})));
|
|
31
54
|
}
|
|
32
55
|
workingDirectory(cwd) {
|
|
33
|
-
return new ToolCommand(
|
|
56
|
+
return new ToolCommand(ChildProcess.setCwd(this.command, cwd));
|
|
34
57
|
}
|
|
35
58
|
stdin(input) {
|
|
36
|
-
return new ToolCommand(
|
|
59
|
+
return new ToolCommand(patchOptions(this.command, (options) => ({
|
|
60
|
+
...options,
|
|
61
|
+
stdin: Stream.succeed(new TextEncoder().encode(input))
|
|
62
|
+
})));
|
|
37
63
|
}
|
|
38
64
|
};
|
|
39
65
|
|