Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ensure suggested app names are valid #5293

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

craigmichaelmartin
Copy link
Contributor

@craigmichaelmartin craigmichaelmartin commented Jan 28, 2025

WHY are these changes introduced?

We currently have an app name length limit of 30 characters, but can suggest names longer than 30 characters.

WHAT is this pull request doing?

Retries if the generated name is too long.

Measuring impact

How do we know this change was effective? Please choose one:

  • n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
  • Existing analytics will cater for this addition
  • PR includes analytics changes to measure impact

Checklist

  • I've considered possible cross-platform impacts (Mac, Linux, Windows)
  • I've considered possible documentation changes

@craigmichaelmartin craigmichaelmartin requested a review from a team as a code owner January 28, 2025 16:49
Copy link
Contributor

We detected some changes at packages/*/src and there are no updates in the .changeset.
If the changes are user-facing, run "pnpm changeset add" to track your changes and include them in the next release CHANGELOG.

Copy link
Contributor

github-actions bot commented Jan 28, 2025

Coverage report

St.
Category Percentage Covered / Total
🟡 Statements
75.43% (-0.04% 🔻)
8996/11927
🟡 Branches
70.62% (-0.02% 🔻)
4387/6212
🟡 Functions
75.25% (-0.05% 🔻)
2362/3139
🟡 Lines
75.95% (-0.02% 🔻)
8498/11189
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / common.ts
80% (-7.5% 🔻)
44.44%
66.67% (-13.33% 🔻)
80% (-7.5% 🔻)
🟢
... / app-event-watcher.ts
95.18% (-1.2% 🔻)
86.49% (-2.7% 🔻)
95.45% 100%

Test suite run success

2032 tests passing in 909 suites.

Report generated by 🧪jest coverage report action from 4a04aa9

@@ -479,14 +484,15 @@ interface GenerateRandomDirectoryOptions {
*/
export async function generateRandomNameForSubdirectory(options: GenerateRandomDirectoryOptions): Promise<string> {
const generated = `${getRandomName(options.family ?? 'business')}-${options.suffix}`

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to ensure that we don't end up in loops, perhaps with a fallback name after X attempts? There's recursion here with no base case other than "we will likely generate a name that works".

Copy link
Contributor Author

@craigmichaelmartin craigmichaelmartin Jan 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, everything about this PR is off-putting to me (I think I'm allowed to say that because it is my PR lol).

I thought about the case you are describing, but didn't want to introduce too much complexity for this edge case of convenience behavior, which would requiring adding a param for counting recursion depth, and some fallback behavior (probably couldn't be to just truncate in case the filepath for that name is already taken, so a secondary fall back to an empty string), or else having some other heavy implementation like eager avoidance of invalid names.

However, taking a step back, do you think this is the right direction? Here is roughly the landscape I see:

  1. Rather than the approach of this PR to gracefully handle too-long names, we preclude their possibility: remove the one long noun (infrastructure) that can alone can cause the name to be greater than 30 characters, extract the max length of an app name (as done in this PR), and add a test which checks that every permutation of the name seeds is not longer than the max length. The resolves the problem this PR sets out to address, and guards against its return (whether from new seed names being added, or the maximum app name length decreasing), with no runtime overhead. However, it introduces over a thousand new assertions and the maintenance costs of these data-validation tests; further if we wanted to swap out this set with some other 1st/3rd party seeds which are larger, we'd have to roll this back and go with option 2.
  2. Keep this PR, and add a base fallback for after X attempts. However this introduces hotpath costs and code complexity to accommodate a scenario which could be prevented ahead of time, and just isn't that bad.

What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All good points! Blast radius is low here, so we don't need to spend a ton of time on it. Probably what you have is fine.

However: regardless of what name we generate, the filesystem state is an unknown variable that'll likely need a check. I like your testing idea, but you're right that swapping the generator library might leave us with a long-running suite. Maybe we can make the generator conform to a max character count? And then just leave the existing FS check? Or just how you've got it is probably fine.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I'm not sure the retries and validation checks are necessary - overall this is a problem of characters being too long, but the idea of the name being "valid" beyond the character length is done through server-side checks anyways. I think retries make sense when the thing that is valid could regularly change at any given time (i.e. uniqueness checks, handle generation, etc), but this collision could be solved by appending some numbers on the end to avoid the subdirectory collision. It doesn't change the name of the app, but we don't need as much recursion logic 🤷🏻

Maybe we can make the generator conform to a max character count? And then just leave the existing FS check?

These names are purely client-side generated and we can set up the seeds such that they never produce invalid data. As you said, if the seeds change, we can have guards against that.

However, it introduces over a thousand new assertions and the maintenance costs of these data-validation tests

The names seem to be generated deterministically, so if the longest words in the seed of each component don't exceed max character length, is that a sufficient test? You wouldn't need thousands of assertions in that scenario because we don't have to check every permutation

@@ -20,3 +20,9 @@ function isValidUrl(input: string, httpsOnly: boolean) {
export function ensurePathStartsWithSlash(arg: unknown) {
return typeof arg === 'string' && !arg.startsWith('/') ? `/${arg}` : arg
}

export const APP_NAME_MAX_LENGTH = 30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this value shared with other constraints in the CLI? Or is it a convention we're inheriting from core?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This value had never been extracted (as far as I could tell). I extracted it to get the uses I found of this validation downstream from this single source of truth, rather than as disparate magic numbers (in dev.ts and wherever the app name length validation happens).

@craigmichaelmartin craigmichaelmartin force-pushed the ensure-suggested-app-names-are-valid branch 2 times, most recently from 77b0734 to 8425c1a Compare January 28, 2025 20:37
Copy link
Contributor

Differences in type declarations

We detected differences in the type declarations generated by Typescript for this branch compared to the baseline ('main' branch). Please, review them to ensure they are backward-compatible. Here are some important things to keep in mind:

  • Some seemingly private modules might be re-exported through public modules.
  • If the branch is behind main you might see odd diffs, rebase main into this branch.

New type declarations

We found no new type declarations in this PR

Existing type declarations

packages/cli-kit/dist/public/node/fs.d.ts
@@ -254,6 +254,10 @@ interface GenerateRandomDirectoryOptions {
     directory: string;
     /** Type of word to use for random name. */
     family?: RandomNameFamily;
+    /** Used to to track how many attempts have been made to generate the name. */
+    attempts?: number;
+    /** Predicate for validating the generated name. */
+    isValidName?: (name: string) => boolean;
 }
 /**
  * It generates a random directory directory name for a sub-directory.

Comment on lines 472 to 476
/** Used to to track how many attempts have been made to generate the name. */
attempts?: number

/** Predicate for validating the generated name. */
isValidName?: (name: string) => boolean
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure about this, the function should be simple, just generate a name following some options (suffix, family and the directory).

It should be responsibility of the caller to validate the proposed name and decide whether or not to try again (and how many times).

attemps should definitely not be part of the options if you want to use it to track the recursion, because it can be set externally and any caller will see this and interpret it as "max attemps" and set a number.

My proposal:

  • keep generateRandomNameForSubdirectory as it is now
  • Make the app init validate the result name and retry again if needed
  • Remove the extra long word, just to be sure.

What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good to me! Thanks, Isaac!

@craigmichaelmartin craigmichaelmartin force-pushed the ensure-suggested-app-names-are-valid branch from 21ea506 to 22f26de Compare January 30, 2025 13:45
@craigmichaelmartin craigmichaelmartin force-pushed the ensure-suggested-app-names-are-valid branch 2 times, most recently from cc3ff48 to be614db Compare January 30, 2025 14:21
@craigmichaelmartin craigmichaelmartin force-pushed the ensure-suggested-app-names-are-valid branch from be614db to 4a04aa9 Compare January 30, 2025 17:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants