Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new GitHub Actions job to check that examples compile and are properly formatted #870

Merged
merged 7 commits into from
Feb 19, 2024
33 changes: 33 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,36 @@ jobs:
if [[ ${{ steps.changes.outputs.changes }} == true ]]; then
./scripts/test.sh ${{ matrix.crate }}
fi
test-examples-compile:
name: "test (examples)"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 2

- name: Install stable Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
components: clippy, rustfmt

- name: Install nightly Rust
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
components: clippy, rustfmt

- uses: actions/cache@v3
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
examples/**/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}_examples

- name: Test that examples compile
run: |
./scripts/validate-examples.sh
2 changes: 1 addition & 1 deletion examples/raw-json-actix/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::{error::Error, net::Ipv4Addr};

use actix_web::{
middleware::Logger, patch, App, HttpResponse, HttpServer, Responder, Result, web::Json,
middleware::Logger, patch, web::Json, App, HttpResponse, HttpServer, Responder, Result,
};
use serde_json::Value;
use utoipa::OpenApi;
Expand Down
4 changes: 2 additions & 2 deletions examples/rocket-todo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ mod todo {

async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
match request.headers().get("todo_apikey").next() {
Some(key) if key == "utoipa-rocks" => Outcome::Success(RequireApiKey),
Some("utoipa-rocks") => Outcome::Success(RequireApiKey),
None => Outcome::Error((
Status::Unauthorized,
TodoError::Unauthorized(String::from("missing api key")),
Expand All @@ -144,7 +144,7 @@ mod todo {

async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self, Self::Error> {
match request.headers().get("todo_apikey").next() {
Some(key) if key == "utoipa-rocks" => {
Some("utoipa-rocks") => {
log::info!("authenticated");
Outcome::Success(LogApiKey)
}
Expand Down
18 changes: 9 additions & 9 deletions examples/simple-axum/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ use axum::{routing::get, Json};
use utoipa::OpenApi;

#[derive(OpenApi)]
#[openapi(
paths(openapi),
)]
#[openapi(paths(openapi))]
struct ApiDoc;

/// Return JSON version of an OpenAPI schema
Expand All @@ -23,10 +21,12 @@ async fn openapi() -> Json<utoipa::openapi::OpenApi> {

#[tokio::main]
async fn main() {
let sa : SocketAddr = "127.0.0.1:8080".parse().unwrap();
let l = tokio::net::TcpListener::bind(sa).await.unwrap();
let app = axum::Router::new()
.route("/api-docs/openapi.json", get(openapi))
;
axum::serve(l, app.into_make_service()).await.unwrap()
let socket_address: SocketAddr = "127.0.0.1:8080".parse().unwrap();
let listener = tokio::net::TcpListener::bind(socket_address).await.unwrap();

let app = axum::Router::new().route("/api-docs/openapi.json", get(openapi));

axum::serve(listener, app.into_make_service())
.await
.unwrap()
}
7 changes: 4 additions & 3 deletions examples/todo-actix/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,11 @@ async fn main() -> Result<(), impl Error> {
SwaggerUi::new("/swagger-ui/{_:.*}").url("/api-docs/openapi.json", openapi.clone()),
)
// There is no need to create RapiDoc::with_openapi because the OpenApi is served
// via SwaggerUi instead we only make rapidoc to point to the existing doc.
.service(RapiDoc::new("/api-docs/openapi.json").path("/rapidoc"))
// Alternative to above
// via SwaggerUi. Instead we only make rapidoc to point to the existing doc.
//
// If we wanted to serve the schema, the following would work:
// .service(RapiDoc::with_openapi("/api-docs/openapi2.json", openapi.clone()).path("/rapidoc"))
.service(RapiDoc::new("/api-docs/openapi.json").path("/rapidoc"))
})
.bind((Ipv4Addr::UNSPECIFIED, 8080))?
.run()
Expand Down
2 changes: 1 addition & 1 deletion examples/todo-actix/src/todo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use actix_web::{
HttpResponse, Responder,
};
use serde::{Deserialize, Serialize};
use utoipa::{ToSchema, IntoParams};
use utoipa::{IntoParams, ToSchema};

use crate::{LogApiKey, RequireApiKey};

Expand Down
26 changes: 26 additions & 0 deletions scripts/validate-examples.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

set -e

: "${CARGO:=cargo}"

# Finds examples in the `./examples` directory. This query will also automatically
# ignore directories that are not Rust projects (i.e. those that don't contain Cargo.toml).
EXAMPLES=$(find ./examples/ -maxdepth 1 -mindepth 1 -type d -exec test -e "{}/Cargo.toml" ";" -print)


for example in $EXAMPLES
do
echo "Checking example: $example..."

pushd $example

$CARGO fmt --check
echo " -> example is properly formatted (passes cargo fmt)"
$CARGO clippy --all-features --all-targets --workspace --quiet
echo " -> example compiles (passes cargo clippy)"

popd
done

echo "All examples are valid!"
Loading