Skip to content
Draft
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
5 changes: 4 additions & 1 deletion packages/cli/src/commands/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,10 @@ class CLIEngine {
* entry point of the CLI engine
*/
async start(rootCmd: CLICommand): Promise<void> {
Correlator.setId();
// Seed the correlation id from ATK_CLI_CORRELATION_ID when a parent process
// (e.g. the wiqd CLI) passes one, so this run's telemetry shares the parent's
// `correlation-id`. Absent/malformed values fall back to a fresh UUID.
Correlator.setId(process.env.ATK_CLI_CORRELATION_ID);

// Fire-and-forget: fetch latest metadata in background, same as VSC extension activation
void getFxCore().fetchOnlineTemplateMetadata();
Expand Down
23 changes: 23 additions & 0 deletions packages/cli/tests/unit/engine.tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
MissingEnvironmentVariablesError,
UserCancelError,
VersionState,
Correlator,
} from "@microsoft/teamsfx-core";
import { assert } from "chai";
import mockedEnv from "mocked-env";
Expand Down Expand Up @@ -746,4 +747,26 @@ describe("CLI Engine", () => {
mockedEnvRestore();
});
});

describe("ATK_CLI_CORRELATION_ID env var", () => {
it("seeds the Correlator with the parent-provided id", async () => {
const externalId = "11111111-1111-4111-8111-111111111111";
const mockedEnvRestore = mockedEnv({ ATK_CLI_CORRELATION_ID: externalId });
const setIdStub = sandbox.stub(Correlator, "setId");
sandbox.stub(process, "argv").value(["node", "cli", "-h"]);
sandbox.stub(logger, "info");
await engine.start(rootCommand);
assert.isTrue(setIdStub.calledWith(externalId));
mockedEnvRestore();
});
it("seeds the Correlator with undefined when the env var is not set", async () => {
const mockedEnvRestore = mockedEnv({ ATK_CLI_CORRELATION_ID: undefined });
const setIdStub = sandbox.stub(Correlator, "setId");
sandbox.stub(process, "argv").value(["node", "cli", "-h"]);
sandbox.stub(logger, "info");
await engine.start(rootCommand);
assert.isTrue(setIdStub.calledWith(undefined));
mockedEnvRestore();
});
});
});
14 changes: 10 additions & 4 deletions packages/fx-core/src/common/correlator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ import * as uuid from "uuid";
const asyncLocalStorage = new AsyncLocalStorage<string>();

export class Correlator {
static setId(): string {
const id = uuid.v4();
asyncLocalStorage.enterWith(id);
return id;
/**
* Sets the ambient correlation id for the current async context. A valid UUID
* `id` is adopted as-is — the seam that lets an external caller (e.g. the wiqd
* CLI) thread its own correlation id in; absent/malformed values mint a fresh
* UUID so the id is always well-formed.
*/
static setId(id?: string): string {
const newId = id && uuid.validate(id) ? id : uuid.v4();
asyncLocalStorage.enterWith(newId);
return newId;
}
static run<T extends unknown[], R>(work: (...args: [...T]) => R, ...args: [...T]): R {
const id = asyncLocalStorage.getStore() || uuid.v4();
Expand Down
19 changes: 19 additions & 0 deletions packages/fx-core/tests/common/correlator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,23 @@ describe("Correlator", () => {
const getId = Correlator.getId();
chai.assert.isDefined(getId);
});

it("setId adopts a valid externally-provided UUID", () => {
const externalId = "11111111-1111-4111-8111-111111111111";
const setedId = Correlator.setId(externalId);
chai.assert.equal(setedId, externalId);
chai.assert.equal(Correlator.getId(), externalId);
});

it("setId mints a fresh UUID when the provided id is malformed", () => {
const setedId = Correlator.setId("not-a-uuid");
chai.assert.notEqual(setedId, "not-a-uuid");
chai.assert.equal(Correlator.getId(), setedId);
});

it("setId mints a fresh UUID when no id is provided", () => {
const setedId = Correlator.setId();
chai.assert.isNotEmpty(setedId);
chai.assert.equal(Correlator.getId(), setedId);
});
});