Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes an issue where bazel could not create runfiles on windows. #1579

Merged
merged 1 commit into from
Sep 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 7 additions & 1 deletion .bazelrc
Expand Up @@ -66,6 +66,13 @@ build:debug --compilation_mode=dbg
# Turn off legacy external runfiles
# This prevents accidentally depending on this feature, which Bazel will remove.
build --nolegacy_external_runfiles
run --nolegacy_external_runfiles
test --nolegacy_external_runfiles

# Do not build runfile forests by default. If an execution strategy relies on runfile
# forests, the forest is created on-demand. See: https://github.com/bazelbuild/bazel/issues/6627
# and https://github.com/bazelbuild/bazel/commit/03246077f948f2790a83520e7dccc2625650e6df
build --nobuild_runfile_links


# Turn on --incompatible_strict_action_env which was on by default
Expand Down Expand Up @@ -116,7 +123,6 @@ test --spawn_strategy=local

build --experimental_inprocess_symlink_creation


# ------------------------------------------------------------------------------------------------
# Possible overrides
# ------------------------------------------------------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions .circleci/config.yml
Expand Up @@ -448,7 +448,7 @@ jobs:
# - static codeanalysis of the style files
bazel_stylelint:
executor: bazel
resource_class: large
resource_class: xlarge
steps:
- setup_bazel_ci
- run_bazel_stylelint
Expand All @@ -472,7 +472,7 @@ jobs:
# - build all targets with bazel
bazel_build:
executor: bazel
resource_class: large
resource_class: xlarge
steps:
- setup_bazel_ci
- run_bazel_build
Expand Down
9 changes: 6 additions & 3 deletions WORKSPACE
Expand Up @@ -27,6 +27,7 @@ http_archive(
url = "https://github.com/bazelbuild/rules_nodejs/releases/download/%s/rules_nodejs-%s.tar.gz" % (RULES_NODEJS_VERSION, RULES_NODEJS_VERSION),
patches = [
"//:rules_nodejs-npm-install+2.0.3.patch",
"//:rules_nodejs-launcher+2.0.3.patch",
]
)

Expand Down Expand Up @@ -54,21 +55,23 @@ npm_install(
data = [
"//:patches/@angular+bazel+10.0.6.patch",
"//:patches/@bazel+typescript+2.0.3.patch",
"//:patches/jest-haste-map+26.1.0.patch",
"//:patches/stylelint+13.2.1.patch",
"//:postinstall.js",
"//:view-engine-tsconfig.json"
],
package_json = "//:package.json",
package_lock_json = "//:package-lock.json",
quiet = False,
quiet = True,
symlink_node_modules = True,
)

# Install the @angular/bazel package into @npm_angular_bazel
# Note, this will probably break in a future rules_nodejs release.
# It causes all builds to fetch npm packages even if not needed (eg. only building go code)
load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")
# load("@npm//:install_bazel_dependencies.bzl", "install_bazel_dependencies")

install_bazel_dependencies(suppress_warning = True)
# install_bazel_dependencies(suppress_warning = True)

