Skip to content

Commit

Permalink
chore(): Fix build in windows and test build/node in different OSes (a…
Browse files Browse the repository at this point in the history
…ngular#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 <30560560+KingDarBoja@users.noreply.github.com>
  • Loading branch information
jamesdaniels and KingDarBoja authored Sep 2, 2021
1 parent b0e147e commit 2788980
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 75 deletions.
83 changes: 68 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ on:
paths-ignore:
- "**/*.md"
pull_request:
branches:
branches:
- "**"
release:
types:
Expand All @@ -29,10 +29,11 @@ jobs:
id: node_modules_cache
with:
path: ./node_modules
key: ${{ runner.os }}-14-9-node_modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-14-9-9-node_modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-14-9-node_modules-
${{ runner.os }}-14-node_modules-
${{ runner.os }}-14-9-9-node_modules-
${{ runner.os }}-14-9-
${{ runner.os }}-14-
- name: Yarn offline cache
if: steps.node_modules_cache.outputs.cache-hit != 'true'
uses: actions/cache@v2
Expand All @@ -57,14 +58,16 @@ jobs:
retention-days: 1

test:
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
needs: build
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest]
node: ["12", "14", "16"]
firebase: ["9"]
firebaseTools: ["9"]
fail-fast: false
name: Test firebase@${{ matrix.firebase }} on Node.js ${{ matrix.node }}
name: Test firebase@${{ matrix.firebase }} firebase-tools@${{ matrix.firebaseTools }} on ${{ matrix.os }} Node.js ${{ matrix.node }}
steps:
- name: Checkout
uses: actions/checkout@v2
Expand All @@ -78,10 +81,11 @@ jobs:
uses: actions/cache@v2
with:
path: ./node_modules
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-${{ matrix.firebaseTools }}-node_modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-node_modules-
${{ runner.os }}-${{ matrix.node }}-node_modules-
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-${{ matrix.firebaseTools }}-node_modules-
${{ runner.os }}-${{ matrix.node }}-${{ matrix.firebase }}-
${{ runner.os }}-${{ matrix.node }}-
- name: Yarn offline cache
if: steps.node_modules_cache.outputs.cache-hit != 'true'
uses: actions/cache@v2
Expand All @@ -95,6 +99,7 @@ jobs:
yarn config set yarn-offline-mirror ~/.npm-packages-offline-cache
yarn install --frozen-lockfile --prefer-offline --ignore-engines
yarn add firebase@${{ matrix.firebase }} --prefer-offline --ignore-engines
yarn add firebase-tools@${{ matrix.firebaseTools }} --prefer-offline --ignore-engines
- name: Firebase emulator cache
uses: actions/cache@v2
with:
Expand All @@ -107,6 +112,52 @@ jobs:
mv angularfire-${{ github.run_id }} dist
yarn test:node
contribute:
runs-on: ${{ matrix.os }}
name: Contribute ${{ matrix.os }} on Node.js ${{ matrix.node }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
node: ["12", "14", "16"]
exclude:
# we build with this combination, safely skip
- os: ubuntu-latest
node: 14
fail-fast: false
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup node
uses: actions/setup-node@v2-beta
with:
node-version: ${{ matrix.node }}
check-latest: true
- name: node_modules cache
uses: actions/cache@v2
id: node_modules_cache
with:
path: ./node_modules
key: ${{ runner.os }}-${{ matrix.node }}-9-9-node_modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.node }}-9-9-node_modules-
${{ runner.os }}-${{ matrix.node }}-9-
${{ runner.os }}-${{ matrix.node }}-
- name: Yarn offline cache
if: steps.node_modules_cache.outputs.cache-hit != 'true'
uses: actions/cache@v2
with:
path: ~/.npm-packages-offline-cache
key: yarn-offline-${{ hashFiles('**/yarn.lock') }}
restore-keys: yarn-offline
- name: Install deps
if: steps.node_modules_cache.outputs.cache-hit != 'true'
run: |
yarn config set yarn-offline-mirror ~/.npm-packages-offline-cache
yarn install --frozen-lockfile --prefer-offline --ignore-engines
- name: Build
id: yarn-pack-dir
run: yarn build

