[dev-tool] Create a symbolic link to recordings when running the proxy tool (#27144)
### Packages impacted by this PR - `@azure-tools/dev-tool` ### Description This is a quality-of-life change which makes inspecting recordings easier. With the new asset sync flow, recordings are no longer stored in the repo with each package. If you want to look at your recordings for some reason (e.g. after re-recording to make sure you aren't leaking any secrets), it takes a few extra steps to find them: navigate to the repo root, look at the `.breadcrumb` file in the `.assets` folder, and then use that to find the location of the recordings corresponding to your package. This PR improves that process by creating a symbolic link to the recordings from each package, restoring the original flow.
This commit is contained in:
Родитель
20321c7ff0
Коммит
418a979e2f
|
@ -174,3 +174,6 @@ code-model-*
|
|||
*.cpuprofile
|
||||
# Temp typespec files
|
||||
TempTypeSpecFiles/
|
||||
|
||||
# Symbolic link from project directory to recordings
|
||||
_recordings
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT license.
|
||||
|
||||
import { ChildProcess, spawn, SpawnOptions } from "child_process";
|
||||
import { ChildProcess, exec, spawn, SpawnOptions } from "child_process";
|
||||
import { createPrinter } from "./printer";
|
||||
import { ProjectInfo, resolveRoot } from "./resolveProject";
|
||||
import { ProjectInfo, resolveProject, resolveRoot } from "./resolveProject";
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import axios from "axios";
|
||||
import decompress from "decompress";
|
||||
import envPaths from "env-paths";
|
||||
import { promisify } from "util";
|
||||
|
||||
const log = createPrinter("test-proxy");
|
||||
const downloadLocation = path.join(envPaths("azsdk-dev-tool").cache, "test-proxy");
|
||||
|
@ -105,10 +106,16 @@ async function downloadTestProxy(downloadLocation: string, downloadUrl: string):
|
|||
await decompress(Buffer.from(data), downloadLocation);
|
||||
}
|
||||
|
||||
let cachedTestProxyExecutableLocation: string | undefined;
|
||||
|
||||
/**
|
||||
* Gets the path to the test-proxy executable. If the test-proxy executable has not been downloaded already, it will first be downloaded.
|
||||
*/
|
||||
export async function getTestProxyExecutable(): Promise<string> {
|
||||
if (cachedTestProxyExecutableLocation) {
|
||||
return cachedTestProxyExecutableLocation;
|
||||
}
|
||||
|
||||
const targetVersion = await getTargetVersion();
|
||||
const binary = await getTestProxyBinary();
|
||||
|
||||
|
@ -132,6 +139,7 @@ export async function getTestProxyExecutable(): Promise<string> {
|
|||
await fs.chmod(executableLocation, 0o755);
|
||||
}
|
||||
|
||||
cachedTestProxyExecutableLocation = executableLocation;
|
||||
return executableLocation;
|
||||
}
|
||||
|
||||
|
@ -164,13 +172,58 @@ function runCommand(executable: string, argv: string[], options: SpawnOptions =
|
|||
}
|
||||
|
||||
export async function runTestProxyCommand(argv: string[]): Promise<void> {
|
||||
return runCommand(await getTestProxyExecutable(), argv, { stdio: "inherit" }).result;
|
||||
const result = runCommand(await getTestProxyExecutable(), argv, { stdio: "inherit" }).result;
|
||||
if (await fs.pathExists("assets.json")) {
|
||||
await linkRecordingsDirectory();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function createAssetsJson(project: ProjectInfo): Promise<void> {
|
||||
return runMigrationScript(project, false);
|
||||
}
|
||||
|
||||
const execPromise = promisify(exec);
|
||||
|
||||
async function getRecordingsDirectory(project: ProjectInfo): Promise<string> {
|
||||
const { stdout } = await execPromise(`${await getTestProxyExecutable()} config locate -a assets.json`, { cwd: project.path });
|
||||
const lines = stdout.split("\n");
|
||||
|
||||
// the directory is the second-to-last line of output (there's some other log output that comes out from the test proxy first, and the last line is empty)
|
||||
return lines[lines.length - 2].trim();
|
||||
}
|
||||
|
||||
export async function linkRecordingsDirectory() {
|
||||
const project = await resolveProject();
|
||||
const root = await resolveRoot();
|
||||
const recordingsDirectory = await getRecordingsDirectory(project);
|
||||
const projectRelativeToRoot = path.relative(root, project.path);
|
||||
|
||||
const trueRecordingsDirectory = path.join(recordingsDirectory, projectRelativeToRoot, 'recordings/');
|
||||
const relativeRecordingsDirectory = path.relative(project.path, trueRecordingsDirectory);
|
||||
|
||||
const symlinkLocation = path.join(project.path, "_recordings");
|
||||
|
||||
if (await fs.pathExists(symlinkLocation)) {
|
||||
const stat = await fs.lstat(symlinkLocation);
|
||||
if (stat.isSymbolicLink()) {
|
||||
await fs.unlink(symlinkLocation);
|
||||
} else {
|
||||
log.warn("Could not create symbolic link to recordings directory: a file exists at _recordings already.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Try and create a symlink but fail gracefully if it doesn't work
|
||||
try {
|
||||
await fs.symlink(relativeRecordingsDirectory, symlinkLocation);
|
||||
} catch (e) {
|
||||
log.warn("Could not create symbolic link to recordings directory");
|
||||
log.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
export async function runMigrationScript(
|
||||
project: ProjectInfo,
|
||||
initialPush: boolean
|
||||
|
@ -219,8 +272,7 @@ export async function isProxyToolActive(): Promise<boolean> {
|
|||
await axios.get(`http://localhost:${process.env.TEST_PROXY_HTTP_PORT ?? 5000}/info/available`);
|
||||
|
||||
log.info(
|
||||
`Proxy tool seems to be active at http://localhost:${
|
||||
process.env.TEST_PROXY_HTTP_PORT ?? 5000
|
||||
`Proxy tool seems to be active at http://localhost:${process.env.TEST_PROXY_HTTP_PORT ?? 5000
|
||||
}\n`
|
||||
);
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче