Files
radicle-explorer/explorer/tests/support/support.ts
T
Daniel Norman d8f363ca99 Replace API version checks with feature detection
httpd:
- Serve the API at /api, not only under /v1
- Keep serving it at /api/v1, without a redirect, until the first
  major release after explorer and the Open Graph worker switch
  to /api
- Remove apiVersion: released explorers do not read it
- Add `httpd.releases` to `/info`, set by the artifacts feature

explorer:
- Remove the API version check, its config and the unused
  compare-versions dependency
- Keep the node version in a plain parse error message
- Add `minimumSupportedVersion`, set to 0.28.0, and warn on nodes
  whose major is older, treating 0.y as the major before 1.0
- Do not warn on builds without a release number
- Show a warning on the node page of an outdated node
- Mark an outdated node in the seed picker on every page
- Name the node version and the floor in parse errors
- Drop the `/node` fallback for httpd without `/info`, which
  predates the floor
- Check the status, not `ResponseError`, so the Open Graph worker
  can import compat without the fetcher
- Name the httpd release each shim serves, not a date
- Drop the mime shim for httpd 0.18.1 and the unused `lib/file.ts`
- Read the node from `/info` in repo views
- Pass the node and its features to repo views as one `node` param
- Show the releases tab and pages when the node supports releases,
  and the counter only when there is a count
- Read a release count as release support on older httpd
- Test the flag and the fallback

docs:
- Restructure docs/api-changes.md: the supported versions, one
  table of removals, fixed fields per change, and a link to ADR
  0001 for the rules
- Say in ADR 0001 that each compat comment names what the other
  side does
- Say in ADR 0001 when a capability needs a flag in /info

tests:
- Run e2e tests on httpd 0.30.0, above the floor, instead of 0.26.0
- Run the release tests on it too, so they cover the compat shims
- Skip only those that need release counts per scope on it
- Test a node without release support through a mocked `/info`
  flag, instead of an httpd that predates the floor
2026-10-29 18:32:03 +01:00

78 lines
2.3 KiB
TypeScript

import type { Options } from "execa";
import { execa } from "execa";
import * as Crypto from "node:crypto";
import { fileURLToPath } from "node:url";
import * as Path from "node:path";
import * as Fs from "node:fs/promises";
// Generate string of 12 random characters with 8 bits of entropy.
export function randomTag(): string {
return Crypto.randomBytes(8).toString("hex");
}
export function createOptions(repoFolder: string, days: number): Options {
return {
cwd: repoFolder,
// eslint-disable-next-line @typescript-eslint/naming-convention
env: { RAD_LOCAL_TIME: (1671211684 + days * 86400).toString() },
};
}
const filename = fileURLToPath(import.meta.url);
export const supportDir = Path.dirname(filename);
export const tmpDir = Path.resolve(supportDir, "..", "./tmp");
export const fixturesDir = Path.resolve(supportDir, "..", "./fixtures");
const workspacePaths = [Path.join(tmpDir, "peers"), Path.join(tmpDir, "repos")];
export const heartwoodRelease = (
await Fs.readFile(`${supportDir}/heartwood-release`, "utf8")
).trim();
export const radicleHttpdRelease = (
await Fs.readFile(`${supportDir}/radicle-httpd-release`, "utf8")
).trim();
export const radicleArtifactRelease = (
await Fs.readFile(`${supportDir}/radicle-artifact-release`, "utf8")
).trim();
export const useLocalHttpd = process.env.USE_LOCAL_HTTPD === "true";
export const releaseCountsOnlyLocal =
"release counts per scope only exist in the local httpd build";
// Assert that binaries are installed and are the correct version.
export async function assertBinariesInstalled(
binary: string,
expectedVersion: string,
expectedPath: string,
): Promise<void> {
let which: string;
try {
({ stdout: which } = await execa("which", [binary]));
} catch {
throw new Error(`${binary} is not installed`);
}
if (Path.dirname(which) !== expectedPath) {
throw new Error(
`${binary} path doesn't match used ${binary} binary: ${expectedPath} !== ${which}`,
);
}
const { stdout: version } = await execa(binary, ["--version"]);
if (!version.includes(expectedVersion)) {
throw new Error(
`${binary} version ${version} does not satisfy ${expectedVersion}`,
);
}
}
export async function removeWorkspace(): Promise<void> {
for (const path of workspacePaths) {
await Fs.rm(path, {
recursive: true,
force: true,
});
}
}