Skip to content

Commit c63b4d8

Browse files
hanslKeen Yee Liau
authored and
Keen Yee Liau
committed
ci: disable bazel in devkit-admin build
Replace the build step with a custom JSON schema output parallel to bazel.
1 parent 30b0cbd commit c63b4d8

File tree

7 files changed

+115
-61
lines changed

7 files changed

+115
-61
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
bazel-*
33
test-project-host-*
44
dist/
5+
dist-schema/
56

67
# IDEs
78
.idea/

scripts/build.ts

+50-8
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@ function _mkdirp(p: string) {
3434
if (!fs.existsSync(path.dirname(p))) {
3535
_mkdirp(path.dirname(p));
3636
}
37-
fs.mkdirSync(p);
37+
if (!fs.existsSync(p)) {
38+
fs.mkdirSync(p);
39+
}
3840
}
3941

4042
function _recursiveFileList(p: string): string[] {
@@ -186,21 +188,61 @@ function _exec(command: string, args: string[], opts: { cwd?: string }, logger:
186188

187189
function _build(logger: logging.Logger) {
188190
logger.info('Building...');
189-
_exec('node_modules/.bin/tsc', ['-p', 'tsconfig.json'], {}, logger);
191+
_exec('node', [
192+
require.resolve('typescript/bin/tsc'),
193+
'-p',
194+
'tsconfig.json',
195+
], {}, logger);
190196
}
191197

192198

193-
function _bazel(logger: logging.Logger) {
194-
logger.info('Bazel build...');
195-
_exec('bazel', ['build', '//packages/...'], {}, logger);
199+
async function _bazel(logger: logging.Logger) {
200+
// TODO: undo this when we fully support bazel on windows.
201+
// logger.info('Bazel build...');
202+
// _exec('bazel', ['build', '//packages/...'], {}, logger);
203+
204+
const allJsonFiles = glob.sync('packages/**/*.json', {
205+
ignore: [
206+
'**/node_modules/**',
207+
'**/files/**',
208+
'**/*-files/**',
209+
'**/package.json',
210+
],
211+
});
212+
213+
const quicktypeRunner = require('../tools/quicktype_runner');
214+
logger.info('Generating JSON Schema....');
215+
216+
for (const fileName of allJsonFiles) {
217+
if (fs.existsSync(fileName.replace(/\.json$/, '.ts'))
218+
|| fs.existsSync(fileName.replace(/\.json$/, '.d.ts'))) {
219+
// Skip files that already exist.
220+
continue;
221+
}
222+
const content = fs.readFileSync(fileName, 'utf-8');
223+
224+
const json = JSON.parse(content);
225+
if (!json.$schema) {
226+
// Skip non-schema files.
227+
continue;
228+
}
229+
const tsContent = await quicktypeRunner.generate(fileName);
230+
const tsPath = path.join(__dirname, '../dist-schema', fileName.replace(/\.json$/, '.ts'));
231+
232+
_mkdirp(path.dirname(tsPath));
233+
fs.writeFileSync(tsPath, tsContent, 'utf-8');
234+
}
196235
}
197236

198237

199-
export default function(argv: { local?: boolean, snapshot?: boolean }, logger: logging.Logger) {
238+
export default async function(
239+
argv: { local?: boolean, snapshot?: boolean },
240+
logger: logging.Logger,
241+
) {
200242
_clean(logger);
201243

202244
const sortedPackages = _sortPackages();
203-
_bazel(logger);
245+
await _bazel(logger);
204246
_build(logger);
205247

206248
logger.info('Moving packages to dist/');
@@ -216,7 +258,7 @@ export default function(argv: { local?: boolean, snapshot?: boolean }, logger: l
216258
for (const packageName of sortedPackages) {
217259
const pkg = packages[packageName];
218260
const bazelBinPath = pkg.build.replace(/([\\\/]dist[\\\/])(packages)/, (_, dist, packages) => {
219-
return path.join(dist, 'bazel-bin', packages);
261+
return path.join(dist, 'dist-schema', packages);
220262
});
221263
if (fs.existsSync(bazelBinPath)) {
222264
packageLogger.info(packageName);

scripts/publish.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ function _exec(command: string, args: string[], opts: { cwd?: string }, logger:
2929
}
3030

3131

32-
export default function (args: { tag?: string }, logger: logging.Logger) {
32+
export default async function (args: { tag?: string }, logger: logging.Logger) {
3333
logger.info('Building...');
34-
build({}, logger.createChild('build'));
34+
await build({}, logger.createChild('build'));
3535

3636
return Object.keys(packages).reduce((acc: Promise<void>, name: string) => {
3737
const pkg = packages[name];

scripts/snapshots.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ export interface SnapshotsOptions {
5353
githubToken?: string;
5454
}
5555

56-
export default function(opts: SnapshotsOptions, logger: logging.Logger) {
56+
export default async function(opts: SnapshotsOptions, logger: logging.Logger) {
5757
// Get the SHA.
5858
if (execSync(`git status --porcelain`).toString() && !opts.force) {
5959
logger.error('You cannot run snapshots with local changes.');
@@ -78,7 +78,7 @@ export default function(opts: SnapshotsOptions, logger: logging.Logger) {
7878

7979
// Run build.
8080
logger.info('Building...');
81-
build({ snapshot: true }, logger.createChild('build'));
81+
await build({ snapshot: true }, logger.createChild('build'));
8282

8383
for (const packageName of Object.keys(packages)) {
8484
const pkg = packages[packageName];

tools/quicktype_runner.js

+53-48
Original file line numberDiff line numberDiff line change
@@ -5,39 +5,41 @@
55
* Use of this source code is governed by an MIT-style license that can be
66
* found in the LICENSE file at https://angular.io/license
77
*/
8-
9-
/**
10-
* This file is pure JavaScript because we want to avoid any dependency or build step
11-
* to it. It's just simple (and zen-ier).
12-
*
13-
* This file wraps around quicktype and can do one of two things;
14-
*
15-
* `node quicktype_runner.js <in_path> <out_path>`
16-
* Reads the in path and outputs the TS file at the out_path.
17-
*
18-
* Using `-` as the out_path will output on STDOUT instead of a file.
19-
*/
20-
21-
// Imports.
228
const fs = require('fs');
239
const path = require('path');
24-
const qtCore = require('quicktype-core');
25-
const tempRoot = process.env['BAZEL_TMPDIR'] || require('os').tmpdir();
10+
const {
11+
InputData,
12+
JSONSchema,
13+
JSONSchemaInput,
14+
JSONSchemaStore,
15+
TypeScriptTargetLanguage,
16+
parseJSON,
17+
quicktype,
18+
} = require('quicktype-core');
2619

27-
// Header to add to all files.
28-
const header = `
2920
/**
30-
* @license
31-
* Copyright Google Inc. All Rights Reserved.
21+
* This file is pure JavaScript because Bazel only support compiling to ES5, while quicktype is
22+
* ES2015. This results in an incompatible call to `super()` in the FetchingJSONSchemaStore
23+
* class as it tries to call JSONSchemaStore's constructor in ES5.
24+
* TODO: move this file to typescript when Bazel supports ES2015 output.
3225
*
33-
* Use of this source code is governed by an MIT-style license that can be
34-
* found in the LICENSE file at https://angular.io/license
26+
* This file wraps around quicktype and can do one of two things;
27+
*
28+
* `node quicktype_runner.js <in_path> <out_path>`
29+
* Reads the in path and outputs the TS file at the out_path.
30+
*
31+
* Using `-` as the out_path will output on STDOUT instead of a file.
3532
*/
3633

37-
// THIS FILE IS AUTOMATICALLY GENERATED IN BAZEL. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
38-
// CORRESPONDING JSON SCHEMA FILE, THEN RUN BAZEL.
34+
// Header to add to all files.
35+
const header = `
36+
// THIS FILE IS AUTOMATICALLY GENERATED. TO UPDATE THIS FILE YOU NEED TO CHANGE THE
37+
// CORRESPONDING JSON SCHEMA FILE, THEN RUN devkit-admin build (or bazel build ...).
38+
39+
// tslint:disable:no-global-tslint-disable
40+
// tslint:disable
3941
40-
`.replace(/^\n/m, ''); // Remove the first \n, it's in the constant because formatting is 👍.
42+
`;
4143

4244
// Footer to add to all files.
4345
const footer = ``;
@@ -46,7 +48,7 @@ const footer = ``;
4648
* The simplest Node JSONSchemaStore implementation we can build which supports our custom protocol.
4749
* Supports reading from ng-cli addresses, valid URLs and files (absolute).
4850
*/
49-
class FetchingJSONSchemaStore extends qtCore.JSONSchemaStore {
51+
class FetchingJSONSchemaStore extends JSONSchemaStore {
5052
constructor(inPath) {
5153
super();
5254
this._inPath = inPath;
@@ -83,10 +85,10 @@ class FetchingJSONSchemaStore extends qtCore.JSONSchemaStore {
8385
}
8486

8587
if (content == null) {
86-
throw new Error(`Address ${JSON.stringify(address)} cannot be resolved.`);
88+
return undefined;
8789
}
8890

89-
return qtCore.parseJSON(content, "JSON Schema", address);
91+
return parseJSON(content, "JSON Schema", address);
9092
}
9193
}
9294

@@ -113,40 +115,43 @@ async function main(inPath, outPath) {
113115
async function generate(inPath) {
114116
// Best description of how to use the API was found at
115117
// https://blog.quicktype.io/customizing-quicktype/
116-
const inputData = new qtCore.InputData();
118+
const inputData = new InputData();
117119
const source = { name: 'Schema', schema: fs.readFileSync(inPath, 'utf-8') };
118120

119121
await inputData.addSource('schema', source, () => {
120-
return new qtCore.JSONSchemaInput(new FetchingJSONSchemaStore(inPath));
122+
return new JSONSchemaInput(new FetchingJSONSchemaStore(inPath));
121123
});
122124

123-
const lang = new qtCore.TypeScriptTargetLanguage();
125+
const lang = new TypeScriptTargetLanguage();
124126

125-
const { lines } = await qtCore.quicktype({
127+
const { lines } = await quicktype({
126128
lang,
127129
inputData,
128130
alphabetizeProperties: true,
129-
src: [inPath],
130131
rendererOptions: {
131-
'just-types': true,
132-
'explicit-unions': true,
133-
}
132+
'just-types': 'true',
133+
'explicit-unions': 'true',
134+
},
134135
});
135136

136137
return header + lines.join('\n') + footer;
137138
}
138139

139-
// Parse arguments and run main().
140-
const argv = process.argv.slice(2);
141-
if (argv.length < 2 || argv.length > 3) {
142-
console.error('Must include 2 or 3 arguments.');
143-
process.exit(1);
140+
if (require.main === module) {
141+
// Parse arguments and run main().
142+
const argv = process.argv.slice(2);
143+
if (argv.length < 2 || argv.length > 3) {
144+
console.error('Must include 2 or 3 arguments.');
145+
process.exit(1);
146+
}
147+
148+
main(argv[0], argv[1])
149+
.then(() => process.exit(0))
150+
.catch(err => {
151+
console.error('An error happened:');
152+
console.error(err);
153+
process.exit(127);
154+
});
144155
}
145156

146-
main(...argv)
147-
.then(() => process.exit(0))
148-
.catch(err => {
149-
console.error('An error happened:');
150-
console.error(err);
151-
process.exit(127);
152-
});
157+
exports.generate = generate;

tools/ts_json_schema.bzl

+6-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ _ts_json_schema_interface = rule(
5252
)
5353

5454

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

5863
_ts_json_schema_interface(

tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
"baseUrl": "",
3030
"rootDirs": [
3131
".",
32+
"./dist-schema/",
3233
"./bazel-bin/"
3334
],
3435
"typeRoots": [

0 commit comments

Comments
 (0)