Skip to content

Commit 2788980

Browse files
chore(): Fix build in windows and test build/node in different OSes (#2922)
* Fix the build process in Windows * Add contribute tests * Add firebase-tools as a matrix in the Node tests * Test Node in Windows and MacOS too Co-authored-by: Manuel Bojato <[email protected]>
1 parent b0e147e commit 2788980

File tree

6 files changed

+151
-75
lines changed

6 files changed

+151
-75
lines changed

.github/workflows/test.yml

Lines changed: 68 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
paths-ignore:
88
- "**/*.md"
99
pull_request:
10-
branches:
10+
branches:
1111
- "**"
1212
release:
1313
types:
@@ -29,10 +29,11 @@ jobs:
2929
id: node_modules_cache
3030
with:
3131
path: ./node_modules
32-
key: ${{ runner.os }}-14-9-node_modules-${{ hashFiles('yarn.lock') }}
32+
key: ${{ runner.os }}-14-9-9-node_modules-${{ hashFiles('yarn.lock') }}
3333
restore-keys: |
34-
${{ runner.os }}-14-9-node_modules-
35-
${{ runner.os }}-14-node_modules-
34+
${{ runner.os }}-14-9-9-node_modules-
35+
${{ runner.os }}-14-9-
36+
${{ runner.os }}-14-
3637
- name: Yarn offline cache
3738
if: steps.node_modules_cache.outputs.cache-hit != 'true'
3839
uses: actions/cache@v2
@@ -57,14 +58,16 @@ jobs:
5758
retention-days: 1
5859

5960
test:
60-
runs-on: ubuntu-latest
61+
runs-on: ${{ matrix.os }}
6162
needs: build
6263
strategy:
6364
matrix:
65+
os: [ ubuntu-latest, macos-latest, windows-latest]
6466
node: ["12", "14", "16"]
6567
firebase: ["9"]
68+
firebaseTools: ["9"]
6669
fail-fast: false
67-
name: Test firebase@${{ matrix.firebase }} on Node.js ${{ matrix.node }}
70+
name: Test firebase@${{ matrix.firebase }} firebase-tools@${{ matrix.firebaseTools }} on ${{ matrix.os }} Node.js ${{ matrix.node }}
6871
steps:
6972
- name: Checkout
7073
uses: actions/checkout@v2
@@ -78,10 +81,11 @@ jobs:
7881
uses: actions/cache@v2
7982
with:
8083
path: ./node_modules
81-
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
84+
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-${{ matrix.firebaseTools }}-node_modules-${{ hashFiles('yarn.lock') }}
8285
restore-keys: |
83-
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-node_modules-
84-
${{ runner.os }}-${{ matrix.node }}-node_modules-
86+
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-${{ matrix.firebaseTools }}-node_modules-
87+
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-
88+
${{ runner.os }}-${{ matrix.node }}-
8589
- name: Yarn offline cache
8690
if: steps.node_modules_cache.outputs.cache-hit != 'true'
8791
uses: actions/cache@v2
@@ -95,6 +99,7 @@ jobs:
9599
yarn config set yarn-offline-mirror ~/.npm-packages-offline-cache
96100
yarn install --frozen-lockfile --prefer-offline --ignore-engines
97101
yarn add firebase@${{ matrix.firebase }} --prefer-offline --ignore-engines
102+
yarn add firebase-tools@${{ matrix.firebaseTools }} --prefer-offline --ignore-engines
98103
- name: Firebase emulator cache
99104
uses: actions/cache@v2
100105
with:
@@ -107,6 +112,52 @@ jobs:
107112
mv angularfire-${{ github.run_id }} dist
108113
yarn test:node
109114
115+
contribute:
116+
runs-on: ${{ matrix.os }}
117+
name: Contribute ${{ matrix.os }} on Node.js ${{ matrix.node }}
118+
strategy:
119+
matrix:
120+
os: [ ubuntu-latest, macos-latest, windows-latest ]
121+
node: ["12", "14", "16"]
122+
exclude:
123+
# we build with this combination, safely skip
124+
- os: ubuntu-latest
125+
node: 14
126+
fail-fast: false
127+
steps:
128+
- name: Checkout
129+
uses: actions/checkout@v2
130+
- name: Setup node
131+
uses: actions/setup-node@v2-beta
132+
with:
133+
node-version: ${{ matrix.node }}
134+
check-latest: true
135+
- name: node_modules cache
136+
uses: actions/cache@v2
137+
id: node_modules_cache
138+
with:
139+
path: ./node_modules
140+
key: ${{ runner.os }}-${{ matrix.node }}-9-9-node_modules-${{ hashFiles('yarn.lock') }}
141+
restore-keys: |
142+
${{ runner.os }}-${{ matrix.node }}-9-9-node_modules-
143+
${{ runner.os }}-${{ matrix.node }}-9-
144+
${{ runner.os }}-${{ matrix.node }}-
145+
- name: Yarn offline cache
146+
if: steps.node_modules_cache.outputs.cache-hit != 'true'
147+
uses: actions/cache@v2
148+
with:
149+
path: ~/.npm-packages-offline-cache
150+
key: yarn-offline-${{ hashFiles('**/yarn.lock') }}
151+
restore-keys: yarn-offline
152+
- name: Install deps
153+
if: steps.node_modules_cache.outputs.cache-hit != 'true'
154+
run: |
155+
yarn config set yarn-offline-mirror ~/.npm-packages-offline-cache
156+
yarn install --frozen-lockfile --prefer-offline --ignore-engines
157+
- name: Build
158+
id: yarn-pack-dir
159+
run: yarn build
160+
110161
headless:
111162
runs-on: ubuntu-latest
112163
needs: build
@@ -129,10 +180,11 @@ jobs:
129180
uses: actions/cache@v2
130181
with:
131182
path: ./node_modules
132-
key: ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
183+
key: ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-${{ hashFiles('yarn.lock') }}
133184
restore-keys: |
134-
${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-
135-
${{ runner.os }}-14-node_modules-
185+
${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-
186+
${{ runner.os }}-14-9-
187+
${{ runner.os }}-14-
136188
- name: Yarn offline cache
137189
if: steps.node_modules_cache.outputs.cache-hit != 'true'
138190
uses: actions/cache@v2
@@ -179,10 +231,11 @@ jobs:
179231
# uses: actions/cache@v2
180232
# with:
181233
# path: ./node_modules
182-
# key: ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
234+
# key: ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-${{ hashFiles('yarn.lock') }}
183235
# restore-keys: |
184-
# ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-
185-
# ${{ runner.os }}-14-node_modules-
236+
# ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-
237+
# ${{ runner.os }}-14-${{ matrix.firebase }}-
238+
# ${{ runner.os }}-14-
186239
# - name: Yarn offline cache
187240
# if: steps.node_modules_cache.outputs.cache-hit != 'true'
188241
# uses: actions/cache@v2

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
"test:typings": "node ./tools/run-typings-test.js",
1717
"test:build": "bash ./test/ng-build/build.sh",
1818
"test:all": "npm run test:node && npm run test:chrome-headless && npm run test:typings && npm run test:build",
19-
"build": "rimraf dist; ttsc -p tsconfig.build.json; node --trace-warnings ./tools/build.js",
20-
"build:jasmine": "tsc -p tsconfig.jasmine.json; cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics",
19+
"build": "rimraf dist && ttsc -p tsconfig.build.json && node --trace-warnings ./tools/build.js",
20+
"build:jasmine": "tsc -p tsconfig.jasmine.json && cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics",
2121
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1"
2222
},
2323
"husky": {
@@ -93,6 +93,7 @@
9393
"codelyzer": "^6.0.0",
9494
"concurrently": "^2.2.0",
9595
"conventional-changelog-cli": "^1.2.0",
96+
"cross-spawn": "^7.0.3",
9697
"file-loader": "^6.2.0",
9798
"firebase-functions-test": "^0.2.2",
9899
"globalthis": "^1.0.1",

src/schematics/deploy/actions.jasmine.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { JsonObject, logging } from '@angular-devkit/core';
22
import { BuilderContext, BuilderRun, ScheduleOptions, Target } from '@angular-devkit/architect';
33
import { BuildTarget, FirebaseDeployConfig, FirebaseTools, FSHost } from '../interfaces';
44
import deploy, { deployToFunction } from './actions';
5+
import { join } from 'path';
56
import 'jasmine';
67

78
let context: BuilderContext;
@@ -169,8 +170,8 @@ describe('universal deployment', () => {
169170
const packageArgs = spy.calls.argsFor(0);
170171
const functionArgs = spy.calls.argsFor(1);
171172

172-
expect(packageArgs[0]).toBe('dist/package.json');
173-
expect(functionArgs[0]).toBe('dist/index.js');
173+
expect(packageArgs[0]).toBe(join('dist', 'package.json'));
174+
expect(functionArgs[0]).toBe(join('dist', 'index.js'));
174175
});
175176

176177
it('should rename the index.html file in the nested dist', async () => {
@@ -191,8 +192,8 @@ describe('universal deployment', () => {
191192
const packageArgs = spy.calls.argsFor(0);
192193

193194
expect(packageArgs).toEqual([
194-
'dist/dist/browser/index.html',
195-
'dist/dist/browser/index.original.html'
195+
join('dist', 'dist', 'browser', 'index.html'),
196+
join('dist', 'dist', 'browser', 'index.original.html')
196197
]);
197198
});
198199

src/schematics/ng-add.jasmine.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Tree } from '@angular-devkit/schematics';
22
import { setupProject } from './ng-add';
33
import 'jasmine';
4+
import { join } from '@angular-devkit/core';
5+
import { join as pathJoin } from 'path';
46

57
const PROJECT_NAME = 'pie-ka-chu';
68
const PROJECT_ROOT = 'pirojok';
@@ -335,7 +337,7 @@ const projectAngularJson = `{
335337
const universalFirebaseJson = {
336338
hosting: [{
337339
target: 'pie-ka-chu',
338-
public: 'dist/dist/ikachu',
340+
public: pathJoin('dist', 'dist', 'ikachu'),
339341
ignore: [
340342
'**/.*'
341343
],

tools/build.ts

Lines changed: 71 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { spawn } from 'child_process';
1+
import { spawn } from 'cross-spawn';
22
import { copy, readFile, writeFile } from 'fs-extra';
33
import { prettySize } from 'pretty-size';
44
import { file as gzipSizeFile } from 'gzip-size';
@@ -44,7 +44,7 @@ function zoneWrapExports() {
4444
});
4545
const zoneWrapped = toBeExported.filter(([, , zoneWrap]) => zoneWrap);
4646
const rawExport = toBeExported.filter(([, , zoneWrap]) => !zoneWrap);
47-
await writeFile(`./src/${module}/${name}.ts`, `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
47+
await writeFile(join(process.cwd(), 'src', `${module}/${name}.ts`), `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
4848
${path.startsWith('firebase/') ? `export * from '${path}';\n` : ''}${
4949
zoneWrapped.length > 0 ? `import { ɵzoneWrap } from '@angular/fire';
5050
import {
@@ -109,13 +109,14 @@ ${zoneWrapped.map(([importName, exportName]) => `export const ${exportName} = ɵ
109109
}
110110

111111
function webpackFirestoreProtos() {
112+
// TODO fix on windows
112113
return new Promise<void>((resolve, reject) => {
113114
glob('./node_modules/@firebase/firestore/dist/src/protos/**/*.proto', {}, async (err, files) => {
114115
if (err) { reject(err); }
115116
const fileLoader = files.map(path =>
116117
`require('file-loader?name=${path.replace('./node_modules/@firebase/firestore/dist/', '')}!${path.replace('./node_modules/', '../../')}');`
117118
).join('\n');
118-
await writeFile('./dist/packages-dist/firestore-protos.js', fileLoader);
119+
await writeFile(dest('firestore-protos.js'), fileLoader);
119120
resolve();
120121
});
121122
});
@@ -132,7 +133,7 @@ function proxyPolyfillCompat() {
132133
};
133134

134135
return Promise.all(Object.keys(defaultObject).map(module =>
135-
writeFile(`./src/${module}/base.ts`, `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
136+
writeFile(join(process.cwd(), 'src', `${module}/base.ts`), `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
136137
// Export a null object with the same keys as firebase/${module}, so Proxy can work with proxy-polyfill in Internet Explorer
137138
export const proxyPolyfillCompat = {
138139
${defaultObject[module].map(it => ` ${it}: null,`).join('\n')}
@@ -197,6 +198,7 @@ async function fixImportForLazyModules() {
197198
const entries = Array.from(new Set(Object.values(packageJson).filter(v => typeof v === 'string' && v.endsWith('.js')))) as string[];
198199
// TODO don't hardcode esm2015 here, perhaps we should scan all the entry directories
199200
// e.g, if ng-packagr starts building other non-flattened entries we'll lose the dynamic import
201+
// TODO fix in Windows
200202
entries.push(`../${module.includes('/') ? '../' : ''}esm2015/${module}/public_api.js`);
201203
await Promise.all(entries.map(async path => {
202204
const source = (await readFile(dest(module, path))).toString();
@@ -233,55 +235,72 @@ function measureLibrary() {
233235
}
234236

235237
async function buildDocs() {
236-
// INVESTIGATE json to stdout rather than FS?
237-
await Promise.all(MODULES.map(module => spawnPromise('npx', ['typedoc', `${module === 'core' ? './src' : `./src/${module}`}`, '--json', `./dist/typedocs/${module}.json`])));
238-
const entries = await Promise.all(MODULES.map(async (module) => {
238+
try {
239+
// INVESTIGATE json to stdout rather than FS?
240+
await Promise.all(
241+
MODULES.map(module =>
242+
spawnPromise('npx', ['typedoc',
243+
`${module === 'core' ?
244+
join(process.cwd(), 'src') :
245+
join(process.cwd(), 'src', module)}`,
246+
'--json',
247+
join(process.cwd(), 'dist', 'typedocs', `${module}.json`)
248+
])));
249+
const entries = await Promise.all(MODULES.map(async (module) => {
239250

240-
const buffer = await readFile(`./dist/typedocs/${module}.json`);
241-
const typedoc = JSON.parse(buffer.toString());
242-
if (!typedoc.children) {
243-
console.error('typedoc fail', module);
244-
}
245-
// TODO infer the entryPoint from the package.json
246-
const entryPoint = typedoc.children.find((c: any) => c.name === '"public_api"');
247-
const allChildren = [].concat(...typedoc.children.map(child =>
248-
// TODO chop out the working directory and filename
249-
child.children ? child.children.map(c => ({ ...c, path: dirname(child.originalName.split(process.cwd())[1]) })) : []
250-
));
251-
return (entryPoint.children || [])
252-
.filter(c => c.name[0] !== 'ɵ' && c.name[0] !== '_' /* private */)
253-
.map(child => ({ ...allChildren.find(c => child.target === c.id) }))
254-
.reduce((acc, child) => ({ ...acc, [encodeURIComponent(child.name)]: child }), {});
255-
}));
256-
const root = await rootPackage;
257-
const pipes = ['MonoTypeOperatorFunction', 'OperatorFunction', 'AuthPipe', 'UnaryFunction'];
258-
const tocType = child => {
259-
const decorators: string[] = child.decorators && child.decorators.map(d => d.name) || [];
260-
if (decorators.includes('NgModule')) {
261-
return 'NgModule';
262-
} else if (child.kindString === 'Type alias') {
263-
return 'Type alias';
264-
} else if (child.kindString === 'Variable' && child.defaultValue && child.defaultValue.startsWith('new InjectionToken')) {
265-
return 'InjectionToken';
266-
} else if (child.type) {
267-
return pipes.includes(child.type.name) ? 'Pipe' : child.type.name;
268-
} else if (child.signatures && child.signatures[0] && child.signatures[0].type && pipes.includes(child.signatures[0].type.name)) {
269-
return 'Pipe';
270-
} else {
271-
return child.kindString;
272-
}
273-
};
274-
const tableOfContents = entries.reduce((acc, entry, index) =>
275-
({
276-
...acc, [MODULES[index]]: {
277-
name: ENTRY_NAMES[index],
278-
exports: Object.keys(entry).reduce((acc, key) => ({ ...acc, [key]: tocType(entry[key]) }), {})
279-
}
280-
}),
281-
{}
282-
);
283-
const afdoc = entries.reduce((acc, entry, index) => ({ ...acc, [MODULES[index]]: entry }), { table_of_contents: tableOfContents });
284-
return writeFile(`./api-${root.version}.json`, JSON.stringify(afdoc, null, 2));
251+
const buffer = await readFile(join(process.cwd(), 'dist', 'typedocs', `${module}.json`));
252+
const typedoc = JSON.parse(buffer.toString());
253+
if (!typedoc.children) {
254+
console.error('typedoc fail', module);
255+
}
256+
// TODO infer the entryPoint from the package.json
257+
const entryPoint = typedoc.children.find((c: any) => c.name === '"public_api"');
258+
const allChildren = [].concat(...typedoc.children.map(child =>
259+
// TODO chop out the working directory and filename
260+
child.children ?
261+
child.children.map(c => {
262+
return { ...c, path: dirname(child.originalName.split(process.cwd())[1]) };
263+
}) :
264+
[]
265+
));
266+
return (entryPoint.children || [])
267+
.filter(c => c.name[0] !== 'ɵ' && c.name[0] !== '_' /* private */)
268+
.map(child => ({ ...allChildren.find(c => child.target === c.id) }))
269+
.reduce((acc, child) => ({ ...acc, [encodeURIComponent(child.name)]: child }), {});
270+
}));
271+
const root = await rootPackage;
272+
const pipes = ['MonoTypeOperatorFunction', 'OperatorFunction', 'AuthPipe', 'UnaryFunction'];
273+
const tocType = child => {
274+
const decorators: string[] = child.decorators && child.decorators.map(d => d.name) || [];
275+
if (decorators.includes('NgModule')) {
276+
return 'NgModule';
277+
} else if (child.kindString === 'Type alias') {
278+
return 'Type alias';
279+
} else if (child.kindString === 'Variable' && child.defaultValue && child.defaultValue.startsWith('new InjectionToken')) {
280+
return 'InjectionToken';
281+
} else if (child.type) {
282+
return pipes.includes(child.type.name) ? 'Pipe' : child.type.name;
283+
} else if (child.signatures && child.signatures[0] && child.signatures[0].type && pipes.includes(child.signatures[0].type.name)) {
284+
return 'Pipe';
285+
} else {
286+
return child.kindString;
287+
}
288+
};
289+
const tableOfContents = entries.reduce((acc, entry, index) =>
290+
({
291+
...acc, [MODULES[index]]: {
292+
name: ENTRY_NAMES[index],
293+
exports: Object.keys(entry).reduce((acc, key) => ({ ...acc, [key]: tocType(entry[key]) }), {})
294+
}
295+
}),
296+
{}
297+
);
298+
const afdoc = entries.reduce((acc, entry, index) => ({ ...acc, [MODULES[index]]: entry }), { table_of_contents: tableOfContents });
299+
return writeFile(join(process.cwd(), `api-${root.version}.json`), JSON.stringify(afdoc, null, 2));
300+
} catch (e) {
301+
console.warn(e);
302+
return Promise.resolve();
303+
}
285304
}
286305

287306
Promise.all([

yarn.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4977,7 +4977,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
49774977
shebang-command "^1.2.0"
49784978
which "^1.2.9"
49794979

4980-
cross-spawn@^7.0.1:
4980+
cross-spawn@^7.0.1, cross-spawn@^7.0.3:
49814981
version "7.0.3"
49824982
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
49834983
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==

0 commit comments

Comments
 (0)