# Setup the rules_sass toolchain
load("@io_bazel_rules_sass//sass:sass_repositories.bzl", "sass_repositories")
Expand Down
17 changes: 14 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -44,7 +44,7 @@
"copy-generated-tokens": "node tools/shell-helpers/copy-folder.js $(bazelisk info bazel-genfiles)/libs/shared/design-tokens/build libs/shared/design-tokens/generated",
"bazel": "bazelisk",
"bazel:test": "bazelisk query \"attr(generator_function, jest, //...)\" | xargs bazelisk test",
"bazel:stylelint": "bazelisk query \"attr(generator_function, stylelint, //...)\" | xargs bazelisk test",
"bazel:stylelint": "node tools/scripts/stylelint.js",
"linting:test": "npx tslint --rules-dir dist/libs/components/tslint/src/rules --test libs/tools/linting/src/test/**/tslint.json"
},
"author": "Dynatrace",
Expand Down Expand Up @@ -173,6 +173,7 @@
"sass-graph": "^3.0.5",
"sass-loader": "^8.0.2",
"semver": "^7.3.2",
"shelljs": "^0.8.4",
"stylelint": "^13.2.1",
"stylelint-checkstyle-formatter": "^0.1.2",
"stylelint-config-prettier": "^8.0.2",
Expand Down
16 changes: 16 additions & 0 deletions patches/jest-haste-map+26.1.0.patch
@@ -0,0 +1,16 @@
diff --git a/node_modules/jest-haste-map/build/crawlers/node.js b/node_modules/jest-haste-map/build/crawlers/node.js
index 6b6e11a..2ff08fa 100644
--- a/node_modules/jest-haste-map/build/crawlers/node.js
+++ b/node_modules/jest-haste-map/build/crawlers/node.js
@@ -205,7 +205,11 @@ function find(roots, extensions, ignore, callback) {

function findNative(roots, extensions, ignore, callback) {
const args = Array.from(roots);
lukasholzer marked this conversation as resolved.
Show resolved Hide resolved
+ args.push('(');
args.push('-type', 'f');
+ args.push('-o');
+ args.push('-type', 'l');
+ args.push(')');

if (extensions.length) {
args.push('(');
16 changes: 16 additions & 0 deletions patches/stylelint+13.2.1.patch
@@ -0,0 +1,16 @@
diff --git a/node_modules/stylelint/lib/standalone.js b/node_modules/stylelint/lib/standalone.js
index 630af7e..dbf55e7 100644
--- a/node_modules/stylelint/lib/standalone.js
+++ b/node_modules/stylelint/lib/standalone.js
@@ -198,9 +198,9 @@ module.exports = function(options) {
fileCache = new FileCache(cacheLocation);
// Remove cache file if cache option is disabled
fileCache.destroy();
- }
+ }

- return globby(fileList, globbyOptions)
+ return Promise.resolve(fileList)
.then((filePaths) => {
// The ignorer filter needs to check paths relative to cwd
filePaths = filterFilePaths(
10 changes: 6 additions & 4 deletions postinstall.js
Expand Up @@ -8,8 +8,10 @@ const { writeFileSync, readFileSync } = require('fs');

const MAIN_FIELD_NAME = 'main';
const NGCC_MAIN_FIELD_NAME = 'main_ivy_ngcc';
const NGCC_BINARY = resolve('./node_modules/.bin/ngcc');
const NGC_BINARY = resolve('./node_modules/.bin/ngc');
const NGCC_BINARY = resolve(
'./node_modules/@angular/compiler-cli/ngcc/main-ngcc.js',
);
const NGC_BINARY = resolve('./node_modules/@angular/compiler-cli/src/main.js');

async function main() {
// Applying all the patches to the packages
Expand All @@ -20,10 +22,10 @@ async function main() {

// Generate Angular ngfactory.js, ngsummary.js files for the dependencies,
// that are needed for ViewEngine
await execCommand(`${NGC_BINARY} -p view-engine-tsconfig.json`);
await execCommand(`node ${NGC_BINARY} -p view-engine-tsconfig.json`);
// Generate Ivy entry points
await execCommand(
`${NGCC_BINARY} --properties es2015 browser module main --first-only --create-ivy-entry-points`,
`node ${NGCC_BINARY} --properties es2015 browser module main --first-only --create-ivy-entry-points`,
);
// link the ivy entry points
updateNgccMainFields();
Expand Down
23 changes: 23 additions & 0 deletions rules_nodejs-launcher+2.0.3.patch
@@ -0,0 +1,23 @@
diff --git internal/node/launcher.sh internal/node/launcher.sh
index e685da73..ba38076e 100644
--- internal/node/launcher.sh
+++ internal/node/launcher.sh
@@ -148,14 +148,16 @@ fi

# Export the location of the runfiles helpers script
export BAZEL_NODE_RUNFILES_HELPER=$(rlocation "TEMPLATED_runfiles_helper_script")
-if [[ "${BAZEL_NODE_RUNFILES_HELPER}" != /* ]] && [[ ! "${BAZEL_NODE_RUNFILES_HELPER}" =~ ^[A-Z]:[\\/] ]]; then
+# Paths can be with lower and upper case on windows because of the msys64 package in the powershell
+if [[ "${BAZEL_NODE_RUNFILES_HELPER}" != /* ]] && [[ ! "${BAZEL_NODE_RUNFILES_HELPER}" =~ ^[A-Za-z]:[\/\\] ]]; then
export BAZEL_NODE_RUNFILES_HELPER=$(pwd)/${BAZEL_NODE_RUNFILES_HELPER}
fi

# Export the location of the require patch script as it can be used to bootstrap
# node require patch if needed
export BAZEL_NODE_PATCH_REQUIRE=$(rlocation "TEMPLATED_require_patch_script")
-if [[ "${BAZEL_NODE_PATCH_REQUIRE}" != /* ]] && [[ ! "${BAZEL_NODE_PATCH_REQUIRE}" =~ ^[A-Z]:[\\/] ]]; then
+# Paths can be with lower and upper case on windows because of the msys64 package in the powershell
+if [[ "${BAZEL_NODE_PATCH_REQUIRE}" != /* ]] && [[ ! "${BAZEL_NODE_PATCH_REQUIRE}" =~ ^[A-Za-z]:[\/\\] ]]; then
export BAZEL_NODE_PATCH_REQUIRE=$(pwd)/${BAZEL_NODE_PATCH_REQUIRE}
fi

9 changes: 7 additions & 2 deletions tools/bazel_rules/jest/jest-resolver.js
@@ -1,9 +1,14 @@
const { sync } = require('resolve');
const { readFileSync, existsSync, lstatSync } = require('fs');
const { resolve } = require('path');
const { resolve, join } = require('path');

// Get the module mappings out of the module mappings file from bazel
const moduleMappingFile = process.env.BAZEL_TEST_MODULE_MAPPING;
const [bazelPackage, bazelTarget] = process.env.BAZEL_TARGET.split(':');
const moduleMappingFile = join(
bazelPackage.replace('//', ''),
`_${bazelTarget}.module_mappings.json`,
);

// bazel run files helper used to resolve paths that are created with `$(location ...)`
const runFilesHelper = require(`${process.env.BAZEL_NODE_RUNFILES_HELPER}`);

Expand Down
50 changes: 25 additions & 25 deletions tools/bazel_rules/jest/jest-runner.js
Expand Up @@ -5,6 +5,8 @@ const { argv } = require('yargs');

// Path of the test.sh binary that gets created from the nodejs_test
const { TEST_BINARY } = process.env;
// Bazels node runfiles helper
const RUNFILES_HELPER = require(process.env.BAZEL_NODE_RUNFILES_HELPER);

/**
* Updates the jest config json with additional properties
Expand Down Expand Up @@ -48,35 +50,33 @@ function updateJestConfig(suiteName, config = undefined) {
async function main() {
const { jestConfig, setupFile, files, suite } = argv;
const jestConfigPath = updateJestConfig(suite, jestConfig);
const base = dirname(jestConfigPath);

process.env.BAZEL_TEST_MODULE_MAPPING = join(
dirname(TEST_BINARY),
`_${suite}.module_mappings.json`,
);

const resolvedFiles = files
.split(',')
.map((source) => join(base, source).replace(/ts$/, 'js'));

const cliArgs = {
/**
* This is a hack to avoid using the jest-haste-map fs that does not support symbolic links
* https://github.com/facebook/metro/issues/1#issuecomment-641633646
*/
_: resolvedFiles,
runTestsByPath: true,
verbose: true,
resolver: resolve('tools/bazel_rules/jest/jest-resolver.js'),
rootDir: resolve('./'),
colors: false,
};
.map((source) =>
join(RUNFILES_HELPER.package, source).replace(/ts$/, 'js'),
);

if (setupFile) {
cliArgs.setupFilesAfterEnv = [resolve(setupFile).replace(/ts$/, 'js')];
}

const { results } = await runCLI(cliArgs, [jestConfigPath]);
const { results } = await runCLI(
{
/**
* This is a hack to avoid using the jest-haste-map fs that does not support symbolic links
* https://github.com/facebook/metro/issues/1#issuecomment-641633646
*/
_: resolvedFiles,
setupFilesAfterEnv: setupFile
? [resolve(setupFile).replace(/ts$/, 'js')]
: [],
runTestsByPath: true,
verbose: true,
expand: true,
cache: false,
resolver: resolve('tools/bazel_rules/jest/jest-resolver.js'),
rootDir: resolve('./'),
colors: true,
},
[jestConfigPath],
);

if (!results.success) {
throw new Error(`Failed executing jest tests`);
Expand Down
7 changes: 2 additions & 5 deletions tools/bazel_rules/stylelint/junit-formatter/parse-suite.ts
Expand Up @@ -15,15 +15,12 @@
*/

import { LintResult, Warning } from 'stylelint';
import { relative, join } from 'path';
import { relative } from 'path';
import { ParsedSuite, ParsedCase } from './parsed-suite.interface';

// bazel run files helper used to resolve paths that are created with `$(location ...)`
const { dir, workspace } = require(`${process.env.BAZEL_NODE_RUNFILES_HELPER}`);

/** Creates an object that can be used to create an XML out of the provided lint result */
export function parseSuite(testSuite: LintResult): ParsedSuite {
const name = relative(join(dir, workspace), testSuite.source);
const name = relative(process.cwd(), testSuite.source);
const failuresCount = testSuite.warnings.length;
const testCases = testSuite.errored
? testSuite.warnings.map((testCase: Warning) =>
Expand Down
27 changes: 19 additions & 8 deletions tools/bazel_rules/stylelint/run-stylelint.ts
Expand Up @@ -16,17 +16,15 @@
import { lint, LinterResult } from 'stylelint';
import { junitFormatter, createXML } from './junit-formatter';
import { writeFileSync } from 'fs';
import { resolve, relative } from 'path';
import { options } from 'yargs';

const { BAZEL_NODE_RUNFILES_HELPER, XML_OUTPUT_FILE } = process.env;
const { XML_OUTPUT_FILE } = process.env;

if (!BAZEL_NODE_RUNFILES_HELPER || !XML_OUTPUT_FILE) {
if (!XML_OUTPUT_FILE) {
throw new Error('Bazel environment variables are not set!');
}

// bazel run files helper used to resolve paths that are created with `$(location ...)`
const runFilesHelper = require(BAZEL_NODE_RUNFILES_HELPER);

const { files, allowEmpty, config } = options({
files: { type: 'array', default: [] },
config: { type: 'string', demandOption: true },
Expand All @@ -44,16 +42,29 @@ async function main(): Promise<void> {
};
} else {
lintingOutcome = await lint({
configFile: runFilesHelper.resolve(config),
files: files.map((f) => runFilesHelper.resolve(f)),
configFile: resolve(config),
files: files.map((f) => resolve(f)),
disableDefaultIgnores: true,
formatter: junitFormatter,
});
}

writeFileSync(XML_OUTPUT_FILE as string, lintingOutcome.output);

const lintResult = lintingOutcome.results.map((suite) => {
const file = relative(process.cwd(), suite.source);
const warnings = suite.warnings.map((c) => `L${c.line}: ${c.text}`);
const icon = suite.errored ? '\u2705' : '\u274C';

return `
${icon} ${file} ${warnings.length ? '\n\n' + warnings.join('\n') : ''}`;
});

if (lintingOutcome.errored) {
throw new Error('Lint errors found in the listed files.');
throw new Error(`Lint errors found in the listed files:

${lintResult}
`);
}
}

Expand Down
4 changes: 2 additions & 2 deletions tools/bazel_rules/stylelint/stylelint_macro.bzl
Expand Up @@ -18,15 +18,15 @@ def stylelint_macro(
**kwargs: remaining args to pass to the stylelint_test rule
"""

args = ["--files=\"$(location %s)\"" % s for s in srcs]
args = ["--files=\"$(rootpath %s)\"" % s for s in srcs]

if config:
srcs.append(config)
else:
config = "//:.stylelintrc"

# append the config file
args.append("--config $(location %s)" % config)
args.append("--config $(rootpath %s)" % config)

# # If no tests are matching the glob the process wont exit if set
if allow_empty_input:
Expand Down
5 changes: 5 additions & 0 deletions tools/scripts/README.md
@@ -0,0 +1,5 @@
# What is the purpose of those scripts

This folder contains scripts to execute commands platform independently. As
node.js is working on Windows, Linux and macOs it is better than having shell
scripts for each language. This should simplify invoking bazel commands.