mirror of
https://github.com/VibedByKaKi/t3-code-android-nightly.git
synced 2026-10-09 11:51:15 +02:00
317 lines
11 KiB
TypeScript
317 lines
11 KiB
TypeScript
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
import { assert, it } from "@effect/vitest";
|
|
import * as Config from "effect/Config";
|
|
import * as ConfigProvider from "effect/ConfigProvider";
|
|
import * as Effect from "effect/Effect";
|
|
import * as FileSystem from "effect/FileSystem";
|
|
import * as Layer from "effect/Layer";
|
|
import * as Path from "effect/Path";
|
|
import * as PlatformError from "effect/PlatformError";
|
|
import * as Schema from "effect/Schema";
|
|
import { Command, CliError } from "effect/cli";
|
|
import * as TestConsole from "effect/testing/TestConsole";
|
|
import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";
|
|
|
|
import {
|
|
ReleaseGitHubOutputConfigurationError,
|
|
ReleaseGitHubOutputWriteError,
|
|
ReleasePackageManifestError,
|
|
releasePackageFiles,
|
|
updateReleasePackageVersions,
|
|
updateReleasePackageVersionsCommand,
|
|
} from "./update-release-package-versions.ts";
|
|
|
|
const ScriptTestLayer = Layer.mergeAll(NodeServices.layer, TestConsole.layer);
|
|
const runCli = Command.runWith(updateReleasePackageVersionsCommand, { version: "0.0.0" });
|
|
const PackageJsonSchema = Schema.Record(Schema.String, Schema.Unknown);
|
|
const PackageJsonPrettyJson = fromJsonStringPretty(PackageJsonSchema);
|
|
const decodePackageJson = Schema.decodeEffect(PackageJsonPrettyJson);
|
|
const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson);
|
|
|
|
const writePackageJsonFixtures = Effect.fn("writePackageJsonFixtures")(function* (
|
|
rootDir: string,
|
|
version: string,
|
|
) {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
|
|
for (const relativePath of releasePackageFiles) {
|
|
const filePath = path.join(rootDir, relativePath);
|
|
yield* fs.makeDirectory(path.dirname(filePath), { recursive: true });
|
|
yield* fs.writeFileString(
|
|
filePath,
|
|
`${yield* encodePackageJson({
|
|
name: relativePath,
|
|
version,
|
|
private: true,
|
|
})}\n`,
|
|
);
|
|
}
|
|
});
|
|
|
|
const readReleaseVersions = Effect.fn("readReleaseVersions")(function* (rootDir: string) {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
const versions = new Map<string, string>();
|
|
|
|
for (const relativePath of releasePackageFiles) {
|
|
const filePath = path.join(rootDir, relativePath);
|
|
const packageJson = yield* fs.readFileString(filePath).pipe(Effect.flatMap(decodePackageJson));
|
|
versions.set(relativePath, String(packageJson.version));
|
|
}
|
|
|
|
return versions;
|
|
});
|
|
|
|
const captureLogs = <A, E, R>(effect: Effect.Effect<A, E, R>) =>
|
|
Effect.gen(function* () {
|
|
const result = yield* effect;
|
|
const logs = (yield* TestConsole.logLines).filter(
|
|
(line): line is string => typeof line === "string",
|
|
);
|
|
return { result, logs };
|
|
});
|
|
|
|
it.layer(ScriptTestLayer)("update-release-package-versions", (it) => {
|
|
it.effect("updates all release package versions under the provided root", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-",
|
|
});
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
|
|
const result = yield* updateReleasePackageVersions("1.2.3", { rootDir: baseDir });
|
|
const versions = yield* readReleaseVersions(baseDir);
|
|
|
|
assert.deepStrictEqual(result, { changed: true });
|
|
assert.deepStrictEqual(
|
|
Array.from(versions.entries()),
|
|
releasePackageFiles.map((relativePath) => [relativePath, "1.2.3"]),
|
|
);
|
|
}),
|
|
);
|
|
|
|
it.effect("returns changed=false when all versions already match", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-unchanged-",
|
|
});
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "1.2.3");
|
|
|
|
const result = yield* updateReleasePackageVersions("1.2.3", { rootDir: baseDir });
|
|
|
|
assert.deepStrictEqual(result, { changed: false });
|
|
}),
|
|
);
|
|
|
|
it.effect("preserves manifest read context and the filesystem cause", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-read-error-",
|
|
});
|
|
const filePath = path.join(baseDir, releasePackageFiles[0]);
|
|
|
|
const error = yield* updateReleasePackageVersions("1.2.3", {
|
|
rootDir: baseDir,
|
|
}).pipe(Effect.flip);
|
|
|
|
assert.instanceOf(error, ReleasePackageManifestError);
|
|
assert.equal(error.operation, "read");
|
|
assert.equal(error.filePath, filePath);
|
|
assert.instanceOf(error.cause, PlatformError.PlatformError);
|
|
assert.equal(error.message, `Failed to read release package manifest '${filePath}'.`);
|
|
}),
|
|
);
|
|
|
|
it.effect("preserves manifest decode context and the schema cause", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-decode-error-",
|
|
});
|
|
const filePath = path.join(baseDir, releasePackageFiles[0]);
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
yield* fs.writeFileString(filePath, "not json");
|
|
|
|
const error = yield* updateReleasePackageVersions("1.2.3", {
|
|
rootDir: baseDir,
|
|
}).pipe(Effect.flip);
|
|
|
|
assert.equal(error.operation, "decode");
|
|
assert.equal(error.filePath, filePath);
|
|
assert.isTrue(Schema.isSchemaError(error.cause));
|
|
assert.equal(error.message, `Failed to decode release package manifest '${filePath}'.`);
|
|
}),
|
|
);
|
|
|
|
it.effect("preserves manifest write context and the filesystem cause", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-write-error-",
|
|
});
|
|
const filePath = path.join(baseDir, releasePackageFiles[0]);
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
yield* fs.chmod(filePath, 0o400);
|
|
|
|
const error = yield* updateReleasePackageVersions("1.2.3", {
|
|
rootDir: baseDir,
|
|
}).pipe(Effect.flip, Effect.ensuring(fs.chmod(filePath, 0o600).pipe(Effect.orDie)));
|
|
|
|
assert.equal(error.operation, "write");
|
|
assert.equal(error.filePath, filePath);
|
|
assert.instanceOf(error.cause, PlatformError.PlatformError);
|
|
assert.equal(error.message, `Failed to write release package manifest '${filePath}'.`);
|
|
}),
|
|
);
|
|
|
|
it.effect("accepts flags before the version positional and appends changed output", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const path = yield* Path.Path;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-cli-",
|
|
});
|
|
const githubOutputPath = path.join(baseDir, "github-output.txt");
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
|
|
yield* runCli(["--github-output", "--root", baseDir, "2.0.0"]).pipe(
|
|
Effect.provide(
|
|
ConfigProvider.layer(
|
|
ConfigProvider.fromEnv({
|
|
env: {
|
|
GITHUB_OUTPUT: githubOutputPath,
|
|
},
|
|
}),
|
|
),
|
|
),
|
|
);
|
|
|
|
const githubOutput = yield* fs.readFileString(githubOutputPath);
|
|
assert.equal(githubOutput, "changed=true\n");
|
|
}),
|
|
);
|
|
|
|
it.effect("logs when nothing changed", () =>
|
|
captureLogs(
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-cli-log-",
|
|
});
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "3.0.0");
|
|
yield* runCli(["3.0.0", "--root", baseDir]);
|
|
}),
|
|
).pipe(
|
|
Effect.tap(({ logs }) => {
|
|
assert.deepStrictEqual(logs, ["All package.json versions already match release version."]);
|
|
return Effect.void;
|
|
}),
|
|
),
|
|
);
|
|
|
|
it.effect("requires GITHUB_OUTPUT when --github-output is set", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-cli-missing-output-",
|
|
});
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
|
|
const error = yield* runCli(["4.0.0", "--root", baseDir, "--github-output"]).pipe(
|
|
Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} }))),
|
|
Effect.flip,
|
|
);
|
|
|
|
assert.instanceOf(error, ReleaseGitHubOutputConfigurationError);
|
|
assert.instanceOf(error.cause, Config.ConfigError);
|
|
assert.equal(
|
|
error.message,
|
|
"Failed to resolve GITHUB_OUTPUT for release package version output.",
|
|
);
|
|
}),
|
|
);
|
|
|
|
it.effect("preserves GITHUB_OUTPUT write context and the filesystem cause", () =>
|
|
Effect.gen(function* () {
|
|
const fs = yield* FileSystem.FileSystem;
|
|
const baseDir = yield* fs.makeTempDirectoryScoped({
|
|
prefix: "update-release-package-versions-cli-output-error-",
|
|
});
|
|
|
|
yield* writePackageJsonFixtures(baseDir, "0.0.1");
|
|
|
|
const error = yield* runCli(["4.0.0", "--root", baseDir, "--github-output"]).pipe(
|
|
Effect.provide(
|
|
ConfigProvider.layer(
|
|
ConfigProvider.fromEnv({
|
|
env: {
|
|
GITHUB_OUTPUT: baseDir,
|
|
},
|
|
}),
|
|
),
|
|
),
|
|
Effect.flip,
|
|
);
|
|
|
|
assert.instanceOf(error, ReleaseGitHubOutputWriteError);
|
|
assert.equal(error.filePath, baseDir);
|
|
assert.instanceOf(error.cause, PlatformError.PlatformError);
|
|
assert.equal(
|
|
error.message,
|
|
`Failed to append release package version output to '${baseDir}'.`,
|
|
);
|
|
}),
|
|
);
|
|
|
|
it.effect("rejects unknown flags during cli parsing", () =>
|
|
Effect.gen(function* () {
|
|
const error = yield* runCli(["1.2.3", "--unknown"]).pipe(Effect.flip);
|
|
|
|
if (!CliError.isCliError(error)) {
|
|
assert.fail(`Expected CliError, got ${String(error)}`);
|
|
}
|
|
|
|
const optionError =
|
|
error._tag === "ShowHelp" ? (error.errors[0] as CliError.CliError | undefined) : error;
|
|
|
|
if (!optionError || optionError._tag !== "UnrecognizedOption") {
|
|
assert.fail(`Expected UnrecognizedOption, got ${String(optionError?._tag)}`);
|
|
}
|
|
|
|
assert.equal(optionError.option, "--unknown");
|
|
}),
|
|
);
|
|
|
|
it.effect("rejects a missing version positional during cli parsing", () =>
|
|
Effect.gen(function* () {
|
|
const error = yield* runCli(["--github-output"]).pipe(Effect.flip);
|
|
|
|
if (!CliError.isCliError(error)) {
|
|
assert.fail(`Expected CliError, got ${String(error)}`);
|
|
}
|
|
|
|
const versionError =
|
|
error._tag === "ShowHelp" ? (error.errors[0] as CliError.CliError | undefined) : error;
|
|
|
|
if (!versionError || versionError._tag !== "MissingArgument") {
|
|
assert.fail(`Expected MissingArgument, got ${String(versionError?._tag)}`);
|
|
}
|
|
|
|
assert.equal(versionError.argument, "version");
|
|
}),
|
|
);
|
|
});
|