From 2fe236c8d94afd2b4c0675a3d90c46bb34ab8d88 Mon Sep 17 00:00:00 2001 From: Blake Friedman Date: Wed, 4 Dec 2024 14:01:35 +0000 Subject: [PATCH] ci: verify JS build artifacts aren't committed Building our JS packages dirties the repo. This makes sure we don't accidentally commit these to the repo, as it'll break Flow tests with an obscure error message. Changelog: [Internal] Testing: Ran this locally, the GH lint action should run on this PR. I'll intentionally add a build artifact to validate. --- .github/actions/lint/action.yml | 3 ++ scripts/build/build.js | 54 +++++++++++++++++++++++++++--- scripts/run-ci-javascript-tests.js | 7 ++++ 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/.github/actions/lint/action.yml b/.github/actions/lint/action.yml index e914b6557b9..6440e7dc5b2 100644 --- a/.github/actions/lint/action.yml +++ b/.github/actions/lint/action.yml @@ -30,6 +30,9 @@ runs: - name: Lint java shell: bash run: ./scripts/circleci/exec_swallow_error.sh yarn lint-java --check + - name: Verify not committing repo after running build + shell: bash + run: yarn run build --check - name: Run flowcheck shell: bash run: yarn flow-check diff --git a/scripts/build/build.js b/scripts/build/build.js index 99bfd9d7524..4cb9de68a0a 100644 --- a/scripts/build/build.js +++ b/scripts/build/build.js @@ -36,13 +36,14 @@ const config = { allowPositionals: true, options: { help: {type: 'boolean'}, + check: {type: 'boolean'}, }, }; async function build() { const { positionals: packageNames, - values: {help}, + values: {help, check}, } = parseArgs(config); if (help) { @@ -58,17 +59,35 @@ async function build() { return; } - console.log('\n' + chalk.bold.inverse('Building packages') + '\n'); + if (!check) { + console.log('\n' + chalk.bold.inverse('Building packages') + '\n'); + } const packagesToBuild = packageNames.length ? packageNames.filter(packageName => packageName in buildConfig.packages) : Object.keys(buildConfig.packages); + let ok = true; for (const packageName of packagesToBuild) { - await buildPackage(packageName); + if (check) { + ok &&= await checkPackage(packageName); + } else { + await buildPackage(packageName); + } } - process.exitCode = 0; + process.exitCode = ok ? 0 : 1; +} + +async function checkPackage(packageName /*: string */) /*: Promise */ { + const artifacts = await exportedBuildArtifacts(packageName); + if (artifacts.length > 0) { + console.log( + `${chalk.bgRed(packageName)}: has been build and the ${chalk.bold('build artifacts')} committed to the repository. This will break Flow checks.`, + ); + return false; + } + return true; } async function buildPackage(packageName /*: string */) { @@ -183,6 +202,33 @@ type PackageJson = { }; */ +function isStringOnly(entries /*: mixed */) /*: entries is string */ { + return typeof entries === 'string'; +} + +async function exportedBuildArtifacts( + packageName /*: string */, +) /*: Promise */ { + const packagePath = path.resolve(PACKAGES_DIR, packageName, 'package.json'); + const pkg /*: PackageJson */ = JSON.parse( + await fs.readFile(packagePath, 'utf8'), + ); + if (pkg.exports == null) { + throw new Error( + packageName + + ' does not define an "exports" field in its package.json. As part ' + + 'of the build setup, this field must be used in order to rewrite ' + + 'paths to built files in production.', + ); + } + + return Object.values(pkg.exports) + .filter(isStringOnly) + .filter(filepath => + path.dirname(filepath).split(path.sep).includes(BUILD_DIR), + ); +} + /** * Get the set of Flow entry points to build. * diff --git a/scripts/run-ci-javascript-tests.js b/scripts/run-ci-javascript-tests.js index 0a6a1351355..c0eefa9432a 100644 --- a/scripts/run-ci-javascript-tests.js +++ b/scripts/run-ci-javascript-tests.js @@ -47,6 +47,13 @@ try { throw Error(exitCode); } + describe('Test: No JS build artifacts'); + if (exec(`${YARN_BINARY} run build --check`).code) { + echo('Failed, there are build artifacts in this commit.'); + exitCode = 1; + throw Error(exitCode); + } + describe('Test: Flow check'); if (exec(`${YARN_BINARY} run flow-check`).code) { echo('Failed to run flow.');