Skip to content

Commit

Permalink
feat: add version and mode support for init (#49)
Browse files Browse the repository at this point in the history
  • Loading branch information
akashrpo authored Aug 25, 2024
1 parent 2d3e6a1 commit d8af9f9
Show file tree
Hide file tree
Showing 8 changed files with 296 additions and 584 deletions.
716 changes: 181 additions & 535 deletions package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions src/cli/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export namespace RudderAPI {
export type TrackingPlan = {
name: string;
display_name: string;
version: string;
version: number;
id: string;
rules: {
events: RuleMetadata[];
Expand Down Expand Up @@ -80,12 +80,14 @@ export namespace RudderAPI {
export async function fetchTrackingPlan(options: {
workspaceSlug: string;
id: string;
version?: number;
token: string;
email: string;
APIVersion: string;
}): Promise<RudderAPI.TrackingPlan> {
const url =
let url =
options.APIVersion === 'v1' ? `trackingplans/${options.id}` : `tracking-plans/${options.id}`;
url = options.version ? `${url}?version=${options.version}` : url;
const response = await apiGet<RudderAPI.GetTrackingPlanResponse>(
url,
options.token,
Expand Down
11 changes: 8 additions & 3 deletions src/cli/api/trackingplans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,12 @@ export function computeDelta(
return deltas;
}

export function parseTrackingPlanName(name: string): {
export function parseTrackingPlanName(
name: string,
version: number,
): {
id: string;
version: number;
workspaceSlug: string;
APIVersion: string;
} {
Expand All @@ -126,22 +130,23 @@ export function parseTrackingPlanName(name: string): {

return {
id,
version,
workspaceSlug,
APIVersion: 'v1',
};
}

export function toTrackingPlanURL(trackingPlan: RudderAPI.TrackingPlan): string {
if (!trackingPlan.creationType) {
const { id } = parseTrackingPlanName(trackingPlan.name);
const { id } = parseTrackingPlanName(trackingPlan.name, trackingPlan.version);
return `https://app.rudderstack.com/trackingplans/${id}`;
}
return `https://app.rudderstack.com/trackingplans/${trackingPlan.id}`;
}

export function toTrackingPlanId(trackingPlan: RudderAPI.TrackingPlan): string {
if (!trackingPlan.creationType) {
const { id } = parseTrackingPlanName(trackingPlan.name);
const { id } = parseTrackingPlanName(trackingPlan.name, trackingPlan.version);
return id;
}
return trackingPlan.id;
Expand Down
10 changes: 7 additions & 3 deletions src/cli/commands/build.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ export const UpdatePlanStep: React.FC<UpdatePlanStepProps> = ({
try {
newTrackingPlan = await fetchTrackingPlan({
id: trackingPlanConfig.id,
version: trackingPlanConfig.version,
workspaceSlug: trackingPlanConfig.workspaceSlug,
token,
email,
Expand Down Expand Up @@ -378,9 +379,12 @@ export const GenerationStep: React.FC<GenerationProps> = ({
<Step name={stepName} isRunning={isRunning} isDone={isDone}>
<Note>Building for {production ? 'production' : 'development'}</Note>
{trackingPlans.map((trackingPlan) => (
<Note key={trackingPlan.url}>
<Link url={trackingPlan.url}>{trackingPlan.name}</Link>
</Note>
<React.Fragment key={trackingPlan.name}>
<Note>{trackingPlan.name}</Note>
<Note key={trackingPlan.name}>
<Link url={trackingPlan.url}>version: {trackingPlan.version}</Link>
</Note>
</React.Fragment>
))}
</Step>
);
Expand Down
67 changes: 59 additions & 8 deletions src/cli/commands/init.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ enum Steps {
Language = 2,
APIToken = 3,
TrackingPlan = 4,
Path = 5,
Summary = 6,
Build = 7,
Done = 8,
Mode = 5,
Path = 6,
Summary = 7,
Build = 8,
Done = 9,
}

export const Init: React.FC<InitProps> = (props) => {
Expand All @@ -55,6 +56,7 @@ export const Init: React.FC<InitProps> = (props) => {
const [step, setStep] = useState(Steps.Confirmation);
const [sdk, setSDK] = useState(config ? config.client.sdk : SDK.WEB);
const [language, setLanguage] = useState(config ? config.client.language : Language.JAVASCRIPT);
const [mode, setMode] = useState('Development' as 'Development' | 'Production');
const [path, setPath] = useState(
config && config.trackingPlans.length > 0 ? config.trackingPlans[0].path : '',
);
Expand All @@ -64,6 +66,7 @@ export const Init: React.FC<InitProps> = (props) => {
workspace: undefined as RudderAPI.Workspace | undefined,
});
const [trackingPlan, setTrackingPlan] = useState<RudderAPI.TrackingPlan>();
const [trackingPlanVersion, setTrackingPlanVersion] = useState(0);

const { exit } = useApp();
useEffect(() => {
Expand Down Expand Up @@ -128,8 +131,10 @@ export const Init: React.FC<InitProps> = (props) => {
email={tokenMetadata.email}
trackingPlan={trackingPlan}
onSubmit={withNextStep(setTrackingPlan)}
onSubmitVersion={withNextStep(setTrackingPlanVersion)}
/>
)}
{step === Steps.Mode && <ModePrompt step={step} onSubmit={withNextStep(setMode)} />}
{step === Steps.Path && (
<PathPrompt
step={step}
Expand All @@ -148,12 +153,14 @@ export const Init: React.FC<InitProps> = (props) => {
token={tokenMetadata.token}
workspace={tokenMetadata.workspace!}
trackingPlan={trackingPlan!}
trackingPlanVersion={trackingPlanVersion}
mode={mode}
onConfirm={onAcceptSummary}
onRestart={onRestart}
/>
)}
{step === Steps.Build && !props.onDone && (
<Build {...{ ...props, config }} production={false} update={true} />
<Build {...{ ...props, config }} production={mode === 'Production'} update={true} />
)}
{/* TODO: step 8 where we show an example script showing how to import ruddertyper */}
</Box>
Expand Down Expand Up @@ -622,6 +629,7 @@ type TrackingPlanPromptProps = {
email: string;
trackingPlan?: RudderAPI.TrackingPlan;
onSubmit: (trackingPlan: RudderAPI.TrackingPlan) => void;
onSubmitVersion: (version: number) => void;
};

/** A prompt to identify which RudderStack Tracking Plan a user wants to use. */
Expand All @@ -632,6 +640,7 @@ const TrackingPlanPrompt: React.FC<TrackingPlanPromptProps> = ({
email,
trackingPlan,
onSubmit,
onSubmitVersion,
}) => {
const [trackingPlans, setTrackingPlans] = useState<RudderAPI.TrackingPlan[]>([]);
const [isLoading, setIsLoading] = useState(true);
Expand Down Expand Up @@ -671,6 +680,7 @@ const TrackingPlanPrompt: React.FC<TrackingPlanPromptProps> = ({
const onSelect = (item: any) => {
const trackingPlan = trackingPlans.find((tp) => getTrackingPlanName(tp) === item.value)!;
onSubmit(trackingPlan);
onSubmitVersion(trackingPlan.version);
};

// Sort the Tracking Plan alphabetically by display name.
Expand Down Expand Up @@ -712,6 +722,29 @@ const TrackingPlanPrompt: React.FC<TrackingPlanPromptProps> = ({
);
};

type ModePromptProps = {
step: number;
onSubmit: (label: 'Development' | 'Production') => void;
};

const ModePrompt: React.FC<ModePromptProps> = ({ step, onSubmit }) => {
const onSelect = (item: any) => {
onSubmit(item.value as 'Development' | 'Production');
};

return (
<Step name="Choose a mode:" step={step}>
<SelectInput
items={[
{ label: 'Production', value: 'Production' },
{ label: 'Development', value: 'Development' },
]}
onSelect={onSelect}
/>
</Step>
);
};

type SummaryPromptProps = {
step: number;
sdk: SDK;
Expand All @@ -721,6 +754,8 @@ type SummaryPromptProps = {
workspace: RudderAPI.Workspace;
configPath: string;
trackingPlan: RudderAPI.TrackingPlan;
trackingPlanVersion: number;
mode: string;
onConfirm: (config: Config) => void;
onRestart: () => void;
};
Expand All @@ -735,6 +770,8 @@ const SummaryPrompt: React.FC<SummaryPromptProps> = ({
token,
workspace,
trackingPlan,
trackingPlanVersion,
mode,
onConfirm,
onRestart,
}) => {
Expand All @@ -759,15 +796,21 @@ const SummaryPrompt: React.FC<SummaryPromptProps> = ({
client.scriptTarget = 'ES5';
}
const tp = trackingPlan.creationType
? { id: trackingPlan.id, workspaceSlug: trackingPlan.workspaceId, APIVersion: 'v2' }
: parseTrackingPlanName(trackingPlan.name);
? {
id: trackingPlan.id,
version: trackingPlan.version,
workspaceSlug: trackingPlan.workspaceId,
APIVersion: 'v2',
}
: parseTrackingPlanName(trackingPlan.name, trackingPlan.version);
try {
const config: Config = {
client,
trackingPlans: [
{
name: getTrackingPlanName(trackingPlan),
id: tp.id,
version: tp.version,
workspaceSlug: tp.workspaceSlug,
path,
APIVersion: tp.APIVersion,
Expand Down Expand Up @@ -799,10 +842,18 @@ const SummaryPrompt: React.FC<SummaryPromptProps> = ({
{ label: 'Directory', value: path },
{ label: 'API Token', value: `${workspace.name} (${token.slice(0, 10)}...)` },
{ label: 'API Version', value: trackingPlan.creationType ? 'v2' : 'v1' },
{
label: 'Build mode',
value: mode,
},
{
label: 'Tracking Plan',
value: <Link url={toTrackingPlanURL(trackingPlan)}>{getTrackingPlanName(trackingPlan)}</Link>,
},
{
label: 'Version',
value: trackingPlanVersion,
},
];

const summary = (
Expand Down Expand Up @@ -858,7 +909,7 @@ const Step: React.FC<StepProps> = ({
</Box>
{step && (
<Box>
<Text color="yellow">[{step}/6]</Text>
<Text color="yellow">[{step}/7]</Text>
</Box>
)}
</Box>
Expand Down
1 change: 1 addition & 0 deletions src/cli/config/ruddertyper.yml.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ trackingPlans:
# Tracking Plan: {{name}}
# https://app.rudderstack.com/trackingplans/{{id}}
- id: {{id}}
version: {{version}}
workspaceSlug: {{workspaceSlug}}
path: {{path}}
APIVersion: {{APIVersion}}
Expand Down
65 changes: 34 additions & 31 deletions src/cli/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ export type TrackingPlanConfig = {
name?: string;
/** The id of the Tracking Plan to generate a client for. */
id: string;
/** The version of the Tracking Plan to generate a client for. */
version: number;
/** The slug of the RudderStack workspace that owns this Tracking Plan. */
workspaceSlug: string;
/**
Expand All @@ -55,39 +57,40 @@ export type TrackingPlanConfig = {
// prettier-ignore
/** Joi schema for performing validation on ruddertyper.yml files. */
const ConfigSchema = Joi.object().required().keys({
scripts: Joi.object().optional().keys({
token: Joi.string().optional().min(1),
after: Joi.string().optional().min(1),
email: Joi.string().optional().min(1),
scripts: Joi.object().optional().keys({
token: Joi.string().optional().min(1),
after: Joi.string().optional().min(1),
email: Joi.string().optional().min(1),
}),
client: Joi.object().required().keys({
sdk: Joi.string().required().valid('analytics.js', 'analytics-node', 'analytics-android', 'analytics-ios'),
language: Joi.string().required().valid('javascript', 'typescript', 'java', 'swift', 'objective-c'),
})
.when('sdk', {
is: Joi.string().valid('analytics.js', 'analytics-node'),
then: {
language: Joi.string().valid('javascript', 'typescript'),
scriptTarget: Joi.string().optional().valid('ES3', 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ESNext', 'Latest'),
moduleTarget: Joi.string().optional().valid('CommonJS', 'AMD', 'UMD', 'System', 'ES2015', 'ESNext'),
},
})
.when('sdk', {
is: Joi.string().valid('analytics-android'),
then: { language: Joi.string().valid('java') },
})
.when('sdk', {
is: Joi.string().valid('analytics-ios'),
then: { language: Joi.string().valid('swift', 'objective-c') },
}),
client: Joi.object().required().keys({
sdk: Joi.string().required().valid('analytics.js', 'analytics-node', 'analytics-android', 'analytics-ios'),
language: Joi.string().required().valid('javascript', 'typescript', 'java', 'swift', 'objective-c'),
})
.when('sdk', {
is: Joi.string().valid('analytics.js', 'analytics-node'),
then: {
language: Joi.string().valid('javascript', 'typescript'),
scriptTarget: Joi.string().optional().valid( 'ES3', 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ESNext', 'Latest'),
moduleTarget: Joi.string().optional().valid('CommonJS', 'AMD', 'UMD', 'System', 'ES2015', 'ESNext'),
},
})
.when('sdk', {
is: Joi.string().valid('analytics-android'),
then: { language: Joi.string().valid('java') },
})
.when('sdk', {
is: Joi.string().valid('analytics-ios'),
then: { language: Joi.string().valid('swift', 'objective-c') },
}),
trackingPlans: Joi.array().required().items(
Joi.object().keys({
id: Joi.string().required().min(1),
workspaceSlug: Joi.string().required().min(1),
path: Joi.string().required().min(1),
trackingPlans: Joi.array().required().items(
Joi.object().keys({
id: Joi.string().required().min(1),
version: Joi.number().optional().min(1),
workspaceSlug: Joi.string().required().min(1),
path: Joi.string().required().min(1),
APIVersion: Joi.string().required().min(1),
})
),
})
),
})

export const validateConfig = (rawConfig: Record<string, unknown>): Config => {
Expand Down
4 changes: 2 additions & 2 deletions src/generators/gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ export type RawTrackingPlan = {
name: string;
url: string;
id: string;
version: string;
version: number;
path: string;
trackCalls: JSONSchema7[];
};

export type TrackingPlan = {
url: string;
id: string;
version: string;
version: number;
trackCalls: {
raw: JSONSchema7;
schema: Schema;
Expand Down

0 comments on commit d8af9f9

Please sign in to comment.