Skip to content

HYPERFLEET-1103 - feat: split core and gcp contracts in separate repos#52

Merged
openshift-merge-bot[bot] merged 2 commits into
openshift-hyperfleet:mainfrom
rh-amarin:remove-gcp-from-core
May 26, 2026
Merged

HYPERFLEET-1103 - feat: split core and gcp contracts in separate repos#52
openshift-merge-bot[bot] merged 2 commits into
openshift-hyperfleet:mainfrom
rh-amarin:remove-gcp-from-core

Conversation

@rh-amarin
Copy link
Copy Markdown
Collaborator

@rh-amarin rh-amarin commented May 26, 2026

  • Move GCP-specific models out of this repo
  • Restructure sources into core/ (core-specific) and shared/ (cross-provider)
  • Add generic Resource model and CRUD service (from main reconciliation)
  • Add force-delete endpoints for clusters, nodepools, and resources (internal)
  • Add ResourceStatusesInternal for adapter resource status reporting
  • Simplify build script: single provider (core only), openapi output only
    • It doesn't require parameters
  • Add npm sub-path exports to enable downstream package imports

The changes convert this to be a npm package that can be imported by a partner to build their own API contract leveraging common structures.

  • The npm version is modified by the build script to keep it aligned with the openapi version

To test the GCP contract

It should generate the openapi.yaml and swagger.yaml files

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

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

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: cec6889c-0bff-400e-8835-72d79f4b226c

📥 Commits

Reviewing files that changed from the base of the PR and between 17ab4a9 and 89b9f9b.

📒 Files selected for processing (1)
  • schemas/core/openapi.yaml

📝 Walkthrough

Summary by CodeRabbit

  • Refactor

    • Focused the published API on the core OpenAPI v3 contract; provider-specific resources moved out of the core spec.
    • Removed Swagger (OpenAPI v2) outputs and simplified the build/release to a single core artifact.
    • Reorganized some status endpoints (PUT/GET grouping and ordering) for clarity.
  • Documentation

    • Updated docs, contribution and release guidance for the core-only workflow and bumped API version to 1.0.18.

Walkthrough

This PR migrates the repo to produce only the core OpenAPI schema: CI and release workflows now build/publish core only, build-schema.sh is simplified to a fixed core build, package.json and Go embedding updated to reference core/openapi.yaml, TypeSpec sources were reorganized to shared/ vs core/ with many GCP-specific models/services removed or emptied, core OpenAPI bumped to 1.0.18 with added PUT status endpoints for clusters and nodepools, and documentation/changelog updated to reflect the core-only workflow.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title accurately reflects the main change: splitting core and GCP contracts into separate repositories by moving GCP-specific models out and restructuring sources.
Description check ✅ Passed The PR description comprehensively covers the major changes including GCP migration, repository restructuring, new features, build script simplification, and npm package configuration—all present in the changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

Review ran into problems

🔥 Problems

Stopped waiting for pipeline failures after 30000ms. One of your pipelines takes longer than our 30000ms fetch window to run, so review may not consider pipeline-failure results for inline comments if any failures occurred after the fetch window. Increase the timeout if you want to wait longer or run a @coderabbit review after the pipeline has finished.


Linked repositories: Couldn't analyze openshift-hyperfleet/hyperfleet-sentinel - clone failed: Clone operation failed: Cloning into '/home/jailuser/git'...
warning: templates not found in /usr/share/git-core/templates
fatal: unable to access 'https://github.com/openshift-hyperfleet/hyperfleet-sentinel.git/': Failed to connect to github.com port 443 after 133289 ms: Couldn't connect to server


Linked repositories: Couldn't analyze openshift-hyperfleet/hyperfleet-api - clone failed: Clone operation failed: Cloning into '/home/jailuser/git'...
warning: templates not found in /usr/share/git-core/templates
fatal: unable to access 'https://github.com/openshift-hyperfleet/hyperfleet-api.git/': Failed to connect to github.com port 443 after 135079 ms: Couldn't connect to server


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

@rh-amarin rh-amarin force-pushed the remove-gcp-from-core branch 4 times, most recently from bd81e1a to 9f365a7 Compare May 26, 2026 14:21
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shared/services/statuses.tsp (1)

37-39: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Missing @useAuth decorator creates unauthenticated endpoint.

NodePoolStatuses interface lacks @useAuth(HyperFleet.BearerAuth) while ClusterStatuses (line 14) has it. This makes getNodePoolsStatuses publicly accessible without authentication, exposing adapter status data for nodepools.

If the intent was to align with cluster-level auth handling, ClusterStatuses does require auth, so NodePoolStatuses should too.

🔒 Proposed fix
 `@tag`("NodePool statuses")
 `@route`("/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses")
