Skip to content

Commit

Permalink
chore: add build system tests
Browse files Browse the repository at this point in the history
  • Loading branch information
tracy-french committed Dec 11, 2024
1 parent 3baeafc commit 1d24666
Show file tree
Hide file tree
Showing 23 changed files with 512 additions and 67 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ jobs:
${{ runner.os }}-test-lint-${{ matrix.package}}-
- name: Validate
run: npx turbo build lint test --filter=@iot-app-kit/${{ matrix.package }}
run: npx turbo build lint test pack --filter=@iot-app-kit/${{ matrix.package }}

playwright:
needs: repo
Expand Down
5 changes: 3 additions & 2 deletions apps/dev-env/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
"type": "module",
"scripts": {
"start": "npm run dev",
"clean": "npx rimraf storybook-static .turbo .cache test-results playwright-report",
"clean:nuke": "npm run clean && npx rimraf node_modules",
"clean": "npx rimraf storybook-static .cache test-results playwright-report",
"clean:turbo": "npx rimraf .turbo",
"clean:nuke": "npm run clean && npm run clean:turbo && npx rimraf node_modules",
"dev": "NODE_OPTIONS='--import tsx/esm' storybook dev -p 6006",
"lint": "eslint . --max-warnings=0 --cache --cache-location .cache/eslint/ & tsc --noEmit",
"fix": "eslint --fix . --cache --cache-location ./cache/eslint/",
Expand Down
5 changes: 3 additions & 2 deletions apps/doc-site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
"scripts": {
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"clean": "npx rimraf storybook-static .turbo",
"clean:nuke": "npm run clean && npx rimraf node_modules",
"clean": "npx rimraf storybook-static",
"clean:turbo": "npx rimraf .turbo",
"clean:nuke": "npm run clean && npm run clean:turbo && npx rimraf node_modules",
"start": "storybook dev -p 6006",
"dev": "npm start",
"build": "storybook build",
Expand Down
10 changes: 7 additions & 3 deletions configuration/vite-config/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@
"./definePackageConfig": "./src/definePackageConfig.ts"
},
"bin": {
"iot-postbuild": "./src/scripts/postbuild.ts",
"iot-prepack": "./src/scripts/prepack.ts",
"iot-postpack": "./src/scripts/postpack.ts"
},
"scripts": {
"clean": "npx rimraf .cache .turbo",
"clean:nuke": "npm run clean && npx rimraf node_modules",
"clean": "npx rimraf .cache",
"clean:turbo": "npx rimraf .turbo",
"clean:nuke": "npm run clean && npm run clean:turbo && npx rimraf node_modules",
"lint": "eslint . --max-warnings=0 --cache --cache-location .cache/eslint/ & tsc --noEmit",
"fix": "eslint --fix . --cache --cache-location ./cache/eslint/",
"test:typescript": "tsc --noEmit"
Expand All @@ -22,7 +24,9 @@
"@iot-app-kit/ts-config": "*",
"@types/fs-extra": "^11.0.4",
"@types/node": "^18.16.18",
"rimraf": "^5.0.1"
"@types/tar-fs": "^2.0.4",
"rimraf": "^5.0.1",
"tar-fs": "^3.0.6"
},
"dependencies": {
"fs-extra": "^11.2.0",
Expand Down
45 changes: 24 additions & 21 deletions configuration/vite-config/src/definePackageConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,24 +42,20 @@ export function definePackageConfig(
const packageJson = readPackageJson(resolve(dirname, './package.json'));

const allPackages = listRegisteredPackages();
const protectedPackages = listRegisteredPackages({
filter: { scope: 'protected' },
});

const packageAliases = protectedPackages.reduce<ViteAliasOptions>(
(acc, protectedPackage) => {
const protectedPackageShortName = getShortName(protectedPackage.name);
const packageAliases = listRegisteredPackages({
filter: { scope: 'protected' },
}).reduce<ViteAliasOptions>((acc, protectedPackage) => {
const protectedPackageShortName = getShortName(protectedPackage.name);

return {
...acc,
[protectedPackage.name]: resolve(
dirname,
`../${protectedPackageShortName}/src`
),
} satisfies ViteAliasOptions;
},
{}
);
return {
...acc,
[protectedPackage.name]: resolve(
dirname,
`../${protectedPackageShortName}/src`
),
} satisfies ViteAliasOptions;
}, {});

// Package-specific configuration is recursively merged with the base
// configuration defined here to provide packages flexibility in their
Expand Down Expand Up @@ -163,11 +159,8 @@ export function definePackageConfig(
// plugin to generate the types.
dts({
tsconfigPath: resolve(dirname, './tsconfig.json'),
// The dts plugin does use all of the settings of the tsconfig.json
// file it is using to build the declaration files. The following
// options need to be set to be set. Consistency across packages
// enables us to avoid package-specific configuration of these
// options.
// Consistency across packages enables us to avoid package-specific
// configuration of these options.
include: ['src'],
outDir: ['dist/esm', 'dist/cjs'],
// All of the code being distributed by a package should be contained
Expand All @@ -176,7 +169,17 @@ export function definePackageConfig(
'./src/**/*.spec.*',
'./src/**/*.test.*',
'./src/**/__mocks__',
'./src/**/testing',
],
beforeWriteFile: (filePath, content) => {
// Ensure stability of declaration file path.
const formattedFilePath = filePath.replace('/src', '');

return {
filePath: formattedFilePath,
content,
};
},
}),
copyProtectedPackagesPlugin({ dir: dirname, packageJson }),
],
Expand Down
10 changes: 10 additions & 0 deletions configuration/vite-config/src/scripts/postbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env -S npx tsx
import { validateBuildArtifacts } from '../validation/validateBuildArtifacts';

postbuild();

function postbuild(): void | never {
console.info('*** Starting postbuild. ***');
validateBuildArtifacts();
console.info('*** Ending postbuild. ***');
}
149 changes: 147 additions & 2 deletions configuration/vite-config/src/scripts/postpack.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,20 @@
#!/usr/bin/env -S npx tsx
import fse from 'fs-extra';
import fs from 'fs';
import { listRegisteredPackages } from '../packageRegistry';
import { type LocalPackageJson, readPackageJson } from '../packageJson';
import { listInstalledPackages } from '../installedPackages';
import { extract } from 'tar-fs';
import { getShortName, type PackageName } from '../package';
import zlib from 'zlib';

function postpack() {
await postpack();

async function postpack() {
console.info('*** Starting postpack. ***');
revertReferencesToCopiedProtectedPackages();
await validatePostpack();
console.info('*** Ending postpack. ***');
}

function revertReferencesToCopiedProtectedPackages() {
Expand All @@ -22,4 +33,138 @@ function revertReferencesToCopiedProtectedPackages() {
fse.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });
}

postpack();
async function validatePostpack() {
console.info(`*** Validating package.json. ***`);

const packageJson = readPackageJson('./package.json');

listInstalledPackages(packageJson, {
filter: { scope: 'protected', dependencyType: 'dependencies' },
}).forEach((p) => {
if (packageJson.dependencies?.[p.name] !== '*') {
console.error(
'*** Failure: Local dependency has incorrect version setting. ***'
);
throw new Error(
`[iot-app-kit] Expected local dependency version to be '*'. Found: ${
packageJson.dependencies?.[p.name] ?? 'No version found'
}.`
);
}
});

try {
console.info(`*** Validating package tarball contents. ***`);

const tarballContentsDest = './package-tarball-contents';
const packageContents = `${tarballContentsDest}/package`;

await extractPackageTarball(packageJson, tarballContentsDest);

const packedPackageJson = readPackageJson(
`./${packageContents}/package.json`
);

listInstalledPackages(packedPackageJson, {
filter: { scope: 'protected', dependencyType: 'dependencies' },
}).forEach((p) => {
if (
packedPackageJson.dependencies?.[p.name] !==
`file:./dist/${getShortName(p.name as PackageName)}`
) {
console.error(
'*** Failure: Packed local dependency has incorrect version setting. ***'
);
throw new Error(
`[iot-app-kit] Expected packed local dependency version to use file reference. Found: ${
packedPackageJson.dependencies?.[p.name] ?? 'No version found'
}.`
);
}
});

fse.readFileSync(`./${packageContents}/README.md`);
fse.readFileSync(`./${packageContents}/LICENSE`);
fse.readFileSync(`./${packageContents}/NOTICE`);
fse.readFileSync(`./${packageContents}/dist/cjs/index.cjs.js`);
fse.readFileSync(`./${packageContents}/dist/cjs/index.cjs.js.map`);
fse.readFileSync(`./${packageContents}/dist/cjs/index.d.ts`);
fse.readFileSync(`./${packageContents}/dist/cjs/index.d.ts.map`);
fse.readFileSync(`./${packageContents}/dist/esm/index.js`);
fse.readFileSync(`./${packageContents}/dist/esm/index.js.map`);
fse.readFileSync(`./${packageContents}/dist/esm/index.d.ts`);
fse.readFileSync(`./${packageContents}/dist/esm/index.d.ts.map`);

listInstalledPackages(packedPackageJson, {
filter: { scope: 'protected', dependencyType: 'dependencies' },
})
.map(({ name, ...protectedPackage }) => ({
shortName: getShortName(name),
name,
...protectedPackage,
}))
.forEach(({ name, shortName }) => {
console.info(
`*** Validating tarball contents for runtime dependency on protected package ${name}. ***`
);
fse.readFileSync(`./${packageContents}/dist/${shortName}/package.json`);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/cjs/index.cjs.js`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/cjs/index.cjs.js.map`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/cjs/index.d.ts`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/cjs/index.d.ts.map`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/esm/index.js`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/esm/index.js.map`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/esm/index.d.ts`
);
fse.readFileSync(
`./${packageContents}/dist/${shortName}/dist/esm/index.d.ts.map`
);
});

// clean up extracted tarball
fse.removeSync(tarballContentsDest);

console.info('*** Success: Package tarball contents are valid. ***');
} catch (error) {
console.error(
'Failure: Validation of package tarball contents failed. Package tarball is invalid.'
);
throw error;
}
}

async function extractPackageTarball(
packageJson: LocalPackageJson,
dest: string
) {
return new Promise((resolve, reject) => {
fs.createReadStream(
`./iot-app-kit-${getShortName(packageJson.name as PackageName)}-${
packageJson.version
}.tgz`
)
.pipe(zlib.createGunzip())
.pipe(
extract(dest)
.on('error', (error) => {
reject(error);
})
.on('finish', () => {
resolve(undefined);
})
);
});
}
40 changes: 38 additions & 2 deletions configuration/vite-config/src/scripts/prepack.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
#!/usr/bin/env -S npx tsx
import fse from 'fs-extra';
import { listRegisteredPackages } from '../packageRegistry';
import { getShortName } from '../package';
import { getShortName, type PackageName } from '../package';
import type { PackageJson } from 'type-fest';
import { validateBuildArtifacts } from '../validation/validateBuildArtifacts';
import { readPackageJson } from '../packageJson';
import { listInstalledPackages } from '../installedPackages';

prepack();

function prepack() {
console.info('*** Starting prepack. ***');
referenceCopiedProtectedPackages();
validateBuildArtifacts();
validatePrepack();
console.info('*** Ending prepack. ***');
}

/**
Expand Down Expand Up @@ -39,4 +48,31 @@ function referenceCopiedProtectedPackages() {
fse.writeJSONSync(packageJsonPath, packageJson, { spaces: 2 });
}

prepack();
function validatePrepack() {
console.info(`*** Starting validating package.json file. ***`);
const packageJson = readPackageJson('./package.json');
const protectedPackagesInstalledAsRuntimeDependencies = listInstalledPackages(
packageJson,
{
filter: { scope: 'protected', dependencyType: 'dependencies' },
}
);

protectedPackagesInstalledAsRuntimeDependencies.forEach((p) => {
if (
packageJson.dependencies?.[p.name] !==
`file:./dist/${getShortName(p.name as PackageName)}`
) {
console.error(
'*** Failure: Local dependency has incorrect version setting. ***'
);
throw new Error(
`[iot-app-kit] Expected local dependency version to use file reference. Found: ${
packageJson.dependencies?.[p.name] ?? 'No version found'
}.`
);
}
});

console.info(`*** Finished validating package.json file. ***`);
}
Loading

0 comments on commit 1d24666

Please sign in to comment.