mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-10 04:22:12 +00:00
[cli] Use detectFrameworks() during vc link --repo (#10203)
Allows for multiple frameworks to be detectable within the same root directory. This is basically specifically for Storybook. <img width="700" alt="Screenshot 2023-07-12 at 6 04 37 PM" src="https://github.com/vercel/vercel/assets/71256/5a240f1e-b000-42ad-b36f-3c151d3cd449">
This commit is contained in:
5
.changeset/weak-days-yawn.md
Normal file
5
.changeset/weak-days-yawn.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
'vercel': patch
|
||||
---
|
||||
|
||||
Detect multiple frameworks within the same root directory during `vc link --repo`
|
||||
@@ -15,6 +15,7 @@ import { emoji, prependEmoji } from '../emoji';
|
||||
import selectOrg from '../input/select-org';
|
||||
import { addToGitIgnore } from './add-to-gitignore';
|
||||
import type Client from '../client';
|
||||
import type { Framework } from '@vercel/frameworks';
|
||||
import type { Project } from '@vercel-internals/types';
|
||||
import createProject from '../projects/create-project';
|
||||
import { detectProjects } from '../projects/detect-projects';
|
||||
@@ -90,7 +91,7 @@ export async function ensureRepoLink(
|
||||
// they will be ready by the time the projects are listed
|
||||
const detectedProjectsPromise = detectProjects(rootPath).catch(err => {
|
||||
output.debug(`Failed to detect local projects: ${err}`);
|
||||
return new Map<string, string>();
|
||||
return new Map<string, Framework[]>();
|
||||
});
|
||||
|
||||
// Not yet linked, so prompt user to begin linking
|
||||
@@ -187,17 +188,21 @@ export async function ensureRepoLink(
|
||||
detectedProjects.delete(project.rootDirectory ?? '');
|
||||
}
|
||||
|
||||
if (detectedProjects.size > 0) {
|
||||
const detectedProjectsCount = Array.from(detectedProjects.values()).reduce(
|
||||
(o, f) => o + f.length,
|
||||
0
|
||||
);
|
||||
if (detectedProjectsCount > 0) {
|
||||
output.log(
|
||||
`Detected ${pluralize(
|
||||
'new Project',
|
||||
detectedProjects.size,
|
||||
detectedProjectsCount,
|
||||
true
|
||||
)} that may be created.`
|
||||
);
|
||||
}
|
||||
|
||||
const addSeparators = projects.length > 0 && detectedProjects.size > 0;
|
||||
const addSeparators = projects.length > 0 && detectedProjectsCount > 0;
|
||||
const { selected } = await client.prompt({
|
||||
type: 'checkbox',
|
||||
name: 'selected',
|
||||
@@ -218,23 +223,30 @@ export async function ensureRepoLink(
|
||||
...(addSeparators
|
||||
? [new inquirer.Separator('----- New Projects to be created -----')]
|
||||
: []),
|
||||
...Array.from(detectedProjects.entries()).map(
|
||||
([rootDirectory, framework]) => {
|
||||
...Array.from(detectedProjects.entries()).flatMap(
|
||||
([rootDirectory, frameworks]) =>
|
||||
frameworks.map((framework, i) => {
|
||||
const name = slugify(
|
||||
[basename(rootPath), basename(rootDirectory)]
|
||||
[
|
||||
basename(rootPath),
|
||||
basename(rootDirectory),
|
||||
i > 0 ? framework.slug : '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('-')
|
||||
);
|
||||
return {
|
||||
name: `${org.slug}/${name} (${framework})`,
|
||||
name: `${org.slug}/${name} (${framework.name})`,
|
||||
value: {
|
||||
newProject: true,
|
||||
rootDirectory,
|
||||
name,
|
||||
framework,
|
||||
},
|
||||
// Checked by default when there are no other existing Projects
|
||||
checked: projects.length === 0,
|
||||
};
|
||||
}
|
||||
})
|
||||
),
|
||||
],
|
||||
});
|
||||
@@ -251,7 +263,10 @@ export async function ensureRepoLink(
|
||||
output.spinner(`Creating new Project: ${orgAndName}`);
|
||||
delete selection.newProject;
|
||||
if (!selection.rootDirectory) delete selection.rootDirectory;
|
||||
selected[i] = await createProject(client, selection);
|
||||
selected[i] = await createProject(client, {
|
||||
...selection,
|
||||
framework: selection.framework.slug,
|
||||
});
|
||||
await connectGitProvider(
|
||||
client,
|
||||
org,
|
||||
@@ -262,7 +277,8 @@ export async function ensureRepoLink(
|
||||
output.log(
|
||||
`Created new Project: ${output.link(
|
||||
orgAndName,
|
||||
`https://vercel.com/${orgAndName}`
|
||||
`https://vercel.com/${orgAndName}`,
|
||||
{ fallback: false }
|
||||
)}`
|
||||
);
|
||||
}
|
||||
@@ -287,9 +303,11 @@ export async function ensureRepoLink(
|
||||
|
||||
output.print(
|
||||
prependEmoji(
|
||||
`Linked to ${repoUrlLink} under ${chalk.bold(
|
||||
org.slug
|
||||
)} (created ${VERCEL_DIR}${
|
||||
`Linked to ${pluralize(
|
||||
'Project',
|
||||
selected.length,
|
||||
true
|
||||
)} under ${chalk.bold(org.slug)} (created ${VERCEL_DIR}${
|
||||
isGitIgnoreUpdated ? ' and added it to .gitignore' : ''
|
||||
})`,
|
||||
emoji('link')
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { join } from 'path';
|
||||
import frameworks from '@vercel/frameworks';
|
||||
import frameworkList, { Framework } from '@vercel/frameworks';
|
||||
import {
|
||||
detectFramework,
|
||||
detectFrameworks,
|
||||
getWorkspacePackagePaths,
|
||||
getWorkspaces,
|
||||
LocalFileSystemDetector,
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
export async function detectProjects(cwd: string) {
|
||||
const fs = new LocalFileSystemDetector(cwd);
|
||||
const workspaces = await getWorkspaces({ fs });
|
||||
const detectedProjects = new Map<string, string>();
|
||||
const detectedProjects = new Map<string, Framework[]>();
|
||||
const packagePaths = (
|
||||
await Promise.all(
|
||||
workspaces.map(workspace =>
|
||||
@@ -26,12 +26,12 @@ export async function detectProjects(cwd: string) {
|
||||
}
|
||||
await Promise.all(
|
||||
packagePaths.map(async p => {
|
||||
const framework = await detectFramework({
|
||||
const frameworks = await detectFrameworks({
|
||||
fs: fs.chdir(join('.', p)),
|
||||
frameworkList: frameworks,
|
||||
frameworkList,
|
||||
});
|
||||
if (!framework) return;
|
||||
detectedProjects.set(p.slice(1), framework);
|
||||
if (frameworks.length === 0) return;
|
||||
detectedProjects.set(p.slice(1), frameworks);
|
||||
})
|
||||
);
|
||||
return detectedProjects;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { join } from 'path';
|
||||
import type { Framework } from '@vercel/frameworks';
|
||||
import { detectProjects } from '../../../../src/util/projects/detect-projects';
|
||||
|
||||
const REPO_ROOT = join(__dirname, '../../../../../..');
|
||||
@@ -8,23 +9,35 @@ const FS_DETECTORS_FIXTURES = join(
|
||||
'packages/fs-detectors/test/fixtures'
|
||||
);
|
||||
|
||||
function mapDetected(
|
||||
detected: Map<string, Framework[]>
|
||||
): Array<[string, string[]]> {
|
||||
return [...detected.entries()]
|
||||
.sort((a, b) => a[0].localeCompare(b[0]))
|
||||
.map(([dir, frameworks]) => [dir, frameworks.map(f => f.slug as string)]);
|
||||
}
|
||||
|
||||
describe('detectProjects()', () => {
|
||||
it('should match "nextjs" example', async () => {
|
||||
it('should match 1 Project in "nextjs" example', async () => {
|
||||
const dir = join(EXAMPLES_DIR, 'nextjs');
|
||||
const detected = await detectProjects(dir);
|
||||
expect([...detected.entries()]).toEqual([['', 'nextjs']]);
|
||||
expect(mapDetected(detected)).toEqual([['', ['nextjs']]]);
|
||||
});
|
||||
|
||||
it('should match 2 Projects in "storybook" example', async () => {
|
||||
const dir = join(EXAMPLES_DIR, 'storybook');
|
||||
const detected = await detectProjects(dir);
|
||||
expect(mapDetected(detected)).toEqual([['', ['nextjs', 'storybook']]]);
|
||||
});
|
||||
|
||||
it('should match "30-double-nested-workspaces"', async () => {
|
||||
const dir = join(FS_DETECTORS_FIXTURES, '30-double-nested-workspaces');
|
||||
const detected = await detectProjects(dir);
|
||||
expect(
|
||||
[...detected.entries()].sort((a, b) => a[0].localeCompare(b[0]))
|
||||
).toEqual([
|
||||
['packages/backend/c', 'remix'],
|
||||
['packages/backend/d', 'nextjs'],
|
||||
['packages/frontend/a', 'hexo'],
|
||||
['packages/frontend/b', 'ember'],
|
||||
expect(mapDetected(detected)).toEqual([
|
||||
['packages/backend/c', ['remix']],
|
||||
['packages/backend/d', ['nextjs']],
|
||||
['packages/frontend/a', ['hexo']],
|
||||
['packages/frontend/b', ['ember']],
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user