aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--scripts/docs/snapshot.mjs14
-rw-r--r--scripts/docs/versions.integration.test.ts17
2 files changed, 23 insertions, 8 deletions
diff --git a/scripts/docs/snapshot.mjs b/scripts/docs/snapshot.mjs
index e9eaf92c..7610715a 100644
--- a/scripts/docs/snapshot.mjs
+++ b/scripts/docs/snapshot.mjs
@@ -1,5 +1,5 @@
import { execFileSync } from 'node:child_process';
-import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
+import { lstat, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
import { dirname, relative, resolve } from 'node:path';
export function createGit(repoRoot) {
@@ -92,10 +92,14 @@ export async function compareGitTree(git, ref, sourceRoot, snapshotRoot) {
export async function listDocumentationPaths(root) {
const paths = [];
async function walk(directory) {
- for (const entry of await readdir(directory, { withFileTypes: true })) {
- const path = resolve(directory, entry.name);
- if (entry.isDirectory()) await walk(path);
- else if (entry.isFile()) paths.push(relative(root, path));
+ for (const name of await readdir(directory)) {
+ const path = resolve(directory, name);
+ // lstat does not follow links, so symlinks and Windows junctions stay
+ // non-ordinary here even if a runtime classifies them as directories in
+ // the readdir entry.
+ const stats = await lstat(path);
+ if (stats.isDirectory()) await walk(path);
+ else if (stats.isFile()) paths.push(relative(root, path));
else throw new Error(`${path} is not an ordinary documentation file`);
}
}
diff --git a/scripts/docs/versions.integration.test.ts b/scripts/docs/versions.integration.test.ts
index 9731d3c0..214bfef9 100644
--- a/scripts/docs/versions.integration.test.ts
+++ b/scripts/docs/versions.integration.test.ts
@@ -100,9 +100,20 @@ describe('documentation release publishing', () => {
correctedArchivedDocs,
);
const linkedPage = resolve(archivedDocsRoot, 'linked.mdx');
- await symlink('index.mdx', linkedPage);
- expect(() => runScript(root, ['check'])).toThrow();
- await rm(linkedPage);
+ if (process.platform === 'win32') {
+ // A normal Windows terminal cannot create file symlinks without Developer
+ // Mode or elevation, but a directory junction is creatable without
+ // either. Link to an empty directory outside the snapshot so the walk
+ // stays finite and only the non-ordinary-file rejection can satisfy the
+ // assertion below.
+ const linkTarget = await mkdtemp(join(tmpdir(), 'herdr-docs-link-'));
+ temporaryDirectories.push(linkTarget);
+ await symlink(linkTarget, linkedPage, 'junction');
+ } else {
+ await symlink('index.mdx', linkedPage);
+ }
+ expect(() => runScript(root, ['check'])).toThrow(/is not an ordinary documentation file/);
+ await rm(linkedPage, { recursive: true, force: true });
runScript(root, ['check']);
delete archivedManifest.versions[0].commit;