ci: disable bazel in devkit-admin build

Replace the build step with a custom JSON schema output parallel to
bazel.
This commit is contained in:
Hans 2018-09-11 19:03:48 -07:00 committed by Keen Yee Liau
parent 30b0cbda0d
commit c63b4d8d2b
7 changed files with 116 additions and 62 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@
bazel-*
test-project-host-*
dist/
dist-schema/
# IDEs
.idea/

View File

@ -34,7 +34,9 @@ function _mkdirp(p: string) {
if (!fs.existsSync(path.dirname(p))) {
_mkdirp(path.dirname(p));
}
fs.mkdirSync(p);
if (!fs.existsSync(p)) {
fs.mkdirSync(p);
}
}
function _recursiveFileList(p: string): string[] {
@ -186,21 +188,61 @@ function _exec(command: string, args: string[], opts: { cwd?: string }, logger:
function _build(logger: logging.Logger) {
logger.info('Building...');
_exec('node_modules/.bin/tsc', ['-p', 'tsconfig.json'], {}, logger);
_exec('node', [
require.resolve('typescript/bin/tsc'),
'-p',
'tsconfig.json',
], {}, logger);
}
function _bazel(logger: logging.Logger) {
logger.info('Bazel build...');
_exec('bazel', ['build', '//packages/...'], {}, logger);
async function _bazel(logger: logging.Logger) {
// TODO: undo this when we fully support bazel on windows.
// logger.info('Bazel build...');
// _exec('bazel', ['build', '//packages/...'], {}, logger);
const allJsonFiles = glob.sync('packages/**/*.json', {
ignore: [
'**/node_modules/**',
'**/files/**',
'**/*-files/**',
'**/package.json',
],
});
const quicktypeRunner = require('../tools/quicktype_runner');
logger.info('Generating JSON Schema....');
for (const fileName of allJsonFiles) {
if (fs.existsSync(fileName.replace(/\.json$/, '.ts'))
|| fs.existsSync(fileName.replace(/\.json$/, '.d.ts'))) {
// Skip files that already exist.
continue;
}
const content = fs.readFileSync(fileName, 'utf-8');
const json = JSON.parse(content);
if (!json.$schema) {
// Skip non-schema files.
continue;
}
const tsContent = await quicktypeRunner.generate(fileName);
const tsPath = path.join(__dirname, '../dist-schema', fileName.replace(/\.json$/, '.ts'));
_mkdirp(path.dirname(tsPath));
fs.writeFileSync(tsPath, tsContent, 'utf-8');
}
}
export default function(argv: { local?: boolean, snapshot?: boolean }, logger: logging.Logger) {
export default async function(
argv: { local?: boolean, snapshot?: boolean },
logger: logging.Logger,
) {
_clean(logger);
const sortedPackages = _sortPackages();
_bazel(logger);
await _bazel(logger);
_build(logger);
logger.info('Moving packages to dist/');
@ -216,7 +258,7 @@ export default function(argv: { local?: boolean, snapshot?: boolean }, logger: l
for (const packageName of sortedPackages) {
const pkg = packages[packageName];
const bazelBinPath = pkg.build.replace(/([\\\/]dist[\\\/])(packages)/, (_, dist, packages) => {
return path.join(dist, 'bazel-bin', packages);
return path.join(dist, 'dist-schema', packages);
});
if (fs.existsSync(bazelBinPath)) {
packageLogger.info(packageName);

View File

@ -29,9 +29,9 @@ function _exec(command: string, args: string[], opts: { cwd?: string }, logger:
}
export default function (args: { tag?: string }, logger: logging.Logger) {
export default async function (args: { tag?: string }, logger: logging.Logger) {
logger.info('Building...');
build({}, logger.createChild('build'));
await build({}, logger.createChild('build'));
return Object.keys(packages).reduce((acc: Promise<void>, name: string) => {
const pkg = packages[name];

View File

@ -53,7 +53,7 @@ export interface SnapshotsOptions {
githubToken?: string;
}
export default function(opts: SnapshotsOptions, logger: logging.Logger) {
export default async function(opts: SnapshotsOptions, logger: logging.Logger) {
// Get the SHA.
if (execSync(`git status --porcelain`).toString() && !opts.force) {
logger.error('You cannot run snapshots with local changes.');
@ -78,7 +78,7 @@ export default function(opts: SnapshotsOptions, logger: logging.Logger) {
// Run build.
logger.info('Building...');
build({ snapshot: true }, logger.createChild('build'));
await build({ snapshot: true }, logger.createChild('build'));
for (const packageName of Object.keys(packages)) {
const pkg = packages[packageName];

View File

@ -5,39 +5,41 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
/**
* This file is pure JavaScript because we want to avoid any dependency or build step
* to it. It's just simple (and zen-ier).
*
* This file wraps around quicktype and can do one of two things;
*
* `node quicktype_runner.js <in_path> <out_path>`
* Reads the in path and outputs the TS file at the out_path.
*
* Using `-` as the out_path will output on STDOUT instead of a file.
*/
// Imports.
const fs = require('fs');
const path = require('path');
const qtCore = require('quicktype-core');
const tempRoot = process.env['BAZEL_TMPDIR'] || require('os').tmpdir();
const {
InputData,
JSONSchema,
JSONSchemaInput,
JSONSchemaStore,
TypeScriptTargetLanguage,
parseJSON,
quicktype,
} = require('quicktype-core');
/**
* This file is pure JavaScript because Bazel only support compiling to ES5, while quicktype is
* ES2015. This results in an incompatible call to `super()` in the FetchingJSONSchemaStore
* class as it tries to call JSONSchemaStore's constructor in ES5.
* TODO: move this file to typescript when Bazel supports ES2015 output.
*
* This file wraps around quicktype and can do one of two things;
*
* `node quicktype_runner.js <in_path> <out_path>`
* Reads the in path and outputs the TS file at the out_path.
*
* Using `-` as the out_path will output on STDOUT instead of a file.
*/
// Header to add to all files.
const header = `
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
// THIS FILE IS AUTOMATICALLY GENERATED IN BAZEL. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
// CORRESPONDING JSON SCHEMA FILE, THEN RUN BAZEL.
// tslint:disable:no-global-tslint-disable
// tslint:disable
`.replace(/^\n/m, ''); // Remove the first \n, it's in the constant because formatting is 👍.
`;
// Footer to add to all files.
const footer = ``;
@ -46,7 +48,7 @@ const footer = ``;
* The simplest Node JSONSchemaStore implementation we can build which supports our custom protocol.
* Supports reading from ng-cli addresses, valid URLs and files (absolute).
*/
class FetchingJSONSchemaStore extends qtCore.JSONSchemaStore {
class FetchingJSONSchemaStore extends JSONSchemaStore {
constructor(inPath) {
super();
this._inPath = inPath;
@ -83,10 +85,10 @@ class FetchingJSONSchemaStore extends qtCore.JSONSchemaStore {
}
if (content == null) {
throw new Error(`Address ${JSON.stringify(address)} cannot be resolved.`);
return undefined;
}
return qtCore.parseJSON(content, "JSON Schema", address);
return parseJSON(content, "JSON Schema", address);
}
}
@ -113,40 +115,43 @@ async function main(inPath, outPath) {
async function generate(inPath) {
// Best description of how to use the API was found at
// https://blog.quicktype.io/customizing-quicktype/
const inputData = new qtCore.InputData();
const inputData = new InputData();
const source = { name: 'Schema', schema: fs.readFileSync(inPath, 'utf-8') };
await inputData.addSource('schema', source, () => {
return new qtCore.JSONSchemaInput(new FetchingJSONSchemaStore(inPath));
return new JSONSchemaInput(new FetchingJSONSchemaStore(inPath));
});
const lang = new qtCore.TypeScriptTargetLanguage();
const lang = new TypeScriptTargetLanguage();
const { lines } = await qtCore.quicktype({
const { lines } = await quicktype({
lang,
inputData,
alphabetizeProperties: true,
src: [inPath],
rendererOptions: {
'just-types': true,
'explicit-unions': true,
}
'just-types': 'true',
'explicit-unions': 'true',
},
});
return header + lines.join('\n') + footer;
}
// Parse arguments and run main().
const argv = process.argv.slice(2);
if (argv.length < 2 || argv.length > 3) {
console.error('Must include 2 or 3 arguments.');
process.exit(1);
if (require.main === module) {
// Parse arguments and run main().
const argv = process.argv.slice(2);
if (argv.length < 2 || argv.length > 3) {
console.error('Must include 2 or 3 arguments.');
process.exit(1);
}
main(argv[0], argv[1])
.then(() => process.exit(0))
.catch(err => {
console.error('An error happened:');
console.error(err);
process.exit(127);
});
}
main(...argv)
.then(() => process.exit(0))
.catch(err => {
console.error('An error happened:');
console.error(err);
process.exit(127);
});
exports.generate = generate;

View File

@ -52,7 +52,12 @@ _ts_json_schema_interface = rule(
)
def ts_json_schema(name, src, data = [], **kwargs):
# Generates a library that contains the interface for a JSON Schema file. Takes a single `src`
# argument as input, an optional data field for reference files, and produces a ts_library()
# rule containing the typescript interface.
# The file produced will have the same name, with the extension replaced from `.json` to `.ts`.
# Any filename collision will be an error thrown by Bazel.
def ts_json_schema(name, src, data = []):
out = src.replace(".json", ".ts")
_ts_json_schema_interface(

View File

@ -29,6 +29,7 @@
"baseUrl": "",
"rootDirs": [
".",
"./dist-schema/",
"./bazel-bin/"
],
"typeRoots": [