Skip to content

Commit 500acfc

Browse files
kormidejosephperrott
authored andcommitted
build(bazel): create AIO example playgrounds for manual testing
After the bazel migration, AIO examples are no longer fully formed in the source tree.
1 parent 8df1dea commit 500acfc

File tree

26 files changed

+393
-164
lines changed

26 files changed

+393
-164
lines changed

.bazelignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
node_modules
77
dist
88
aio/node_modules
9+
aio/content/example-playground
910
aio/tools/examples/shared/node_modules
1011
aio/tools/examples/shared/example-scaffold
1112
packages/bazel/node_modules

aio/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ testem.log
4242
# e2e
4343
protractor-results*.txt
4444

45+
# Example playground
46+
content/example-playground
47+
4548
# System files
4649
.DS_Store
4750
Thumbs.db

aio/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Here are the most important tasks you might need to use:
3030
* `yarn docs-lint` - check that the doc gen code follows our style rules.
3131

3232
* `yarn create-example` - create a new example directory containing initial source files.
33+
* `yarn example-playground <exampleName>` - set up a playground to manually test an example combined with its boilerplate files
34+
- `--local` - link locally build Angular packages as deps
3335

3436
* `yarn example-e2e` - run all e2e tests for examples. Available options:
3537
- `--local`: run e2e tests against locally built Angular packages.

aio/content/examples/examples.bzl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}):
182182

183183
# Local package deps are passed as args to the test script in the form "@package/name#path/to/package"
184184
# for the script's convenience.
185-
LOCAL_PACKAGE_ARGS = ["%s#$(rootpath %s)" % (dep, to_package_label(dep)) for dep in AIO_EXAMPLE_PACKAGES]
185+
LOCAL_PACKAGE_ARGS = ["--localPackage=%s#$(rootpath %s)" % (dep, to_package_label(dep)) for dep in AIO_EXAMPLE_PACKAGES]
186186

