From c03175e4baff11d8aad2d25e23e5712e7b979fd9 Mon Sep 17 00:00:00 2001 From: Gert Hengeveld Date: Tue, 15 Jun 2021 13:10:49 +0200 Subject: [PATCH] Support resolving webpack stats in subdirectory --- bin/git/git.js | 6 ++ bin/lib/getDependentStoryFiles.js | 10 +++- bin/lib/getDependentStoryFiles.test.js | 82 +++++++++++++++++++++++++- bin/tasks/upload.js | 2 +- scripts/stats-to-story-files.js | 2 +- 5 files changed, 96 insertions(+), 6 deletions(-) diff --git a/bin/git/git.js b/bin/git/git.js index 65103312f..69bd504d6 100644 --- a/bin/git/git.js +++ b/bin/git/git.js @@ -1,3 +1,4 @@ +import path from 'path'; import execa from 'execa'; import gql from 'fake-tag'; import { EOL } from 'os'; @@ -446,3 +447,8 @@ export async function checkoutPrevious() { export async function discardChanges() { return execGitCommand(`git reset --hard`); } + +export async function getWorkingDir() { + const rootDir = await execGitCommand(`git rev-parse --show-toplevel`); + return path.relative(rootDir, '.'); +} diff --git a/bin/lib/getDependentStoryFiles.js b/bin/lib/getDependentStoryFiles.js index a89073b19..6030b2f2d 100644 --- a/bin/lib/getDependentStoryFiles.js +++ b/bin/lib/getDependentStoryFiles.js @@ -1,3 +1,4 @@ +import { getWorkingDir } from '../git/git'; import bailFile from '../ui/messages/warnings/bailFile'; // Bail whenever one of these was changed @@ -9,8 +10,10 @@ const EXTERNALS = [/\/node_modules\//, /\/webpack\/runtime\//, /^\(webpack\)/]; const isGlobal = (name) => GLOBALS.some((re) => re.test(name)); const isUserCode = ({ name, moduleName }) => !EXTERNALS.some((re) => re.test(name || moduleName)); -export function getDependentStoryFiles(ctx, stats, changedFiles) { +export async function getDependentStoryFiles(ctx, stats, changedFiles) { const { configDir = './.storybook', staticDir = [] } = ctx.storybook || {}; + const workingDir = await getWorkingDir(); + const workingDirRegExp = workingDir && new RegExp(`^./${workingDir}`); // TODO deal with Windows path separator const storybookDir = configDir.startsWith('./') ? configDir : `./${configDir}`; @@ -68,7 +71,10 @@ export function getDependentStoryFiles(ctx, stats, changedFiles) { } } - changedFiles.forEach(traceName); + changedFiles.forEach((gitFilePath) => { + const webpackFilePath = workingDir ? gitFilePath.replace(workingDirRegExp, '.') : gitFilePath; + traceName(webpackFilePath); + }); while (toCheck.length > 0) { const id = toCheck.pop(); checkedIds[id] = true; diff --git a/bin/lib/getDependentStoryFiles.test.js b/bin/lib/getDependentStoryFiles.test.js index 909814d00..a50803d22 100644 --- a/bin/lib/getDependentStoryFiles.test.js +++ b/bin/lib/getDependentStoryFiles.test.js @@ -1,7 +1,85 @@ +import path from 'path'; + import { getDependentStoryFiles } from './getDependentStoryFiles'; +import { getWorkingDir } from '../git/git'; + +jest.mock('../git/git'); + +const CSF_GLOB = './src sync ^\\.\\/(?:(?!\\.)(?=.)[^/]*?\\.stories\\.js)$'; + +const ctx = { + log: { warn: jest.fn() }, +}; describe('getDependentStoryFiles', () => { - it('traverses the reasons to find affected CSF files', () => { - // getDependentStoryFiles([], { idsByName: {}, reasonsById: {}, isCsfGlob: {} }); + it('detects direct changes to CSF files', async () => { + const changedFiles = ['./src/foo.stories.js']; + const modules = [ + { + id: 1, + name: './src/foo.stories.js', + reasons: [{ moduleName: CSF_GLOB }], + }, + { + id: 999, + name: CSF_GLOB, + reasons: [{ moduleName: './.storybook/generated-stories-entry.js' }], + }, + ]; + const res = await getDependentStoryFiles(ctx, { modules }, changedFiles); + expect(res).toEqual({ + 1: './src/foo.stories.js', + }); + }); + + it('detects indirect changes to CSF files', async () => { + const changedFiles = ['./src/foo.js']; + const modules = [ + { + id: 1, + name: './src/foo.js', + reasons: [{ moduleName: './src/foo.stories.js' }], + }, + { + id: 2, + name: './src/foo.stories.js', + reasons: [{ moduleName: CSF_GLOB }], + }, + { + id: 999, + name: CSF_GLOB, + reasons: [{ moduleName: './.storybook/generated-stories-entry.js' }], + }, + ]; + const res = await getDependentStoryFiles(ctx, { modules }, changedFiles); + expect(res).toEqual({ + 2: './src/foo.stories.js', + }); + }); + + it('supports webpack root in git subdirectory', async () => { + getWorkingDir.mockResolvedValueOnce('frontend'); + const changedFiles = ['./frontend/src/foo.js']; + const modules = [ + { + id: 1, + name: './src/foo.js', + reasons: [{ moduleName: './src/foo.stories.js' }], + }, + { + id: 2, + name: './src/foo.stories.js', + reasons: [{ moduleName: CSF_GLOB }], + }, + { + id: 999, + name: CSF_GLOB, + reasons: [{ moduleName: './.storybook/generated-stories-entry.js' }], + }, + ]; + const res = await getDependentStoryFiles(ctx, { modules }, changedFiles); + expect(res).toEqual({ + 2: './src/foo.stories.js', + }); }); }); diff --git a/bin/tasks/upload.js b/bin/tasks/upload.js index ff1a8f45e..d07fa8b65 100644 --- a/bin/tasks/upload.js +++ b/bin/tasks/upload.js @@ -119,7 +119,7 @@ export const traceChangedFiles = async (ctx, task) => { const { changedFiles } = ctx.git; try { const stats = await fs.readJson(statsPath); - ctx.onlyStoryFiles = getDependentStoryFiles(ctx, stats, changedFiles); + ctx.onlyStoryFiles = await getDependentStoryFiles(ctx, stats, changedFiles); ctx.log.debug( `Found affected story files:\n${Object.entries(ctx.onlyStoryFiles) .map(([id, f]) => ` ${f} [${id}]`) diff --git a/scripts/stats-to-story-files.js b/scripts/stats-to-story-files.js index 4b71dabdf..83fb1e65d 100644 --- a/scripts/stats-to-story-files.js +++ b/scripts/stats-to-story-files.js @@ -13,7 +13,7 @@ const main = async () => { }, }; // eslint-disable-next-line no-console - console.log(getDependentStoryFiles(ctx, stats, changedFiles)); + console.log(await getDependentStoryFiles(ctx, stats, changedFiles)); }; main();