Skip to content

chore(ci): publish an openapi json artifact with nightly releases#999

Merged
zachyale merged 2 commits into
developfrom
chore/publish-api-artifacts-on-nightly-releases
Apr 30, 2026
Merged

chore(ci): publish an openapi json artifact with nightly releases#999
zachyale merged 2 commits into
developfrom
chore/publish-api-artifacts-on-nightly-releases

Conversation

@zachyale

@zachyale zachyale commented Apr 29, 2026

Copy link
Copy Markdown
Member

Description

Adds automated OpenAPI JSON exports to the nightly build pipeline

Once this is in, nightly will generate backend/build/openapi/grimmory-openapi.json from a dedicated openapi-export profile and upload it as a workflow artifact. This will give us a consistent source for the latest nightly API spec without depending on an external database or running it locally.

Once we've confirmed this behaves to our liking, we can merge in the next PR to introduce this flow to stable releases.

Linked Issue: Fixes #291

Changes

  • add a dedicated backend openapi-export profile for lightweight OpenAPI generation
  • add just api openapi-export / buildOpenApiArtifacts support for exporting grimmory-openapi.json
  • wire nightly CI to generate and upload the OpenAPI JSON artifact
  • add a small shared GitHub action for OpenAPI export setup
  • kills outdated refs to application-dev.yml

Summary by CodeRabbit

  • Chores
    • Added automated OpenAPI specification export to nightly builds, published as a versioned artifact
    • Updated development and release documentation to reflect workflow changes

@coderabbitai

coderabbitai Bot commented Apr 29, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR establishes an OpenAPI artifact export pipeline for nightly releases. It introduces a composite GitHub Action orchestrating checkout, Java 25 setup, and Gradle task execution; adds a new nightly workflow job that exports OpenAPI JSON and gates downstream notifications; implements Gradle tasks and a bash script to extract the OpenAPI specification from a running Spring Boot instance; and provides supporting configuration files and documentation updates.

Changes

Cohort / File(s) Summary
GitHub Workflow Integration
.github/actions/export-openapi/action.yml, .github/workflows/publish-nightly.yml
New composite action orchestrates repository checkout, Java 25 setup, and Gradle task execution; nightly workflow adds export-openapi job with dependencies and versioned artifact upload; notification job gated on export success.
Gradle Build Pipeline
backend/build.gradle.kts, backend/Justfile
New Gradle configuration openApiExportRuntimeOnly added; exportOpenApi task launches export script with dynamically computed classpath; buildOpenApiArtifacts task chains bootJar and exportOpenApi; new openapi-export Just recipe invokes the Gradle task.
OpenAPI Export Execution
backend/scripts/export-openapi.sh
New shell script starts Spring Boot application on dynamic port, polls /api/openapi.json endpoint with 60-second timeout, retrieves JSON, writes to output file, terminates background process on exit; enforces strict Bash safety options.
Export Configuration & Documentation
backend/src/main/resources/application-openapi-export.yaml, backend/DEVELOPMENT.md, docs/MAKING-A-RELEASE.md
New Spring profile disables migrations/scheduling, configures H2 in-memory datasource, enables API docs/CORS for localhost; development guide documents just openapi-export workflow; release documentation lists grimmory-openapi.json as published output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related PRs

Suggested labels

backend, chore

Suggested reviewers

  • imajes
  • balazs-szucs

Poem

