Skip to content

Commit

Permalink
build(bazel): create AIO example playgrounds for manual testing
Browse files Browse the repository at this point in the history
After the bazel migration, AIO examples are no longer fully formed in
the source tree.
  • Loading branch information
kormide authored and josephperrott committed Nov 22, 2022
1 parent 2dd8235 commit f37dd0f
Show file tree
Hide file tree
Showing 26 changed files with 393 additions and 164 deletions.
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions aio/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ testem.log
# e2e
protractor-results*.txt

# Example playground
content/example-playground

# System files
.DS_Store
Thumbs.db
2 changes: 2 additions & 0 deletions aio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions aio/content/examples/examples.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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)",
Expand Down
1 change: 1 addition & 0 deletions aio/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
45 changes: 44 additions & 1 deletion aio/tools/examples/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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 changes: 10 additions & 0 deletions aio/tools/examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
43 changes: 43 additions & 0 deletions aio/tools/examples/create-example-playground-wrapper.mjs
Original file line number Diff line number Diff line change
@@ -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(' '));
66 changes: 66 additions & 0 deletions aio/tools/examples/create-example-playground.mjs
Original file line number Diff line number Diff line change
@@ -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)))();
Loading

0 comments on commit f37dd0f

Please sign in to comment.