From 41b5c4133be689dda610c1c110e96fc67f68aaa7 Mon Sep 17 00:00:00 2001 From: kazogihara <33021308+kazogihara@users.noreply.github.com> Date: Thu, 21 Jul 2022 22:52:35 +0900 Subject: [PATCH] Add dead link check CI (#679) --- .github/CONTRIBUTING.md | 28 +++++++++++++++++++++++++++- .github/workflows/check.yml | 13 ++++++++++--- docs/basics/client.md | 4 ++-- docs/basics/client.zh.md | 4 ++-- docs/basics/content.zh.md | 2 +- docs/basics/routing.md | 2 +- docs/fluent/advanced.zh.md | 2 +- docs/fluent/migration.zh.md | 4 ++-- docs/fluent/model.md | 2 +- docs/fluent/schema.md | 2 +- docs/index.de.md | 2 +- docs/install/linux.de.md | 2 +- docs/install/macos.de.md | 2 +- docs/leaf/custom-tags.md | 2 +- docs/leaf/getting-started.md | 3 +-- docs/leaf/getting-started.zh.md | 4 ++-- docs/leaf/overview.md | 2 +- docs/redis/sessions.md | 12 ++++++------ docs/security/jwt.md | 2 +- docs/upgrading.md | 2 +- markdown-link-check-config.yml | 4 ++++ 21 files changed, 68 insertions(+), 32 deletions(-) create mode 100644 markdown-link-check-config.yml diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 694d090d..220cc91b 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -33,8 +33,34 @@ pip3 install mkdocs-material Run with `mkdocs serve` +## Testing + +If you want to check dead links, use markdown-link-check + +```sh +npm install --save-dev markdown-link-check +``` + +Run with + +```sh +find . -name \*.md -print0 | xargs -0 -n1 markdown-link-check -q -c markdown-link-check-config.yml +``` +on directly under the repository. + + +OR + +Run docker directly under the repository + +```sh +docker run -v ${PWD}:/tmp:ro --rm -i --entrypoint "sh" ghcr.io/tcort/markdown-link-check:stable "-c" "find /tmp -name \*.md -print0 | xargs -0 -n1 markdown-link-check -q -c /tmp/markdown-link-check-config.yml" +``` + + + ### Maintainers - [@0xtim](https://github.com/0xTim) - [@mcdappdev](https://github.com/mcdappdev) -See https://github.com/vapor/vapor/blob/master/.github/maintainers.md for more information. +See https://github.com/vapor/vapor/blob/main/.github/maintainers.md for more information. diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 48aa47aa..412fbdc1 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -1,4 +1,4 @@ -name: Build docs and check cloudformation +name: Build docs and check cloudformation and dead links on: pull_request: @@ -6,7 +6,7 @@ on: - main jobs: - build: + check: name: build docs runs-on: ubuntu-latest steps: @@ -21,4 +21,11 @@ jobs: - name: Setup cloudformation linter uses: ScottBrenner/cfn-lint-action@v2.2.1 - name: Run cloudformation lint - run: cfn-lint -t stack.yml \ No newline at end of file + run: cfn-lint -t stack.yml + - name: Check dead links + uses: gaurav-nelson/github-action-markdown-link-check@v1 + with: + folder-path: '.' + config-file: 'markdown-link-check-config.yml' + use-verbose-mode: 'yes' + use-quiet-mode: 'yes' diff --git a/docs/basics/client.md b/docs/basics/client.md index c7d6eb59..9d18d783 100644 --- a/docs/basics/client.md +++ b/docs/basics/client.md @@ -1,6 +1,6 @@ # Client -Vapor's client API allows you to make HTTP calls to external resources. It is built on [async-http-client](https://github.com/swift-server/async-http-client) and integrates with the [content](./content.md) API. +Vapor's client API allows you to make HTTP calls to external resources. It is built on [async-http-client](https://github.com/swift-server/async-http-client) and integrates with the [content](content.md) API. ## Overview @@ -28,7 +28,7 @@ There are methods for each of the HTTP verbs like `get`, `post`, and `delete`. T ### Content -Vapor's [content](./content.md) API is available for handling data in client requests and responses. To encode content, query parameters or add headers to the request, use the `beforeSend` closure. +Vapor's [content](content.md) API is available for handling data in client requests and responses. To encode content, query parameters or add headers to the request, use the `beforeSend` closure. ```swift let response = try await req.client.post("https://httpbin.org/status/200") { req in diff --git a/docs/basics/client.zh.md b/docs/basics/client.zh.md index 3cd51326..6ba46c65 100644 --- a/docs/basics/client.zh.md +++ b/docs/basics/client.zh.md @@ -1,6 +1,6 @@ # Client -Vapor的 `Client` API 允许您使用 HTTP 调用外部资源,它基于 [async-http-client](https://github.com/swift-server/async-http-client) 构建,并集成了 [Content](./content.md) API。 +Vapor的 `Client` API 允许您使用 HTTP 调用外部资源,它基于 [async-http-client](https://github.com/swift-server/async-http-client) 构建,并集成了 [Content](content.md) API。 ## 概述 @@ -32,7 +32,7 @@ HTTP 的常用方法(例如 `get`, `post`, `delete`)都有便捷的调用方式 ### Content -Vapor 的 [Content](./content.md) API 可用于处理客户请求和响应中的数据,如果要在请求体中添加参数或编码,请在 `beforeSend` 闭包中进行。 +Vapor 的 [Content](content.md) API 可用于处理客户请求和响应中的数据,如果要在请求体中添加参数或编码,请在 `beforeSend` 闭包中进行。 ```swift let response = try await req.client.post("https://httpbin.org/status/200") { req in diff --git a/docs/basics/content.zh.md b/docs/basics/content.zh.md index 987f5651..5a87dc38 100644 --- a/docs/basics/content.zh.md +++ b/docs/basics/content.zh.md @@ -257,7 +257,7 @@ extension HTML: AsyncResponseEncodable { } } ``` -注意,它允许自定义“Content-Type”头,查看更多请查阅 [`HTTPHeaders` reference](https://api.vapor.codes/vapor/master/Vapor/) +注意,它允许自定义“Content-Type”头,查看更多请查阅 [`HTTPHeaders` reference](https://api.vapor.codes/vapor/main/Vapor/) 接下来,你可以在你的路由中使用 `HTML` 作为 response: diff --git a/docs/basics/routing.md b/docs/basics/routing.md index 70daf189..5e4febb0 100644 --- a/docs/basics/routing.md +++ b/docs/basics/routing.md @@ -212,7 +212,7 @@ app.get("hello", ":name") { req -> String in We can be sure that `req.parameters.get` will never return `nil` here since our route path includes `:name`. However, if you are accessing route parameters in middleware or in code triggered by multiple routes, you will want to handle the possibility of `nil`. !!! tip - If you want to retrieve URL query params, e.g. `/hello/?name=foo` you need to use Vapor's Content APIs to handle URL encoded data in the URL's query string. See [`Content` reference](/content/) for more details. + If you want to retrieve URL query params, e.g. `/hello/?name=foo` you need to use Vapor's Content APIs to handle URL encoded data in the URL's query string. See [`Content` reference](content.md) for more details. `req.parameters.get` also supports casting the parameter to `LosslessStringConvertible` types automatically. diff --git a/docs/fluent/advanced.zh.md b/docs/fluent/advanced.zh.md index 0b1c56f0..02ebc47d 100644 --- a/docs/fluent/advanced.zh.md +++ b/docs/fluent/advanced.zh.md @@ -102,7 +102,7 @@ builder.create() ## MongoDB -Fluent MongoDB 是一个集成了 [Fluent](../fluent/overview.zh.md) 和 [MongoKitten](https://github.com/OpenKitten/MongoKitten/) 的驱动程序。它利用 Swift 的强类型特性以及 Fluent 使用与 MongoDB 数据库无关的接口。 +Fluent MongoDB 是一个集成了 [Fluent](../fluent/overview.md) 和 [MongoKitten](https://github.com/OpenKitten/MongoKitten/) 的驱动程序。它利用 Swift 的强类型特性以及 Fluent 使用与 MongoDB 数据库无关的接口。 MongoDB 中最常见的标识符是 ObjectId。你可以在项目中使用 `@ID(custom: .id)` 自定义标志符。 如果需要在 SQL 中使用相同的模型,请不要使用 `ObjectId`。改为使用 `UUID`。 diff --git a/docs/fluent/migration.zh.md b/docs/fluent/migration.zh.md index 8fe1d090..99fc134f 100644 --- a/docs/fluent/migration.zh.md +++ b/docs/fluent/migration.zh.md @@ -60,7 +60,7 @@ app.migrations.add(MyMigration(), to: .myDatabase) vapor run migrate ``` -你也可以[通过 Xcode 运行这个命令](../advanced/commands.zh.md#xcode)。migrate 命令将检查数据库,查看自上次运行以来是否注册了新的迁移。如果有新的迁移,运行它之前会要求确认。 +你也可以[通过 Xcode 运行这个命令](../advanced/commands.md#xcode)。migrate 命令将检查数据库,查看自上次运行以来是否注册了新的迁移。如果有新的迁移,运行它之前会要求确认。 ### 撤销 @@ -93,6 +93,6 @@ try await app.autoMigrate() ## 下一步 -请查看[schema builder](schema.md) 和 [query builder](query.zh.md) 指南,以了解更多迁移相关的信息。 +请查看[schema builder](schema.md) 和 [query builder](query.md) 指南,以了解更多迁移相关的信息。 diff --git a/docs/fluent/model.md b/docs/fluent/model.md index 0ed0a22d..34eac25f 100644 --- a/docs/fluent/model.md +++ b/docs/fluent/model.md @@ -517,7 +517,7 @@ Models expose a static method `query(on:)` that returns a query builder. Planet.query(on: database).all() ``` -Learn more about querying in the [query](./query.md) section. +Learn more about querying in the [query](query.md) section. ## Find diff --git a/docs/fluent/schema.md b/docs/fluent/schema.md index 4c7eb056..8d6f9732 100644 --- a/docs/fluent/schema.md +++ b/docs/fluent/schema.md @@ -382,7 +382,7 @@ Note that for this migration to work, we need to be able to reference both the r ## Setting Model Space -To define the [space for a model](/fluent/model/#database-space), pass the space to the `schema(_:space:)` when creating the table. E.g. +To define the [space for a model](model.md#database-space), pass the space to the `schema(_:space:)` when creating the table. E.g. ```swift try await db.schema("planets", space: "mirror_universe") diff --git a/docs/index.de.md b/docs/index.de.md index f3ed03a3..7917a389 100644 --- a/docs/index.de.md +++ b/docs/index.de.md @@ -4,7 +4,7 @@ Willkommen zur Dokumentation von Vapor! Vapor ist ein Web-Framework für Swift, ## Einstieg -Für die Installation, folge den Anweisungen im Abschnitt [Installation → macOS](install/macos.de.md). Nach der Installation, folge den Anweisungen [Erste Schritte → Hello, world](getting-started/hello-world.de.md) um deine erste Vapor-Anwendungen zu erstellen. +Für die Installation, folge den Anweisungen im Abschnitt [Installation → macOS](install/macos.md). Nach der Installation, folge den Anweisungen [Erste Schritte → Hello, world](getting-started/hello-world.md) um deine erste Vapor-Anwendungen zu erstellen. ## Hilfen diff --git a/docs/install/linux.de.md b/docs/install/linux.de.md index 35c8561a..d4e44e7a 100644 --- a/docs/install/linux.de.md +++ b/docs/install/linux.de.md @@ -54,4 +54,4 @@ vapor --help ausführst. Dir sollten nun mehrere Befehl der Toolbox angezeigt werden. -Nach der Swift-Installation kannst du mit der Erstellung deiner ersten Vapor-Anwendung beginnen. Folge dazu den Anweisungen im Abschnitt [Erste Schritte → Hello, world](/hallo-world.de.md). \ No newline at end of file +Nach der Swift-Installation kannst du mit der Erstellung deiner ersten Vapor-Anwendung beginnen. Folge dazu den Anweisungen im Abschnitt [Erste Schritte → Hello, world](../getting-started/hello-world.md). \ No newline at end of file diff --git a/docs/install/macos.de.md b/docs/install/macos.de.md index a4a3ffd3..3ccd6c27 100644 --- a/docs/install/macos.de.md +++ b/docs/install/macos.de.md @@ -29,4 +29,4 @@ brew install vapor ## -Nach den Installationen kannst du mit der Erstellung deiner ersten Vapor-Anwendung beginnen. Folge dazu den Anweisungen im Abschnitt [Erste Schritte → Hello, world](../getting-started/hello-world.de.md). +Nach den Installationen kannst du mit der Erstellung deiner ersten Vapor-Anwendung beginnen. Folge dazu den Anweisungen im Abschnitt [Erste Schritte → Hello, world](../getting-started/hello-world.md). diff --git a/docs/leaf/custom-tags.md b/docs/leaf/custom-tags.md index bfd86394..0dfb42c9 100644 --- a/docs/leaf/custom-tags.md +++ b/docs/leaf/custom-tags.md @@ -1,6 +1,6 @@ # Custom Tags -You can create custom Leaf tags using the [`LeafTag`](https://api.vapor.codes/leaf-kit/latest/LeafKit/LeafSyntax/LeafTag.html) protocol. +You can create custom Leaf tags using the [`LeafTag`](https://api.vapor.codes/leaf-kit/main/LeafKit/LeafTag) protocol. To demonstrate this, let's take a look at creating a custom tag `#now` that prints the current timestamp. The tag will also support a single, optional parameter for specifying the date format. diff --git a/docs/leaf/getting-started.md b/docs/leaf/getting-started.md index d7c1bdc5..8768d4a7 100644 --- a/docs/leaf/getting-started.md +++ b/docs/leaf/getting-started.md @@ -45,8 +45,7 @@ This tells Vapor to use the `LeafRenderer` when you call `req.view` in your code Leaf has an internal cache for rendering pages. When the `Application`'s environment is set to `.development`, this cache is disabled, so that changes to templates take effect immediately. In `.production` and all other environments, the cache is enabled by default; any changes made to templates will not take effect until the application is restarted. !!! warning - For Leaf to be able to find the templates when running from Xcode, you must set the [custom working directory](/xcode/#custom-working-directory) for you Xcode workspace. - + For Leaf to be able to find the templates when running from Xcode, you must set the [custom working directory](../getting-started/xcode.md#custom-working-directory) for you Xcode workspace. ## Folder Structure Once you have configured Leaf, you will need to ensure you have a `Views` folder to store your `.leaf` files in. By default, Leaf expects the views folder to be a `./Resources/Views` relative to your project's root. diff --git a/docs/leaf/getting-started.zh.md b/docs/leaf/getting-started.zh.md index 6614fcd8..68574a15 100644 --- a/docs/leaf/getting-started.zh.md +++ b/docs/leaf/getting-started.zh.md @@ -31,7 +31,7 @@ let package = Package( ## 配置 -将包添加到项目后,通常在 [`configure.swift`](../getting-started/folder-structure.zh.md#configureswift) 中进行配置,这样 Vapor 就可以使用它了。 +将包添加到项目后,通常在 [`configure.swift`](../getting-started/folder-structure.md#configureswift) 中进行配置,这样 Vapor 就可以使用它了。 ```swift import Leaf @@ -45,7 +45,7 @@ app.views.use(.leaf) Leaf 有一个用于渲染页面的内部缓存。当 `Application` 的运行环境设置为 `.development` 时,此缓存被禁用,因此对模板的更改会立即生效。在 `.production` 环境和所有的其它环境中,默认启用缓存;应用重启之前,对模板所做的任何更改都不会生效。 !!! 警告 - 从 Xcode 运行项目时为了 Leaf 能够找到模板,你必须为你的 Xcode 工作区设置[自定义工作目录](../getting-started/xcode.zh.md#working-directory)。 + 从 Xcode 运行项目时为了 Leaf 能够找到模板,你必须为你的 Xcode 工作区设置[自定义工作目录](../getting-started/xcode.md#working-directory)。 ## 目录结构 diff --git a/docs/leaf/overview.md b/docs/leaf/overview.md index 6c386349..5b912dac 100644 --- a/docs/leaf/overview.md +++ b/docs/leaf/overview.md @@ -53,7 +53,7 @@ Leaf also supports many expressions you are familiar with in Swift. ## Context -In the example from [Getting Started](./getting-started.md), we used a `[String: String]` dictionary to pass data to Leaf. However, you can pass anything that conforms to `Encodable`. It's actually preferred to use `Encodable` structs since `[String: Any]` is not supported. This means you *can not* pass in an array, and should instead wrap it in a struct: +In the example from [Getting Started](getting-started.md), we used a `[String: String]` dictionary to pass data to Leaf. However, you can pass anything that conforms to `Encodable`. It's actually preferred to use `Encodable` structs since `[String: Any]` is not supported. This means you *can not* pass in an array, and should instead wrap it in a struct: ```swift struct WelcomeContext: Encodable { diff --git a/docs/redis/sessions.md b/docs/redis/sessions.md index 7048dc44..2a542139 100644 --- a/docs/redis/sessions.md +++ b/docs/redis/sessions.md @@ -2,13 +2,13 @@ Redis can act as a storage provider for caching [session data](../advanced/sessions.md#session-data) such as user credentials. -If a custom [`RedisSessionsDelegate`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/) isn't provided, a default will be used. +If a custom [`RedisSessionsDelegate`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/) isn't provided, a default will be used. ## Default Behavior ### SessionID Creation -Unless you implement the [`makeNewID()`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/#redissessionsdelegate.makeNewID()) method in [your own `RedisSessionsDelegate`](#RedisSessionsDelegate), all [`SessionID`](https://api.vapor.codes/vapor/master/Vapor/SessionID/) values will be created by doing the following: +Unless you implement the [`makeNewID()`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/#redissessionsdelegate.makeNewID()) method in [your own `RedisSessionsDelegate`](#redissessionsdelegate), all [`SessionID`](https://api.vapor.codes/vapor/main/Vapor/SessionID/) values will be created by doing the following: 1. Generate 32 bytes of random characters 1. base64 encode the value @@ -17,9 +17,9 @@ For example: `Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=` ### SessionData Storage -The default implementation of `RedisSessionsDelegate` will store [`SessionData`](https://api.vapor.codes/vapor/master/Vapor/SessionData/) as a simple JSON string value using `Codable`. +The default implementation of `RedisSessionsDelegate` will store [`SessionData`](https://api.vapor.codes/vapor/main/Vapor/SessionData/) as a simple JSON string value using `Codable`. -Unless you implement the [`makeRedisKey(for:)`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/#redissessionsdelegate.makeRedisKey(for:)) method in your own `RedisSessionsDelegate`, `SessionData` will be stored in Redis with a key that prefixes the `SessionID` with `vrs-` (**V**apor **R**edis **S**essions) +Unless you implement the [`makeRedisKey(for:)`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/#redissessionsdelegate.makeRedisKey(for:)) method in your own `RedisSessionsDelegate`, `SessionData` will be stored in Redis with a key that prefixes the `SessionID` with `vrs-` (**V**apor **R**edis **S**essions) For example: `vrs-Hbxozx8rTj+XXGWAzOhh1npZFXaGLpTWpWCaXuo44xQ=` @@ -39,11 +39,11 @@ app.sessions.use(.redis(delegate: CustomRedisSessionsDelegate())) ## RedisSessionsDelegate -> API Documentation: [`RedisSessionsDelegate`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/) +> API Documentation: [`RedisSessionsDelegate`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/) An object that conforms to this protocol can be used to change how `SessionData` is stored in Redis. -Only two methods are required to be implemented by a type conforming to the protocol: [`redis(_:store:with:)`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/#redissessionsdelegate.redis(_:store:with:)) and [`redis(_:fetchDataFor:)`](https://api.vapor.codes/redis/master/Redis/RedisSessionsDelegate/#redissessionsdelegate.redis(_:fetchDataFor:)). +Only two methods are required to be implemented by a type conforming to the protocol: [`redis(_:store:with:)`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/#redissessionsdelegate.redis(_:store:with:)) and [`redis(_:fetchDataFor:)`](https://api.vapor.codes/redis/main/Redis/RedisSessionsDelegate/#redissessionsdelegate.redis(_:fetchDataFor:)). Both are required, as the way you customize writing the session data to Redis is intrinsically linked to how it is to be read from Redis. diff --git a/docs/security/jwt.md b/docs/security/jwt.md index e720c9d1..d8817871 100644 --- a/docs/security/jwt.md +++ b/docs/security/jwt.md @@ -229,7 +229,7 @@ try app.jwt.signers.use(.rs256(key: .public(pem: rsaPublicKey))) ECDSA is a more modern algorithm that is similar to RSA. It is considered to be more secure for a given key length than RSA[^1]. However, you should do your own research before deciding. -[^1]: [https://sectigostore.com/blog/ecdsa-vs-rsa-everything-you-need-to-know/](https://sectigostore.com/blog/ecdsa-vs-rsa-everything-you-need-to-know/) +[^1]: https://sectigostore.com/blog/ecdsa-vs-rsa-everything-you-need-to-know/ Like RSA, you can load ECDSA keys using PEM files: diff --git a/docs/upgrading.md b/docs/upgrading.md index 8f22d971..755b6b34 100644 --- a/docs/upgrading.md +++ b/docs/upgrading.md @@ -10,7 +10,7 @@ The Install section of the docs goes over installing dependencies. ## Package.swift -The first step to upgrading to Vapor 4 is to update your package's dependencies. Below is an example of an upgraded Package.swift file. You can also check out the updated [template Package.swift](https://github.com/vapor/template/blob/master/Package.swift). +The first step to upgrading to Vapor 4 is to update your package's dependencies. Below is an example of an upgraded Package.swift file. You can also check out the updated [template Package.swift](https://github.com/vapor/template/blob/main/Package.swift). ```diff -// swift-tools-version:4.0 diff --git a/markdown-link-check-config.yml b/markdown-link-check-config.yml new file mode 100644 index 00000000..098c6163 --- /dev/null +++ b/markdown-link-check-config.yml @@ -0,0 +1,4 @@ +{ + "ignorePatterns": [{ "pattern": ".*(localhost|127.0.0.1).*" }], + "aliveStatusCodes": [403, 429, 200] +}