feat: add local OneNote and ONEPKG reader
This commit is contained in:
126
scripts/package-release.mjs
Normal file
126
scripts/package-release.mjs
Normal file
@@ -0,0 +1,126 @@
|
||||
import { createHash } from 'node:crypto';
|
||||
import { access, mkdir, readFile, writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import {
|
||||
collectDirectoryFiles,
|
||||
createDeterministicZip,
|
||||
createThirdPartyLicenseBundle,
|
||||
} from './release-archive.mjs';
|
||||
|
||||
const modulePath = fileURLToPath(import.meta.url);
|
||||
const defaultProjectRoot = path.resolve(path.dirname(modulePath), '..');
|
||||
|
||||
export async function collectReleaseMetadataFiles(projectRoot) {
|
||||
const files = {};
|
||||
|
||||
for (const fileName of [
|
||||
'CHANGELOG.md',
|
||||
'LICENSE',
|
||||
'README.md',
|
||||
'SOURCE.md',
|
||||
'THIRD_PARTY_NOTICES.md',
|
||||
]) {
|
||||
files[fileName] = await readFile(path.join(projectRoot, fileName));
|
||||
}
|
||||
|
||||
for (const licenseName of [
|
||||
'AGPL-3.0.txt',
|
||||
'MPL-2.0.txt',
|
||||
'lzxd-MIT.txt',
|
||||
'rust-cab-MIT.txt',
|
||||
]) {
|
||||
files[`LICENSES/${licenseName}`] = await readFile(
|
||||
path.join(projectRoot, 'LICENSES', licenseName)
|
||||
);
|
||||
}
|
||||
|
||||
files['LICENSES/THIRD-PARTY-LICENSES.txt'] =
|
||||
await createThirdPartyLicenseBundle(projectRoot, [
|
||||
'@add-ideas/toolbox-contract',
|
||||
'@add-ideas/toolbox-shell-react',
|
||||
'react',
|
||||
'react-dom',
|
||||
'scheduler',
|
||||
]);
|
||||
|
||||
for (const documentName of [
|
||||
'FORMAT_SUPPORT.md',
|
||||
'PORTING.md',
|
||||
'REFERENCE_IMPLEMENTATIONS.md',
|
||||
'SECURITY.md',
|
||||
]) {
|
||||
files[`docs/${documentName}`] = await readFile(
|
||||
path.join(projectRoot, 'docs', documentName)
|
||||
);
|
||||
}
|
||||
|
||||
files['tests/fixtures/README.md'] = await readFile(
|
||||
path.join(projectRoot, 'tests', 'fixtures', 'README.md')
|
||||
);
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
async function packageRelease(projectRoot, arguments_) {
|
||||
const packageJson = JSON.parse(
|
||||
await readFile(path.join(projectRoot, 'package.json'), 'utf8')
|
||||
);
|
||||
const releaseDirectory = path.join(projectRoot, 'release');
|
||||
const archiveName = `onenote-tools-${packageJson.version}.zip`;
|
||||
const archivePath = path.join(releaseDirectory, archiveName);
|
||||
const checksumPath = path.join(
|
||||
releaseDirectory,
|
||||
`onenote-tools-${packageJson.version}.sha256`
|
||||
);
|
||||
const force = arguments_.includes('--force');
|
||||
const unknownArguments = arguments_.filter(
|
||||
(argument) => argument !== '--force'
|
||||
);
|
||||
if (unknownArguments.length > 0) {
|
||||
throw new Error(`Unknown release argument: ${unknownArguments.join(', ')}`);
|
||||
}
|
||||
|
||||
await mkdir(releaseDirectory, { recursive: true });
|
||||
if (!force) {
|
||||
await assertDoesNotExist(archivePath, projectRoot);
|
||||
await assertDoesNotExist(checksumPath, projectRoot);
|
||||
}
|
||||
|
||||
const files = await collectDirectoryFiles(path.join(projectRoot, 'dist'));
|
||||
if (Object.keys(files).some((fileName) => fileName.endsWith('.wasm'))) {
|
||||
throw new Error('Release input contains a forbidden WebAssembly file.');
|
||||
}
|
||||
Object.assign(files, await collectReleaseMetadataFiles(projectRoot));
|
||||
|
||||
const archive = createDeterministicZip(files);
|
||||
const checksum = createHash('sha256').update(archive).digest('hex');
|
||||
const writeFlag = force ? 'w' : 'wx';
|
||||
await writeFile(archivePath, archive, { flag: writeFlag });
|
||||
await writeFile(checksumPath, `${checksum} ${archiveName}\n`, {
|
||||
encoding: 'utf8',
|
||||
flag: writeFlag,
|
||||
});
|
||||
|
||||
console.log(`Created release/${archiveName}`);
|
||||
console.log(`SHA-256 ${checksum}`);
|
||||
}
|
||||
|
||||
async function assertDoesNotExist(outputPath, projectRoot) {
|
||||
try {
|
||||
await access(outputPath);
|
||||
} catch (error) {
|
||||
if (error && typeof error === 'object' && error.code === 'ENOENT') return;
|
||||
throw error;
|
||||
}
|
||||
throw new Error(
|
||||
`${path.relative(projectRoot, outputPath)} already exists; pass --force to replace this exact version.`
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
process.argv[1] !== undefined &&
|
||||
path.resolve(process.argv[1]) === modulePath
|
||||
) {
|
||||
await packageRelease(defaultProjectRoot, process.argv.slice(2));
|
||||
}
|
||||
Reference in New Issue
Block a user