build(bazel): create AIO example playgrounds for manual testing

After the bazel migration, AIO examples are no longer fully formed in
the source tree.
This commit is contained in:
Derek Cormier
2022-09-29 11:24:32 -07:00
committed by Joey Perrott
parent 2dd8235d5e
commit f37dd0fc96
26 changed files with 393 additions and 164 deletions
+1
View File
@@ -6,6 +6,7 @@
node_modules
dist
aio/node_modules
aio/content/example-playground
aio/tools/examples/shared/node_modules
aio/tools/examples/shared/example-scaffold
packages/bazel/node_modules
+3
View File
@@ -42,6 +42,9 @@ testem.log
# e2e
protractor-results*.txt
# Example playground
content/example-playground
# System files
.DS_Store
Thumbs.db
+2
View File
@@ -30,6 +30,8 @@ Here are the most important tasks you might need to use:
* `yarn docs-lint` - check that the doc gen code follows our style rules.
* `yarn create-example` - create a new example directory containing initial source files.
* `yarn example-playground <exampleName>` - set up a playground to manually test an example combined with its boilerplate files
- `--local` - link locally build Angular packages as deps
* `yarn example-e2e` - run all e2e tests for examples. Available options:
- `--local`: run e2e tests against locally built Angular packages.
+2 -2
View File
@@ -182,7 +182,7 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}):
# Local package deps are passed as args to the test script in the form "@package/name#path/to/package"
# for the script's convenience.
LOCAL_PACKAGE_ARGS = ["%s#$(rootpath %s)" % (dep, to_package_label(dep)) for dep in AIO_EXAMPLE_PACKAGES]
LOCAL_PACKAGE_ARGS = ["--localPackage=%s#$(rootpath %s)" % (dep, to_package_label(dep)) for dep in AIO_EXAMPLE_PACKAGES]
nodejs_test(
name = "e2e",
@@ -206,7 +206,7 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}):
"//conditions:default": [],
}),
configuration_env_vars = ["NG_BUILD_CACHE"],
entry_point = "//aio/tools/examples:run-example-e2e",
entry_point = "//aio/tools/examples:run-example-e2e.mjs",
env = {
"CHROME_BIN": "$(CHROMIUM)",
"CHROMEDRIVER_BIN": "$(CHROMEDRIVER)",
+1
View File
@@ -33,6 +33,7 @@
"example-e2e": "node --experimental-import-meta-resolve tools/examples/run-filtered-example-e2es.mjs",
"example-list-overrides": "bazel run //aio/tools/examples:example-boilerplate list-overrides",
"example-lint": "eslint content/examples",
"example-playground": "node ./tools/examples/create-example-playground-wrapper.mjs",
"deploy-production": "bazel run //aio/scripts/deploy-to-firebase",
"check-env": "yarn ~~check-env",
"payload-size": "scripts/payload.sh",
+44 -1
View File
@@ -1,9 +1,15 @@
load("//tools:defaults.bzl", "nodejs_binary")
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
load("@aio_npm//@bazel/jasmine:index.bzl", "jasmine_node_test")
load("//aio/content/examples:examples.bzl", "EXAMPLES")
load("//:packages.bzl", "AIO_EXAMPLE_PACKAGES", "to_package_label")
package(default_visibility = ["//visibility:public"])
exports_files([
"run-example-e2e.mjs",
])
EXAMPLE_BOILERPLATE_SRCS = [
"example-boilerplate.js",
"constants.js",
@@ -58,15 +64,25 @@ jasmine_node_test(
CREATE_EXAMPLE_SRCS + CREATE_EXAMPLE_DEPS,
)
js_library(
name = "example-sandbox",
srcs = ["example-sandbox.mjs"],
deps = [
"@aio_npm//cjson",
"@aio_npm//fs-extra",
"@aio_npm//globby",
],
)
js_library(
name = "run-example-e2e",
srcs = [
"run-example-e2e.mjs",
],
deps = [
":example-sandbox",
"@aio_npm//@bazel/runfiles",
"@aio_npm//canonical-path",
"@aio_npm//cjson",
"@aio_npm//cross-spawn",
"@aio_npm//fs-extra",
"@aio_npm//get-port",
@@ -76,3 +92,30 @@ js_library(
"@aio_npm//yargs",
],
)
EXAMPLES_WITH_BOILERPLATE = ["//aio/content/examples/%s" % example for example in EXAMPLES]
LOCAL_PACKAGE_DEPS = [to_package_label(dep) for dep in AIO_EXAMPLE_PACKAGES]
LOCAL_PACKAGE_ARGS = ["--localPackage=%s#$(rootpath %s)" % (
dep,
to_package_label(dep),
) for dep in AIO_EXAMPLE_PACKAGES]
nodejs_binary(
name = "create-example-playground",
args = select({
# Hardcode package names/paths in args
"//aio:aio_local_deps": LOCAL_PACKAGE_ARGS,
"//conditions:default": [],
}),
data = [
":example-sandbox",
"@aio_example_deps//:node_modules_files",
"@aio_npm//yargs",
] + EXAMPLES_WITH_BOILERPLATE + select({
"//aio:aio_local_deps": LOCAL_PACKAGE_DEPS,
"//conditions:default": [],
}),
entry_point = "create-example-playground.mjs",
)
+10
View File
@@ -140,6 +140,16 @@ By default the script will place basic scaffold files into the new example (from
But you can also specify the path to a separate CLI project, from which the script will copy files that would not be considered "boilerplate".
See the [Boilerplate overview](#boilerplate-overview) for more information.
### `create-example-playground.mjs`
The [create-example-playground.mjs](./create-example-playground.mjs) script combines example sources, boilerplate, and shared node_modules deps into git-ignored playground directory `content/example-playground/{{EXAMPLE}}` that can be used for manual testing. This should be invoked via the yarn script:
```bash
yarn example-playground <exampleName> [--local]
```
The `--local` flag links in locally-built angular packages as dependencies.
### Updating example dependencies
With every major Angular release, we update the examples to be on the latest version.
@@ -0,0 +1,43 @@
import shelljs from 'shelljs';
import yargs from 'yargs'
import {hideBin} from 'yargs/helpers';
import {getNativeBinary as getNativeBazelBinary} from '@bazel/bazelisk';
shelljs.set('-e')
shelljs.set('-v')
/**
* Create an example playground with shared example deps and optionally linked local
* angular packages in the source tree under content/examples/example-playground. This
* is a wrapper around the equivalent bazel binary but adds the --local option to link
* local packages.
*
* Usage: node ./tools/examples/create-example-playground-wrapper.mjs <example> [options]
*
* Args:
* example: name of the example
*
* Flags:
* --local: use locally built angular packages
*/
const options = yargs(hideBin(process.argv))
.command('$0 <example>', 'Set up a playground for <example> in the source tree for manual testing')
.option('local', {default: false, type: 'boolean'})
.version(false)
.strict()
.argv;
const cmd = [
getNativeBazelBinary(),
'run',
'//aio/tools/examples:create-example-playground',
'--',
`--example=${options.example}`,
];
if (options.local) {
cmd.splice(2, 0, '--config=aio_local_deps');
}
shelljs.exec(cmd.join(' '));
@@ -0,0 +1,66 @@
import path from 'node:path';
import yargs from 'yargs';
import {hideBin} from 'yargs/helpers'
import {constructExampleSandbox} from './example-sandbox.mjs';
if (!process.env.BUILD_WORKSPACE_DIRECTORY) {
console.error(
'Not running script as part of `bazel run`.'
)
process.exit(1);
}
const sourceRoot = process.env.BUILD_WORKSPACE_DIRECTORY;
const runfilesRoot = path.join(process.env.RUNFILES, 'angular');
const playgroundRoot = path.join(sourceRoot, 'aio', 'content', 'example-playground');
/**
* Create an example playground with shared example deps and optionally linked local
* angular packages in the source tree under content/examples/example-playground. This
* script is intended to only be run under bazel as it has the localPackage arguments
* hardcoded into the binary via starlark.
*
* Usage: bazel run //aio/tools/examples:create-example-playground -- --example=<example>
*
* Args:
* example: name of the example
*/
async function main(args) {
const options =
yargs(args)
// Note: localPackage not listed above in usage as it's hardcoded in by the nodejs_binary
.option('localPackage', {
array: true,
type: 'string',
default: [],
describe: 'Locally built package to substitute, in the form `packageName#packagePath`'
})
.option('example', {
type: 'string',
describe: 'Name of the example'
})
.demandOption('example')
.strict()
.version(false)
.argv;
const localPackages = options.localPackage.reduce((pkgs, pkgNameAndPath) => {
const [pkgName, pkgPath] = pkgNameAndPath.split('#');
pkgs[pkgName] = path.resolve(pkgPath);
return pkgs;
}, {});
const exampleName = options.example;
// Note: the example sources plus boilerplate are merged into a target named after the example
const fullExamplePath = path.join(runfilesRoot, 'aio', 'content', 'examples', exampleName, exampleName);
const destPath = path.join(playgroundRoot, exampleName);
const nodeModules = path.join(runfilesRoot, '..', 'aio_example_deps', 'node_modules');
await constructExampleSandbox(fullExamplePath, destPath, nodeModules, localPackages);
console.log(`A playground folder for ${exampleName} has been set up at\n\n ${destPath}\n`);
}
(async () => await main(hideBin(process.argv)))();
+172
View File
@@ -0,0 +1,172 @@
import jsonc from 'cjson';
import fs from 'fs-extra';
import {globbySync} from 'globby';
import path from 'node:path';
import os from 'node:os';
// Construct a sandbox environment for an example, linking in shared example node_modules
// and optionally linking in locally-built angular packages.
export async function constructExampleSandbox(examplePath, destPath, nodeModulesPath, localPackages) {
fs.rmSync(destPath, {
recursive: true,
force: true
});
fs.copySync(examplePath, destPath);
// Remove write protection as the example was copied from bazel output tree
chmodSyncRec(destPath);
// Symlink shared example node_modules, substituting for locally built deps if requested
await constructSymlinkedNodeModules(destPath, nodeModulesPath, localPackages);
// Add preserveSymlinks fixups to various files --- needed when linkin in local deps
preserveSymlinksWhenUsingLocalPackages(localPackages, destPath);
}
async function constructSymlinkedNodeModules(examplePath, exampleDepsNodeModules, localPackages) {
const linkedNodeModules = path.resolve(examplePath, 'node_modules');
fs.ensureDirSync(linkedNodeModules);
await Promise.all([
linkExampleDeps(exampleDepsNodeModules, linkedNodeModules, localPackages),
linkLocalDeps(exampleDepsNodeModules, linkedNodeModules, localPackages)
]);
fs.copySync(path.join(exampleDepsNodeModules, '.bin'), path.join(linkedNodeModules, '.bin'));
pointBinSymlinksToLocalPackages(linkedNodeModules, exampleDepsNodeModules, localPackages);
}
function linkExampleDeps(exampleDepsNodeModules, linkedNodeModules, localPackages) {
const exampleDepsPackages = getPackageNamesFromNodeModules(exampleDepsNodeModules);
return Promise.all(exampleDepsPackages
.filter(pkgName => !(pkgName in localPackages))
.map(pkgName => fs.ensureSymlink(
path.join(exampleDepsNodeModules, pkgName),
path.join(linkedNodeModules, pkgName), 'dir'))
);
}
function getPackageNamesFromNodeModules(nodeModulesPath) {
return globbySync([
'@*/*',
'!@*$', // Exclude a namespace folder itself
'(?!@)*',
'!.bin',
'!.yarn-integrity',
'!_*'
], {
cwd: nodeModulesPath,
onlyDirectories: true,
dot: true
});
}
async function linkLocalDeps(exampleDepsNodeModules, linkedNodeModules, localPackages) {
const hasNpmDepForPkg = await Promise.all(Object.keys(localPackages)
.map(pkgName => fs.pathExists(path.join(exampleDepsNodeModules, pkgName))));
return Promise.all(Object.keys(localPackages).filter((pkgName, i) => hasNpmDepForPkg[i])
.map(pkgName => fs.ensureSymlinkSync(localPackages[pkgName], path.join(linkedNodeModules, pkgName), 'dir')));
}
// The .bin folder is copied over from the original yarn_install repository, so the
// bin symlinks point there. When we link local packages in place of their npm equivalent,
// we need to alter those symlinks to point into the local package.
function pointBinSymlinksToLocalPackages(linkedNodeModules, exampleDepsNodeModules, localPackages) {
if (os.platform() === 'win32') {
// Bins on Windows are not symlinks; they are scripts that will invoke the bin
// relative to their location. The relative path will already point to the symlinked
// local package, so no further action is required.
return;
}
const allNodeModuleBins = globbySync(['**'], {
cwd: path.join(linkedNodeModules, '.bin'),
onlyFiles: true
});
allNodeModuleBins.forEach(bin => {
// TODO: Swapping the symlink to ngc with the local package equivalent
// doesn't seem to work. When ngc runs in upgrade-phonecat-2-hybrid via
// the build:aot yarn script, node cannot resolve @angular/compiler.
if (bin === 'ngc') {
return;
}
const symlinkTarget = fs.readlinkSync(path.join(linkedNodeModules, '.bin', bin));
for (const pkgName of Object.keys(localPackages)) {
const binMightBeInLocalPackage = symlinkTarget.includes(path.join(exampleDepsNodeModules, pkgName) + path
.sep);
if (binMightBeInLocalPackage) {
const pathToBinWithinPackage = symlinkTarget.substring(symlinkTarget.indexOf(pkgName) +
pkgName.length + path.sep.length);
const binExistsInLocalPackage = fs.existsSync(path.join(linkedNodeModules, pkgName,
pathToBinWithinPackage));
if (binExistsInLocalPackage) {
// Replace the copied bin symlink with one that points to the symlinked local package.
fs.rmSync(path.join(linkedNodeModules, '.bin', bin));
fs.ensureSymlinkSync(path.join(
'..',
pkgName,
pathToBinWithinPackage),
path.join(linkedNodeModules, '.bin', bin)
);
}
break;
}
}
});
}
// When local packages are symlinked in, node has trouble resolving some peer deps. Setting
// preserveSymlinks in relevant files fixes this. This isn't required without local packages
// because in the worst case we would leak into the original Bazel repository and it would
// still find a node_modules folder for resolution. Add the preserveSymlinks options to various
// files that are used by the cli and systemjs tests (and sometimes both).
function preserveSymlinksWhenUsingLocalPackages(LOCAL_PACKAGES, appDir) {
if (Object.keys(LOCAL_PACKAGES).length === 0) {
return;
}
// Set preserveSymlinks in angular.json
const angularJsonPath = path.join(appDir, 'angular.json');
if (fs.existsSync(angularJsonPath)) {
const angularJson = jsonc.load(angularJsonPath, {
encoding: 'utf-8'
});
angularJson.projects['angular.io-example'].architect.build.options.preserveSymlinks = true;
fs.writeFileSync(angularJsonPath, JSON.stringify(angularJson, undefined, 2));
}
// Set preserveSymlinks in any tsconfig.json files
const tsConfigPaths = globbySync([path.join(appDir, 'tsconfig*.json')]);
for (const tsConfigPath of tsConfigPaths) {
const tsConfig = jsonc.load(tsConfigPath, {
encoding: 'utf-8'
});
const isRootConfig = !tsConfig.extends;
if (isRootConfig) {
tsConfig.compilerOptions.preserveSymlinks = true;
fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, undefined, 2));
}
}
// Call rollup with --preserveSymlinks
const packageJsonPath = path.join(appDir, 'package.json');
const packageJson = jsonc.load(packageJsonPath, {
encoding: 'utf-8'
});
if ('rollup' in packageJson.dependencies || 'rollup' in packageJson.devDependencies) {
packageJson.scripts.rollup = 'rollup --preserveSymlinks';
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, undefined, 2));
}
}
function chmodSyncRec(dest) {
// Glob patterns always use unix-style paths
const allFilesPattern = path.join(dest, '**').replace(/\\/g, '/');
globbySync(allFilesPattern, {
dot: true,
onlyFiles: false
}).forEach(file => fs.chmodSync(file, '755'));
fs.chmodSync(dest, '755');
}
+22 -140
View File
@@ -2,13 +2,13 @@ import path from 'canonical-path';
import {spawn} from 'cross-spawn';
import fs from 'fs-extra';
import {globbySync} from 'globby';
import jsonc from 'cjson';
import os from 'os';
import shelljs from 'shelljs';
import treeKill from 'tree-kill';
import yargs from 'yargs';
import {hideBin} from 'yargs/helpers'
import getPort from 'get-port';
import {constructExampleSandbox} from "./example-sandbox.mjs";
shelljs.set('-e');
@@ -19,13 +19,17 @@ process.env.CHROME_BIN = adjustChromeBinPathForWindows();
process.env.CHROME_BIN = path.resolve(process.env.CHROME_BIN);
process.env.CHROMEDRIVER_BIN = path.resolve(process.env.CHROMEDRIVER_BIN);
const {argv} = yargs(hideBin(process.argv));
const {argv} = yargs(hideBin(process.argv))
.command("* <examplePath> <yarnPath> <exampleDepsWorkspaceName>")
.option('localPackage', {array: true, type: 'string', default: [], describe: 'Locally built package to substitute, in the form `packageName#packagePath`'})
.version(false)
.strict();
const EXAMPLE_PATH = path.resolve(argv._[0]);
const EXAMPLE_PATH = path.resolve(argv.examplePath);
const NODE = process.execPath;
const VENDORED_YARN = path.resolve(argv._[1]);
const EXAMPLE_DEPS_WORKSPACE_NAME = argv._[2];
const LOCAL_PACKAGES = argv._.slice(3).reduce((pkgs, pkgNameAndPath) => {
const VENDORED_YARN = path.resolve(argv.yarnPath);
const EXAMPLE_DEPS_WORKSPACE_NAME = argv.exampleDepsWorkspaceName;
const LOCAL_PACKAGES = argv.localPackage.reduce((pkgs, pkgNameAndPath) => {
const [pkgName, pkgPath] = pkgNameAndPath.split('#');
pkgs[pkgName] = path.resolve(pkgPath);
return pkgs;
@@ -55,15 +59,17 @@ const MAX_NO_OUTPUT_TIMEOUT = 1000 * 60 * 5; // 5 minutes
async function runE2e(examplePath) {
const exampleName = path.basename(examplePath);
const maxAttempts = argv.retry || 1;
const exampleTestPath = generatePathForExampleTest(exampleName);
try {
examplePath = createCopyOfExampleForTest(exampleName, examplePath);
await constructNodeModules(examplePath);
await constructExampleSandbox(examplePath, exampleTestPath, path.resolve('..', EXAMPLE_DEPS_WORKSPACE_NAME, 'node_modules'), LOCAL_PACKAGES);
let testFn;
if (isSystemJsTest(examplePath)) {
testFn = () => runE2eTestsSystemJS(exampleName, examplePath);
} else if (isCliTest(examplePath)) {
testFn = () => runE2eTestsCLI(exampleName, examplePath);
if (isSystemJsTest(exampleTestPath)) {
testFn = () => runE2eTestsSystemJS(exampleName, exampleTestPath);
} else if (isCliTest(exampleTestPath)) {
testFn = () => runE2eTestsCLI(exampleName, exampleTestPath);
} else {
throw new Error(`Unknown e2e test type for example ${exampleName}`);
}
@@ -73,7 +79,7 @@ async function runE2e(examplePath) {
console.error(e);
process.exitCode = 1;
} finally {
fs.rmSync(examplePath, {recursive: true, force: true});
fs.rmSync(exampleTestPath, {recursive: true, force: true});
}
}
@@ -93,18 +99,13 @@ async function attempt(testFn, maxAttempts) {
}
}
function createCopyOfExampleForTest(exampleName, examplePath) {
function generatePathForExampleTest(exampleName) {
// Note that bazel provides a writeable tmp dir for tests in the env var TEST_TMPDIR,
// however we do not use it here as in non-sandboxed mode the temp dir sits under the
// execroot, so yarn will find the .yarnrc in the root of the workspace. If there is ever
// a version mismatch (e.g., if we use multiple vendored yarn versions) then this could
// cause subtle errors. Instead, just use a temp dir that bazel doesn't know about.
const testPath = fs.mkdtempSync(`${os.tmpdir()}${path.sep}${exampleName}-`)
globbySync(['**'], {cwd: examplePath, dot: true}).forEach(file => {
fs.copySync(path.join(examplePath, file), path.join(testPath, file));
fs.chmodSync(path.join(testPath, file), '755');
});
return testPath;
return fs.mkdtempSync(`${os.tmpdir()}${path.sep}${exampleName}-`)
}
function isSystemJsTest(examplePath) {
@@ -118,8 +119,6 @@ function isCliTest(examplePath) {
async function runE2eTestsSystemJS(exampleName, appDir) {
const config = loadExampleConfig(appDir);
preserveSymlinksWhenUsingLocalPackages(LOCAL_PACKAGES, appDir);
const runArgs = await overrideSystemJsExampleToUseRandomPort(config, appDir);
const appBuildSpawnInfo = spawnExt(NODE, [VENDORED_YARN, config.build], {cwd: appDir});
@@ -220,82 +219,6 @@ function runProtractorAoT(exampleName, appDir) {
return runProtractorSystemJS(exampleName, promise, appDir, aotRunSpawnInfo);
}
async function constructNodeModules(examplePath) {
const linkedNodeModules = path.resolve(examplePath, 'node_modules');
const exampleDepsNodeModules = path.resolve('..', EXAMPLE_DEPS_WORKSPACE_NAME, 'node_modules');
fs.ensureDirSync(linkedNodeModules);
await Promise.all([
linkExampleDeps(exampleDepsNodeModules, linkedNodeModules),
linkLocalDeps(exampleDepsNodeModules, linkedNodeModules)
]);
fs.copySync(path.join(exampleDepsNodeModules, '.bin'), path.join(linkedNodeModules, '.bin'));
pointBinSymlinksToLocalPackages(linkedNodeModules);
}
// The .bin folder is copied over from the original yarn_install repository, so the
// bin symlinks point there. When we link local packages in place of their npm equivalent,
// we need to alter those symlinks to point into the local package.
function pointBinSymlinksToLocalPackages(linkedNodeModules) {
if (os.platform() === 'win32') {
// Bins on Windows are not symlinks; they are scripts that will invoke the bin
// relative to their location. The relative path will already point to the symlinked
// local package, so no further action is required.
return;
}
const allNodeModuleBins = globbySync(['**'], {cwd: path.join(linkedNodeModules, '.bin'), onlyFiles: true});
allNodeModuleBins.forEach(bin => {
// TODO: Swapping the symlink to ngc with the local package equivalent
// doesn't seem to work. When ngc runs in upgrade-phonecat-2-hybrid via
// the build:aot yarn script, node cannot resolve @angular/compiler.
if (bin === "ngc") {
return;
}
const symlinkTarget = fs.readlinkSync(path.join(linkedNodeModules, '.bin', bin));
for (const pkgName of Object.keys(LOCAL_PACKAGES)) {
const binMightBeInLocalPackage = symlinkTarget.includes(path.join(EXAMPLE_DEPS_WORKSPACE_NAME, 'node_modules', pkgName) + path.sep);
if (binMightBeInLocalPackage) {
const pathToBinWithinPackage = symlinkTarget.substring(symlinkTarget.indexOf(pkgName) + pkgName.length + path.sep.length);
const binExistsInLocalPackage = fs.existsSync(path.join(linkedNodeModules, pkgName, pathToBinWithinPackage));
if (binExistsInLocalPackage) {
// Replace the copied bin symlink with one that points to the symlinked local package.
fs.rmSync(path.join(linkedNodeModules, '.bin', bin));
fs.ensureSymlinkSync(path.join('..', pkgName, pathToBinWithinPackage), path.join(linkedNodeModules, '.bin', bin));
}
break;
}
}
});
}
function linkExampleDeps(exampleDepsNodeModules, linkedNodeModules) {
const exampleDepsPackages = getPackageNamesFromNodeModules(exampleDepsNodeModules);
return Promise.all(exampleDepsPackages
.filter(pkgName => !(pkgName in LOCAL_PACKAGES))
.map(pkgName => fs.ensureSymlink(path.join(exampleDepsNodeModules, pkgName), path.join(linkedNodeModules, pkgName), 'dir'))
);
}
async function linkLocalDeps(exampleDepsNodeModules, linkedNodeModules) {
const hasNpmDepForPkg = await Promise.all(Object.keys(LOCAL_PACKAGES).map(pkgName => fs.pathExists(path.join(exampleDepsNodeModules, pkgName))));
return Promise.all(Object.keys(LOCAL_PACKAGES).filter((pkgName, i) => hasNpmDepForPkg[i])
.map(pkgName => fs.ensureSymlinkSync(LOCAL_PACKAGES[pkgName], path.join(linkedNodeModules, pkgName), 'dir')));
}
function getPackageNamesFromNodeModules(nodeModulesPath) {
return globbySync([
'@*/*',
'!@*$', // Exclude a namespace folder itself
'(?!@)*',
'!.bin',
'!.yarn-integrity',
'!_*'
], {cwd: nodeModulesPath, onlyDirectories: true, dot: true});
}
// Start the example in appDir; then run protractor with the specified
// fileName; then shut down the example.
// All protractor output is appended to the outputFile.
@@ -315,8 +238,6 @@ function runE2eTestsCLI(exampleName, appDir) {
}
}
preserveSymlinksWhenUsingLocalPackages(LOCAL_PACKAGES, appDir);
// `--no-webdriver-update` is needed to preserve the ChromeDriver version already installed.
const testCommands = config.tests || [{
cmd: NODE,
@@ -435,43 +356,4 @@ function adjustChromeBinPathForWindows() {
return process.env.CHROME_BIN;
}
// When local packages are symlinked in, node has trouble resolving some peer deps. Setting
// preserveSymlinks in relevant files fixes this. This isn't required without local packages
// because in the worst case we would leak into the original Bazel repository and it would
// still find a node_modules folder for resolution. Add the preserveSymlinks options to various
// files that are used by the cli and systemjs tests (and sometimes both).
function preserveSymlinksWhenUsingLocalPackages(LOCAL_PACKAGES, appDir) {
if (Object.keys(LOCAL_PACKAGES).length == 0) {
return;
}
// Set preserveSymlinks in angular.json
const angularJsonPath = path.join(appDir, 'angular.json');
if (fs.existsSync(angularJsonPath)) {
const angularJson = jsonc.load(angularJsonPath, {encoding: 'utf-8'});
angularJson.projects['angular.io-example'].architect.build.options.preserveSymlinks = true;
fs.writeFileSync(angularJsonPath, JSON.stringify(angularJson, undefined, 2));
}
// Set preserveSymlinks in any tsconfig.json files
const tsConfigPaths = globbySync([path.join(appDir, 'tsconfig*.json')]);
for (let tsConfigPath of tsConfigPaths) {
const tsConfig = jsonc.load(tsConfigPath, {encoding: 'utf-8'});
const isRootConfig = !tsConfig.extends;
if (isRootConfig) {
tsConfig.compilerOptions.preserveSymlinks = true;
fs.writeFileSync(tsConfigPath, JSON.stringify(tsConfig, undefined, 2));
}
}
// Call rollup with --preserveSymlinks
const packageJsonPath = path.join(appDir, 'package.json');
const packageJson = jsonc.load(packageJsonPath, {encoding: 'utf-8'});
if ('rollup' in packageJson.dependencies || 'rollup' in packageJson.devDependencies) {
packageJson.scripts['rollup'] = 'rollup --preserveSymlinks';
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, undefined, 2));
}
}
runE2e(EXAMPLE_PATH);
+2 -2
View File
@@ -29,6 +29,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
"//packages/compiler/test:__pkg__",
@@ -66,6 +67,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+1
View File
@@ -33,6 +33,7 @@ pkg_npm(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
],
deps = [
+2 -2
View File
@@ -48,6 +48,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/bazel/test/ng_package:__pkg__",
"//packages/compiler-cli/integrationtest:__pkg__",
@@ -92,6 +93,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+1
View File
@@ -133,6 +133,7 @@ pkg_npm(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
],
+1
View File
@@ -31,6 +31,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
"//packages/language-service/test:__pkg__",
+3 -1
View File
@@ -62,6 +62,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/bazel/test/ng_package:__pkg__",
"//packages/compiler-cli/integrationtest:__pkg__",
@@ -121,8 +122,9 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
]) + [
"PACKAGE.md",
"global/index.ts",
"global/PACKAGE.md",
]),
],
)
+2 -2
View File
@@ -29,6 +29,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
],
deps = [
@@ -51,6 +52,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -29,6 +29,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
"//packages/compiler-cli/test/diagnostics:__pkg__",
@@ -64,6 +65,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+1
View File
@@ -28,6 +28,7 @@ pkg_npm(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
],
deps = [
@@ -33,6 +33,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
],
@@ -57,6 +58,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -39,6 +39,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
"//packages/compiler-cli/test:__pkg__",
@@ -65,6 +66,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -50,6 +50,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
],
@@ -75,6 +76,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -32,6 +32,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
"//packages/compiler-cli/integrationtest:__pkg__",
"//packages/compiler-cli/test:__pkg__",
@@ -69,6 +70,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -51,6 +51,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
],
deps = [
@@ -74,6 +75,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)
+2 -2
View File
@@ -32,6 +32,7 @@ ng_package(
visibility = [
"//aio:__pkg__",
"//aio/content/examples:__subpackages__",
"//aio/tools/examples:__pkg__",
"//integration:__subpackages__",
],
deps = [
@@ -56,6 +57,5 @@ filegroup(
srcs = glob([
"*.ts",
"src/**/*.ts",
"PACKAGE.md",
]),
]) + ["PACKAGE.md"],
)