Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/server/src/cli/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const runWithEnvironmentAuth = Effect.fn("auth.runWithEnvironmentAuth")(function
},
) {
const logLevel = yield* GlobalFlag.LogLevel;
const config = yield* resolveCliAuthConfig(flags, logLevel);
const config = yield* resolveCliAuthConfig(flags, logLevel, options);
const minimumLogLevel = options?.quietLogs ? "Error" : config.logLevel;
return yield* Effect.gen(function* () {
const environmentAuth = yield* EnvironmentAuth.EnvironmentAuth;
Expand Down
12 changes: 10 additions & 2 deletions apps/server/src/cli/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import * as LogLevel from "effect/LogLevel";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as Redacted from "effect/Redacted";
import * as References from "effect/References";
import * as Schema from "effect/Schema";
import * as SchemaIssue from "effect/SchemaIssue";
import * as SchemaTransformation from "effect/SchemaTransformation";
Expand Down Expand Up @@ -513,8 +514,9 @@ export const resolveServerConfig = Effect.fn("config.resolveServerConfig")(funct
export const resolveCliAuthConfig = (
flags: CliAuthLocationFlags,
cliLogLevel: Option.Option<LogLevel.LogLevel>,
) =>
resolveServerConfig(
options?: { readonly quietLogs?: boolean },
) => {
const resolved = resolveServerConfig(
{
mode: Option.none(),
port: Option.none(),
Expand All @@ -531,6 +533,12 @@ export const resolveCliAuthConfig = (
},
cliLogLevel,
);
// Logs go to stdout, where --json and --token-only print, and resolving can
// log, for example when it sweeps abandoned attachment uploads.
return options?.quietLogs === true
? resolved.pipe(Effect.provideService(References.MinimumLogLevel, "Error"))
: resolved;
};

const DurationShorthandPattern = /^(?<value>\d+)(?<unit>ms|s|m|h|d|w)$/i;

Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/cli/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ const runCloudCommand = Effect.fn("cloud.cli.run_cloud_command")(function* <A, E
},
) {
const logLevel = yield* GlobalFlag.LogLevel;
const config = yield* resolveCliAuthConfig(flags, logLevel);
const config = yield* resolveCliAuthConfig(flags, logLevel, options);
const minimumLogLevel = options?.quietLogs ? "Error" : config.logLevel;
const layerRuntime = Layer.mergeAll(
ServerSecretStore.layer,
Expand Down
2 changes: 1 addition & 1 deletion apps/server/src/cli/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const runWithPeerLinks = Effect.fn("environment.runWithPeerLinks")(function* <A,
options?: { readonly quietLogs?: boolean },
) {
const logLevel = yield* GlobalFlag.LogLevel;
const config = yield* resolveCliAuthConfig(flags, logLevel);
const config = yield* resolveCliAuthConfig(flags, logLevel, options);
return yield* PeerLinks.PeerLinks.pipe(
Effect.flatMap(run),
Effect.provide(
Expand Down
40 changes: 40 additions & 0 deletions apps/server/src/cli/pair.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import * as Sink from "effect/Sink";
import * as Stream from "effect/Stream";
import { FetchHttpClient } from "effect/http";
import { ChildProcess, ChildProcessSpawner } from "effect/process";
import * as TestClock from "effect/testing/TestClock";
import * as TestConsole from "effect/testing/TestConsole";
import { Command, CliError } from "effect/cli";

Expand Down Expand Up @@ -548,3 +549,42 @@ describe("auth pairing create --base-url", () => {
}),
);
});

describe("scripted auth output", () => {
it.effect.each(
[
["auth", "session", "issue", "--token-only"],
["auth", "session", "list", "--json"],
["auth", "pairing", "list", "--json"],
].map((command) => ({ command, label: command.join(" ") })),
)("prints only the result for $label after removing an abandoned upload", ({ command }) =>
Effect.gen(function* () {
const baseDir = NodeFS.mkdtempSync(NodePath.join(NodeOS.tmpdir(), "t3-cli-quiet-test-"));
const attachmentsDir = NodePath.join(baseDir, "userdata", "attachments");
NodeFS.mkdirSync(attachmentsDir, { recursive: true });
// An abandoned upload makes config resolution log that it removed it.
const abandoned = NodePath.join(attachmentsDir, "abandoned.part");
NodeFS.writeFileSync(abandoned, "");
const jan2020Seconds = 1_577_836_800;
NodeFS.utimesSync(abandoned, jan2020Seconds, jan2020Seconds);
// The sweep reads Clock, so a week past the upload's mtime makes it expired.
yield* TestClock.setTime((jan2020Seconds + 7 * 24 * 60 * 60) * 1000);

const lines = yield* provideCliTestLayers(
Effect.gen(function* () {
yield* runCli([...command, "--base-dir", baseDir]);
return yield* TestConsole.logLines;
}),
);

assert.isFalse(NodeFS.existsSync(abandoned));
assert.lengthOf(lines, 1);
const output = String(lines[0]);
if (command.includes("--json")) {
assert.deepEqual(JSON.parse(output), []);
} else {
assert.match(output.trim(), /^[\w-]+\.[\w-]+/);
}
}),
);
});
Loading