Skip to content

Commit fd3cfbb

Browse files
devversionAndrewKushnir
authored andcommitted
build: create bazel marco to test for circular dependencies (angular#34774)
Creates a Bazel macro that can be used to test packages for circular dependencies. We face one limitation with Bazel: * Built packages use module imports, and not relative source file paths. This means we need custom resolution. Fortunately, tools like `madge` support custom resolution. Also removes the outdated `check-cycles` gulp task that didn't catch circular dependencies. It seems like the test became broken when we switched the packages-dist output to Bazel. It breaks because the Bazel output doesn't use relative paths, but uses the module imports. This will be handled in the new Bazel macro/rule. PR Close angular#34774
1 parent 0c8d085 commit fd3cfbb

File tree

8 files changed

+591
-250
lines changed

8 files changed

+591
-250
lines changed

.circleci/config.yml

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -682,16 +682,6 @@ jobs:
682682
- run: yarn karma start ./karma-js.conf.js --single-run --browsers=${KARMA_JS_BROWSERS}
683683
- run: ./scripts/saucelabs/stop-tunnel.sh
684684

685-
legacy-misc-tests:
686-
executor: default-executor
687-
steps:
688-
- custom_attach_workspace
689-
- init_environment
690-
- run: yarn gulp check-cycle
691-
# TODO: disabled because the Bazel packages-dist does not seem to have map files for
692-
# the ESM5/ES2015 output. See: https://github.com/angular/angular/issues/27966
693-
# - run: yarn gulp source-map-test
694-
695685
# Job to run unit tests from angular/components. Needs a browser since all
696686
# component unit tests assume they're running in the browser environment.
697687
material-unit-tests:
@@ -802,9 +792,6 @@ workflows:
802792
- build-ivy-npm-packages:
803793
requires:
804794
- setup
805-
- legacy-misc-tests:
806-
requires:
807-
- build-npm-packages
808795
- legacy-unit-tests-saucelabs:
809796
requires:
810797
- setup
@@ -879,7 +866,6 @@ workflows:
879866
- build-npm-packages
880867
- build-ivy-npm-packages
881868
- legacy-unit-tests-saucelabs
882-
- legacy-misc-tests
883869
- material-unit-tests:
884870
requires:
885871
- build-npm-packages

gulpfile.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,6 @@ gulp.task('tslint', ['tools:build'], loadTask('lint'));
5050
gulp.task('validate-commit-messages', loadTask('validate-commit-message'));
5151
gulp.task('source-map-test', loadTask('source-map-test'));
5252
gulp.task('tools:build', loadTask('tools-build'));
53-
gulp.task('check-cycle', loadTask('check-cycle'));
5453
gulp.task('changelog', loadTask('changelog'));
5554
gulp.task('changelog:zonejs', loadTask('changelog-zonejs'));
5655
gulp.task('check-env', () => {/* this is a noop because the env test ran already above */});

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@
158158
"jpm": "1.3.1",
159159
"karma-browserstack-launcher": "^1.3.0",
160160
"karma-sauce-launcher": "^2.0.2",
161-
"madge": "0.5.0",
161+
"madge": "^3.6.0",
162162
"mutation-observer": "^1.0.3",
163163
"rewire": "2.5.2",
164164
"sauce-connect": "https://saucelabs.com/downloads/sc-4.5.1-linux.tar.gz",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports_files(["madge-resolve.config.js"])
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Copyright Google Inc. All Rights Reserved.
2+
#
3+
# Use of this source code is governed by an MIT-style license that can be
4+
# found in the LICENSE file at https://angular.io/license
5+
6+
load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_test")
7+
8+
MADGE_CONFIG_LABEL = "//tools/circular_dependency_test:madge-resolve.config.js"
9+
10+
"""
11+
Creates a test target that ensures that no circular dependencies can
12+
be found in the given entry point file.
13+
"""
14+
15+
def circular_dependency_test(name, deps, entry_point, **kwargs):
16+
nodejs_test(
17+
name = name,
18+
data = ["@npm//madge", MADGE_CONFIG_LABEL] + deps,
19+
entry_point = "@npm//:node_modules/madge/bin/cli.js",
20+
templated_args = [
21+
"--circular",
22+
"--no-spinner",
23+
# NOTE: We cannot use `$(location)` to resolve labels. This is because `ts_library`
24+
# does not pre-declare outputs in the rule. Hence, the outputs cannot be referenced
25+
# through labels (i.e. `//packages/core:index.js`). Read more here:
26+
# https://docs.bazel.build/versions/2.0.0/skylark/rules.html#outputs
27+
# TODO: revisit once https://github.com/bazelbuild/rules_nodejs/issues/1563 is solved.
28+
"$(rlocation %s)" % entry_point,
29+
# Madge supports custom module resolution, but expects a configuration file
30+
# similar to a Webpack configuration file setting the `resolve` option.
31+
"--webpack-config",
32+
"$(rlocation $(location %s))" % MADGE_CONFIG_LABEL,
33+
],
34+
testonly = 1,
35+
expected_exit_code = 0,
36+
**kwargs
37+
)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @license
3+
* Copyright Google Inc. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* Custom resolution plugin for Webpack's `resolve-enhanced` package that is used by
11+
* Madge for resolving imports. The plugin extends the resolution by leveraging the
12+
* runfile resolution and module mappings handled in the module info aspect.
13+
*/
14+
class BazelRunfileResolutionPlugin {
15+
apply(resolver) {
16+
resolver.plugin('module', (request, callback) => {
17+
try {
18+
// Resolve the module through the `require.resolve` method which has been patched
19+
// in the Bazel NodeJS loader to respect runfiles and module mappings. This allows
20+
// Madge to handle module mappings specified in `ts_library` and `ng_module` targets.
21+
const resolvedPath = require.resolve(request.request);
22+
// Update the request to refer to the runfile resolved file path.
23+
resolver.doResolve('resolve', {...request, request: resolvedPath}, null, callback, true);
24+
return;
25+
} catch {
26+
}
27+
// If the file could not be resolved through Bazel's runfile resolution, proceed
28+
// with the default module resolvers.
29+
callback();
30+
});
31+
}
32+
}
33+
34+
// Configures a plugin which ensures that Madge can properly resolve specified
35+
// dependencies through their configured module names.
36+
module.exports = {
37+
resolve: {plugins: [new BazelRunfileResolutionPlugin()]}
38+
};

tools/gulp-tasks/check-cycle.js

Lines changed: 0 additions & 28 deletions
This file was deleted.

0 commit comments

Comments
 (0)