Files
azuredatastudio/build/hygiene.js
Karl Burtram 8a3d08f0de Merge vscode 1.67 (#20883)
* Fix initial build breaks from 1.67 merge (#2514)

* Update yarn lock files

* Update build scripts

* Fix tsconfig

* Build breaks

* WIP

* Update yarn lock files

* Misc breaks

* Updates to package.json

* Breaks

* Update yarn

* Fix breaks

* Breaks

* Build breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Missing file

* Breaks

* Breaks

* Breaks

* Breaks

* Breaks

* Fix several runtime breaks (#2515)

* Missing files

* Runtime breaks

* Fix proxy ordering issue

* Remove commented code

* Fix breaks with opening query editor

* Fix post merge break

* Updates related to setup build and other breaks (#2516)

* Fix bundle build issues

* Update distro

* Fix distro merge and update build JS files

* Disable pipeline steps

* Remove stats call

* Update license name

* Make new RPM dependencies a warning

* Fix extension manager version checks

* Update JS file

* Fix a few runtime breaks

* Fixes

* Fix runtime issues

* Fix build breaks

* Update notebook tests (part 1)

* Fix broken tests

* Linting errors

* Fix hygiene

* Disable lint rules

* Bump distro

* Turn off smoke tests

* Disable integration tests

* Remove failing "activate" test

* Remove failed test assertion

* Disable other broken test

* Disable query history tests

* Disable extension unit tests

* Disable failing tasks
2022-10-19 19:13:18 -07:00

309 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
const filter = require('gulp-filter');
const es = require('event-stream');
const VinylFile = require('vinyl');
const vfs = require('vinyl-fs');
const path = require('path');
const fs = require('fs');
const pall = require('p-all');
const { all, copyrightFilter, unicodeFilter, indentationFilter, tsFormattingFilter, eslintFilter } = require('./filters');
const copyrightHeaderLines = [
'/*---------------------------------------------------------------------------------------------',
' * Copyright (c) Microsoft Corporation. All rights reserved.',
' * Licensed under the Source EULA. See License.txt in the project root for license information.',
' *--------------------------------------------------------------------------------------------*/',
];
function hygiene(some, linting = true) {
const gulpeslint = require('gulp-eslint');
const tsfmt = require('typescript-formatter');
let errorCount = 0;
const productJson = es.through(function (file) {
// const product = JSON.parse(file.contents.toString('utf8'));
// if (product.extensionsGallery) { // {{SQL CARBON EDIT}} @todo we need to research on what the point of this is
// console.error('product.json: Contains "extensionsGallery"');
// errorCount++;
// }
this.emit('data', file);
});
const unicode = es.through(function (file) {
const lines = file.contents.toString('utf8').split(/\r\n|\r|\n/);
file.__lines = lines;
let skipNext = false;
lines.forEach((line, i) => {
if (/allow-any-unicode-next-line/.test(line)) {
skipNext = true;
return;
}
if (skipNext) {
skipNext = false;
return;
}
// Please do not add symbols that resemble ASCII letters!
const m = /([^\t\n\r\x20-\x7E⊃⊇✔✓🎯⚠🛑🔴🚗🚙🚕🎉✨❗⇧⌥⌘×÷¦⋯…↑↓→→←↔⟷·•●◆▼⟪⟫┌└├⏎↩√φ]+)/g.exec(line);
if (m) {
console.error(
file.relative + `(${i + 1},${m.index + 1}): Unexpected unicode character: "${m[0]}". To suppress, use // allow-any-unicode-next-line`
);
errorCount++;
}
});
this.emit('data', file);
});
const indentation = es.through(function (file) {
const lines = file.__lines || file.contents.toString('utf8').split(/\r\n|\r|\n/);
file.__lines = lines;
lines.forEach((line, i) => {
if (/^\s*$/.test(line)) {
// empty or whitespace lines are OK
} else if (/^[\t]*[^\s]/.test(line)) {
// good indent
} else if (/^[\t]* \*/.test(line)) {
// block comment using an extra space
} else {
console.error(
file.relative + '(' + (i + 1) + ',1): Bad whitespace indentation'
);
errorCount++;
}
});
this.emit('data', file);
});
const copyrights = es.through(function (file) {
const lines = file.__lines;
for (let i = 0; i < copyrightHeaderLines.length; i++) {
if (lines[i] !== copyrightHeaderLines[i]) {
//console.error(file.relative + ': Missing or bad copyright statement');
//errorCount++;
break;
}
}
this.emit('data', file);
});
const formatting = es.map(function (file, cb) {
tsfmt
.processString(file.path, file.contents.toString('utf8'), {
verify: false,
tsfmt: true,
// verbose: true,
// keep checkJS happy
editorconfig: undefined,
replace: undefined,
tsconfig: undefined,
tsconfigFile: undefined,
tsfmtFile: undefined,
vscode: undefined,
vscodeFile: undefined,
})
.then(
(result) => {
let original = result.src.replace(/\r\n/gm, '\n');
let formatted = result.dest.replace(/\r\n/gm, '\n');
if (original !== formatted) {
console.error(
`File not formatted. Run the 'Format Document' command to fix it:`,
file.relative
);
errorCount++;
}
cb(null, file);
},
(err) => {
cb(err);
}
);
});
let input;
if (Array.isArray(some) || typeof some === 'string' || !some) {
const options = { base: '.', follow: true, allowEmpty: true };
if (some) {
input = vfs.src(some, options).pipe(filter(all)); // split this up to not unnecessarily filter all a second time
} else {
input = vfs.src(all, options);
}
} else {
input = some;
}
const productJsonFilter = filter('product.json', { restore: true });
const unicodeFilterStream = filter(unicodeFilter, { restore: true });
const result = input
.pipe(filter((f) => !f.stat.isDirectory()))
.pipe(productJsonFilter)
.pipe(process.env['BUILD_SOURCEVERSION'] ? es.through() : productJson)
.pipe(productJsonFilter.restore)
.pipe(filter(indentationFilter))
.pipe(indentation)
.pipe(unicodeFilterStream)
.pipe(unicode)
.pipe(unicodeFilterStream.restore)
.pipe(filter(copyrightFilter))
.pipe(copyrights);
const streams = [
result.pipe(filter(tsFormattingFilter)).pipe(formatting)
];
if (linting) {
streams.push(
result
.pipe(filter(eslintFilter))
.pipe(
gulpeslint({
configFile: '.eslintrc.json',
rulePaths: ['./build/lib/eslint'],
})
)
.pipe(gulpeslint.formatEach('compact'))
.pipe(
gulpeslint.results((results) => {
errorCount += results.warningCount;
errorCount += results.errorCount;
})
)
);
}
let count = 0;
return es.merge(...streams).pipe(
es.through(
function (data) {
count++;
if (process.env['TRAVIS'] && count % 10 === 0) {
process.stdout.write('.');
}
this.emit('data', data);
},
function () {
process.stdout.write('\n');
if (errorCount > 0) {
this.emit(
'error',
'Hygiene failed with ' +
errorCount +
` errors. Check 'build / gulpfile.hygiene.js'.`
);
} else {
this.emit('end');
}
}
)
);
}
module.exports.hygiene = hygiene;
function createGitIndexVinyls(paths) {
const cp = require('child_process');
const repositoryPath = process.cwd();
const fns = paths.map((relativePath) => () =>
new Promise((c, e) => {
const fullPath = path.join(repositoryPath, relativePath);
fs.stat(fullPath, (err, stat) => {
if (err && err.code === 'ENOENT') {
// ignore deletions
return c(null);
} else if (err) {
return e(err);
}
cp.exec(
process.platform === 'win32' ? `git show :${relativePath}` : `git show ':${relativePath}'`,
{ maxBuffer: 2000 * 1024, encoding: 'buffer' },
(err, out) => {
if (err) {
return e(err);
}
c(
new VinylFile({
path: fullPath,
base: repositoryPath,
contents: out,
stat,
})
);
}
);
});
})
);
return pall(fns, { concurrency: 4 }).then((r) => r.filter((p) => !!p));
}
// this allows us to run hygiene as a git pre-commit hook
if (require.main === module) {
const cp = require('child_process');
process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
process.exit(1);
});
if (process.argv.length > 2) {
hygiene(process.argv.slice(2)).on('error', (err) => {
console.error();
console.error(err);
process.exit(1);
});
} else {
cp.exec(
'git diff --cached --name-only',
{ maxBuffer: 2000 * 1024 },
(err, out) => {
if (err) {
console.error();
console.error(err);
process.exit(1);
}
const some = out.split(/\r?\n/).filter((l) => !!l);
if (some.length > 0) {
console.log('Reading git index versions...');
createGitIndexVinyls(some)
.then(
(vinyls) =>
new Promise((c, e) =>
hygiene(es.readArray(vinyls))
.on('end', () => c())
.on('error', e)
)
)
.catch((err) => {
console.error();
console.error(err);
process.exit(1);
});
}
}
);
}
}