Skip to content

Commit

Permalink
add link validation (#132)
Browse files Browse the repository at this point in the history
  • Loading branch information
zacharyblasczyk authored Oct 13, 2024
1 parent 6abfd7d commit f918859
Show file tree
Hide file tree
Showing 16 changed files with 3,164 additions and 34 deletions.
78 changes: 78 additions & 0 deletions apps/docs/.remarkrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import fs from "fs";
import path from "path";
import remarkMdx from "remark-mdx";
import remarkParse from "remark-parse";
import { unified } from "unified";
import { visit } from "unist-util-visit";

const validateInternalLinks = () => {
return async function transformer(tree, file) {
const fileDir = path.dirname(file.path);

const resolveFilePath = (basePath) =>
basePath.startsWith("/")
? path.resolve(process.cwd(), "pages", `${basePath.slice(1)}.mdx`)
: path.resolve(fileDir, `${basePath}.mdx`);

const hasValidFragment = (ast, fragment) => {
const isHeadingNode = (node) => node.type === "heading";
const isTextNode = (child) => child.type === "text";
const normalizeText = (text) =>
text.trim().replace(/\s+/g, "-").toLowerCase();

return ast.children?.some((node) => {
if (isHeadingNode(node))
return node.children?.some(
(child) =>
isTextNode(child) && normalizeText(child.value) === fragment,
);
return false;
});
};

const validateLink = async (url) => {
if (url.startsWith("http://") || url.startsWith("https://")) return;

const [basePath, fragment] = url.split("#");
const resolvedPath = resolveFilePath(basePath);

if (!fs.existsSync(resolvedPath))
throw new Error(`File not found for ${basePath}. URL: ${url}`);

if (!fragment) return;

const fileContent = fs.readFileSync(resolvedPath, "utf-8");
const ast = await unified()
.use(remarkParse)
.use(remarkMdx)
.parse(fileContent);

if (!hasValidFragment(ast, fragment))
throw new Error(`Fragment "${fragment}" not found in ${url}`);
};

visit(tree, "link", (node) => validateLink(node.url));

visit(tree, "mdxJsxFlowElement", (node) => {
const hrefAttr = node.attributes?.find((attr) => attr.name === "href");
if (hrefAttr?.value) validateLink(hrefAttr.value);
});
};
};

export default {
plugins: [
"remark-preset-lint-recommended",
"remark-frontmatter",
"remark-lint",
"remark-mdx",
"remark-lint-are-links-valid",
"remark-lint-no-dead-urls",
"remark-lint-no-undefined-references",
validateInternalLinks,
],
settings: {
atxHeadingWithMarker: false,
headingStyle: "atx",
},
};
2 changes: 1 addition & 1 deletion apps/docs/eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import reactConfig from "@ctrlplane/eslint-config/react";
/** @type {import('typescript-eslint').Config} */
export default [
{
ignores: [".next/**", "out/**"],
ignores: [".next/**", "out/**", ".remarkrc.js"],
},
...baseConfig,
...reactConfig,
Expand Down
13 changes: 12 additions & 1 deletion apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@
"build": "next build",
"start": "next start -p 3001",
"lint": "eslint",
"lint:mdx": "remark \"pages/**/*.mdx\" --frail",
"build:docker": "docker build -f apps/docs/Dockerfile -t docs .",
"format": "prettier --check . --ignore-path ../../.gitignore"
"format": "prettier --check . --ignore-path ../../.gitignore",
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
},
"dependencies": {
"@ctrlplane/ui": "workspace:*",
Expand All @@ -32,6 +34,15 @@
"eslint": "catalog:",
"postcss-load-config": "^6.0.1",
"prettier": "catalog:",
"remark": "^15.0.1",
"remark-cli": "^12.0.1",
"remark-frontmatter": "^5.0.0",
"remark-lint": "^10.0.0",
"remark-lint-are-links-valid": "^1.0.3",
"remark-lint-no-dead-urls": "^2.0.1",
"remark-mdx": "^3.0.1",
"remark-preset-lint-consistent": "^6.0.0",
"remark-preset-lint-recommended": "^7.0.0",
"tailwindcss": "catalog:",
"typescript": "catalog:",
"typescript-eslint": "catalog:",
Expand Down
2 changes: 0 additions & 2 deletions apps/docs/pages/core-concepts/targets/schemas.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ Ctrlplane comes with a set of pre-built schemas for common target types, saving
you time and effort in defining your own. These schemas cover widely used
configurations, ensuring consistency and ease of use across different projects.

You can learn about all the builtin kinds [here](/docs/targets/schemas).

## Why Use Schema Registration?

Schema registration offers several benefits:
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/pages/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ setup more efficient, secure, and easy to manage
<Cards.Card
icon={<TbServer className="h-8 w-8 stroke-yellow-400" />}
title="Core Concepts"
href="/core-concepts"
href="/core-concepts/systems"
/>
<Cards.Card
icon={<TbPlug className="h-8 w-8 stroke-purple-400" />}
Expand Down
41 changes: 41 additions & 0 deletions apps/docs/pages/integrations.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
title: Integrations Overview
---

# Integrations Overview

Integrations allow you to connect Ctrlplane with various services, enhancing
your deployment capabilities and workflows. Below are the available integrations
you can set up.

## Available Integrations

import { Cards } from "nextra/components";
import { SiGithub, SiGooglecloud, SiKubernetes } from "react-icons/si";

<Cards>
<Cards.Card
icon={<SiGithub className="h-8 w-8" />}
title="GitHub"
href="/integrations/github"
/>
<Cards.Card
icon={<SiGooglecloud className="h-8 w-8" />}
title="Google Cloud"
href="/integrations/google-cloud/compute-scanner"
/>
<Cards.Card
icon={<SiKubernetes className="h-8 w-8" />}
title="Kubernetes"
href="/integrations/kubernetes/jobs-agent"
/>
</Cards>

## How to Set Up Integrations

To set up an integration, follow the specific instructions provided in the
respective integration documentation. Ensure you have the necessary permissions
and configurations in place to connect Ctrlplane with the external service.

For more detailed information on each integration, please refer to the links
provided in the cards above.
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
title: Self-hosted
---

# Overview

Ctrlplane is still in its early days, not everything is perfect yet, and hiccups
Expand Down
3 changes: 2 additions & 1 deletion apps/docs/pages/self-hosted/cloud-providers/google-cloud.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ the official Terraform/Opentofu module. You can customize it to accommodate your
needs.

If you cannot use the Terraform module, you can install Ctrlplane manually to a
GKE cluster and use the [Helm Chart](/install/helm) based install.
GKE cluster and use the [Helm Chart](../methods/kubernetes#installing-ctrlplane)
based install.

### Using Terraform

Expand Down
2 changes: 1 addition & 1 deletion apps/docs/pages/self-hosted/methods/docker-compose.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ The Ctrplane has mutiple docker images used to deploy the application.

The easiest way to install Ctrlplane is to use the Docker Compose file provided
in the
[Ctrlplane repository](https://github.com/ctrlplanedev/ctrlplane/blob/main/deploy/docker-compose.yaml).
[Ctrlplane repository](https://github.com/ctrlplanedev/ctrlplane/blob/main/docker-compose.yaml).

Make sure you are in the same directory as `docker-compose.yaml` and start
Ctrlplane:
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/pages/self-hosted/services/event-worker.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Deployment

- Docker Image: `docker.io/ctrlplane/event-worker:latest`,
[Dockerfile](https://github.com/ctrlplanedev/ctrlplane/blob/main/apps/event-worker/Dockerfile)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlchart/blob/main/charts/event-worker)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlcharts/tree/main/charts/ctrlplane/charts/event-worker)

Technology:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Deployment

- Docker Image: `docker.io/ctrlplane/job-policy-checker:latest`,
[Dockerfile](https://github.com/ctrlplanedev/ctrlplane/blob/main/apps/job-policy-checker/Dockerfile)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlchart/blob/main/charts/job-policy-checker)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlcharts/tree/main/charts/ctrlplane/charts/job-policy-checker)

Technology:

Expand Down
4 changes: 2 additions & 2 deletions apps/docs/pages/self-hosted/services/webservice.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ Deployment

- Docker Image: `docker.io/ctrlplane/webservice:latest`,
[Dockerfile](https://github.com/ctrlplanedev/ctrlplane/blob/main/apps/webservice/Dockerfile)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlchart/blob/main/charts/webservice)
- [Helm Chart](https://github.com/ctrlplanedev/ctrlcharts/tree/main/charts/ctrlplane/charts/webservice)

Technology:

- [NextJS](https://nextjs.org/)
- [TypeScript](https://www.typescriptlang.org/)
- [React](https://reactjs.org/)
- [React](https://react.dev/)
- [TailwindCSS](https://tailwindcss.com/)
- [tRPC](https://trpc.io/)

Expand Down
1 change: 0 additions & 1 deletion apps/webshell-router/src/routing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ const onConnect = async (ws: WebSocket, request: IncomingMessage) => {
};

export const addSocket = (expressApp: Express) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const server = createServer(expressApp);
const wss = new WebSocketServer({ noServer: true });

Expand Down
1 change: 0 additions & 1 deletion github/get-job-inputs/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f918859

Please sign in to comment.