🐰 Hop, hop, the API docs take flight,
Gradle gathers them, polished and bright,
A JSON artifact, bundled with care,
For nightly releases, there to share!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title follows conventional commit format with type 'chore', scope 'ci', and a clear description of the changes.
Linked Issues check ✅ Passed All code changes directly implement the requirements from #291: generating normalized OpenAPI JSON and bundling it as workflow artifacts for nightly builds.
Out of Scope Changes check ✅ Passed All changes are directly aligned with objectives; the removal of application-dev.yml references is a natural cleanup accompanying the new profile addition.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering the purpose, changes, and linked issue as required by the template.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/publish-api-artifacts-on-nightly-releases
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch chore/publish-api-artifacts-on-nightly-releases

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@backend/build.gradle.kts`:
- Around line 252-282: The exportOpenApi task currently misses the APP_VERSION
as an input, so Gradle can reuse a cached output when the APP_VERSION
environment variable changes; add an inputs.property entry to the
tasks.register("exportOpenApi") configuration (before doLast) that declares the
APP_VERSION (e.g. inputs.property("APP_VERSION", System.getenv("APP_VERSION") ?:
"")) so Gradle will consider APP_VERSION when up-to-date checking and not reuse
stale openApiOutputFile / grimmory-openapi.json produced by exportOpenApi.

In `@backend/scripts/export-openapi.sh`:
- Around line 18-38: The script currently chooses an ephemeral port into
variable port, closes the socket, then starts the JVM which creates a race;
change this by either (A) letting Spring bind port 0 and discovering the
assigned port from the running process (start org.booklore.BookloreApplication
with -Dserver.port=0, tail/grep the application log for the bound port or probe
the application’s /actuator or /api/openapi.json endpoint repeatedly until it
responds and then set endpoint accordingly) or (B) implement a safe startup
retry: after picking port as done today, start the JVM (using "$java_executable"
launching org.booklore.BookloreApplication) and if startup fails to bind that
port detect the failure (check process exit or log for “Address already in use”)
then pick a new ephemeral port and retry a limited number of times before
failing; update variables port, endpoint, app_pid and log handling accordingly
so there is no window where another process can claim the chosen port.
- Around line 54-56: The current check uses grep to look for the string
"openapi" which accepts false positives; instead parse and validate the fetched
JSON by using a JSON parser (e.g., jq) on "$output_file" and verify it contains
a top-level "openapi" field (e.g., test that .openapi exists and is a string)
before exiting successfully; update the conditional around the curl/grep block
(referencing variables endpoint and output_file) to run a jq validation step and
fail (non-zero exit) if the file is not valid OpenAPI JSON.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 2c19d8c0-9649-4d30-ab4f-564ebaeda841

📥 Commits

Reviewing files that changed from the base of the PR and between 9e14f3b and 030c2fa.

📒 Files selected for processing (8)
  • .github/actions/export-openapi/action.yml
  • .github/workflows/publish-nightly.yml
  • backend/DEVELOPMENT.md
  • backend/Justfile
  • backend/build.gradle.kts
  • backend/scripts/export-openapi.sh
  • backend/src/main/resources/application-openapi-export.yaml
  • docs/MAKING-A-RELEASE.md
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test Suite / Backend Tests
  • GitHub Check: Test Suite / Frontend Tests
  • GitHub Check: Analyze (java-kotlin)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: Frontend Lint Threshold Check
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2026-03-31T06:22:25.311Z
Learnt from: imnotjames
Repo: grimmory-tools/grimmory PR: 113
File: booklore-api/build.gradle.kts:89-90
Timestamp: 2026-03-31T06:22:25.311Z
Learning: When reviewing build logic or CI checks that call the JitPack build status API, do not treat a response like {"status":"none"} as evidence that a dependency is unavailable or that a build has failed. JitPack typically builds packages on-demand the first time they’re requested (e.g., via Gradle); "none" means the package isn’t pre-built/cached yet. Only raise a build failure concern when the status explicitly indicates an error/failure (e.g., failed/cancelled), or when dependent resolution actually fails.

Applied to files:

  • backend/build.gradle.kts
📚 Learning: 2026-04-02T09:12:48.158Z
Learnt from: balazs-szucs
Repo: grimmory-tools/grimmory PR: 334
File: booklore-api/build.gradle.kts:0-0
Timestamp: 2026-04-02T09:12:48.158Z
Learning: In this repo, nightcompress (groupId `com.github.gotson.nightcompress`, artifact `nightcompress`) is the preferred library for archive/unarchive operations (including RAR and other formats). During code review, flag changes to Gradle dependency declarations that remove nightcompress or replace it with an alternative for unarchiving (e.g., junrar, commons-compress, JNI-based libraries, or standard Java `ZipInputStream`/`ZipFile`) unless there’s a justified exception. Exceptions are acceptable only when nightcompress cannot handle a specific archive format; in that case, require the PR to clearly document the format limitation, the alternative being used, and get maintainer confirmation of the trade-off.

Applied to files:

  • backend/build.gradle.kts
🪛 Shellcheck (0.11.0)
backend/scripts/export-openapi.sh

[info] 40-45: This function is never invoked. Check usage (or ignored if invoked indirectly).

(SC2329)

Comment thread backend/build.gradle.kts
Comment thread backend/scripts/export-openapi.sh
Comment thread backend/scripts/export-openapi.sh
@zachyale zachyale merged commit 1757d78 into develop Apr 30, 2026
24 checks passed
@zachyale zachyale deleted the chore/publish-api-artifacts-on-nightly-releases branch April 30, 2026 02:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Publish API artifacts on stable release/nightly releases

2 participants