@yahoo/uds 1.5.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/cli/README.md CHANGED
@@ -179,6 +179,22 @@ Commands are organized in a tree structure in `uds/cli/commands`. The root comma
179
179
 
180
180
  Adding nested commands, i.e. `uds expo dev` does work correctly when UDS is consumed from npm. As a workaround, please see code for expo/expo.ts for re-routing sub-commands from the root command file. To verify your CLI command works correctly you should run `npm pack` within the packages/uds directory. Once you have your generated tarball you should copy that tarball to a test application such as https://github.com/yahoo-uds/uds-nextjs-demo, then add `"@yahoo/uds": "file:./tarball-generated-from-npm-pack.tgz` to it's dependencies and run an install. Now you should be able to run `bun uds [your command name]` to test your functionality.
181
181
 
182
+ ### Testing the login flow
183
+
184
+ To test the login flow, the CLI starts a web server and opens browser window to
185
+ a login page in Configurator. In prod, it opens https://config.uds.build/login.
186
+ In local dev, http://localhost:4001/login is opened.
187
+
188
+ In the root of the UDS monorepo, run the following commands:
189
+
190
+ ```
191
+ # Start configurator app web server:
192
+ turbo --filter uds-configurator dev
193
+
194
+ # Run the CLI login command:
195
+ bun run --cwd packages/uds uds login
196
+ ```
197
+
182
198
  ### API Reference
183
199
 
