From 6dce4bc90241a1476d3d4ef68d0875a3196c0322 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Mon, 19 Sep 2022 12:04:38 +0200 Subject: [PATCH 1/5] chore: Northstar screener should read from screenerStates.json Screener is now separated into two workflows for secrets encapsulation, the code to trigger the screener run is actually run on the master branch. The current northstar screener states are generated directly before running, this means that any changes to N* screener tests will never result in updated screenshots Update the `screener:build` gulp command to write all states to a json file and updeates the `screener:runner` gulp tasks to read states from the json file. Since the entire `docs/dist` artifact is uploaded, there should be no changes needed for the pipeline --- .../screener.config.js | 3 ++- apps/vr-tests/screener.config.js | 3 ++- scripts/gulp/tasks/screener.ts | 26 ++++++++++++++----- scripts/screener/screener.config.js | 10 +++---- scripts/screener/screener.types.ts | 6 ++--- 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/apps/vr-tests-react-components/screener.config.js b/apps/vr-tests-react-components/screener.config.js index 56a9934f99dc1c..0e229136d99d10 100644 --- a/apps/vr-tests-react-components/screener.config.js +++ b/apps/vr-tests-react-components/screener.config.js @@ -24,7 +24,7 @@ function getCurrentHash() { * @param {string} options.sourceBranchName * @param {string} options.deployUrl * @param {string} options.targetBranch - * @returns + * @returns {import('@fluentui/scripts/screener/screener.types').ScreenerRunnerConfig} */ function getConfig({ screenerApiKey, sourceBranchName, deployUrl, targetBranch }) { const baseBranch = targetBranch ? targetBranch.replace(/^refs\/heads\//, '') : 'master'; @@ -38,6 +38,7 @@ function getConfig({ screenerApiKey, sourceBranchName, deployUrl, targetBranch } baseBranch, failureExitCode: 0, alwaysAcceptBaseBranch: true, + states: [], ...(sourceBranchName !== 'master' ? { commit: getCurrentHash() } : null), baseUrl: `${deployUrl}/react-components-screener/iframe.html`, }; diff --git a/apps/vr-tests/screener.config.js b/apps/vr-tests/screener.config.js index b928986b51524a..13f073e99c97d0 100644 --- a/apps/vr-tests/screener.config.js +++ b/apps/vr-tests/screener.config.js @@ -27,7 +27,7 @@ function getCurrentHash() { * @param {string} options.sourceBranchName * @param {string} options.deployUrl * @param {string} options.targetBranch - * @returns + * @returns {import('@fluentui/scripts/screener/screener.types').ScreenerRunnerConfig} */ function getConfig({ screenerApiKey, sourceBranchName, deployUrl, targetBranch }) { const baseBranch = targetBranch ? targetBranch.replace(/^refs\/heads\//, '') : 'master'; @@ -44,6 +44,7 @@ function getConfig({ screenerApiKey, sourceBranchName, deployUrl, targetBranch } alwaysAcceptBaseBranch: true, ...(sourceBranchName !== 'master' ? { commit: getCurrentHash() } : null), baseUrl: `${deployUrl}/react-screener/iframe.html`, + states: [], }; console.log('Screener config: ' + JSON.stringify({ ...config, apiKey: '...' }, null, 2)); return config; diff --git a/scripts/gulp/tasks/screener.ts b/scripts/gulp/tasks/screener.ts index 329bf716c30e82..7c05f665dea2c4 100644 --- a/scripts/gulp/tasks/screener.ts +++ b/scripts/gulp/tasks/screener.ts @@ -1,11 +1,15 @@ import { task, series } from 'gulp'; import { argv } from 'yargs'; +import fs from 'fs'; import config from '../../config'; import { getAllPackageInfo } from '../../monorepo'; import { screenerRunner } from '../../screener/screener.runner'; +import states from '../../screener/screener.states'; +import getConfig from '../../screener/screener.config'; const { paths } = config; +const docsPackageName = '@fluentui/docs'; // ---------------------------------------- // Visual @@ -15,15 +19,11 @@ task('screener:runner', cb => { // screener-runner doesn't allow to pass custom options if (argv.filter) process.env.SCREENER_FILTER = argv.filter as string; - const docsPackageName = '@fluentui/docs'; - const packageInfos = getAllPackageInfo(); if (Object.values(packageInfos).every(packageInfo => packageInfo.packageJson.name !== docsPackageName)) { throw new Error(`package ${docsPackageName} does not exist in the repo`); } - const screenerConfigPath = paths.base('scripts/screener/screener.config.js'); - // kill the server when done const handlePromiseExit = promise => promise @@ -36,12 +36,15 @@ task('screener:runner', cb => { process.exit(1); }); - const getConfig = require(screenerConfigPath); const screenerConfig = getConfig({ screenerApiKey: process.env.SCREENER_API_KEY, sourceBranchName: process.env.BUILD_SOURCEBRANCHNAME, + deployUrl: process.env.DEPLOYURL, }); + const screenerStates = require(paths.docsDist('screenerStates.json')); + screenerConfig.states = screenerStates; + handlePromiseExit(screenerRunner(screenerConfig)); }); @@ -49,4 +52,15 @@ task('screener:runner', cb => { // Default // ---------------------------------------- -task('screener:build', series('build:docs')); +task('screener:states', cb => { + const statesJson = JSON.stringify(states, null, 2); + fs.writeFile(paths.docsDist('screenerStates.json'), statesJson, { encoding: 'utf8' }, err => { + if (err) { + cb(err); + } + + cb(); + }); +}); + +task('screener:build', series('build:docs', 'screener:states')); diff --git a/scripts/screener/screener.config.js b/scripts/screener/screener.config.js index 64384043d2cab5..ee63d4dea9ec77 100644 --- a/scripts/screener/screener.config.js +++ b/scripts/screener/screener.config.js @@ -36,11 +36,13 @@ const baseBranch = 'master'; * @param {Object} options * @param {string} options.screenerApiKey * @param {string} options.sourceBranchName - * @returns + * @param {string} options.deployUrl + * @returns {import('./screener.types').ScreenerRunnerConfig} */ -function getConfig({ screenerApiKey, sourceBranchName }) { +function getConfig({ screenerApiKey, sourceBranchName, deployUrl }) { // https://github.com/screener-io/screener-runner return { + baseUrl: `${deployUrl}/react-northstar-screener`, apiKey: screenerApiKey, projectRepo: 'microsoft/fluentui/fluentui', @@ -54,9 +56,7 @@ function getConfig({ screenerApiKey, sourceBranchName }) { minShiftGraphic: 1, // Optional threshold for pixel shifts in graphics. compareSVGDOM: false, // Pass if SVG DOM is the same. Defaults to false. }, - - // screenshot every example in maximized mode - states: require('./screener.states').default, + states: [], alwaysAcceptBaseBranch: true, baseBranch, diff --git a/scripts/screener/screener.types.ts b/scripts/screener/screener.types.ts index 087f92d7ef536d..d7f38c24ec7f43 100644 --- a/scripts/screener/screener.types.ts +++ b/scripts/screener/screener.types.ts @@ -2,7 +2,7 @@ export type ScreenerRunnerConfig = { apiKey: string; projectRepo: string; - diffOptions: { + diffOptions?: { structure: boolean; layout: boolean; style: boolean; @@ -10,14 +10,14 @@ export type ScreenerRunnerConfig = { minLayoutPosition: number; // Optional threshold for Layout changes. Defaults to 4 pixels. minLayoutDimension: number; // Optional threshold for Layout changes. Defaults to 10 pixels. minShiftGraphic: number; // Optional threshold for pixel shifts in graphics. - compareSVGDOM: number; // Pass if SVG DOM is the same. Defaults to false. + compareSVGDOM: boolean; // Pass if SVG DOM is the same. Defaults to false. }; states: ScreenerState[]; alwaysAcceptBaseBranch: boolean; baseBranch: string; - commit: string; + commit?: string; failureExitCode: number; /** Base url of deployed storybook screener should test */ From 393af13e74f13b719c1648c9c36f8520e5cb40ec Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Mon, 19 Sep 2022 12:28:56 +0200 Subject: [PATCH 2/5] fix danger --- scripts/gulp/tasks/screener.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/gulp/tasks/screener.ts b/scripts/gulp/tasks/screener.ts index 7c05f665dea2c4..2c02948414843b 100644 --- a/scripts/gulp/tasks/screener.ts +++ b/scripts/gulp/tasks/screener.ts @@ -5,7 +5,6 @@ import fs from 'fs'; import config from '../../config'; import { getAllPackageInfo } from '../../monorepo'; import { screenerRunner } from '../../screener/screener.runner'; -import states from '../../screener/screener.states'; import getConfig from '../../screener/screener.config'; const { paths } = config; @@ -53,6 +52,8 @@ task('screener:runner', cb => { // ---------------------------------------- task('screener:states', cb => { + const screenerStatesPath = paths.base('scripts/screener/screener.states.ts'); + const states = require(screenerStatesPath); const statesJson = JSON.stringify(states, null, 2); fs.writeFile(paths.docsDist('screenerStates.json'), statesJson, { encoding: 'utf8' }, err => { if (err) { From 453a44574459d64b2b3c1d4a56681397c59c5916 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Mon, 19 Sep 2022 12:37:07 +0200 Subject: [PATCH 3/5] refactored screener states and gulp tasks --- gulpfile.ts | 3 +- scripts/gulp/tasks/vr-build.ts | 21 ++++++ .../gulp/tasks/{screener.ts => vr-test.ts} | 22 +----- scripts/screener/screener.states.ts | 74 ++++++++++--------- 4 files changed, 62 insertions(+), 58 deletions(-) create mode 100644 scripts/gulp/tasks/vr-build.ts rename scripts/gulp/tasks/{screener.ts => vr-test.ts} (70%) diff --git a/gulpfile.ts b/gulpfile.ts index e7f72e8db3565c..dd562b2ee3f980 100644 --- a/gulpfile.ts +++ b/gulpfile.ts @@ -22,7 +22,8 @@ tsPaths.register({ require('./scripts/gulp/tasks/bundle'); require('./scripts/gulp/tasks/component-info'); require('./scripts/gulp/tasks/docs'); -require('./scripts/gulp/tasks/screener'); +require('./scripts/gulp/tasks/vr-build'); +require('./scripts/gulp/tasks/vr-test'); require('./scripts/gulp/tasks/stats'); require('./scripts/gulp/tasks/test-unit'); require('./scripts/gulp/tasks/perf'); diff --git a/scripts/gulp/tasks/vr-build.ts b/scripts/gulp/tasks/vr-build.ts new file mode 100644 index 00000000000000..61ae279f3acf4d --- /dev/null +++ b/scripts/gulp/tasks/vr-build.ts @@ -0,0 +1,21 @@ +import { task, series } from 'gulp'; +import fs from 'fs'; + +import config from '../../config'; +import getScreenerStates from '../../screener/screener.states'; + +const { paths } = config; + +task('screener:states', cb => { + const states = getScreenerStates(); + const statesJson = JSON.stringify(states, null, 2); + fs.writeFile(paths.docsDist('screenerStates.json'), statesJson, { encoding: 'utf8' }, err => { + if (err) { + cb(err); + } + + cb(); + }); +}); + +task('screener:build', series('screener:states')); diff --git a/scripts/gulp/tasks/screener.ts b/scripts/gulp/tasks/vr-test.ts similarity index 70% rename from scripts/gulp/tasks/screener.ts rename to scripts/gulp/tasks/vr-test.ts index 2c02948414843b..9e99e85fda6182 100644 --- a/scripts/gulp/tasks/screener.ts +++ b/scripts/gulp/tasks/vr-test.ts @@ -1,6 +1,5 @@ -import { task, series } from 'gulp'; +import { task } from 'gulp'; import { argv } from 'yargs'; -import fs from 'fs'; import config from '../../config'; import { getAllPackageInfo } from '../../monorepo'; @@ -46,22 +45,3 @@ task('screener:runner', cb => { handlePromiseExit(screenerRunner(screenerConfig)); }); - -// ---------------------------------------- -// Default -// ---------------------------------------- - -task('screener:states', cb => { - const screenerStatesPath = paths.base('scripts/screener/screener.states.ts'); - const states = require(screenerStatesPath); - const statesJson = JSON.stringify(states, null, 2); - fs.writeFile(paths.docsDist('screenerStates.json'), statesJson, { encoding: 'utf8' }, err => { - if (err) { - cb(err); - } - - cb(); - }); -}); - -task('screener:build', series('build:docs', 'screener:states')); diff --git a/scripts/screener/screener.states.ts b/scripts/screener/screener.states.ts index 20ad7881f1b9fc..5876517c02c5df 100644 --- a/scripts/screener/screener.states.ts +++ b/scripts/screener/screener.states.ts @@ -7,42 +7,44 @@ import path from 'path'; import getScreenerSteps from './screener.steps'; import { ScreenerState } from './screener.types'; -const baseUrl = `${process.env.DEPLOYURL}/react-northstar-screener`; -const examplePaths = glob.sync('packages/fluentui/docs/src/examples/**/*.tsx', { - ignore: ['**/index.tsx', '**/*.knobs.tsx', '**/BestPractices/*.tsx', '**/Playground.tsx'], -}); - -const pathFilter = process.env.SCREENER_FILTER; -const filteredPaths: string[] = minimatch.match(examplePaths, pathFilter || '*', { - matchBase: true, -}); - -if (pathFilter) { - console.log(chalk.bgGreen.black(' --filter '), pathFilter); - filteredPaths.forEach(filteredPath => console.log(`${_.repeat(' ', 10)} ${filteredPath}`)); -} - -const getStateForPath = (examplePath: string): ScreenerState => { - const { name: exampleNameWithoutExtension, base: exampleNameWithExtension, dir: exampleDir } = path.parse( - examplePath, - ); - - const rtl = exampleNameWithExtension.endsWith('.rtl.tsx'); - const exampleUrl = _.kebabCase(exampleNameWithoutExtension); - const pageUrl = `${baseUrl}/maximize/${exampleUrl}/${rtl}`; - - return { - url: pageUrl, - name: exampleNameWithExtension, - - // https://www.npmjs.com/package/screener-runner#testing-interactions - steps: getScreenerSteps(pageUrl, `${exampleDir}/${exampleNameWithoutExtension}.steps`), +export default function getScreenerStates() { + const baseUrl = `${process.env.DEPLOYURL}/react-northstar-screener`; + const examplePaths = glob.sync('packages/fluentui/docs/src/examples/**/*.tsx', { + ignore: ['**/index.tsx', '**/*.knobs.tsx', '**/BestPractices/*.tsx', '**/Playground.tsx'], + }); + + const pathFilter = process.env.SCREENER_FILTER; + const filteredPaths: string[] = minimatch.match(examplePaths, pathFilter || '*', { + matchBase: true, + }); + + if (pathFilter) { + console.log(chalk.bgGreen.black(' --filter '), pathFilter); + filteredPaths.forEach(filteredPath => console.log(`${_.repeat(' ', 10)} ${filteredPath}`)); + } + + const getStateForPath = (examplePath: string): ScreenerState => { + const { name: exampleNameWithoutExtension, base: exampleNameWithExtension, dir: exampleDir } = path.parse( + examplePath, + ); + + const rtl = exampleNameWithExtension.endsWith('.rtl.tsx'); + const exampleUrl = _.kebabCase(exampleNameWithoutExtension); + const pageUrl = `${baseUrl}/maximize/${exampleUrl}/${rtl}`; + + return { + url: pageUrl, + name: exampleNameWithExtension, + + // https://www.npmjs.com/package/screener-runner#testing-interactions + steps: getScreenerSteps(pageUrl, `${exampleDir}/${exampleNameWithoutExtension}.steps`), + }; }; -}; -const screenerStates = filteredPaths.reduce((states, examplePath) => { - states.push(getStateForPath(examplePath)); - return states; -}, [] as ReturnType[]); + const screenerStates = filteredPaths.reduce((states, examplePath) => { + states.push(getStateForPath(examplePath)); + return states; + }, [] as ReturnType[]); -export default screenerStates; + return screenerStates; +} From 8ee3bbc532b6c6880cf8a57f8222e18583628f84 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Mon, 19 Sep 2022 12:43:30 +0200 Subject: [PATCH 4/5] add docs build --- scripts/gulp/tasks/vr-build.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gulp/tasks/vr-build.ts b/scripts/gulp/tasks/vr-build.ts index 61ae279f3acf4d..268a157ec615a9 100644 --- a/scripts/gulp/tasks/vr-build.ts +++ b/scripts/gulp/tasks/vr-build.ts @@ -18,4 +18,4 @@ task('screener:states', cb => { }); }); -task('screener:build', series('screener:states')); +task('screener:build', series('docs:build', 'screener:states')); From ebde1226c54bad0f57d20d8cbef56e2f718e8e76 Mon Sep 17 00:00:00 2001 From: Lingfan Gao Date: Mon, 19 Sep 2022 12:44:04 +0200 Subject: [PATCH 5/5] fix to build:docs --- scripts/gulp/tasks/vr-build.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/gulp/tasks/vr-build.ts b/scripts/gulp/tasks/vr-build.ts index 268a157ec615a9..6fe6cb4460b0ff 100644 --- a/scripts/gulp/tasks/vr-build.ts +++ b/scripts/gulp/tasks/vr-build.ts @@ -18,4 +18,4 @@ task('screener:states', cb => { }); }); -task('screener:build', series('docs:build', 'screener:states')); +task('screener:build', series('build:docs', 'screener:states'));