From c5a0e0f82d5bf955aa9eec76d9ec9229e29747af Mon Sep 17 00:00:00 2001
From: Jack Hsu <jack.hsu@gmail.com>
Date: Wed, 8 Jan 2025 14:18:14 -0500
Subject: [PATCH] feat(core): also update run-many and show project

---
 packages/nx/src/command-line/run/run-one.ts   |  6 +++++-
 packages/nx/src/command-line/show/project.ts  | 21 ++++++++++++++++---
 .../src/utils/find-matching-projects.spec.ts  |  7 +++++++
 .../nx/src/utils/find-matching-projects.ts    | 14 +++++++++++++
 4 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/packages/nx/src/command-line/run/run-one.ts b/packages/nx/src/command-line/run/run-one.ts
index dcaae3ac58ed1e..2ee7ed338b8be8 100644
--- a/packages/nx/src/command-line/run/run-one.ts
+++ b/packages/nx/src/command-line/run/run-one.ts
@@ -129,7 +129,11 @@ function getProjects(
       };
     } else if (matchingProjects.length > 1) {
       output.error({
-        title: `Multiple projects matched:\n- ${matchingProjects.join('\n- ')}`,
+        title: `Multiple projects matched:`,
+        bodyLines:
+          matchingProjects.length > 100
+            ? [...matchingProjects.slice(0, 100), '...']
+            : matchingProjects,
       });
       process.exit(1);
     }
diff --git a/packages/nx/src/command-line/show/project.ts b/packages/nx/src/command-line/show/project.ts
index ab093399fe2732..d715e559e9aa95 100644
--- a/packages/nx/src/command-line/show/project.ts
+++ b/packages/nx/src/command-line/show/project.ts
@@ -9,10 +9,25 @@ export async function showProjectHandler(
   performance.mark('code-loading:end');
   performance.measure('code-loading', 'init-local', 'code-loading:end');
   const graph = await createProjectGraphAsync();
-  const node = graph.nodes[args.projectName];
+  let node = graph.nodes[args.projectName];
   if (!node) {
-    console.log(`Could not find project ${args.projectName}`);
-    process.exit(1);
+    const matchingProjects = Object.keys(graph.nodes).filter((name) =>
+      name.includes(args.projectName)
+    );
+    if (matchingProjects.length === 1) {
+      node = graph.nodes[matchingProjects[0]];
+    } else if (matchingProjects.length > 1) {
+      console.log(
+        `Multiple projects matched:\n  ${(matchingProjects.length > 100
+          ? [...matchingProjects.slice(0, 100), '...']
+          : matchingProjects
+        ).join('  \n')}`
+      );
+      process.exit(1);
+    } else {
+      console.log(`Could not find project ${args.projectName}`);
+      process.exit(1);
+    }
   }
   if (args.json) {
     console.log(JSON.stringify(node.data));
diff --git a/packages/nx/src/utils/find-matching-projects.spec.ts b/packages/nx/src/utils/find-matching-projects.spec.ts
index 7420b22faa4701..25f9dd4e27d608 100644
--- a/packages/nx/src/utils/find-matching-projects.spec.ts
+++ b/packages/nx/src/utils/find-matching-projects.spec.ts
@@ -178,6 +178,13 @@ describe('findMatchingProjects', () => {
       findMatchingProjects(['!tag:api', 'test-project'], projectGraph)
     ).toEqual(['b', 'nested', 'test-project']);
   });
+
+  it('should match on substring of names', () => {
+    expect(findMatchingProjects(['test', 'nest'], projectGraph)).toEqual([
+      'test-project',
+      'nested',
+    ]);
+  });
 });
 
 const projects = [
diff --git a/packages/nx/src/utils/find-matching-projects.ts b/packages/nx/src/utils/find-matching-projects.ts
index b119e653f46a9c..7730cd811f9e3f 100644
--- a/packages/nx/src/utils/find-matching-projects.ts
+++ b/packages/nx/src/utils/find-matching-projects.ts
@@ -167,6 +167,20 @@ function addMatchingProjectsByName(
   }
 
   if (!isGlobPattern(pattern.value)) {
+    // Only matching substrings when string is long enough, otherwise there will be too many matches.
+    // This is consistent with the behavior of run-one.ts.
+    if (pattern.value.length > 1) {
+      const matchingProjects = Object.keys(projects).filter((name) =>
+        name.includes(pattern.value)
+      );
+      for (const projectName of matchingProjects) {
+        if (pattern.exclude) {
+          matchedProjects.delete(projectName);
+        } else {
+          matchedProjects.add(projectName);
+        }
+      }
+    }
     return;
   }