184
200
  Bluebun comes with a number of built-in utilities that are exported from the main `bluebun` package. See [reference guide](https://github.com/jamonholmgren/bluebun/blob/main/docs/reference.md) for more.
Binary file
Binary file
@@ -1,6 +1,7 @@
1
1
  import { type Props } from 'bluebun';
2
2
  import prompts from 'prompts';
3
3
 
4
+ import { trackEvent } from '../../utils/analytics';
4
5
  import { getCommandHelp, getSubCommandsChoices } from '../../utils/getCommandHelp';
5
6
  import { getDirChoices } from '../../utils/getDirChoices';
6
7
 
@@ -13,6 +14,11 @@ export default {
13
14
  const isRootCommand = Boolean(!props?.first);
14
15
  const dirChoices = getDirChoices();
15
16
 
17
+ const runCodeMod = async (codemod: string, selectedDirs: string[]) => {
18
+ const mod = (await import(`./${codemod}`)).default;
19
+ return mod.run({ ...props, selectedDirs });
20
+ };
21
+
16
22
  if (isRootCommand) {
17
23
  // Prompt the user to setup the codemod runner
18
24
  const { selectedDirs, selectedCodemods, didConfirm } = await prompts([
@@ -49,10 +55,9 @@ export default {
49
55
 
50
56
  // Run each codemod and provide the selectedDirs
51
57
  return Promise.all(
52
- selectedCodemods.map(async (selectedCodemod: string[]) => {
53
- return await import(`./${selectedCodemod}`).then((codemod) =>
54
- codemod.default.run({ ...props, selectedDirs }),
55
- );
58
+ selectedCodemods.map(async (codemod: string) => {
59
+ await runCodeMod(codemod, selectedDirs);
60
+ return trackEvent('codemod', { codemod });
56
61
  }),
57
62
  );
58
63
  } else if (subCommandIsValid) {
@@ -71,11 +76,9 @@ export default {
71
76
  process.exit(1);
72
77
  }
73
78
 
74
- // Run the codemod
75
- return (await import(`./${props.first}`)).default.run({
76
- ...props,
77
- selectedDirs,
78
- });
79
+ const codemod = props.first!;
80
+ await runCodeMod(codemod, selectedDirs);
81
+ return trackEvent('codemod', { codemod });
79
82
  } else {
80
83
  // Throw the help message
81
84
  await getCommandHelp({
@@ -1,5 +1,6 @@
1
1
  import { magenta, print, red } from 'bluebun';
2
2
 
3
+ import { trackEvent } from '../utils/analytics';
3
4
  import { login } from '../utils/auth';
4
5
 
5
6
  export default {
@@ -11,6 +12,7 @@ export default {
11
12
  const user = await login();
12
13
  if (user) {
13
14
  print(magenta(`🔒 Logged in as ${user.email}`));
15
+ return await trackEvent('login');
14
16
  }
15
17
  } catch (error) {
16
18
  if (error instanceof Error) {
@@ -1,5 +1,6 @@
1
1
  import { magenta, print, red } from 'bluebun';
2
2
 
3
+ import { trackEvent } from '../utils/analytics';
3
4
  import { logout } from '../utils/auth';
4
5
 
5
6
  export default {
@@ -7,6 +8,8 @@ export default {
7
8
  description: '👤 Sign out of UDS CLI',
8
9
  run: async () => {
9
10
  try {
11
+ // Track logout event before logout is run. Otherwise, there's no user object to track.
12
+ await trackEvent('logout');
10
13
  await logout();
11
14
  print(magenta('👋 You have been logged out.'));
12
15
  } catch (error) {
@@ -1,5 +1,6 @@
1
1
  import { Props, spinStart, spinStop } from 'bluebun';
2
2
 
3
+ import { trackEvent } from '../utils/analytics';
3
4
  import { purge, PurgeOptions } from '../utils/purgeCSS';
4
5
 
5
6
  interface PurgeProps extends Props {
@@ -15,6 +16,7 @@ export default {
15
16
  try {
16
17
  await purge(props.options);
17
18
  spinStop('✅', 'Purging css done!');
19
+ return await trackEvent('purge');
18
20
  } catch (error) {
19
21
  if (error instanceof Error) {
20
22
  spinStop('❌', error.message);
@@ -1,5 +1,6 @@
1
1
  import { magenta, print, Props } from 'bluebun';
2
2
 
3
+ import { trackEvent } from '../utils/analytics';
3
4
  import { setupConfigWorker } from '../utils/setupConfigWorker';
4
5
  import { SyncOptions } from '../utils/types';
5
6
 
@@ -31,6 +32,7 @@ export default {
31
32
  }
32
33
  },
33
34
  });
35
+ return await trackEvent('sync', { id });
34
36
  } catch {
35
37
  console.error(
36
38
  '❌ An error occurred while syncing. Please reach out to #uds-ask channel for support.',
@@ -1,5 +1,6 @@
1
1
  import { print, type Props, red } from 'bluebun';
2
2
 
3
+ import { trackEvent } from '../utils/analytics';
3
4
  import { getAuthenticatedUser } from '../utils/auth';
4
5
  import { getCommandHelp } from '../utils/getCommandHelp';
5
6
 
@@ -9,6 +10,7 @@ export default {
9
10
  run: async (props: Props) => {
10
11
  if (props.first) {
11
12
  print(red(`Unknown command: ${props.first}`));
13
+ await trackEvent('unknown_cmd', { cmd: props.first });
12
14
  }
13
15
  const user = await getAuthenticatedUser();
14
16
  const notes = user ? `🔒 Logged in as ${user.email}` : undefined;
@@ -1,11 +1,13 @@
1
1
  import { print } from 'bluebun';
2
2
 
3
3
  import packageJson from '../../package.json';
4
+ import { trackEvent } from '../utils/analytics';
4
5
 
5
6
  export default {
6
7
  name: 'version',
7
8
  description: `${packageJson.version}`,
8
9
  run: async () => {
9
10
  print(packageJson.version);
11
+ await trackEvent('version', { version: packageJson.version });
10
12
  },
11
13
  };
package/cli/tsconfig.json CHANGED
@@ -18,14 +18,15 @@
18
18
  "strict": true,
19
19
  "types": ["bun-types"],
20
20
  "target": "esnext",
21
- "lib": ["esnext"],
21
+ "lib": ["ESNext"],
22
22
  "module": "esnext",
23
23
  "moduleResolution": "bundler",
24
24
  "paths": {
25
25
  "@yahoo/uds/scripts/*": ["../scripts/*"],
26
26
  "@yahoo/uds/*": ["../src/*"],
27
27
  "@yahoo/uds/tailwind/tsMorph": ["../scripts/utils/tsMorph.ts"],
28
- "root/*": ["../../*"],
29
- },
30
- },
28
+ "analytics/*": ["../../analytics/*"],
29
+ "root/*": ["../../*"]
30
+ }
31
+ }
31
32
  }
@@ -0,0 +1,27 @@
1
+ import { getFeatureFlags } from '@yahoo/uds/flags';
2
+ import { GA_MEASUREMENT_IDS, GA_MEASUREMENT_SECRETS } from 'analytics/providers/google/consts';
3
+ import { track } from 'analytics/providers/google/server';
4
+ import { EventName } from 'analytics/types';
5
+
6
+ import { getAuthenticatedUser } from '../utils/auth';
7
+
8
+ export async function setup() {
9
+ const user = await getAuthenticatedUser();
10
+ if (user) {
11
+ await track.init({
12
+ appName: 'cli',
13
+ apiSecret: GA_MEASUREMENT_SECRETS.cli,
14
+ measurementId: GA_MEASUREMENT_IDS.cli,
15
+ // @ts-expect-error type is fine
16
+ user,
17
+ });
18
+ }
19
+ }
20
+
21
+ export const trackEvent = async (...args: Parameters<typeof track.event<EventName['cli']>>) => {
22
+ const { useCLIAuth } = getFeatureFlags();
23
+ if (useCLIAuth) {
24
+ await setup();
25
+ return track.event(...args);
26
+ }
27
+ };
package/cli/utils/auth.ts CHANGED
@@ -9,11 +9,11 @@ import {
9
9
  getAuth,
10
10
  GoogleAuthProvider,
11
11
  signInWithCredential,
12
- User as FirebaseUser,
13
12
  } from 'firebase/auth';
14
13
  import { google, oauth2_v2 } from 'googleapis';
15
14
  import http from 'http';
16
15
  import open from 'open';
16
+ import { type FirebaseUser } from 'root/database/firebase';
17
17
 
18
18
  import clientSecrets from './client_secrets.json';
19
19