chore: import upstream snapshot with attribution
build container image / cpu (push) Waiting to run
build container image / cuda (push) Waiting to run
build container image / rocm (push) Waiting to run
frontend tests / frontend-tests (push) Waiting to run
openapi checks / openapi-checks (push) Waiting to run
python tests / py3.12: macos-default (push) Waiting to run
python tests / py3.11: windows-cpu (push) Waiting to run
python tests / py3.12: windows-cpu (push) Waiting to run
python tests / py3.11: linux-cpu (push) Waiting to run
python tests / py3.12: linux-cpu (push) Waiting to run
typegen checks / typegen-checks (push) Waiting to run
uv lock checks / uv-lock-checks (push) Waiting to run
frontend checks / frontend-checks (push) Waiting to run
lfs checks / lfs-check (push) Waiting to run
python checks / python-checks (push) Waiting to run
python tests / py3.11: macos-default (push) Waiting to run
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
build container image / cpu (push) Waiting to run
build container image / cuda (push) Waiting to run
build container image / rocm (push) Waiting to run
frontend tests / frontend-tests (push) Waiting to run
openapi checks / openapi-checks (push) Waiting to run
python tests / py3.12: macos-default (push) Waiting to run
python tests / py3.11: windows-cpu (push) Waiting to run
python tests / py3.12: windows-cpu (push) Waiting to run
python tests / py3.11: linux-cpu (push) Waiting to run
python tests / py3.12: linux-cpu (push) Waiting to run
typegen checks / typegen-checks (push) Waiting to run
uv lock checks / uv-lock-checks (push) Waiting to run
frontend checks / frontend-checks (push) Waiting to run
lfs checks / lfs-check (push) Waiting to run
python checks / python-checks (push) Waiting to run
python tests / py3.11: macos-default (push) Waiting to run
docs / deploy (push) Has been cancelled
docs / changes (push) Has been cancelled
docs / check-and-build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
||||
import { dirname, join, relative } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const docsRoot = join(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const contentRoot = join(docsRoot, 'src', 'content', 'docs');
|
||||
const redirectsFile = join(docsRoot, 'src', 'config', 'redirects.ts');
|
||||
|
||||
const normalizeRoute = (route) => {
|
||||
const normalized = route
|
||||
.replace(/^\/+|\/+$/g, '')
|
||||
.split('/')
|
||||
.filter(Boolean)
|
||||
.map((segment) => segment.toLowerCase().replaceAll(' ', '-'))
|
||||
.join('/');
|
||||
|
||||
return normalized ? `/${normalized}` : '/';
|
||||
};
|
||||
|
||||
const collectDocsRoutes = (dir, routes = new Set()) => {
|
||||
for (const entry of readdirSync(dir)) {
|
||||
const entryPath = join(dir, entry);
|
||||
const stats = statSync(entryPath);
|
||||
|
||||
if (stats.isDirectory()) {
|
||||
collectDocsRoutes(entryPath, routes);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entry.endsWith('.md') && !entry.endsWith('.mdx')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const relativePath = relative(contentRoot, entryPath).replace(/\\/g, '/').replace(/\.mdx?$/, '');
|
||||
const route = relativePath.endsWith('/index') ? relativePath.slice(0, -'/index'.length) : relativePath;
|
||||
routes.add(normalizeRoute(route));
|
||||
|
||||
const segments = route.split('/').filter(Boolean);
|
||||
for (let index = 1; index < segments.length; index++) {
|
||||
routes.add(normalizeRoute(segments.slice(0, index).join('/')));
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
};
|
||||
|
||||
if (!existsSync(contentRoot)) {
|
||||
throw new Error(`Docs content directory not found: ${contentRoot}`);
|
||||
}
|
||||
|
||||
const redirectsSource = readFileSync(redirectsFile, 'utf8');
|
||||
const redirectMatches = redirectsSource.matchAll(/^\s*['"]([^'"]+)['"]:\s*['"]([^'"]+)['"]/gm);
|
||||
const redirectTargets = Array.from(redirectMatches, ([, from, to]) => ({ from, to }));
|
||||
const docsRoutes = collectDocsRoutes(contentRoot);
|
||||
const missingTargets = redirectTargets.filter(({ to }) => !docsRoutes.has(normalizeRoute(to)));
|
||||
|
||||
if (missingTargets.length > 0) {
|
||||
console.error('Redirect targets must resolve to generated docs routes:');
|
||||
for (const { from, to } of missingTargets) {
|
||||
console.error(` ${from} -> ${to}`);
|
||||
}
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`Validated ${redirectTargets.length} redirect targets.`);
|
||||
@@ -0,0 +1,70 @@
|
||||
import { readFileSync } from 'node:fs';
|
||||
|
||||
const deployTarget = process.env.DEPLOY_TARGET ?? 'custom';
|
||||
const base = deployTarget === 'ghpages' ? '/InvokeAI' : '';
|
||||
const withBase = (path) => `${base}${path}`;
|
||||
|
||||
const expectations = [
|
||||
{
|
||||
file: 'index.html',
|
||||
includes: [
|
||||
`href="${withBase('/_astro/')}`,
|
||||
`src="${withBase('/_astro/')}`,
|
||||
`href="${withBase('/start-here/installation/')}`,
|
||||
],
|
||||
excludes: deployTarget === 'custom' ? ['href="/InvokeAI/', 'src="/InvokeAI/'] : ['href="/_astro/', 'src="/_astro/'],
|
||||
},
|
||||
{
|
||||
file: 'contributing/index.html',
|
||||
includes: [`href="${withBase('/contributing/new-contributor-guide/')}`],
|
||||
excludes: [
|
||||
deployTarget === 'custom'
|
||||
? 'href="/InvokeAI/contributing/new-contributor-guide/"'
|
||||
: 'href="/contributing/new-contributor-guide/"',
|
||||
'newContributorChecklist.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
file: 'contributing/contribution_guides/newContributorChecklist/index.html',
|
||||
includes: [
|
||||
`Redirecting to: ${withBase('/contributing/new-contributor-guide')}`,
|
||||
`content="0;url=${withBase('/contributing/new-contributor-guide')}`,
|
||||
`href="${withBase('/contributing/new-contributor-guide')}`,
|
||||
],
|
||||
excludes: deployTarget === 'custom'
|
||||
? [
|
||||
'Redirecting to: /InvokeAI/contributing/new-contributor-guide',
|
||||
'content="0;url=/InvokeAI/contributing/new-contributor-guide',
|
||||
'href="/InvokeAI/contributing/new-contributor-guide',
|
||||
]
|
||||
: [
|
||||
'Redirecting to: /contributing/new-contributor-guide',
|
||||
'content="0;url=/contributing/new-contributor-guide',
|
||||
'href="/contributing/new-contributor-guide',
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const errors = [];
|
||||
|
||||
for (const { file, includes = [], excludes = [] } of expectations) {
|
||||
const html = readFileSync(new URL(`../dist/${file}`, import.meta.url), 'utf8');
|
||||
|
||||
for (const expected of includes) {
|
||||
if (!html.includes(expected)) {
|
||||
errors.push(`${file} is missing ${expected}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const unexpected of excludes) {
|
||||
if (html.includes(unexpected)) {
|
||||
errors.push(`${file} still contains ${unexpected}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.length > 0) {
|
||||
throw new Error(`${deployTarget} output validation failed:\n- ${errors.join('\n- ')}`);
|
||||
}
|
||||
|
||||
console.log(`${deployTarget} output links and assets look correct.`);
|
||||
Reference in New Issue
Block a user