mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-04-20 15:36:16 -04:00
restructure: move bin/ and tests/ to src/
Also add symlinks from the old `bin/` and `tests/` locations to avoid breaking scripts and other tools. Motivations: * Scripts and tests no longer have to do dubious things like: require('ep_etherpad-lite/node_modules/foo') to access packages installed as dependencies in `src/package.json`. * Plugins can access the backend test helper library in a non-hacky way: require('ep_etherpad-lite/tests/backend/common') * We can delete the top-level `package.json` without breaking our ability to lint the files in `bin/` and `tests/`. Deleting the top-level `package.json` has downsides: It will cause `npm` to print warnings whenever plugins are installed, npm will no longer be able to enforce a plugin's peer dependency on ep_etherpad-lite, and npm will keep deleting the `node_modules/ep_etherpad-lite` symlink that points to `../src`. But there are significant upsides to deleting the top-level `package.json`: It will drastically speed up plugin installation because `npm` doesn't have to recursively walk the dependencies in `src/package.json`. Also, deleting the top-level `package.json` avoids npm's horrible dependency hoisting behavior (where it moves stuff from `src/node_modules/` to the top-level `node_modules/` directory). Dependency hoisting causes numerous mysterious problems such as silent failures in `npm outdated` and `npm update`. Dependency hoisting also breaks plugins that do: require('ep_etherpad-lite/node_modules/foo')
This commit is contained in:
parent
efde0b787a
commit
2ea8ea1275
146 changed files with 191 additions and 1161 deletions
476
src/bin/plugins/checkPlugin.js
Executable file
476
src/bin/plugins/checkPlugin.js
Executable file
|
@ -0,0 +1,476 @@
|
|||
'use strict';
|
||||
|
||||
/*
|
||||
* Usage -- see README.md
|
||||
*
|
||||
* Normal usage: node bin/plugins/checkPlugin.js ep_whatever
|
||||
* Auto fix the things it can: node bin/plugins/checkPlugin.js ep_whatever autofix
|
||||
* Auto commit, push and publish to npm (highly dangerous):
|
||||
* node bin/plugins/checkPlugin.js ep_whatever autocommit
|
||||
*/
|
||||
|
||||
// As of v14, Node.js does not exit when there is an unhandled Promise rejection. Convert an
|
||||
// unhandled rejection into an uncaught exception, which does cause Node.js to exit.
|
||||
process.on('unhandledRejection', (err) => { throw err; });
|
||||
|
||||
const fs = require('fs');
|
||||
const childProcess = require('child_process');
|
||||
|
||||
// get plugin name & path from user input
|
||||
const pluginName = process.argv[2];
|
||||
|
||||
if (!pluginName) throw new Error('no plugin name specified');
|
||||
|
||||
const pluginPath = `node_modules/${pluginName}`;
|
||||
|
||||
console.log(`Checking the plugin: ${pluginName}`);
|
||||
|
||||
const optArgs = process.argv.slice(3);
|
||||
const autoCommit = optArgs.indexOf('autocommit') !== -1;
|
||||
const autoFix = autoCommit || optArgs.indexOf('autofix') !== -1;
|
||||
|
||||
const execSync = (cmd, opts = {}) => (childProcess.execSync(cmd, {
|
||||
cwd: `${pluginPath}/`,
|
||||
...opts,
|
||||
}) || '').toString().replace(/\n+$/, '');
|
||||
|
||||
const writePackageJson = (obj) => {
|
||||
let s = JSON.stringify(obj, null, 2);
|
||||
if (s.length && s.slice(s.length - 1) !== '\n') s += '\n';
|
||||
return fs.writeFileSync(`${pluginPath}/package.json`, s);
|
||||
};
|
||||
|
||||
const updateDeps = (parsedPackageJson, key, wantDeps) => {
|
||||
const {[key]: deps = {}} = parsedPackageJson;
|
||||
let changed = false;
|
||||
for (const [pkg, verInfo] of Object.entries(wantDeps)) {
|
||||
const {ver, overwrite = true} = typeof verInfo === 'string' ? {ver: verInfo} : verInfo;
|
||||
if (deps[pkg] === ver) continue;
|
||||
if (deps[pkg] == null) {
|
||||
console.warn(`Missing dependency in ${key}: '${pkg}': '${ver}'`);
|
||||
} else {
|
||||
if (!overwrite) continue;
|
||||
console.warn(`Dependency mismatch in ${key}: '${pkg}': '${ver}' (current: ${deps[pkg]})`);
|
||||
}
|
||||
if (autoFix) {
|
||||
deps[pkg] = ver;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
parsedPackageJson[key] = deps;
|
||||
writePackageJson(parsedPackageJson);
|
||||
}
|
||||
};
|
||||
|
||||
const prepareRepo = () => {
|
||||
let branch = execSync('git symbolic-ref HEAD');
|
||||
if (branch !== 'refs/heads/master' && branch !== 'refs/heads/main') {
|
||||
throw new Error('master/main must be checked out');
|
||||
}
|
||||
branch = branch.replace(/^refs\/heads\//, '');
|
||||
execSync('git rev-parse --verify -q HEAD^0 || ' +
|
||||
`{ echo "Error: no commits on ${branch}" >&2; exit 1; }`);
|
||||
execSync('git rev-parse --verify @{u}'); // Make sure there's a remote tracking branch.
|
||||
const modified = execSync('git diff-files --name-status');
|
||||
if (modified !== '') throw new Error(`working directory has modifications:\n${modified}`);
|
||||
const untracked = execSync('git ls-files -o --exclude-standard');
|
||||
if (untracked !== '') throw new Error(`working directory has untracked files:\n${untracked}`);
|
||||
const indexStatus = execSync('git diff-index --cached --name-status HEAD');
|
||||
if (indexStatus !== '') throw new Error(`uncommitted staged changes to files:\n${indexStatus}`);
|
||||
execSync('git pull --ff-only', {stdio: 'inherit'});
|
||||
if (execSync('git rev-list @{u}...') !== '') throw new Error('repo contains unpushed commits');
|
||||
if (autoCommit) {
|
||||
execSync('git config --get user.name');
|
||||
execSync('git config --get user.email');
|
||||
}
|
||||
};
|
||||
|
||||
if (autoCommit) {
|
||||
console.warn('Auto commit is enabled, I hope you know what you are doing...');
|
||||
}
|
||||
|
||||
fs.readdir(pluginPath, (err, rootFiles) => {
|
||||
// handling error
|
||||
if (err) {
|
||||
return console.log(`Unable to scan directory: ${err}`);
|
||||
}
|
||||
|
||||
// rewriting files to lower case
|
||||
const files = [];
|
||||
|
||||
// some files we need to know the actual file name. Not compulsory but might help in the future.
|
||||
let readMeFileName;
|
||||
let repository;
|
||||
|
||||
for (let i = 0; i < rootFiles.length; i++) {
|
||||
if (rootFiles[i].toLowerCase().indexOf('readme') !== -1) readMeFileName = rootFiles[i];
|
||||
files.push(rootFiles[i].toLowerCase());
|
||||
}
|
||||
|
||||
if (files.indexOf('.git') === -1) throw new Error('No .git folder, aborting');
|
||||
prepareRepo();
|
||||
|
||||
try {
|
||||
const path = `${pluginPath}/.github/workflows/npmpublish.yml`;
|
||||
if (!fs.existsSync(path)) {
|
||||
console.log('no .github/workflows/npmpublish.yml');
|
||||
console.log('create one and set npm secret to auto publish to npm on commit');
|
||||
if (autoFix) {
|
||||
const npmpublish =
|
||||
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||
fs.writeFileSync(path, npmpublish);
|
||||
console.log("If you haven't already, setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo");
|
||||
} else {
|
||||
console.log('Setup autopublish for this plugin https://github.com/ether/etherpad-lite/wiki/Plugins:-Automatically-publishing-to-npm-on-commit-to-Github-Repo');
|
||||
}
|
||||
} else {
|
||||
// autopublish exists, we should check the version..
|
||||
// checkVersion takes two file paths and checks for a version string in them.
|
||||
const currVersionFile = fs.readFileSync(path, {encoding: 'utf8', flag: 'r'});
|
||||
const existingConfigLocation = currVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||
const existingValue = parseInt(
|
||||
currVersionFile.substr(existingConfigLocation + 17, existingConfigLocation.length));
|
||||
|
||||
const reqVersionFile =
|
||||
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||
const reqConfigLocation = reqVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||
const reqValue =
|
||||
parseInt(reqVersionFile.substr(reqConfigLocation + 17, reqConfigLocation.length));
|
||||
|
||||
if (!existingValue || (reqValue > existingValue)) {
|
||||
const npmpublish =
|
||||
fs.readFileSync('bin/plugins/lib/npmpublish.yml', {encoding: 'utf8', flag: 'r'});
|
||||
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||
fs.writeFileSync(path, npmpublish);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
const path = `${pluginPath}/.github/workflows/backend-tests.yml`;
|
||||
if (!fs.existsSync(path)) {
|
||||
console.log('no .github/workflows/backend-tests.yml');
|
||||
console.log('create one and set npm secret to auto publish to npm on commit');
|
||||
if (autoFix) {
|
||||
const backendTests =
|
||||
fs.readFileSync('bin/plugins/lib/backend-tests.yml', {encoding: 'utf8', flag: 'r'});
|
||||
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||
fs.writeFileSync(path, backendTests);
|
||||
}
|
||||
} else {
|
||||
// autopublish exists, we should check the version..
|
||||
// checkVersion takes two file paths and checks for a version string in them.
|
||||
const currVersionFile = fs.readFileSync(path, {encoding: 'utf8', flag: 'r'});
|
||||
const existingConfigLocation = currVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||
const existingValue = parseInt(
|
||||
currVersionFile.substr(existingConfigLocation + 17, existingConfigLocation.length));
|
||||
|
||||
const reqVersionFile =
|
||||
fs.readFileSync('bin/plugins/lib/backend-tests.yml', {encoding: 'utf8', flag: 'r'});
|
||||
const reqConfigLocation = reqVersionFile.indexOf('##ETHERPAD_NPM_V=');
|
||||
const reqValue =
|
||||
parseInt(reqVersionFile.substr(reqConfigLocation + 17, reqConfigLocation.length));
|
||||
|
||||
if (!existingValue || (reqValue > existingValue)) {
|
||||
const backendTests =
|
||||
fs.readFileSync('bin/plugins/lib/backend-tests.yml', {encoding: 'utf8', flag: 'r'});
|
||||
fs.mkdirSync(`${pluginPath}/.github/workflows`, {recursive: true});
|
||||
fs.writeFileSync(path, backendTests);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
|
||||
if (files.indexOf('package.json') === -1) {
|
||||
console.warn('no package.json, please create');
|
||||
}
|
||||
|
||||
if (files.indexOf('package.json') !== -1) {
|
||||
const packageJSON =
|
||||
fs.readFileSync(`${pluginPath}/package.json`, {encoding: 'utf8', flag: 'r'});
|
||||
const parsedPackageJSON = JSON.parse(packageJSON);
|
||||
if (autoFix) {
|
||||
let updatedPackageJSON = false;
|
||||
if (!parsedPackageJSON.funding) {
|
||||
updatedPackageJSON = true;
|
||||
parsedPackageJSON.funding = {
|
||||
type: 'individual',
|
||||
url: 'https://etherpad.org/',
|
||||
};
|
||||
}
|
||||
if (updatedPackageJSON) {
|
||||
writePackageJson(parsedPackageJSON);
|
||||
}
|
||||
}
|
||||
|
||||
if (packageJSON.toLowerCase().indexOf('repository') === -1) {
|
||||
console.warn('No repository in package.json');
|
||||
if (autoFix) {
|
||||
console.warn('Repository not detected in package.json. Add repository section.');
|
||||
}
|
||||
} else {
|
||||
// useful for creating README later.
|
||||
repository = parsedPackageJSON.repository.url;
|
||||
}
|
||||
|
||||
updateDeps(parsedPackageJSON, 'devDependencies', {
|
||||
'eslint': '^7.18.0',
|
||||
'eslint-config-etherpad': '^1.0.24',
|
||||
'eslint-plugin-eslint-comments': '^3.2.0',
|
||||
'eslint-plugin-mocha': '^8.0.0',
|
||||
'eslint-plugin-node': '^11.1.0',
|
||||
'eslint-plugin-prefer-arrow': '^1.2.3',
|
||||
'eslint-plugin-promise': '^4.2.1',
|
||||
'eslint-plugin-you-dont-need-lodash-underscore': '^6.10.0',
|
||||
});
|
||||
|
||||
updateDeps(parsedPackageJSON, 'peerDependencies', {
|
||||
// Some plugins require a newer version of Etherpad so don't overwrite if already set.
|
||||
'ep_etherpad-lite': {ver: '>=1.8.6', overwrite: false},
|
||||
});
|
||||
|
||||
if (packageJSON.toLowerCase().indexOf('eslintconfig') === -1) {
|
||||
console.warn('No esLintConfig in package.json');
|
||||
if (autoFix) {
|
||||
const eslintConfig = {
|
||||
root: true,
|
||||
extends: 'etherpad/plugin',
|
||||
};
|
||||
parsedPackageJSON.eslintConfig = eslintConfig;
|
||||
writePackageJson(parsedPackageJSON);
|
||||
}
|
||||
}
|
||||
|
||||
if (packageJSON.toLowerCase().indexOf('scripts') === -1) {
|
||||
console.warn('No scripts in package.json');
|
||||
if (autoFix) {
|
||||
const scripts = {
|
||||
'lint': 'eslint .',
|
||||
'lint:fix': 'eslint --fix .',
|
||||
};
|
||||
parsedPackageJSON.scripts = scripts;
|
||||
writePackageJson(parsedPackageJSON);
|
||||
}
|
||||
}
|
||||
|
||||
if ((packageJSON.toLowerCase().indexOf('engines') === -1) || !parsedPackageJSON.engines.node) {
|
||||
console.warn('No engines or node engine in package.json');
|
||||
if (autoFix) {
|
||||
const engines = {
|
||||
node: '^10.17.0 || >=11.14.0',
|
||||
};
|
||||
parsedPackageJSON.engines = engines;
|
||||
writePackageJson(parsedPackageJSON);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('package-lock.json') === -1) {
|
||||
console.warn('package-lock.json not found');
|
||||
if (!autoFix) {
|
||||
console.warn('Run npm install in the plugin folder and commit the package-lock.json file.');
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('readme') === -1 && files.indexOf('readme.md') === -1) {
|
||||
console.warn('README.md file not found, please create');
|
||||
if (autoFix) {
|
||||
console.log('Autofixing missing README.md file');
|
||||
console.log('please edit the README.md file further to include plugin specific details.');
|
||||
let readme = fs.readFileSync('bin/plugins/lib/README.md', {encoding: 'utf8', flag: 'r'});
|
||||
readme = readme.replace(/\[plugin_name\]/g, pluginName);
|
||||
if (repository) {
|
||||
const org = repository.split('/')[3];
|
||||
const name = repository.split('/')[4];
|
||||
readme = readme.replace(/\[org_name\]/g, org);
|
||||
readme = readme.replace(/\[repo_url\]/g, name);
|
||||
fs.writeFileSync(`${pluginPath}/README.md`, readme);
|
||||
} else {
|
||||
console.warn('Unable to find repository in package.json, aborting.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('contributing') === -1 && files.indexOf('contributing.md') === -1) {
|
||||
console.warn('CONTRIBUTING.md file not found, please create');
|
||||
if (autoFix) {
|
||||
console.log('Autofixing missing CONTRIBUTING.md file, please edit the CONTRIBUTING.md ' +
|
||||
'file further to include plugin specific details.');
|
||||
let contributing =
|
||||
fs.readFileSync('bin/plugins/lib/CONTRIBUTING.md', {encoding: 'utf8', flag: 'r'});
|
||||
contributing = contributing.replace(/\[plugin_name\]/g, pluginName);
|
||||
fs.writeFileSync(`${pluginPath}/CONTRIBUTING.md`, contributing);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (files.indexOf('readme') !== -1 && files.indexOf('readme.md') !== -1) {
|
||||
const readme =
|
||||
fs.readFileSync(`${pluginPath}/${readMeFileName}`, {encoding: 'utf8', flag: 'r'});
|
||||
if (readme.toLowerCase().indexOf('license') === -1) {
|
||||
console.warn('No license section in README');
|
||||
if (autoFix) {
|
||||
console.warn('Please add License section to README manually.');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('license') === -1 && files.indexOf('license.md') === -1) {
|
||||
console.warn('LICENSE.md file not found, please create');
|
||||
if (autoFix) {
|
||||
console.log('Autofixing missing LICENSE.md file, including Apache 2 license.');
|
||||
let license = fs.readFileSync('bin/plugins/lib/LICENSE.md', {encoding: 'utf8', flag: 'r'});
|
||||
license = license.replace('[yyyy]', new Date().getFullYear());
|
||||
license = license.replace('[name of copyright owner]', execSync('git config user.name'));
|
||||
fs.writeFileSync(`${pluginPath}/LICENSE.md`, license);
|
||||
}
|
||||
}
|
||||
|
||||
let travisConfig = fs.readFileSync('bin/plugins/lib/travis.yml', {encoding: 'utf8', flag: 'r'});
|
||||
travisConfig = travisConfig.replace(/\[plugin_name\]/g, pluginName);
|
||||
|
||||
if (files.indexOf('.travis.yml') === -1) {
|
||||
console.warn('.travis.yml file not found, please create. ' +
|
||||
'.travis.yml is used for automatically CI testing Etherpad. ' +
|
||||
'It is useful to know if your plugin breaks another feature for example.');
|
||||
// TODO: Make it check version of the .travis file to see if it needs an update.
|
||||
if (autoFix) {
|
||||
console.log('Autofixing missing .travis.yml file');
|
||||
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||
console.log('Travis file created, please sign into travis and enable this repository');
|
||||
}
|
||||
}
|
||||
if (autoFix) {
|
||||
// checks the file versioning of .travis and updates it to the latest.
|
||||
const existingConfig =
|
||||
fs.readFileSync(`${pluginPath}/.travis.yml`, {encoding: 'utf8', flag: 'r'});
|
||||
const existingConfigLocation = existingConfig.indexOf('##ETHERPAD_TRAVIS_V=');
|
||||
const existingValue =
|
||||
parseInt(existingConfig.substr(existingConfigLocation + 20, existingConfig.length));
|
||||
|
||||
const newConfigLocation = travisConfig.indexOf('##ETHERPAD_TRAVIS_V=');
|
||||
const newValue = parseInt(travisConfig.substr(newConfigLocation + 20, travisConfig.length));
|
||||
if (existingConfigLocation === -1) {
|
||||
console.warn('no previous .travis.yml version found so writing new.');
|
||||
// we will write the newTravisConfig to the location.
|
||||
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||
} else if (newValue > existingValue) {
|
||||
console.log('updating .travis.yml');
|
||||
fs.writeFileSync(`${pluginPath}/.travis.yml`, travisConfig);
|
||||
}//
|
||||
}
|
||||
|
||||
if (files.indexOf('.gitignore') === -1) {
|
||||
console.warn('.gitignore file not found, please create. .gitignore files are useful to ' +
|
||||
"ensure files aren't incorrectly commited to a repository.");
|
||||
if (autoFix) {
|
||||
console.log('Autofixing missing .gitignore file');
|
||||
const gitignore = fs.readFileSync('bin/plugins/lib/gitignore', {encoding: 'utf8', flag: 'r'});
|
||||
fs.writeFileSync(`${pluginPath}/.gitignore`, gitignore);
|
||||
}
|
||||
} else {
|
||||
let gitignore =
|
||||
fs.readFileSync(`${pluginPath}/.gitignore`, {encoding: 'utf8', flag: 'r'});
|
||||
if (gitignore.indexOf('node_modules/') === -1) {
|
||||
console.warn('node_modules/ missing from .gitignore');
|
||||
if (autoFix) {
|
||||
gitignore += 'node_modules/';
|
||||
fs.writeFileSync(`${pluginPath}/.gitignore`, gitignore);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we include templates but don't have translations...
|
||||
if (files.indexOf('templates') !== -1 && files.indexOf('locales') === -1) {
|
||||
console.warn('Translations not found, please create. ' +
|
||||
'Translation files help with Etherpad accessibility.');
|
||||
}
|
||||
|
||||
|
||||
if (files.indexOf('.ep_initialized') !== -1) {
|
||||
console.warn(
|
||||
'.ep_initialized found, please remove. .ep_initialized should never be commited to git ' +
|
||||
'and should only exist once the plugin has been executed one time.');
|
||||
if (autoFix) {
|
||||
console.log('Autofixing incorrectly existing .ep_initialized file');
|
||||
fs.unlinkSync(`${pluginPath}/.ep_initialized`);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('npm-debug.log') !== -1) {
|
||||
console.warn('npm-debug.log found, please remove. npm-debug.log should never be commited to ' +
|
||||
'your repository.');
|
||||
if (autoFix) {
|
||||
console.log('Autofixing incorrectly existing npm-debug.log file');
|
||||
fs.unlinkSync(`${pluginPath}/npm-debug.log`);
|
||||
}
|
||||
}
|
||||
|
||||
if (files.indexOf('static') !== -1) {
|
||||
fs.readdir(`${pluginPath}/static`, (errRead, staticFiles) => {
|
||||
if (staticFiles.indexOf('tests') === -1) {
|
||||
console.warn('Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.warn('Test files not found, please create tests. https://github.com/ether/etherpad-lite/wiki/Creating-a-plugin#writing-and-running-front-end-tests-for-your-plugin');
|
||||
}
|
||||
|
||||
// Install dependencies so we can run ESLint. This should also create or update package-lock.json
|
||||
// if autoFix is enabled.
|
||||
const npmInstall = `npm install${autoFix ? '' : ' --no-package-lock'}`;
|
||||
execSync(npmInstall, {stdio: 'inherit'});
|
||||
// The ep_etherpad-lite peer dep must be installed last otherwise `npm install` will nuke it. An
|
||||
// absolute path to etherpad-lite/src is used here so that pluginPath can be a symlink.
|
||||
execSync(
|
||||
`${npmInstall} --no-save ep_etherpad-lite@file:${__dirname}/../../`, {stdio: 'inherit'});
|
||||
|
||||
// linting begins
|
||||
try {
|
||||
console.log('Linting...');
|
||||
const lintCmd = autoFix ? 'npx eslint --fix .' : 'npx eslint';
|
||||
execSync(lintCmd, {stdio: 'inherit'});
|
||||
} catch (e) {
|
||||
// it is gonna throw an error anyway
|
||||
console.log('Manual linting probably required, check with: npm run lint');
|
||||
}
|
||||
// linting ends.
|
||||
|
||||
if (autoFix) {
|
||||
const unchanged = JSON.parse(execSync(
|
||||
'untracked=$(git ls-files -o --exclude-standard) || exit 1; ' +
|
||||
'git diff-files --quiet && [ -z "$untracked" ] && echo true || echo false'));
|
||||
if (!unchanged) {
|
||||
// Display a diff of changes. Git doesn't diff untracked files, so they must be added to the
|
||||
// index. Use a temporary index file to avoid modifying Git's default index file.
|
||||
execSync('git read-tree HEAD; git add -A && git diff-index -p --cached HEAD && echo ""', {
|
||||
env: {...process.env, GIT_INDEX_FILE: '.git/checkPlugin.index'},
|
||||
stdio: 'inherit',
|
||||
});
|
||||
fs.unlinkSync(`${pluginPath}/.git/checkPlugin.index`);
|
||||
|
||||
const cmd = [
|
||||
'git add -A',
|
||||
'git commit -m "autofixes from Etherpad checkPlugin.js"',
|
||||
'git push',
|
||||
].join(' && ');
|
||||
if (autoCommit) {
|
||||
console.log('Attempting autocommit and auto publish to npm');
|
||||
execSync(cmd, {stdio: 'inherit'});
|
||||
} else {
|
||||
console.log('Fixes applied. Check the above git diff then run the following command:');
|
||||
console.log(`(cd node_modules/${pluginName} && ${cmd})`);
|
||||
}
|
||||
} else {
|
||||
console.log('No changes.');
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Finished');
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue