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
8 changes: 4 additions & 4 deletions src/base-command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {

import config from './config';
import { GraphqlApiClient, Logger } from './util';
import { getLaunchHubUrl } from './util/common-utility';
import { getLaunchHubUrl, getAnalyticsInfo } from './util/common-utility';
import { ConfigType, LogFn, Providers, GraphqlHeaders } from './types';

export type Flags<T extends typeof Command> = Interfaces.InferredFlags<(typeof BaseCommand)['baseFlags'] & T['flags']>;
Expand Down Expand Up @@ -202,8 +202,8 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
*/
async prepareApiClients(): Promise<void> {
let headers: GraphqlHeaders = {
'X-CS-CLI': this.context.analyticsInfo
}
'X-CS-CLI': getAnalyticsInfo(this.context, this.config),
};

const { uid, organizationUid } = this.sharedConfig.currentConfig;

Expand Down Expand Up @@ -232,7 +232,7 @@ export abstract class BaseCommand<T extends typeof Command> extends Command {
* @memberof BaseCommand
*/
async initCmaSDK() {
managementSDKInitiator.init(this.context);
managementSDKInitiator.init({ ...this.context, analyticsInfo: getAnalyticsInfo(this.context, this.config) });
this.managementSdk = await managementSDKClient({
host: this.sharedConfig.host,
});
Expand Down
5 changes: 3 additions & 2 deletions src/commands/launch/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import config from '../../config';
import { BaseCommand } from '../../base-command';
import { AdapterConstructorInputs, Providers } from '../../types';
import { FileUpload, GitHub, PreCheck } from '../../adapters';
import { getAnalyticsInfo } from '../../util/common-utility';
import { FlagInput, Flags, cliux } from '@contentstack/cli-utilities';

export default class Launch extends BaseCommand<typeof Launch> {
Expand Down Expand Up @@ -137,7 +138,7 @@ export default class Launch extends BaseCommand<typeof Launch> {
config: this.sharedConfig,
apolloClient: this.apolloClient,
managementSdk: this.managementSdk,
analyticsInfo: this.context.analyticsInfo,
analyticsInfo: getAnalyticsInfo(this.context, this.config),
};

switch (this.sharedConfig.provider) {
Expand Down Expand Up @@ -167,7 +168,7 @@ export default class Launch extends BaseCommand<typeof Launch> {
config: this.sharedConfig,
apolloClient: this.apolloClient,
managementSdk: this.managementSdk,
analyticsInfo: this.context.analyticsInfo,
analyticsInfo: getAnalyticsInfo(this.context, this.config),
});

await this.preCheck.run();
Expand Down
23 changes: 22 additions & 1 deletion src/util/common-utility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,27 @@ async function selectProject(options: {
}
}

/**
* Resolve the `X-CS-CLI` header value. oclif reloads the Config after the init hook, so
* `context.analyticsInfo` is often undefined at command runtime; reconstruct it from the
* Config and the persisted config store (clientId/sessionId) when that happens.
*/
function getAnalyticsInfo(context?: Record<string, any>, config?: Record<string, any>): string {
const fromContext = context?.analyticsInfo;
if (typeof fromContext === 'string' && fromContext.length > 0) {
return fromContext;
}

const platform = config?.platform && config?.arch ? `${config.platform}-${config.arch}` : 'none';
const nodeVersion = process.versions.node ? `v${process.versions.node}` : process.version;
const cliVersion = config?.version || 'none';
const clientId = configHandler.get('clientId') || 'none';
const sessionId = configHandler.get('sessionId') || 'none';
const command = configHandler.get('currentCommandId') || 'launch';

return [platform, nodeVersion, cliVersion, clientId, sessionId, command].join(';');
}

function getLaunchHubUrl(): string {
const { cma } = configHandler.get('region') || {};
if (!cma) {
Expand All @@ -151,4 +172,4 @@ function getLaunchHubUrl(): string {
return `https://${launchHubBaseUrl}`;
}

export { getOrganizations, selectOrg, selectProject, getLaunchHubUrl };
export { getOrganizations, selectOrg, selectProject, getLaunchHubUrl, getAnalyticsInfo };
64 changes: 64 additions & 0 deletions test/unit/util/common-utility.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { describe, it, beforeEach, afterEach } from 'mocha';
import { expect } from 'chai';
import { createSandbox, SinonSandbox } from 'sinon';
import { configHandler } from '@contentstack/cli-utilities';

import { getAnalyticsInfo } from '../../../src/util/common-utility';

describe('getAnalyticsInfo', () => {
let sandbox: SinonSandbox;

beforeEach(() => {
sandbox = createSandbox();
const getStub = sandbox.stub(configHandler, 'get');
getStub.withArgs('clientId').returns('client-123');
getStub.withArgs('sessionId').returns('session-456');
getStub.withArgs('currentCommandId').returns('launch:deployments');
});

afterEach(() => {
sandbox.restore();
});

it('returns the canonical context.analyticsInfo when it is a non-empty string', () => {
const result = getAnalyticsInfo(
{ analyticsInfo: 'darwin-arm64;v22.0.0;2.0.0;abc;def;launch' },
{ platform: 'linux', arch: 'x64', version: '9.9.9' },
);

expect(result).to.equal('darwin-arm64;v22.0.0;2.0.0;abc;def;launch');
});

it('reconstructs the value from config and config store when context has no analyticsInfo', () => {
const result = getAnalyticsInfo({}, { platform: 'darwin', arch: 'arm64', version: '2.0.0-beta.15' });

expect(result).to.equal(
`darwin-arm64;v${process.versions.node};2.0.0-beta.15;client-123;session-456;launch:deployments`,
);
});

it('falls back to reconstruction when context.analyticsInfo is an empty string', () => {
const result = getAnalyticsInfo({ analyticsInfo: '' }, { platform: 'darwin', arch: 'arm64', version: '2.0.0' });

expect(result).to.equal(`darwin-arm64;v${process.versions.node};2.0.0;client-123;session-456;launch:deployments`);
});

it('uses safe defaults when config is missing but still reads the config store', () => {
const result = getAnalyticsInfo(undefined, undefined);

expect(result).to.equal(`none;v${process.versions.node};none;client-123;session-456;launch:deployments`);
});

it('defaults the command segment to "launch" when currentCommandId is not set', () => {
sandbox.restore();
sandbox = createSandbox();
const getStub = sandbox.stub(configHandler, 'get');
getStub.withArgs('clientId').returns('client-123');
getStub.withArgs('sessionId').returns('session-456');
getStub.withArgs('currentCommandId').returns(undefined);

const result = getAnalyticsInfo({}, { platform: 'darwin', arch: 'arm64', version: '2.0.0' });

expect(result).to.equal(`darwin-arm64;v${process.versions.node};2.0.0;client-123;session-456;launch`);
});
});
Loading