George Kalpakas 1c385a1c22 build(docs-infra): do not include CI-specific config in docs examples ZIP archives (#36018)
In #35381, a new Protractor config file was introduced in docs examples,
`protractor-puppeteer.conf.js`, that was only supposed to be used on CI
and not be shipped with the ZIP archives provided for users to download
and experiment with the docs examples locally.

The logic to ignore the `protractor-puppeteer.conf.js` file was
incorrect, resulting in the file being retained in some examples (e.g.
[universal][1]). The problem was not immediately obvious, because most
examples explicitly specify all `**/*.js` files as ignored, but for
other examples the file was retained in the ZIP archive.

This commit fixes the logic to ensure the file is excluded from all docs
examples ZIP archives.

[1]: https://v9.angular.io/generated/zips/universal/universal.zip

PR Close #36018
2020-03-27 10:48:30 -07:00

187 lines
6.3 KiB
JavaScript

'use strict';
// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes
const path = require('canonical-path');
const archiver = require('archiver');
const fs = require('fs-extra');
const globby = require('globby');
const PackageJsonCustomizer = require('./customizer/package-json/packageJsonCustomizer');
const regionExtractor = require('../transforms/examples-package/services/region-parser');
const EXAMPLE_CONFIG_NAME = 'example-config.json';
class ExampleZipper {
constructor(sourceDirName, outputDirName) {
this.examplesPackageJson = path.join(__dirname, '../examples/shared/package.json');
this.examplesSystemjsConfig = path.join(__dirname, '../examples/shared/boilerplate/systemjs/src/systemjs.config.js');
this.examplesSystemjsLoaderConfig = path.join(__dirname, '../examples/shared/boilerplate/systemjs/src/systemjs-angular-loader.js');
this.exampleTsconfig = path.join(__dirname, '../examples/shared/boilerplate/systemjs/src/tsconfig.json');
this.customizer = new PackageJsonCustomizer();
let gpathStackblitz = path.join(sourceDirName, '**/*stackblitz.json');
let gpathZipper = path.join(sourceDirName, '**/zipper.json');
let configFileNames = globby.sync([gpathStackblitz, gpathZipper], { ignore: ['**/node_modules/**'] });
configFileNames.forEach((configFileName) => {
this._zipExample(configFileName, sourceDirName, outputDirName);
});
}
_changeTypeRoots(tsconfig) {
return tsconfig.replace('../../../', '../');
}
_createZipArchive(zipFileName) {
let dirName = path.dirname(zipFileName);
fs.ensureDirSync(dirName);
let output = fs.createWriteStream(zipFileName);
let archive = archiver('zip');
archive.on('error', function (err) {
throw err;
});
archive.pipe(output);
return archive;
}
_getExampleType(sourceFolder) {
const filePath = path.join(sourceFolder, EXAMPLE_CONFIG_NAME);
try {
return require(filePath, 'utf-8').projectType || 'cli';
} catch (err) { // empty file, so it is cli
return 'cli';
}
}
// rename a custom main.ts or index.html file
_renameFile(file, exampleType) {
if (/src\/main[-.]\w+\.ts$/.test(file) && exampleType !== 'universal') {
return 'src/main.ts';
}
if (/src\/index[-.]\w+\.html$/.test(file)) {
return 'src/index.html';
}
return file;
}
_zipExample(configFileName, sourceDirName, outputDirName) {
let json = require(configFileName, 'utf-8');
const basePath = json.basePath || '';
const jsonFileName = configFileName.replace(/^.*[\\\/]/, '');
let relativeDirName = path.dirname(path.relative(sourceDirName, configFileName));
let exampleZipName;
const exampleType = this._getExampleType(path.join(sourceDirName, relativeDirName));
if (relativeDirName.indexOf('/') !== -1) { // Special example
exampleZipName = relativeDirName.split('/').join('-');
} else {
exampleZipName = jsonFileName.replace(/(stackblitz|zipper).json/, relativeDirName);
}
const exampleDirName = path.dirname(configFileName);
const outputFileName = path.join(outputDirName, relativeDirName, exampleZipName + '.zip');
let defaultIncludes = ['**/*.ts', '**/*.js', '**/*.es6', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png', '**/*.svg'];
let alwaysIncludes = [
'.editorconfig',
'.gitignore',
'angular.json',
'browserslist',
'bs-config.json',
'karma.conf.js',
'karma-test-shim.js',
'tsconfig.*',
'tslint.*',
'e2e/protractor.conf.js',
'e2e/tsconfig.json',
'src/favicon.ico',
'src/polyfills.ts',
'src/test.ts',
'src/typings.d.ts',
'src/environments/**/*',
'src/testing/**/*',
// Only ignore root package.json
'!package.json'
];
var alwaysExcludes = [
'!**/bs-config.e2e.json',
'!**/*stackblitz.*',
'!**/*zipper.*',
'!**/systemjs.config.js',
'!**/npm-debug.log',
'!**/example-config.json',
'!**/wallaby.js',
'!**/e2e/protractor-puppeteer.conf.js',
// AOT related files
'!**/aot/**/*.*',
'!**/*-aot.*'
];
if (json.files) {
if (json.files.length > 0) {
json.files = json.files.map(file => {
if (file.startsWith('!')) {
if (file.startsWith('!**')) {
return file;
}
return '!' + basePath + file.substr(1);
}
return basePath + file;
});
if (json.files[0][0] === '!') {
json.files = defaultIncludes.concat(json.files);
}
}
} else {
json.files = defaultIncludes;
}
json.files = json.files.concat(alwaysIncludes);
let gpaths = json.files.map((fileName) => {
fileName = fileName.trim();
if (fileName[0] === '!') {
return '!' + path.join(exampleDirName, fileName.substr(1));
} else {
return path.join(exampleDirName, fileName);
}
});
gpaths.push(...alwaysExcludes);
let fileNames = globby.sync(gpaths, { ignore: ['**/node_modules/**'] });
let zip = this._createZipArchive(outputFileName);
fileNames.forEach((fileName) => {
let relativePath = path.relative(exampleDirName, fileName);
relativePath = this._renameFile(relativePath, exampleType);
let content = fs.readFileSync(fileName, 'utf8');
let extn = path.extname(fileName).substr(1);
// if we don't need to clean up the file then we can do the following.
// zip.append(fs.createReadStream(fileName), { name: relativePath });
let output = regionExtractor()(content, extn).contents;
zip.append(output, { name: relativePath } );
});
// we need the package.json from _examples root, not the _boilerplate one
zip.append(this.customizer.generate(exampleType), { name: 'package.json' });
// also a systemjs config
if (exampleType === 'systemjs') {
zip.append(fs.readFileSync(this.examplesSystemjsConfig, 'utf8'), { name: 'src/systemjs.config.js' });
zip.append(fs.readFileSync(this.examplesSystemjsLoaderConfig, 'utf8'), { name: 'src/systemjs-angular-loader.js' });
// a modified tsconfig
let tsconfig = fs.readFileSync(this.exampleTsconfig, 'utf8');
zip.append(this._changeTypeRoots(tsconfig), {name: 'src/tsconfig.json'});
}
zip.finalize();
}
}
module.exports = ExampleZipper;