puppeteer/tools/analyze_issue.mjs
2023-01-11 14:09:45 +01:00

287 lines
8.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
// @ts-check
'use strict';
import {writeFile, mkdir, copyFile} from 'fs/promises';
import {dirname, join} from 'path';
import semver from 'semver';
import {fileURLToPath} from 'url';
import {
versionsPerRelease,
lastMaintainedChromiumVersion,
} from '../versions.js';
import core from '@actions/core';
import packageJson from '../packages/puppeteer/package.json' assert {type: 'json'};
const codifyAndJoinValues = values => {
return values
.map(value => {
return `\`${value}\``;
})
.join(' ,');
};
const formatMessage = value => {
return value.trim();
};
const removeVersionPrefix = value => {
return value.startsWith('v') ? value.slice(1) : value;
};
const LAST_SUPPORTED_PUPPETEER_VERSION = removeVersionPrefix(
versionsPerRelease.get(lastMaintainedChromiumVersion) ?? ''
);
if (!LAST_SUPPORTED_PUPPETEER_VERSION) {
core.setFailed('No maintained version found.');
}
const LAST_SUPPORTED_NODE_VERSION = removeVersionPrefix(
packageJson.engines.node.slice(2).trim()
);
const SUPPORTED_OSES = ['windows', 'macos', 'linux'];
const SUPPORTED_PACKAGE_MANAGERS = ['yarn', 'npm', 'pnpm'];
const ERROR_MESSAGES = {
unsupportedOs(value) {
return formatMessage(`
This issue has an unsupported OS: \`${value}\`. Only the following operating systems are supported: ${codifyAndJoinValues(
SUPPORTED_OSES
)}. Please verify the issue on a supported OS and update the form.
`);
},
unsupportedPackageManager(value) {
return formatMessage(`
This issue has an unsupported package manager: \`${value}\`. Only the following package managers are supported: ${codifyAndJoinValues(
SUPPORTED_PACKAGE_MANAGERS
)}. Please verify the issue using a supported package manager and update the form.
`);
},
invalidPackageManagerVersion(value) {
return formatMessage(`
This issue has an invalid package manager version: \`${value}\`. Versions must follow [SemVer](https://semver.org/) formatting. Please update the form with a valid version.
`);
},
unsupportedNodeVersion(value) {
return formatMessage(`
This issue has an unsupported Node.js version: \`${value}\`. Only versions above \`v${LAST_SUPPORTED_NODE_VERSION}\` are supported. Please verify the issue on a supported version of Node.js and update the form.
`);
},
invalidNodeVersion(value) {
return formatMessage(`
This issue has an invalid Node.js version: \`${value}\`. Versions must follow [SemVer](https://semver.org/) formatting. Please update the form with a valid version.
`);
},
unsupportedPuppeteerVersion(value) {
return formatMessage(`
This issue has an unsupported Puppeteer version: \`${value}\`. Only versions above \`v${LAST_SUPPORTED_PUPPETEER_VERSION}\` are supported. Please verify the issue on a supported version of Puppeteer and update the form.
`);
},
invalidPuppeteerVersion(value) {
return formatMessage(`
This issue has an invalid Puppeteer version: \`${value}\`. Versions must follow [SemVer](https://semver.org/) formatting. Please update the form with a valid version.
`);
},
};
(async () => {
let input = '';
// @ts-expect-error: `iterator` is new and experimental.
for await (const chunk of process.stdin.iterator({
destroyOnReturn: false,
})) {
input += chunk;
}
input = JSON.parse(input).trim();
let mvce = '';
let error = '';
let configuration = '';
let puppeteerVersion = '';
let nodeVersion = '';
let packageManagerVersion = '';
let packageManager = '';
let os = '';
const behavior = {};
const lines = input.split('\n');
{
/** @type {(value: string) => void} */
let set = () => {
return void 0;
};
let j = 1;
let i = 1;
for (; i < lines.length; ++i) {
if (lines[i].startsWith('### Bug behavior')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
if (value.match(/\[x\] Flaky/i)) {
behavior.flaky = true;
}
if (value.match(/\[x\] pdf/i)) {
behavior.noError = true;
}
};
} else if (lines[i].startsWith('### Minimal, reproducible example')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
mvce = value;
};
} else if (lines[i].startsWith('### Error string')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
if (value.match(/no error/i)) {
behavior.noError = true;
} else {
error = value;
}
};
} else if (lines[i].startsWith('### Puppeteer configuration')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
configuration = value;
};
} else if (lines[i].startsWith('### Puppeteer version')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
puppeteerVersion = removeVersionPrefix(value);
};
} else if (lines[i].startsWith('### Node version')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
nodeVersion = removeVersionPrefix(value);
};
} else if (lines[i].startsWith('### Package manager version')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
packageManagerVersion = removeVersionPrefix(value);
};
} else if (lines[i].startsWith('### Package manager')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
packageManager = value.toLowerCase();
};
} else if (lines[i].startsWith('### Operating system')) {
set(lines.slice(j, i).join('\n').trim());
j = i + 1;
set = value => {
os = value.toLowerCase();
};
}
}
set(lines.slice(j, i).join('\n').trim());
}
let runsOn;
switch (os) {
case 'windows':
runsOn = 'windows-latest';
break;
case 'macos':
runsOn = 'macos-latest';
break;
case 'linux':
runsOn = 'ubuntu-latest';
break;
default:
core.setOutput('errorMessage', ERROR_MESSAGES.unsupportedOs(os));
core.setFailed(`Unsupported OS: ${os}`);
}
if (!SUPPORTED_PACKAGE_MANAGERS.includes(packageManager)) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.unsupportedPackageManager(packageManager)
);
core.setFailed(`Unsupported package manager: ${packageManager}`);
}
if (!semver.valid(nodeVersion)) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.invalidNodeVersion(nodeVersion)
);
core.setFailed('Invalid Node version');
}
if (semver.lt(nodeVersion, LAST_SUPPORTED_NODE_VERSION)) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.unsupportedNodeVersion(nodeVersion)
);
core.setFailed(`Unsupported node version: ${nodeVersion}`);
}
if (!semver.valid(puppeteerVersion)) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.invalidPuppeteerVersion(puppeteerVersion)
);
core.setFailed(`Invalid puppeteer version: ${puppeteerVersion}`);
}
if (
!LAST_SUPPORTED_PUPPETEER_VERSION ||
semver.lt(puppeteerVersion, LAST_SUPPORTED_PUPPETEER_VERSION)
) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.unsupportedPuppeteerVersion(puppeteerVersion)
);
core.setFailed(`Unsupported puppeteer version: ${puppeteerVersion}`);
}
if (!semver.valid(packageManagerVersion)) {
core.setOutput(
'errorMessage',
ERROR_MESSAGES.invalidPackageManagerVersion(packageManagerVersion)
);
core.setFailed(`Invalid package manager version: ${packageManagerVersion}`);
}
core.setOutput('errorMessage', '');
core.setOutput('runsOn', runsOn);
core.setOutput('nodeVersion', nodeVersion);
core.setOutput('packageManager', packageManager);
await mkdir('out');
Promise.all([
writeFile(join('out', 'main.ts'), mvce.split('\n').slice(1, -1).join('\n')),
writeFile(join('out', 'puppeteer-error.txt'), error),
writeFile(
join('out', 'puppeteer.config.js'),
configuration.split('\n').slice(1, -1).join('\n')
),
writeFile(join('out', 'puppeteer-behavior.json'), JSON.stringify(behavior)),
writeFile(
join('out', 'package.json'),
JSON.stringify({
packageManager: `${packageManager}@${packageManagerVersion}`,
scripts: {
start: 'tsx main.ts',
verify: 'tsx verify_issue.ts',
},
dependencies: {
puppeteer: puppeteerVersion,
},
devDependencies: {
tsx: 'latest',
},
})
),
copyFile(
join(
dirname(fileURLToPath(import.meta.url)),
'assets',
'verify_issue.ts'
),
join('out', 'verify_issue.ts')
),
]);
})();