headless:
runs-on: ubuntu-latest
needs: build
Expand All @@ -129,10 +180,11 @@ jobs:
uses: actions/cache@v2
with:
path: ./node_modules
key: ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
key: ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-${{ hashFiles('yarn.lock') }}
restore-keys: |
${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-
${{ runner.os }}-14-node_modules-
${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-
${{ runner.os }}-14-9-
${{ runner.os }}-14-
- name: Yarn offline cache
if: steps.node_modules_cache.outputs.cache-hit != 'true'
uses: actions/cache@v2
Expand Down Expand Up @@ -179,10 +231,11 @@ jobs:
# uses: actions/cache@v2
# with:
# path: ./node_modules
# key: ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-${{ hashFiles('yarn.lock') }}
# key: ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-${{ hashFiles('yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-14-${{ matrix.firebase }}-node_modules-
# ${{ runner.os }}-14-node_modules-
# ${{ runner.os }}-14-${{ matrix.firebase }}-9-node_modules-
# ${{ runner.os }}-14-${{ matrix.firebase }}-
# ${{ runner.os }}-14-
# - name: Yarn offline cache
# if: steps.node_modules_cache.outputs.cache-hit != 'true'
# uses: actions/cache@v2
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
"test:typings": "node ./tools/run-typings-test.js",
"test:build": "bash ./test/ng-build/build.sh",
"test:all": "npm run test:node && npm run test:chrome-headless && npm run test:typings && npm run test:build",
"build": "rimraf dist; ttsc -p tsconfig.build.json; node --trace-warnings ./tools/build.js",
"build:jasmine": "tsc -p tsconfig.jasmine.json; cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics",
"build": "rimraf dist && ttsc -p tsconfig.build.json && node --trace-warnings ./tools/build.js",
"build:jasmine": "tsc -p tsconfig.jasmine.json && cp ./dist/packages-dist/schematics/versions.json ./dist/out-tsc/jasmine/schematics",
"changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 1"
},
"husky": {
Expand Down Expand Up @@ -93,6 +93,7 @@
"codelyzer": "^6.0.0",
"concurrently": "^2.2.0",
"conventional-changelog-cli": "^1.2.0",
"cross-spawn": "^7.0.3",
"file-loader": "^6.2.0",
"firebase-functions-test": "^0.2.2",
"globalthis": "^1.0.1",
Expand Down
9 changes: 5 additions & 4 deletions src/schematics/deploy/actions.jasmine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { JsonObject, logging } from '@angular-devkit/core';
import { BuilderContext, BuilderRun, ScheduleOptions, Target } from '@angular-devkit/architect';
import { BuildTarget, FirebaseDeployConfig, FirebaseTools, FSHost } from '../interfaces';
import deploy, { deployToFunction } from './actions';
import { join } from 'path';
import 'jasmine';

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

expect(packageArgs[0]).toBe('dist/package.json');
expect(functionArgs[0]).toBe('dist/index.js');
expect(packageArgs[0]).toBe(join('dist', 'package.json'));
expect(functionArgs[0]).toBe(join('dist', 'index.js'));
});

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

expect(packageArgs).toEqual([
'dist/dist/browser/index.html',
'dist/dist/browser/index.original.html'
join('dist', 'dist', 'browser', 'index.html'),
join('dist', 'dist', 'browser', 'index.original.html')
]);
});

Expand Down
4 changes: 3 additions & 1 deletion src/schematics/ng-add.jasmine.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Tree } from '@angular-devkit/schematics';
import { setupProject } from './ng-add';
import 'jasmine';
import { join } from '@angular-devkit/core';
import { join as pathJoin } from 'path';

