Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/lint_openapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
name: OpenAPI Lint

on:
push:
branches: [stable, development, '*.x']
paths:
- 'use-cases/**'
- '.github/workflows/lint_openapi.yml'
pull_request:
branches: [stable, development, '*.x']
paths:
- 'use-cases/**'
- '.github/workflows/lint_openapi.yml'

jobs:
vacuum:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Checkout timefold-quickstarts
uses: actions/checkout@v7

# The GitHub token prevents intermittent installation failures caused by
# API rate limiting. It only accesses public repository information.
- name: Install vacuum
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: curl -fsSL https://quobix.com/scripts/install_vacuum.sh | sh

# Lints the committed OpenAPI spec of every model that ships a vacuum ruleset.
- name: Lint OpenAPI specs
run: |
found=0
for ruleset in use-cases/*/.vacuum-ruleset.yaml; do
model_dir="$(dirname "$ruleset")"
spec="$model_dir/src/build/openapi.json"
if [ ! -f "$spec" ]; then
echo "::error::$model_dir has a vacuum ruleset but no committed spec at $spec"
exit 1
fi
Comment on lines +36 to +40
found=1
echo "::group::vacuum lint $spec"
vacuum lint --ruleset "$ruleset" --details --fail-severity error "$spec"
echo "::endgroup::"
done
if [ "$found" -eq 0 ]; then
echo "::error::no .vacuum-ruleset.yaml found under use-cases/"
exit 1
fi
108 changes: 108 additions & 0 deletions use-cases/conference-scheduling/.vacuum-ruleset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Spectral-compatible vacuum ruleset.
# Enforces that every project-owned component schema and each of its properties
# has a 'description' field. SDK-provided schemas are intentionally excluded.
# All other built-in rules are explicitly disabled so the checks are focused.
#
# SDK schemas are identified by their name prefix and excluded via a JSONPath
# filter expression using search(@property, ...). Any schema whose name does NOT
# start with a known SDK prefix is treated as project-owned and must have
# descriptions. This means the ruleset automatically covers renamed or newly
# added domain classes without requiring any changes here.
#
# Known SDK name prefixes (kept in sync with timefold-sdk-model-parent releases):
# Dataset, Demo, Duration, Empty, Error, Log, Maps, Metadata, Model,
# Offset, Operation, Resources, Run, Score, Solver, Solving,
# ValidationError, ValidationResultSummary
#
# Run in CI: .github/workflows/lint_openapi.yml lints the committed spec of every
# model that ships a .vacuum-ruleset.yaml.
# Run locally: install vacuum (https://quobix.com/vacuum/installing/), then
# vacuum lint --ruleset .vacuum-ruleset.yaml --details --fail-severity error src/build/openapi.json
Comment on lines +17 to +20
extends:
- - vacuum:oas
- recommended
rules:
# disable all built-in rules (including the generic component-description)
camel-case-properties: off
component-description: off # replaced below with a scoped custom rule
description-duplication: off
duplicate-paths: off
duplicated-entry-in-enum: off
info-description: off
info-license-spdx: off
migrate-zally-ignore: off
no-$ref-siblings: off
no-ambiguous-paths: off
no-eval-in-markdown: off
no-http-verbs-in-path: off
no-request-body: off
no-script-tags-in-markdown: off
no-unnecessary-combinator: off
nullable-enum-contains-null: off
oas-missing-type: off
oas-schema-check: off
oas2-anyOf: off
oas2-api-host: off
oas2-api-schemes: off
oas2-discriminator: off
oas2-host-not-example: off
oas2-host-trailing-slash: off
oas2-oneOf: off
oas2-operation-formData-consume-check: off
oas2-operation-security-defined: off
oas2-parameter-description: off
oas2-schema: off
oas2-unused-definition: off
oas3-api-servers: off
oas3-example-external-check: off
oas3-missing-example: off
oas3-no-$ref-siblings: off
oas3-operation-security-defined: off
oas3-parameter-description: off
oas3-schema: off
oas3-unused-component: off
oas3-valid-schema-example: off
operation-description: off
operation-operationId: off
operation-operationId-unique: off
operation-operationId-valid-in-url: off
operation-parameters: off
operation-success-response: off
operation-tag-defined: off
operation-tags: off
path-declarations-must-exist: off
path-item-refs: off
path-keys-no-trailing-slash: off
path-not-include-query: off
path-params: off
paths-kebab-case: off
typed-enum: off

# Circular $ref chains in schemas must be treated as build-breaking errors.
circular-references: error

# Every project-owned schema must have a top-level 'description'.
# SDK schemas are excluded by rejecting all names that start with a known SDK prefix.
# Any schema whose name does NOT match the prefix pattern is considered project-owned
# and is automatically checked — no changes needed here when classes are renamed or added.
project-schema-description:
description: "Every project-owned component schema must have a top-level 'description'."
howToFix: 'Add a @Schema(description = "...") annotation to the Java class.'
severity: error
given:
- "$.components.schemas[?!search(@property, '^(Dataset|Demo|Duration|Empty|Error|Issue|Log|Maps|Metadata|Model|Offset|Operation|Resources|Run|Score|Solving|Solver|StringDetail|Validation)')]"
then:
field: description
function: truthy

# Every property of a project-owned schema must also have a 'description'.
# SDK schemas are excluded using the same prefix filter as above.
project-schema-property-description:
description: "Every property in a project-owned schema must have a 'description'."
howToFix: 'Add a @Schema(description = "...") annotation to the field or getter in the Java source.'
severity: error
given:
- "$.components.schemas[?!search(@property, '^(Dataset|Demo|Duration|Empty|Error|Issue|Log|Maps|Metadata|Model|Offset|Operation|Resources|Run|Score|Solving|Solver|StringDetail|Validation)')].properties[*]"
then:
field: description
function: truthy
28 changes: 14 additions & 14 deletions use-cases/conference-scheduling/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,34 +55,34 @@ Assign conference talks to timeslots and rooms to produce a better schedule for
1. Install Java and Maven, for example with [Sdkman](https://sdkman.io):

```sh
$ sdk install java
$ sdk install maven
sdk install java
sdk install maven
```

## Run the application

1. Git clone the timefold-quickstarts repo and navigate to this directory:

```sh
$ git clone https://github.com/TimefoldAI/timefold-quickstarts.git
git clone https://github.com/TimefoldAI/timefold-quickstarts.git
...
$ cd timefold-quickstarts/use-cases/conference-scheduling
cd timefold-quickstarts/use-cases/conference-scheduling
```
Comment thread
larsbeck marked this conversation as resolved.

2. (Optional) If you want to run a licensed edition (Plus / Enterprise), set up your license key first. See the [Timefold license tool](https://licenses.timefold.ai/) for instructions.

3. Start the application with Maven:

1. Community Edition

```sh
$ mvn quarkus:dev
mvn quarkus:dev
```

2. Plus / Enterprise Edition: The profile sets up the correct Maven artifacts to run the licensed version. See the `pom.xml` for the implementation details.

```sh
$ mvn quarkus:dev -Denterprise
mvn quarkus:dev -Denterprise
```

4. Visit [http://localhost:8080](http://localhost:8080) in your browser.
Expand All @@ -103,13 +103,13 @@ When you're done iterating in `quarkus:dev` mode, package the application to run
1. Build it with Maven:

```sh
$ mvn package
mvn package
```

2. Run the Maven output:

```sh
$ java -jar ./target/quarkus-app/quarkus-run.jar
java -jar ./target/quarkus-app/quarkus-run.jar
```

> **Note**
Expand All @@ -124,13 +124,13 @@ When you're done iterating in `quarkus:dev` mode, package the application to run
1. Build a container image:

```sh
$ mvn package -Dcontainer
mvn package -Dcontainer
```

2. Run a container:

```sh
$ docker run -p 8080:8080 --rm $USER/conference-scheduling:1.0-SNAPSHOT
docker run -p 8080:8080 --rm $USER/conference-scheduling:1.0-SNAPSHOT
```

## Run it native
Expand All @@ -142,13 +142,13 @@ To increase startup performance for serverless deployments, build the applicatio
2. Compile it natively. This takes a few minutes:

```sh
$ mvn package -Dnative
mvn package -Dnative
```

3. Run the native executable:

```sh
$ ./target/*-runner
./target/*-runner
```

4. Visit [http://localhost:8080](http://localhost:8080) in your browser.
Expand Down
Loading
Loading