187187
nodejs_test(
188188
name = "e2e",
@@ -206,7 +206,7 @@ def docs_example(name, test = True, test_tags = [], test_exec_properties = {}):
206206
"//conditions:default": [],
207207
}),
208208
configuration_env_vars = ["NG_BUILD_CACHE"],
209-
entry_point = "//aio/tools/examples:run-example-e2e",
209+
entry_point = "//aio/tools/examples:run-example-e2e.mjs",
210210
env = {
211211
"CHROME_BIN": "$(CHROMIUM)",
212212
"CHROMEDRIVER_BIN": "$(CHROMEDRIVER)",

aio/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"example-e2e": "node --experimental-import-meta-resolve tools/examples/run-filtered-example-e2es.mjs",
3434
"example-list-overrides": "bazel run //aio/tools/examples:example-boilerplate list-overrides",
3535
"example-lint": "eslint content/examples",
36+
"example-playground": "node ./tools/examples/create-example-playground-wrapper.mjs",
3637
"deploy-production": "bazel run //aio/scripts/deploy-to-firebase",
3738
"check-env": "yarn ~~check-env",
3839
"payload-size": "scripts/payload.sh",

aio/tools/examples/BUILD.bazel

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
load("//tools:defaults.bzl", "nodejs_binary")
22
load("@build_bazel_rules_nodejs//:index.bzl", "js_library")
33
load("@aio_npm//@bazel/jasmine:index.bzl", "jasmine_node_test")
4+
load("//aio/content/examples:examples.bzl", "EXAMPLES")
5+
load("//:packages.bzl", "AIO_EXAMPLE_PACKAGES", "to_package_label")
46

57
package(default_visibility = ["//visibility:public"])
68

9+
exports_files([
10+
"run-example-e2e.mjs",
11+
])
12+
713
EXAMPLE_BOILERPLATE_SRCS = [
814
"example-boilerplate.js",
915
"constants.js",
@@ -58,15 +64,25 @@ jasmine_node_test(
5864
CREATE_EXAMPLE_SRCS + CREATE_EXAMPLE_DEPS,
5965
)
6066

67+
js_library(
68+
name = "example-sandbox",
69+
srcs = ["example-sandbox.mjs"],
70+
deps = [
71+
"@aio_npm//cjson",
72+
"@aio_npm//fs-extra",
73+
"@aio_npm//globby",
74+
],
75+
)
76+
6177
js_library(
6278
name = "run-example-e2e",
6379
srcs = [
6480
"run-example-e2e.mjs",
6581
],
6682
deps = [
83+
":example-sandbox",
6784
"@aio_npm//@bazel/runfiles",
6885
"@aio_npm//canonical-path",
69-
"@aio_npm//cjson",
7086
"@aio_npm//cross-spawn",
7187
"@aio_npm//fs-extra",
7288
"@aio_npm//get-port",
@@ -76,3 +92,30 @@ js_library(
7692
"@aio_npm//yargs",
7793
],
7894
)
95+
96+
EXAMPLES_WITH_BOILERPLATE = ["//aio/content/examples/%s" % example for example in EXAMPLES]
97+
98+
LOCAL_PACKAGE_DEPS = [to_package_label(dep) for dep in AIO_EXAMPLE_PACKAGES]
99+
100+
LOCAL_PACKAGE_ARGS = ["--localPackage=%s#$(rootpath %s)" % (
101+
dep,
102+
to_package_label(dep),
103+
) for dep in AIO_EXAMPLE_PACKAGES]
104+
105+
nodejs_binary(
106+
name = "create-example-playground",
107+
args = select({
108+
# Hardcode package names/paths in args
109+
"//aio:aio_local_deps": LOCAL_PACKAGE_ARGS,
110+
"//conditions:default": [],
111+
}),
112+
data = [
113+
":example-sandbox",
114+
"@aio_example_deps//:node_modules_files",
115+
"@aio_npm//yargs",
116+
] + EXAMPLES_WITH_BOILERPLATE + select({
117+
"//aio:aio_local_deps": LOCAL_PACKAGE_DEPS,
118+
"//conditions:default": [],
119+
}),
120+
entry_point = "create-example-playground.mjs",
121+
)

aio/tools/examples/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,16 @@ By default the script will place basic scaffold files into the new example (from
140140
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".
141141
See the [Boilerplate overview](#boilerplate-overview) for more information.
142142

143+
### `create-example-playground.mjs`
144+
145+
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:
146+
147+
```bash
148+
yarn example-playground <exampleName> [--local]
149+
```
150+
151+
The `--local` flag links in locally-built angular packages as dependencies.
152+
143153
### Updating example dependencies
144154

145155
With every major Angular release, we update the examples to be on the latest version.
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import shelljs from 'shelljs';
2+
import yargs from 'yargs'
3+
import {hideBin} from 'yargs/helpers';
4+
import {getNativeBinary as getNativeBazelBinary} from '@bazel/bazelisk';
5+
6+
shelljs.set('-e')
7+
shelljs.set('-v')
8+
9+
/**
10+
* Create an example playground with shared example deps and optionally linked local
11+
* angular packages in the source tree under content/examples/example-playground. This
12+
* is a wrapper around the equivalent bazel binary but adds the --local option to link
13+
* local packages.
14+
*
15+
* Usage: node ./tools/examples/create-example-playground-wrapper.mjs <example> [options]
16+
*
17+
* Args:
18+
* example: name of the example
19+
*
20+
* Flags:
21+
* --local: use locally built angular packages
22+
*/
23+
24+
const options = yargs(hideBin(process.argv))
25+
.command('$0 <example>', 'Set up a playground for <example> in the source tree for manual testing')
26+
.option('local', {default: false, type: 'boolean'})
27+
.version(false)
28+
.strict()
29+
.argv;
30+
31+
const cmd = [
32+
getNativeBazelBinary(),
33+
'run',
34+
'//aio/tools/examples:create-example-playground',
35+
'--',
36+
`--example=${options.example}`,
37+
];
38+
39+
if (options.local) {
40+
cmd.splice(2, 0, '--config=aio_local_deps');
41+
}
42+
43+
shelljs.exec(cmd.join(' '));
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import path from 'node:path';
2+
import yargs from 'yargs';
3+
import {hideBin} from 'yargs/helpers'
4+
import {constructExampleSandbox} from './example-sandbox.mjs';
5+
6+
if (!process.env.BUILD_WORKSPACE_DIRECTORY) {
7+
console.error(
8+
'Not running script as part of `bazel run`.'
9+
)
10+
process.exit(1);
11+
}
12+
const sourceRoot = process.env.BUILD_WORKSPACE_DIRECTORY;
13+
const runfilesRoot = path.join(process.env.RUNFILES, 'angular');
14+
const playgroundRoot = path.join(sourceRoot, 'aio', 'content', 'example-playground');
15+
16+
/**
17+
* Create an example playground with shared example deps and optionally linked local
18+
* angular packages in the source tree under content/examples/example-playground. This
19+
* script is intended to only be run under bazel as it has the localPackage arguments
20+
* hardcoded into the binary via starlark.
21+
*
22+
* Usage: bazel run //aio/tools/examples:create-example-playground -- --example=<example>
23+
*
24+
* Args:
25+
* example: name of the example
26+
*/
27+
28+
async function main(args) {
29+
const options =
30+
yargs(args)
31+
// Note: localPackage not listed above in usage as it's hardcoded in by the nodejs_binary
32+
.option('localPackage', {
33+
array: true,
34+
type: 'string',
35+
default: [],
36+
describe: 'Locally built package to substitute, in the form `packageName#packagePath`'
37+
})
38+
.option('example', {
39+
type: 'string',
40+
describe: 'Name of the example'
41+
})
42+
.demandOption('example')
43+
.strict()
44+
.version(false)
45+
.argv;
46+
47+
const localPackages = options.localPackage.reduce((pkgs, pkgNameAndPath) => {
48+
const [pkgName, pkgPath] = pkgNameAndPath.split('#');
49+
pkgs[pkgName] = path.resolve(pkgPath);
50+
return pkgs;
51+
}, {});
52+
53+
const exampleName = options.example;
54+
55+
// Note: the example sources plus boilerplate are merged into a target named after the example
56+
const fullExamplePath = path.join(runfilesRoot, 'aio', 'content', 'examples', exampleName, exampleName);
57+
58+
const destPath = path.join(playgroundRoot, exampleName);
59+
const nodeModules = path.join(runfilesRoot, '..', 'aio_example_deps', 'node_modules');
60+
61+
await constructExampleSandbox(fullExamplePath, destPath, nodeModules, localPackages);
62+
63+
console.log(`A playground folder for ${exampleName} has been set up at\n\n ${destPath}\n`);
64+
}
65+
66+
(async () => await main(hideBin(process.argv)))();

0 commit comments

Comments
 (0)