const PROJECT_NAME = 'pie-ka-chu';
const PROJECT_ROOT = 'pirojok';
Expand Down Expand Up @@ -335,7 +337,7 @@ const projectAngularJson = `{
const universalFirebaseJson = {
hosting: [{
target: 'pie-ka-chu',
public: 'dist/dist/ikachu',
public: pathJoin('dist', 'dist', 'ikachu'),
ignore: [
'**/.*'
],
Expand Down
123 changes: 71 additions & 52 deletions tools/build.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { spawn } from 'child_process';
import { spawn } from 'cross-spawn';
import { copy, readFile, writeFile } from 'fs-extra';
import { prettySize } from 'pretty-size';
import { file as gzipSizeFile } from 'gzip-size';
Expand Down Expand Up @@ -44,7 +44,7 @@ function zoneWrapExports() {
});
const zoneWrapped = toBeExported.filter(([, , zoneWrap]) => zoneWrap);
const rawExport = toBeExported.filter(([, , zoneWrap]) => !zoneWrap);
await writeFile(`./src/${module}/${name}.ts`, `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
await writeFile(join(process.cwd(), 'src', `${module}/${name}.ts`), `// DO NOT MODIFY, this file is autogenerated by tools/build.ts
${path.startsWith('firebase/') ? `export * from '${path}';\n` : ''}${
zoneWrapped.length > 0 ? `import { ɵzoneWrap } from '@angular/fire';
import {
Expand Down Expand Up @@ -109,13 +109,14 @@ ${zoneWrapped.map(([importName, exportName]) => `export const ${exportName} = ɵ
}

function webpackFirestoreProtos() {
// TODO fix on windows
return new Promise<void>((resolve, reject) => {
glob('./node_modules/@firebase/firestore/dist/src/protos/**/*.proto', {}, async (err, files) => {
if (err) { reject(err); }
const fileLoader = files.map(path =>
`require('file-loader?name=${path.replace('./node_modules/@firebase/firestore/dist/', '')}!${path.replace('./node_modules/', '../../')}');`
).join('\n');
await writeFile('./dist/packages-dist/firestore-protos.js', fileLoader);
await writeFile(dest('firestore-protos.js'), fileLoader);
resolve();
});
});
Expand All @@ -132,7 +133,7 @@ function proxyPolyfillCompat() {
};

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

async function buildDocs() {
// INVESTIGATE json to stdout rather than FS?
await Promise.all(MODULES.map(module => spawnPromise('npx', ['typedoc', `${module === 'core' ? './src' : `./src/${module}`}`, '--json', `./dist/typedocs/${module}.json`])));
const entries = await Promise.all(MODULES.map(async (module) => {
try {
// INVESTIGATE json to stdout rather than FS?
await Promise.all(
MODULES.map(module =>
spawnPromise('npx', ['typedoc',
`${module === 'core' ?
join(process.cwd(), 'src') :
join(process.cwd(), 'src', module)}`,
'--json',
join(process.cwd(), 'dist', 'typedocs', `${module}.json`)
])));
const entries = await Promise.all(MODULES.map(async (module) => {

const buffer = await readFile(`./dist/typedocs/${module}.json`);
const typedoc = JSON.parse(buffer.toString());
if (!typedoc.children) {
console.error('typedoc fail', module);
}
// TODO infer the entryPoint from the package.json
const entryPoint = typedoc.children.find((c: any) => c.name === '"public_api"');
const allChildren = [].concat(...typedoc.children.map(child =>
// TODO chop out the working directory and filename
child.children ? child.children.map(c => ({ ...c, path: dirname(child.originalName.split(process.cwd())[1]) })) : []
));
return (entryPoint.children || [])
.filter(c => c.name[0] !== 'ɵ' && c.name[0] !== '_' /* private */)
.map(child => ({ ...allChildren.find(c => child.target === c.id) }))
.reduce((acc, child) => ({ ...acc, [encodeURIComponent(child.name)]: child }), {});
}));
const root = await rootPackage;
const pipes = ['MonoTypeOperatorFunction', 'OperatorFunction', 'AuthPipe', 'UnaryFunction'];
const tocType = child => {
const decorators: string[] = child.decorators && child.decorators.map(d => d.name) || [];
if (decorators.includes('NgModule')) {
return 'NgModule';
} else if (child.kindString === 'Type alias') {
return 'Type alias';
} else if (child.kindString === 'Variable' && child.defaultValue && child.defaultValue.startsWith('new InjectionToken')) {
return 'InjectionToken';
} else if (child.type) {
return pipes.includes(child.type.name) ? 'Pipe' : child.type.name;
} else if (child.signatures && child.signatures[0] && child.signatures[0].type && pipes.includes(child.signatures[0].type.name)) {
return 'Pipe';
} else {
return child.kindString;
}
};
const tableOfContents = entries.reduce((acc, entry, index) =>
({
...acc, [MODULES[index]]: {
name: ENTRY_NAMES[index],
exports: Object.keys(entry).reduce((acc, key) => ({ ...acc, [key]: tocType(entry[key]) }), {})
}
}),
{}
);
const afdoc = entries.reduce((acc, entry, index) => ({ ...acc, [MODULES[index]]: entry }), { table_of_contents: tableOfContents });
return writeFile(`./api-${root.version}.json`, JSON.stringify(afdoc, null, 2));
const buffer = await readFile(join(process.cwd(), 'dist', 'typedocs', `${module}.json`));
const typedoc = JSON.parse(buffer.toString());
if (!typedoc.children) {
console.error('typedoc fail', module);
}
// TODO infer the entryPoint from the package.json
const entryPoint = typedoc.children.find((c: any) => c.name === '"public_api"');
const allChildren = [].concat(...typedoc.children.map(child =>
// TODO chop out the working directory and filename
child.children ?
child.children.map(c => {
return { ...c, path: dirname(child.originalName.split(process.cwd())[1]) };
}) :
[]
));
return (entryPoint.children || [])
.filter(c => c.name[0] !== 'ɵ' && c.name[0] !== '_' /* private */)
.map(child => ({ ...allChildren.find(c => child.target === c.id) }))
.reduce((acc, child) => ({ ...acc, [encodeURIComponent(child.name)]: child }), {});
}));
const root = await rootPackage;
const pipes = ['MonoTypeOperatorFunction', 'OperatorFunction', 'AuthPipe', 'UnaryFunction'];
const tocType = child => {
const decorators: string[] = child.decorators && child.decorators.map(d => d.name) || [];
if (decorators.includes('NgModule')) {
return 'NgModule';
} else if (child.kindString === 'Type alias') {
return 'Type alias';
} else if (child.kindString === 'Variable' && child.defaultValue && child.defaultValue.startsWith('new InjectionToken')) {
return 'InjectionToken';
} else if (child.type) {
return pipes.includes(child.type.name) ? 'Pipe' : child.type.name;
} else if (child.signatures && child.signatures[0] && child.signatures[0].type && pipes.includes(child.signatures[0].type.name)) {
return 'Pipe';
} else {
return child.kindString;
}
};
const tableOfContents = entries.reduce((acc, entry, index) =>
({
...acc, [MODULES[index]]: {
name: ENTRY_NAMES[index],
exports: Object.keys(entry).reduce((acc, key) => ({ ...acc, [key]: tocType(entry[key]) }), {})
}
}),
{}
);
const afdoc = entries.reduce((acc, entry, index) => ({ ...acc, [MODULES[index]]: entry }), { table_of_contents: tableOfContents });
return writeFile(join(process.cwd(), `api-${root.version}.json`), JSON.stringify(afdoc, null, 2));
} catch (e) {
console.warn(e);
return Promise.resolve();
}
}

Promise.all([
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4977,7 +4977,7 @@ cross-spawn@^6.0.0, cross-spawn@^6.0.5:
shebang-command "^1.2.0"
which "^1.2.9"

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

0 comments on commit 2788980

Please sign in to comment.