From 7408e13cd3873c3f8e8a3ee4f28dbd711d6875bd Mon Sep 17 00:00:00 2001 From: skulidropek Date: Wed, 11 Feb 2026 14:46:47 +0000 Subject: [PATCH 1/2] fix(lint): include tests in effect-ts analyzer --- .../app/eslint.effect-ts-check.config.mjs | 2 +- packages/app/tests/app/main.test.ts | 15 +++-- .../lib/eslint.effect-ts-check.config.mjs | 2 +- .../lib/tests/usecases/prepare-files.test.ts | 66 ++++++++++++------- 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/packages/app/eslint.effect-ts-check.config.mjs b/packages/app/eslint.effect-ts-check.config.mjs index b36df69e..665af850 100644 --- a/packages/app/eslint.effect-ts-check.config.mjs +++ b/packages/app/eslint.effect-ts-check.config.mjs @@ -136,7 +136,7 @@ const restrictedSyntaxBaseNoServiceFactory = [ export default tseslint.config( { name: "effect-ts-compliance-check", - files: ["src/**/*.ts", "scripts/**/*.ts"], + files: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts"], languageOptions: { parser: tseslint.parser, globals: { ...globals.node } diff --git a/packages/app/tests/app/main.test.ts b/packages/app/tests/app/main.test.ts index 4a93e7c2..5d953c1c 100644 --- a/packages/app/tests/app/main.test.ts +++ b/packages/app/tests/app/main.test.ts @@ -26,15 +26,20 @@ const withArgv = (nextArgv: ReadonlyArray) => }) ) -const usageCases = [ - { argv: ["node", "main"], needle: "pnpm docker-git" as const }, - { argv: ["node", "main", "Alice"], needle: "Usage:" as const } -] as const +type UsageCase = { + readonly argv: ReadonlyArray + readonly needle: string +} + +const usageCases: ReadonlyArray = [ + { argv: ["node", "main"], needle: "pnpm docker-git" }, + { argv: ["node", "main", "Alice"], needle: "Usage:" } +] const runUsageCase = ({ argv, needle -}: (typeof usageCases)[number]) => +}: UsageCase) => Effect.scoped( Effect.gen(function*(_) { const logSpy = yield* _(withLogSpy) diff --git a/packages/lib/eslint.effect-ts-check.config.mjs b/packages/lib/eslint.effect-ts-check.config.mjs index b36df69e..665af850 100644 --- a/packages/lib/eslint.effect-ts-check.config.mjs +++ b/packages/lib/eslint.effect-ts-check.config.mjs @@ -136,7 +136,7 @@ const restrictedSyntaxBaseNoServiceFactory = [ export default tseslint.config( { name: "effect-ts-compliance-check", - files: ["src/**/*.ts", "scripts/**/*.ts"], + files: ["src/**/*.ts", "scripts/**/*.ts", "tests/**/*.ts"], languageOptions: { parser: tseslint.parser, globals: { ...globals.node } diff --git a/packages/lib/tests/usecases/prepare-files.test.ts b/packages/lib/tests/usecases/prepare-files.test.ts index e34bd913..1e90d3d0 100644 --- a/packages/lib/tests/usecases/prepare-files.test.ts +++ b/packages/lib/tests/usecases/prepare-files.test.ts @@ -1,7 +1,5 @@ -import * as fs from "node:fs" -import * as os from "node:os" -import * as path from "node:path" - +import * as FileSystem from "@effect/platform/FileSystem" +import * as Path from "@effect/platform/Path" import { NodeContext } from "@effect/platform-node" import { describe, expect, it } from "@effect/vitest" import { Effect } from "effect" @@ -9,20 +7,22 @@ import { Effect } from "effect" import type { TemplateConfig } from "../../src/core/domain.js" import { prepareProjectFiles } from "../../src/usecases/actions/prepare-files.js" -const withTempDir = (use: (tempDir: string) => Effect.Effect): Effect.Effect => +const withTempDir = ( + use: (tempDir: string) => Effect.Effect +): Effect.Effect => Effect.scoped( Effect.gen(function*(_) { + const fs = yield* _(FileSystem.FileSystem) const tempDir = yield* _( - Effect.acquireRelease( - Effect.sync(() => fs.mkdtempSync(path.join(os.tmpdir(), "docker-git-force-env-"))), - (dir) => Effect.sync(() => fs.rmSync(dir, { recursive: true, force: true })) - ) + fs.makeTempDirectoryScoped({ + prefix: "docker-git-force-env-" + }) ) return yield* _(use(tempDir)) }) ) -const makeGlobalConfig = (root: string): TemplateConfig => ({ +const makeGlobalConfig = (root: string, path: Path.Path): TemplateConfig => ({ containerName: "dg-test", serviceName: "dg-test", sshUser: "dev", @@ -41,7 +41,11 @@ const makeGlobalConfig = (root: string): TemplateConfig => ({ pnpmVersion: "10.27.0" }) -const makeProjectConfig = (outDir: string, enableMcpPlaywright: boolean): TemplateConfig => ({ +const makeProjectConfig = ( + outDir: string, + enableMcpPlaywright: boolean, + path: Path.Path +): TemplateConfig => ({ containerName: "dg-test", serviceName: "dg-test", sshUser: "dev", @@ -60,14 +64,33 @@ const makeProjectConfig = (outDir: string, enableMcpPlaywright: boolean): Templa pnpmVersion: "10.27.0" }) +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null + +const readEnableMcpPlaywrightFlag = (value: unknown): boolean | undefined => { + if (!isRecord(value)) { + return undefined + } + + const template = value.template + if (!isRecord(template)) { + return undefined + } + + const flag = template.enableMcpPlaywright + return typeof flag === "boolean" ? flag : undefined +} + describe("prepareProjectFiles", () => { it.effect("force-env refresh rewrites managed templates", () => withTempDir((root) => Effect.gen(function*(_) { + const fs = yield* _(FileSystem.FileSystem) + const path = yield* _(Path.Path) const outDir = path.join(root, "project") - const globalConfig = makeGlobalConfig(root) - const withoutMcp = makeProjectConfig(outDir, false) - const withMcp = makeProjectConfig(outDir, true) + const globalConfig = makeGlobalConfig(root, path) + const withoutMcp = makeProjectConfig(outDir, false, path) + const withMcp = makeProjectConfig(outDir, true, path) yield* _( prepareProjectFiles(outDir, root, globalConfig, withoutMcp, { @@ -76,9 +99,7 @@ describe("prepareProjectFiles", () => { }) ) - const composeBefore = yield* _( - Effect.sync(() => fs.readFileSync(path.join(outDir, "docker-compose.yml"), "utf8")) - ) + const composeBefore = yield* _(fs.readFileString(path.join(outDir, "docker-compose.yml"))) expect(composeBefore).not.toContain("dg-test-browser") yield* _( @@ -88,16 +109,13 @@ describe("prepareProjectFiles", () => { }) ) - const composeAfter = yield* _( - Effect.sync(() => fs.readFileSync(path.join(outDir, "docker-compose.yml"), "utf8")) - ) - const configAfter = yield* _( - Effect.sync(() => JSON.parse(fs.readFileSync(path.join(outDir, "docker-git.json"), "utf8"))) - ) + const composeAfter = yield* _(fs.readFileString(path.join(outDir, "docker-compose.yml"))) + const configAfterText = yield* _(fs.readFileString(path.join(outDir, "docker-git.json"))) + const configAfter = yield* _(Effect.sync((): unknown => JSON.parse(configAfterText))) expect(composeAfter).toContain("dg-test-browser") expect(composeAfter).toContain('MCP_PLAYWRIGHT_ENABLE: "1"') - expect(configAfter.template.enableMcpPlaywright).toBe(true) + expect(readEnableMcpPlaywrightFlag(configAfter)).toBe(true) }) ).pipe(Effect.provide(NodeContext.layer))) }) From b0a1f0efa1ea0fc33900ba1c2fdb85aa07f27922 Mon Sep 17 00:00:00 2001 From: skulidropek Date: Wed, 11 Feb 2026 14:53:34 +0000 Subject: [PATCH 2/2] chore(ci): retrigger checks after runner stall