+@useAuth(HyperFleet.BearerAuth)
 interface NodePoolStatuses{
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shared/services/statuses.tsp` around lines 37 - 39, The NodePoolStatuses
interface is missing the authentication decorator, making its endpoints (e.g.,
getNodePoolsStatuses) unauthenticated; add the same decorator used by
ClusterStatuses — `@useAuth`(HyperFleet.BearerAuth) — directly above the
NodePoolStatuses declaration so all routes under NodePoolStatuses require the
BearerAuth protection.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Line 141: The changelog link for [Unreleased] was reset to
compare/v1.0.14...HEAD which breaks released-version traceability; update the
[Unreleased] link to compare/v1.0.15...HEAD (or to the last published tag
appropriate for downstream consumers) and restore the missing release note
sections for 1.0.15 through 1.0.17 so historical, authoritative release notes
remain present; locate the `[Unreleased]:
https://github.com/openshift-hyperfleet/hyperfleet-api-spec/compare/v1.0.14...HEAD`
entry and the removed "1.0.15"–"1.0.17" sections in CHANGELOG.md and reinsert
the released entries and their contents verbatim (or merge any upstream changes)
to preserve accurate history.

In `@main.tsp`:
- Around line 33-35: CI fails because the release-version extractor cannot parse
the current `@info` map-style declaration in main.tsp (the `@info`(...) block
containing version: "1.0.18"); either change the `@info` declaration so the
version appears as the extractor-expected inline token (put the version as the
inline/positional string the extractor expects instead of nested inside the map
under the key version) or update the extractor to accept the existing map-shaped
`@info` with the version key; update the `@info` usage and any tests referencing it
(symbol: `@info` and the version field) to ensure the extractor finds the version
string during CI.

In `@schemas/schemas.go`:
- Line 13: You removed "gcp/openapi.yaml" from the embedded filesystem (the
//go:embed declaration that populates FS), breaking callers that do
FS.ReadFile("gcp/openapi.yaml"); restore compatibility by either re-adding
gcp/openapi.yaml to the //go:embed list (e.g., embed both core/openapi.yaml and
gcp/openapi.yaml into FS) or provide a compatibility shim that falls back to the
new core/openapi.yaml path when FS.ReadFile("gcp/openapi.yaml") is called; if
you intend a breaking change instead, update the RELEASING.md and add a clear
migration note in the same PR describing the removal and the new path so
consumers can update their usage of FS.ReadFile("gcp/openapi.yaml").

---

Outside diff comments:
In `@shared/services/statuses.tsp`:
- Around line 37-39: The NodePoolStatuses interface is missing the
authentication decorator, making its endpoints (e.g., getNodePoolsStatuses)
unauthenticated; add the same decorator used by ClusterStatuses —
`@useAuth`(HyperFleet.BearerAuth) — directly above the NodePoolStatuses
declaration so all routes under NodePoolStatuses require the BearerAuth
protection.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: c89f0c5f-0286-4c18-aff9-e0f3419b6e46

📥 Commits

Reviewing files that changed from the base of the PR and between a769d48 and ae46114.

📒 Files selected for processing (56)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
  • aliases-core.tsp
  • aliases-gcp.tsp
  • aliases.tsp
  • build-schema.sh
  • core/models/cluster/example_cluster.tsp
  • core/models/cluster/example_patch.tsp
  • core/models/cluster/example_post.tsp
  • core/models/cluster/model.tsp
  • core/models/nodepool/example_nodepool.tsp
  • core/models/nodepool/example_patch.tsp
  • core/models/nodepool/example_post.tsp
  • core/models/nodepool/model.tsp
  • core/services/force-delete-internal.tsp
  • core/services/statuses-internal.tsp
  • main.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/cluster/example_patch.tsp
  • models-gcp/cluster/example_post.tsp
  • models-gcp/cluster/model.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/version/example_version.tsp
  • models-gcp/version/model.tsp
  • models/compatibility/README.md
  • package.json
  • schemas/core/openapi.yaml
  • schemas/core/swagger.yaml
  • schemas/gcp/openapi.yaml
  • schemas/gcp/swagger.yaml
  • schemas/schemas.go
  • services/channels.tsp
  • services/versions.tsp
  • shared/models/clusters/model.tsp
  • shared/models/common/model.tsp
  • shared/models/nodepools/model.tsp
  • shared/models/resource/example_patch.tsp
  • shared/models/resource/example_post.tsp
  • shared/models/resource/example_resource.tsp
  • shared/models/resource/model.tsp
  • shared/models/statuses/example_adapter_status.tsp
  • shared/models/statuses/model.tsp
  • shared/services/clusters.tsp
  • shared/services/nodepools.tsp
  • shared/services/resources.tsp
  • shared/services/statuses.tsp
💤 Files with no reviewable changes (25)
  • models-gcp/nodepool/model.tsp
  • models-gcp/nodepool/example_patch.tsp
  • aliases.tsp
  • schemas/core/swagger.yaml
  • models-gcp/version/model.tsp
  • models-gcp/cluster/example_post.tsp
  • services/versions.tsp
  • schemas/gcp/openapi.yaml
  • models-gcp/cluster/model.tsp
  • models-gcp/cluster/example_cluster.tsp
  • services/channels.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • aliases-core.tsp
  • models-gcp/cluster/example_patch.tsp
  • models/compatibility/README.md
  • models-gcp/channel/example_channel.tsp
  • models-gcp/version/example_version.tsp
  • schemas/gcp/swagger.yaml
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/version/example_patch.tsp
  • aliases-gcp.tsp

Comment thread CHANGELOG.md Outdated
Comment thread main.tsp
Comment thread schemas/schemas.go
@rh-amarin rh-amarin marked this pull request as ready for review May 26, 2026 14:23
@openshift-ci openshift-ci Bot requested review from aredenba-rh and vkareh May 26, 2026 14:23
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
shared/services/statuses.tsp (1)

37-40: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore auth on NodePoolStatuses to avoid unintended public access.

@useAuth(HyperFleet.BearerAuth) was removed from this interface, which leaves GET /clusters/{cluster_id}/nodepools/{nodepool_id}/statuses unauthenticated while adjacent status endpoints remain protected.

Suggested fix
 `@tag`("NodePool statuses")
 `@route`("/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses")
+@useAuth(HyperFleet.BearerAuth)
 interface NodePoolStatuses{
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shared/services/statuses.tsp` around lines 37 - 40, The NodePoolStatuses
interface lost its authentication decorator causing GET
/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses to be publicly
accessible; restore the auth by re-adding the `@useAuth`(HyperFleet.BearerAuth)
decorator above the NodePoolStatuses interface (the same place other status
interfaces are protected) so the NodePoolStatuses interface and its route are
guarded by the HyperFleet.BearerAuth scheme.
♻️ Duplicate comments (1)
main.tsp (1)

33-35: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

CI blocker: version extraction from @info still failing

Pipeline still fails to parse version from this block (Failed to extract version from main.tsp). This remains a release-gating issue; please align the @info formatting with the extractor or update the extractor to parse the current layout.

Compatible formatting option
-@info(#{
-  version: "1.0.18",
+@info(#{ version: "1.0.18",
   contact: #{
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@main.tsp` around lines 33 - 35, The CI fails because the pipeline extractor
can't read the version from the `@info` block (the "version" key inside `@info` is
laid out in a way the extractor doesn't handle). Fix by either (A) normalizing
the `@info` block so the version appears in the extractor's expected format (e.g.,
move/version key to the exact single-line/quoted format the extractor expects
under `@info`) or (B) update the extractor code (the function that reads `@info` /
extractVersion or parseInfoBlock) to accept the current #{} nested layout and
robustly parse the "version" token; choose one approach and make sure the
"version" string under `@info` is discoverable by the extractor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@core/models/cluster/example_cluster.tsp`:
- Around line 1-3: Add a namespace declaration immediately after the import
block in example_cluster.tsp (e.g., namespace core.models.cluster) so the file
follows the rule that imports come first then namespace; update or create the
namespace line to match the module's logical path and ensure subsequent type
definitions are inside that namespace (find the import block and insert the
namespace declaration directly beneath it, then move/confirm types like any
cluster interfaces or models are declared under that namespace).

In `@core/models/nodepool/example_post.tsp`:
- Around line 1-2: The file contains only imports (import "./model.tsp"; import
"../../../shared/models/nodepools/model.tsp";) but is missing the required
namespace declaration; add a namespace declaration immediately after those
import statements (e.g., add a line like `namespace <AppropriateName>;`) using
the same namespace name convention as other TypeSpec files in this module so
imports remain first and the namespace follows.

In `@package.json`:
- Around line 18-19: package.json currently pins "`@typespec/rest`" and
"`@typespec/versioning`" to ^0.81.0 which conflicts with other `@typespec/`*
packages; update the dependency entries for "`@typespec/rest`" and
"`@typespec/versioning`" to "^1.6.0" in package.json (keeping the same dependency
type), then run your package manager (npm install / yarn install / pnpm install)
to update the lockfile so the project uses the consistent TypeSpec ^1.6.0 set.

In `@shared/models/statuses/example_adapter_status.tsp`:
- Around line 1-2: This file has imports (import "./model.tsp"; import
"../common/model.tsp";) but is missing the required TypeSpec namespace
declaration immediately after them; add a namespace declaration line (e.g.,
namespace <your_namespace>; ) directly following the import statements so the
file follows the rule "imports first, then namespace" and ensure the namespace
name matches your project's naming conventions and other .tsp files.

---

Outside diff comments:
In `@shared/services/statuses.tsp`:
- Around line 37-40: The NodePoolStatuses interface lost its authentication
decorator causing GET /clusters/{cluster_id}/nodepools/{nodepool_id}/statuses to
be publicly accessible; restore the auth by re-adding the
`@useAuth`(HyperFleet.BearerAuth) decorator above the NodePoolStatuses interface
(the same place other status interfaces are protected) so the NodePoolStatuses
interface and its route are guarded by the HyperFleet.BearerAuth scheme.

---

Duplicate comments:
In `@main.tsp`:
- Around line 33-35: The CI fails because the pipeline extractor can't read the
version from the `@info` block (the "version" key inside `@info` is laid out in a
way the extractor doesn't handle). Fix by either (A) normalizing the `@info` block
so the version appears in the extractor's expected format (e.g., move/version
key to the exact single-line/quoted format the extractor expects under `@info`) or
(B) update the extractor code (the function that reads `@info` / extractVersion or
parseInfoBlock) to accept the current #{} nested layout and robustly parse the
"version" token; choose one approach and make sure the "version" string under
`@info` is discoverable by the extractor.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: ccd75fa4-64cc-43d8-b6d9-12fac1268546

📥 Commits

Reviewing files that changed from the base of the PR and between ae46114 and 9f365a7.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (60)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • RELEASING.md
  • aliases-core.tsp
  • aliases-gcp.tsp
  • aliases.tsp
  • build-schema.sh
  • core/models/cluster/example_cluster.tsp
  • core/models/cluster/example_patch.tsp
  • core/models/cluster/example_post.tsp
  • core/models/cluster/model.tsp
  • core/models/nodepool/example_nodepool.tsp
  • core/models/nodepool/example_patch.tsp
  • core/models/nodepool/example_post.tsp
  • core/models/nodepool/model.tsp
  • core/services/force-delete-internal.tsp
  • core/services/statuses-internal.tsp
  • main.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/cluster/example_patch.tsp
  • models-gcp/cluster/example_post.tsp
  • models-gcp/cluster/model.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/version/example_version.tsp
  • models-gcp/version/model.tsp
  • models/compatibility/README.md
  • package.json
  • schemas/core/openapi.yaml
  • schemas/core/swagger.yaml
  • schemas/gcp/openapi.yaml
  • schemas/gcp/swagger.yaml
  • schemas/schemas.go
  • services/channels.tsp
  • services/versions.tsp
  • shared/models/clusters/model.tsp
  • shared/models/common/model.tsp
  • shared/models/nodepools/model.tsp
  • shared/models/resource/example_patch.tsp
  • shared/models/resource/example_post.tsp
  • shared/models/resource/example_resource.tsp
  • shared/models/resource/model.tsp
  • shared/models/statuses/example_adapter_status.tsp
  • shared/models/statuses/model.tsp
  • shared/services/clusters.tsp
  • shared/services/nodepools.tsp
  • shared/services/resources.tsp
  • shared/services/statuses.tsp
💤 Files with no reviewable changes (25)
  • models-gcp/channel/example_patch.tsp
  • schemas/core/swagger.yaml
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/channel/example_post.tsp
  • aliases.tsp
  • models/compatibility/README.md
  • models-gcp/version/model.tsp
  • aliases-core.tsp
  • services/versions.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/cluster/model.tsp
  • services/channels.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/cluster/example_patch.tsp
  • aliases-gcp.tsp
  • schemas/gcp/openapi.yaml
  • models-gcp/nodepool/example_nodepool.tsp
  • schemas/gcp/swagger.yaml
  • models-gcp/version/example_version.tsp
  • models-gcp/cluster/example_post.tsp
  • models-gcp/version/example_post.tsp

Comment thread core/models/cluster/example_cluster.tsp
Comment thread core/models/nodepool/example_post.tsp
Comment thread package.json
Comment thread shared/models/statuses/example_adapter_status.tsp
@rh-amarin rh-amarin force-pushed the remove-gcp-from-core branch from 9f365a7 to 33d57f0 Compare May 26, 2026 16:08
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
.github/workflows/release.yml (1)

39-50: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Tag-based skip logic can permanently block release creation after partial failure.

Using tag existence as the global skip gate means a failed Create GitHub Release after tag push cannot be recovered by rerun (skip=true short-circuits all later steps). Gate on release existence (or separate tag creation from release creation) instead of tag existence alone.

Suggested adjustment
-      - name: Check if release already exists
-        id: check_tag
+      - name: Check if GitHub release already exists
+        id: check_release
         env:
           TAG: ${{ steps.version.outputs.tag }}
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
         run: |
-          git fetch --tags
-          if git rev-parse "$TAG" >/dev/null 2>&1; then
-            echo "Tag $TAG already exists — skipping release"
+          if gh release view "$TAG" >/dev/null 2>&1; then
+            echo "Release $TAG already exists — skipping release"
             echo "skip=true" >> "$GITHUB_OUTPUT"
           else
             echo "skip=false" >> "$GITHUB_OUTPUT"
           fi

-      - name: Build core schema
-        if: steps.check_tag.outputs.skip == 'false'
+      - name: Build core schema
+        if: steps.check_release.outputs.skip == 'false'
         run: ./build-schema.sh

Also applies to: 61-73

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/release.yml around lines 39 - 50, The workflow currently
uses the check_tag step (env TAG) to skip when a git tag exists, which blocks
reruns if release creation failed; change the gating to check for a GitHub
release instead (or split tag push and release creation into two distinct steps)
by replacing the tag-existence test in the check_tag logic with a
release-existence query against the GitHub API (or add a new step like
check_release that calls GET /repos/{owner}/{repo}/releases/tags/{tag}) and use
that step's output to set skip; update downstream consumers (e.g., the Create
GitHub Release step) to rely on the release-existence output so a missing
release can be retried even if the tag already exists.
README.md (1)

158-177: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Update “Adding a New Service” paths to the shared/core layout.

The section still points contributors to services/new-service.tsp and ./services/new-service.tsp, which conflicts with this repo’s split structure and will send new endpoints to the wrong location.

Suggested correction
-1. Create a new service file: `services/new-service.tsp`
+1. Create a new service file under the correct scope:
+   - Public/shared endpoint: `shared/services/new-service.tsp`
+   - Internal/core-only endpoint: `core/services/new-service.tsp`
@@
-   import "../models/common/model.tsp";
+   import "../models/common/model.tsp";
@@
-2. Import the new service in `main.tsp`:
+2. Import the new service in `main.tsp` using its scoped path:
@@
-   import "./services/new-service.tsp";
+   import "./shared/services/new-service.tsp";
+   // or: import "./core/services/new-service.tsp";

As per coding guidelines **: Focus on major issues impacting performance, readability, maintainability and security. Validate changes against HyperFleet architecture standards from the linked architecture repository.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 158 - 177, The README's "Adding a New Service"
section incorrectly points to services/new-service.tsp and
./services/new-service.tsp which conflicts with the repo's split layout; update
the example to create the service under the shared/core layout (e.g.,
shared/core/services/new-service.tsp) and update the import in main.tsp to the
corresponding shared/core path, keeping the same interface name NewService and
route("/new-resource") so examples match the repository structure and will place
new endpoints in the correct shared/core location.
core/services/force-delete-internal.tsp (1)

12-60: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Split this service into one-resource-per-file.

ClustersForceDelete and NodePoolsForceDelete are defined in the same service file, which violates the service-file boundary rule and makes ownership/maintenance harder.

As per coding guidelines {shared,core}/services/**/*.tsp: Keep TypeSpec service files focused with one resource per service file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/services/force-delete-internal.tsp` around lines 12 - 60, Split the
combined service into two TypeSpec service files so each resource has its own
service: move the ClustersForceDelete interface (including its `@tag`("Clusters"),
`@route`("/clusters") and forceDeleteCluster operation) into a new file and move
the NodePoolsForceDelete interface (including `@tag`("NodePools"),
`@route`("/clusters/{cluster_id}/nodepools") and forceDeleteNodePool) into a
separate file; preserve the same interface names, decorators, request/response
types (ForceDeleteRequest, statusCode 204, and the same error union), update any
imports or references to these interfaces elsewhere, and ensure each new file
follows the project service-file pattern ({shared,core}/services/**/*.tsp) and
compiles.
shared/services/statuses.tsp (1)

37-40: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Restore auth on NodePoolStatuses GET endpoints.

@useAuth(HyperFleet.BearerAuth) was dropped from NodePoolStatuses, which makes nodepool status reads unauthenticated in the generated contract.

Suggested fix
 `@tag`("NodePool statuses")
 `@route`("/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses")
+@useAuth(HyperFleet.BearerAuth)
 interface NodePoolStatuses{
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shared/services/statuses.tsp` around lines 37 - 40, The NodePoolStatuses
interface's routes lost authentication — restore the
`@useAuth`(HyperFleet.BearerAuth) decorator on the NodePoolStatuses contract so
all GET endpoints under interface NodePoolStatuses (route
"/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses") require bearer auth;
add the `@useAuth`(HyperFleet.BearerAuth) annotation immediately above the
`@tag/`@route declarations for NodePoolStatuses to re-enable authenticated reads.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CHANGELOG.md`:
- Around line 10-18: The CHANGELOG entry for [1.0.18] only has "### Changed";
update the section to include the full Keep a Changelog heading set by adding
"### Added", "### Changed", "### Fixed", and "### Removed" subsections under the
[1.0.18] header (populate "Changed" with the existing bullets and add the other
three with either relevant bullets or a single "- None." placeholder), ensuring
the version header "[1.0.18] - 2026-05-26" remains unchanged and the overall
format matches other releases in CHANGELOG.md.

In `@package.json`:
- Around line 18-19: Update the two package entries "`@typespec/rest`" and
"`@typespec/versioning`" in package.json so their versions match the repository
TypeSpec policy; change their version strings from "^0.81.0" to "^1.6.0" (the
same version used by "`@typespec/compiler`", "`@typespec/http`",
"`@typespec/openapi`", and "`@typespec/openapi3`") to prevent dependency-version
drift.

In `@README.md`:
- Around line 94-96: The README table is inaccurate:
`core/services/statuses-internal.tsp` is marked "❌ No (opt-in)" but the current
core schema includes the PUT (write) status operations; update the table row for
`core/services/statuses-internal.tsp` to reflect that PUT (write) is included in
the core build (e.g., change to "✅ Yes (included)") and adjust the descriptive
note accordingly, and then re-validate the change against HyperFleet
architecture standards to ensure wording matches project conventions.

---

Outside diff comments:
In @.github/workflows/release.yml:
- Around line 39-50: The workflow currently uses the check_tag step (env TAG) to
skip when a git tag exists, which blocks reruns if release creation failed;
change the gating to check for a GitHub release instead (or split tag push and
release creation into two distinct steps) by replacing the tag-existence test in
the check_tag logic with a release-existence query against the GitHub API (or
add a new step like check_release that calls GET
/repos/{owner}/{repo}/releases/tags/{tag}) and use that step's output to set
skip; update downstream consumers (e.g., the Create GitHub Release step) to rely
on the release-existence output so a missing release can be retried even if the
tag already exists.

In `@core/services/force-delete-internal.tsp`:
- Around line 12-60: Split the combined service into two TypeSpec service files
so each resource has its own service: move the ClustersForceDelete interface
(including its `@tag`("Clusters"), `@route`("/clusters") and forceDeleteCluster
operation) into a new file and move the NodePoolsForceDelete interface
(including `@tag`("NodePools"), `@route`("/clusters/{cluster_id}/nodepools") and
forceDeleteNodePool) into a separate file; preserve the same interface names,
decorators, request/response types (ForceDeleteRequest, statusCode 204, and the
same error union), update any imports or references to these interfaces
elsewhere, and ensure each new file follows the project service-file pattern
({shared,core}/services/**/*.tsp) and compiles.

In `@README.md`:
- Around line 158-177: The README's "Adding a New Service" section incorrectly
points to services/new-service.tsp and ./services/new-service.tsp which
conflicts with the repo's split layout; update the example to create the service
under the shared/core layout (e.g., shared/core/services/new-service.tsp) and
update the import in main.tsp to the corresponding shared/core path, keeping the
same interface name NewService and route("/new-resource") so examples match the
repository structure and will place new endpoints in the correct shared/core
location.

In `@shared/services/statuses.tsp`:
- Around line 37-40: The NodePoolStatuses interface's routes lost authentication
— restore the `@useAuth`(HyperFleet.BearerAuth) decorator on the NodePoolStatuses
contract so all GET endpoints under interface NodePoolStatuses (route
"/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses") require bearer auth;
add the `@useAuth`(HyperFleet.BearerAuth) annotation immediately above the
`@tag/`@route declarations for NodePoolStatuses to re-enable authenticated reads.
🪄 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: Central YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 832e3815-fdaa-474e-9f80-c57df94e33c7

📥 Commits

Reviewing files that changed from the base of the PR and between 9f365a7 and 33d57f0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (60)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • RELEASING.md
  • aliases-core.tsp
  • aliases-gcp.tsp
  • aliases.tsp
  • build-schema.sh
  • core/models/cluster/example_cluster.tsp
  • core/models/cluster/example_patch.tsp
  • core/models/cluster/example_post.tsp
  • core/models/cluster/model.tsp
  • core/models/nodepool/example_nodepool.tsp
  • core/models/nodepool/example_patch.tsp
  • core/models/nodepool/example_post.tsp
  • core/models/nodepool/model.tsp
  • core/services/force-delete-internal.tsp
  • core/services/statuses-internal.tsp
  • main.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/cluster/example_patch.tsp
  • models-gcp/cluster/example_post.tsp
  • models-gcp/cluster/model.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/version/example_version.tsp
  • models-gcp/version/model.tsp
  • models/compatibility/README.md
  • package.json
  • schemas/core/openapi.yaml
  • schemas/core/swagger.yaml
  • schemas/gcp/openapi.yaml
  • schemas/gcp/swagger.yaml
  • schemas/schemas.go
  • services/channels.tsp
  • services/versions.tsp
  • shared/models/clusters/model.tsp
  • shared/models/common/model.tsp
  • shared/models/nodepools/model.tsp
  • shared/models/resource/example_patch.tsp
  • shared/models/resource/example_post.tsp
  • shared/models/resource/example_resource.tsp
  • shared/models/resource/model.tsp
  • shared/models/statuses/example_adapter_status.tsp
  • shared/models/statuses/model.tsp
  • shared/services/clusters.tsp
  • shared/services/nodepools.tsp
  • shared/services/resources.tsp
  • shared/services/statuses.tsp
💤 Files with no reviewable changes (25)
  • models-gcp/version/example_version.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/channel/example_post.tsp
  • services/channels.tsp
  • aliases-gcp.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/nodepool/example_post.tsp
  • schemas/core/swagger.yaml
  • models-gcp/cluster/model.tsp
  • models-gcp/cluster/example_patch.tsp
  • models/compatibility/README.md
  • models-gcp/version/model.tsp
  • schemas/gcp/swagger.yaml
  • services/versions.tsp
  • models-gcp/cluster/example_post.tsp
  • schemas/gcp/openapi.yaml
  • aliases.tsp
  • aliases-core.tsp

Comment thread CHANGELOG.md
Comment thread package.json
Comment thread README.md
Comment thread shared/services/statuses.tsp
Comment thread shared/models/common/model.tsp Outdated
…ared

- Move GCP-specific models out of this repo (now in hyperfleet-api-spec-gcp)
- Restructure sources into core/ (core-specific) and shared/ (cross-provider)
- Add generic Resource model and CRUD service (from main reconciliation)
- Add force-delete endpoints for clusters, nodepools, and resources (internal)
- Add ResourceStatusesInternal for adapter resource status reporting
- Simplify build script: single provider (core only), openapi output only
- Add npm sub-path exports to enable downstream package imports

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

chore: fix CI/CD workflow path for version extraction

main.tsp moved from core/main.tsp to root main.tsp as part of restructuring.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@rh-amarin rh-amarin force-pushed the remove-gcp-from-core branch from 33d57f0 to 17ab4a9 Compare May 26, 2026 17:40
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
schemas/core/openapi.yaml (1)

621-659: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add BearerAuth to getNodePoolsStatuses and regenerate schema.

Line 621–659 is missing a security block for GET /clusters/{cluster_id}/nodepools/{nodepool_id}/statuses. CI already reports generated output differs here, so the committed schema is both out-of-sync and currently under-specifies auth for this endpoint.

Suggested fix
   /api/hyperfleet/v1/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses:
@@
     get:
@@
       tags:
         - NodePool statuses
+      security:
+        - BearerAuth: []

Then run ./build-schema.sh and commit regenerated schemas/core/openapi.yaml.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@schemas/core/openapi.yaml` around lines 621 - 659, The getNodePoolsStatuses
operation is missing the security requirement; add a security block under the
GET operation for operationId getNodePoolsStatuses that enforces bearer
authentication (e.g., security: - bearerAuth: []) for the path GET
/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses, then run
./build-schema.sh to regenerate schemas/core/openapi.yaml and commit the updated
generated file so the spec and generated output stay in sync.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@schemas/core/openapi.yaml`:
- Around line 621-659: The getNodePoolsStatuses operation is missing the
security requirement; add a security block under the GET operation for
operationId getNodePoolsStatuses that enforces bearer authentication (e.g.,
security: - bearerAuth: []) for the path GET
/clusters/{cluster_id}/nodepools/{nodepool_id}/statuses, then run
./build-schema.sh to regenerate schemas/core/openapi.yaml and commit the updated
generated file so the spec and generated output stay in sync.

ℹ️ Review info
⚙️ Run configuration

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

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: 213d6c9f-4667-424e-b506-63c355384a8e

📥 Commits

Reviewing files that changed from the base of the PR and between 33d57f0 and 17ab4a9.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (60)
  • .github/workflows/ci.yml
  • .github/workflows/release.yml
  • CHANGELOG.md
  • CLAUDE.md
  • CONTRIBUTING.md
  • README.md
  • RELEASING.md
  • aliases-core.tsp
  • aliases-gcp.tsp
  • aliases.tsp
  • build-schema.sh
  • core/models/cluster/example_cluster.tsp
  • core/models/cluster/example_patch.tsp
  • core/models/cluster/example_post.tsp
  • core/models/cluster/model.tsp
  • core/models/nodepool/example_nodepool.tsp
  • core/models/nodepool/example_patch.tsp
  • core/models/nodepool/example_post.tsp
  • core/models/nodepool/model.tsp
  • core/services/force-delete-internal.tsp
  • core/services/statuses-internal.tsp
  • main.tsp
  • models-gcp/channel/example_channel.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/channel/model.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/cluster/example_patch.tsp
  • models-gcp/cluster/example_post.tsp
  • models-gcp/cluster/model.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/version/example_post.tsp
  • models-gcp/version/example_version.tsp
  • models-gcp/version/model.tsp
  • models/compatibility/README.md
  • package.json
  • schemas/core/openapi.yaml
  • schemas/core/swagger.yaml
  • schemas/gcp/openapi.yaml
  • schemas/gcp/swagger.yaml
  • schemas/schemas.go
  • services/channels.tsp
  • services/versions.tsp
  • shared/models/clusters/model.tsp
  • shared/models/common/model.tsp
  • shared/models/nodepools/model.tsp
  • shared/models/resource/example_patch.tsp
  • shared/models/resource/example_post.tsp
  • shared/models/resource/example_resource.tsp
  • shared/models/resource/model.tsp
  • shared/models/statuses/example_adapter_status.tsp
  • shared/models/statuses/model.tsp
  • shared/services/clusters.tsp
  • shared/services/nodepools.tsp
  • shared/services/resources.tsp
  • shared/services/statuses.tsp
💤 Files with no reviewable changes (25)
  • models-gcp/cluster/example_post.tsp
  • aliases-gcp.tsp
  • schemas/core/swagger.yaml
  • aliases.tsp
  • models-gcp/cluster/model.tsp
  • models-gcp/nodepool/model.tsp
  • models-gcp/channel/example_patch.tsp
  • models-gcp/cluster/example_cluster.tsp
  • models-gcp/channel/example_channel.tsp
  • models/compatibility/README.md
  • schemas/gcp/openapi.yaml
  • models-gcp/channel/model.tsp
  • models-gcp/channel/example_post.tsp
  • models-gcp/nodepool/example_patch.tsp
  • models-gcp/version/model.tsp
  • models-gcp/version/example_patch.tsp
  • models-gcp/cluster/example_patch.tsp
  • models-gcp/nodepool/example_post.tsp
  • models-gcp/nodepool/example_nodepool.tsp
  • services/versions.tsp
  • models-gcp/version/example_version.tsp
  • models-gcp/version/example_post.tsp
  • aliases-core.tsp
  • schemas/gcp/swagger.yaml
  • services/channels.tsp

…uses GET

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread build-schema.sh
# Step 3: Compile TypeSpec to generate OpenAPI schema
echo -e "${YELLOW}Step 3: Compiling TypeSpec...${NC}"
TEMP_OUTPUT_DIR="tsp-output-${PROVIDER}"
echo -e "${YELLOW}Step 3: Compiling TypeSpec from core/main.tsp...${NC}"
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.

Tip

nit — non-blocking suggestion

Category: Bug

The log message says core/main.tsp but the compile command below uses ./main.tsp (root level). Mismatch will confuse folks debugging builds.

Suggested change
echo -e "${YELLOW}Step 3: Compiling TypeSpec from core/main.tsp...${NC}"
echo -e "${YELLOW}Step 3: Compiling TypeSpec from main.tsp...${NC}"

Comment thread package.json
Comment on lines +5 to +7
"exports": {
"./*": "./*"
},
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.

Tip

nit — non-blocking suggestion

Category: Security

The "./*": "./*" wildcard exports everything in the repo — CI workflows, CLAUDE.md, build scripts, etc. If downstream consumers only need shared/ models and maybe core/ types, consider narrowing the export map:

Suggested change
"exports": {
"./*": "./*"
},
"./shared/*": "./shared/*",
"./core/*": "./core/*"

This prevents accidental imports of internal files while still supporting the intended npm consumption pattern.

@rafabene
Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci
Copy link
Copy Markdown

openshift-ci Bot commented May 26, 2026

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: rafabene

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot openshift-merge-bot Bot merged commit 78199f6 into openshift-hyperfleet:main May 26, 2026
3 checks passed
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.

2 participants