Skip to content

Commit

Permalink
ci(bazel): Fixes an issue where bazel could not create runfiles on wi…
Browse files Browse the repository at this point in the history
…ndows.

This issue is due to som legacy runfiles linking where a manifest file was expected where it was not on windows.
  • Loading branch information
Lukas Holzer committed Sep 23, 2020
1 parent f035263 commit cfcf850
Show file tree
Hide file tree
Showing 16 changed files with 234 additions and 52 deletions.
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
5 changes: 4 additions & 1 deletion 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,12 +55,14 @@ 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,
)

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 @@ -172,6 +172,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);
+ 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(
8 changes: 4 additions & 4 deletions postinstall.js
Expand Up @@ -8,8 +8,8 @@ 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 +20,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.
19 changes: 19 additions & 0 deletions tools/scripts/stylelint.js
@@ -0,0 +1,19 @@
#!/usr/bin/env node
const shelljs = require('shelljs');
const { join } = require('path');
const { bazelQuery, bazelTest } = require('./utils/execute-bazel');

// The workspace root
const PROJECT_DIR = join(__dirname, '../../');

// ShellJS should exit if any command fails.
shelljs.set('-e');
shelljs.cd(PROJECT_DIR);

const targets = bazelQuery('attr(generator_function, stylelint, //...)');

console.log(`
[ Running Stylelint on ${targets.length} Targets] =>
`);

bazelTest(targets, [], { silent: false });

0 comments on commit cfcf850

Please sign in to comment.