Skip to content

chore: Workflow for controller release#1900

Merged
morri-son merged 11 commits into
open-component-model:mainfrom
morri-son:enhance-controller-release-v2
Mar 11, 2026
Merged

chore: Workflow for controller release#1900
morri-son merged 11 commits into
open-component-model:mainfrom
morri-son:enhance-controller-release-v2

Conversation

@morri-son

@morri-son morri-son commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

On-behalf-of: Gerald Morrison (SAP) gerald.morrison@sap.com

What this PR does / why we need it

This PR improves the existing workflow that builds, tests and publishes the OCM controller and introduces a new workflow that creates releases for the controller.

build workflow:

  • add on workflow_call trigger to be able to call from release workflow
  • remove duplicate build in different steps and replace with buidling just one multi-arch image and extract and reformat single-arch image for later use in e2e (kind load). Since ORAS cannot handle the correct format, skopeo is used for exactly that purpose. All other steps keep using ORAS.
  • Attestate all published artifacts
  • add floating tag "main" on push to main
  • Pushes to branches `releases/v*' don't publish images/charts, but only do E2E tests
  • Trigger "workflow_dispatch" that allows to publish/charts if OCI tests are required

release workflow:

  • Align with release workflow for cli as much as possible (chore: Enhance cli release workflow #1755)
  • Call build workflow (build, e2e)
  • build and publish docker image only once and promote from RC to final release
  • Repackage and re-attest Helm Chart for Final release
  • add floating tags
    • "latest" for highest release (including pre-releases)
    • "stable" for highest final release

Summary by CodeRabbit

  • New Features

    • Introduced a two-phase release process (Release Candidate and Final Release) with automated tag management, artifact promotion, and provenance attestation.
    • Added OCI image digest support to Helm charts for enhanced image reference flexibility.
    • Implemented automated changelog generation and release notes publishing.
  • Chores

    • Updated default controller image versions from "latest" to "0.0.0-main".
    • Expanded build and release workflows with multi-stage architecture including build, testing, publishing, and conformance stages.

@morri-son morri-son requested a review from a team as a code owner March 5, 2026 13:50
@morri-son morri-son added the kind/chore chore, maintenance, etc. label Mar 5, 2026
@github-actions github-actions Bot added component/github-actions Changes on GitHub Actions or within `.github/` directory size/l Large labels Mar 5, 2026
@morri-son morri-son changed the title chore: enhance controller release with component version creation chore: Workflow for controller release with component version creation Mar 5, 2026
@coderabbitai

coderabbitai Bot commented Mar 5, 2026

Copy link
Copy Markdown
Contributor

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
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

The PR introduces a two-phase release process for the Kubernetes controller through new GitHub Actions workflows, tagging infrastructure, and release publishing utilities. It adds orchestration workflows (controller-release.yml), refactors kubernetes-controller.yml into modular jobs (verify-chart, build, E2E, publish, conformance), implements tagging and release publishing scripts, updates Helm configurations to support image digest resolution, and adds changelog generation configuration.

Changes

Cohort / File(s) Summary
Release Orchestration
.github/workflows/controller-release.yml
Introduces two-phase release workflow composing RC and final release processes with artifact management, OCI tagging/promotion, provenance attestation, and release note publication.
Modular Kubernetes Controller Workflow
.github/workflows/kubernetes-controller.yml
Restructures workflow from monolithic to multi-job architecture (verify-chart, build, E2E, publish, conformance) with explicit outputs, artifact propagation, ORAS/Skopeo tooling, and provenance attestation steps.
Release Tagging Infrastructure
.github/scripts/create-tag.js, create-tag.test.js
Implements idempotent RC and final tag creation with commit validation, tag resolution, and git-based tag lifecycle management with comprehensive test coverage.
Release Publishing
.github/scripts/publish-final-release.js, publish-final-release.test.js
Orchestrates final release publishing via RC promotion, release note preparation/rewriting, asset uploading with duplicate replacement, and GitHub Actions summary generation with comprehensive tests.
Helm Chart Image Digest Support
kubernetes/controller/chart/manager.yaml, kubernetes/controller/chart/values.yaml, kubernetes/controller/chart/values.schema.json, kubernetes/controller/chart/README.md
Extends Helm chart to support image digest-based resolution with digest precedence over tag, updated value schema and documentation.
Task & Configuration Updates
kubernetes/controller/Taskfile.yml, kubernetes/controller/chart/test-values.yaml
Adds OCI output handling, helm push/verify-promote tasks, enhanced helm/package with digest editing, helm/install with dynamic image value injection, and updates default image versions to 0.0.0-main.
Supporting Configuration
.github/workflows/conformance.yml, kubernetes/controller/cliff.toml
Updates CLI image default version and adds git-cliff changelog generation configuration with conventional commits parsing and custom grouping rules.

Sequence Diagram(s)

sequenceDiagram
    actor Developer
    participant GitHub
    participant Workflow as controller-release
    participant TagScript as create-tag.js
    participant KubeCtrl as kubernetes-controller
    participant Registry as GHCR/Registry
    participant Attestation
    participant ReleaseScript as publish-final-release.js

    Developer->>GitHub: Push commit
    GitHub->>Workflow: Trigger controller-release
    
    rect rgba(100, 150, 200, 0.5)
    Note over Workflow,Registry: Phase 1: Release Candidate
    Workflow->>TagScript: Create RC tag
    TagScript->>GitHub: Push RC tag
    Workflow->>KubeCtrl: Build Controller (RC)
    KubeCtrl->>Registry: Push image & chart (RC)
    Workflow->>GitHub: Create RC pre-release with assets
    end

    rect rgba(150, 100, 200, 0.5)
    Note over Workflow,ReleaseScript: Phase 2: Final Release (Gated)
    Workflow->>Attestation: Verify RC attestations
    Workflow->>TagScript: Create final tag from RC
    TagScript->>GitHub: Push final tag
    Workflow->>Registry: Promote/tag OCI artifacts
    Workflow->>Registry: Package & push Helm chart
    Workflow->>Attestation: Attest final artifacts
    Workflow->>ReleaseScript: Publish final release
    ReleaseScript->>GitHub: Update release with notes & assets
    Workflow->>GitHub: Publish OCM component
    end

    GitHub-->>Developer: Release published
Loading
sequenceDiagram
    participant Workflow as kubernetes-controller
    participant Job1 as verify-chart
    participant Job2 as build
    participant Job3 as E2E
    participant Job4 as publish
    participant Job5 as conformance
    participant Registry as Container Registry

    Workflow->>Job1: Check Helm chart validity
    Job1-->>Workflow: Status

    Workflow->>Job2: Build multi-arch image (OCI)
    Job2->>Job2: Compute version, check publish eligibility
    Job2->>Registry: Upload OCI layout artifact
    Job2-->>Workflow: image_digest, chart_digest outputs

    Workflow->>Job3: Run E2E tests
    Job3->>Job2: Download build artifacts
    Job3-->>Workflow: Test results

    Workflow->>Job4: Publish artifacts (if eligible)
    Job4->>Registry: Push images to GHCR
    Job4->>Registry: Push Helm chart
    Job4->>Job4: Attest provenance
    Job4-->>Workflow: image_digest, chart_digest, chart_artifact_name

    Workflow->>Job5: Run conformance (uses publish outputs)
    Job5->>Job4: Consume image/chart digests
    Job5-->>Workflow: Conformance results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • jakobmoellerdev
  • matthiasbruns
  • frewilhelm

Poem

🐰 Hops through workflows, two phases aligned,
RC tags dancing, final ones signed,
OCI treasures pushed to the registry,
Digests and charts, a release symphony! 🎉
From test-values.yaml to conformance's delight,
The release automation shines ever so bright!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'chore: Workflow for controller release' is directly related to the main change—adding a comprehensive release workflow for the controller alongside build workflow enhancements.
Docstring Coverage ✅ Passed Docstring coverage is 86.96% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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: 4

🧹 Nitpick comments (2)
.github/scripts/compute-version.test.js (1)

27-33: Extract deterministic test fixtures into shared constants.

The same now/gitSha literals are repeated across many assertions; centralizing them will reduce drift and make updates safer.

♻️ Suggested refactor
 import assert from "assert";
 import { computeVersion } from "./compute-version.js";
 
+const FIXED_NOW = new Date("2026-03-03T12:34:56Z");
+const FIXED_GIT_SHA = "abcdef1234567890";
+const DETERMINISTIC_OPTIONS = { now: FIXED_NOW, gitSha: FIXED_GIT_SHA };
+
 // ----------------------------------------------------------
 // CLI version tests
 // ----------------------------------------------------------
@@
-    computeVersion("main", "cli/v", {
-        now: new Date("2026-03-03T12:34:56Z"),
-        gitSha: "abcdef1234567890",
-    }),
+    computeVersion("main", "cli/v", DETERMINISTIC_OPTIONS),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/compute-version.test.js around lines 27 - 33, Extract the
repeated test fixtures into shared constants and update assertions to use them:
define top-level constants (e.g., FIXED_NOW = new Date("2026-03-03T12:34:56Z")
and FIXED_GIT_SHA = "abcdef1234567890") in the test file and replace inline
literals in calls to computeVersion(...) with these constants (referencing
computeVersion from the diff); ensure all assertions use the shared FIXED_NOW
and FIXED_GIT_SHA so the fixtures are deterministic and centrally maintained.
.github/scripts/compute-version.js (1)

118-118: Consider adding an optional timestamp override in the action path for reproducible reruns.

computeVersionAction passes gitSha but not now, so rerunning the same commit can generate a different non-tag version. An optional env-driven timestamp keeps current behavior while enabling reproducible reruns when needed.

♻️ Suggested adjustment
 export default async function computeVersionAction({ core }) {
     const ref = process.env.REF;
     const tagPrefix = process.env.TAG_PREFIX;
     const gitSha = process.env.GITHUB_SHA;
+    const timestamp = process.env.VERSION_TIMESTAMP;
+    const now = timestamp ? new Date(timestamp) : undefined;
 
@@
     try {
-        const version = computeVersion(ref, tagPrefix, { gitSha });
+        if (timestamp && Number.isNaN(now.getTime())) {
+            core.setFailed("VERSION_TIMESTAMP must be a valid date/time");
+            return;
+        }
+        const version = computeVersion(ref, tagPrefix, { gitSha, now });

Also applies to: 131-131

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/compute-version.js at line 118, Add an optional timestamp
override so reruns can be reproducible: read an env var (e.g.,
process.env.VERSION_TIMESTAMP or process.env.NOW) into a new const (e.g., const
nowOverride) alongside the existing const gitSha = process.env.GITHUB_SHA, and
pass that value into computeVersionAction (or use it when building the version)
so the action uses the override when present but falls back to current time when
not provided; reference the existing gitSha variable and the
computeVersionAction call to locate where to add the new const and where to
forward the override.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/scripts/compute-version.test.js:
- Around line 132-137: The test assertion title is incorrect:
computeVersion("feature/issue#123", ...) sanitizes '#' to '-' (expected
"0.0.0-feature-issue-123..."), so update the assertion message to reflect
sanitization rather than preservation; locate the test using computeVersion in
.github/scripts/compute-version.test.js and change the message from "Branch with
# should be preserved" to something like "Branch with # should be sanitized to
-".

In @.github/workflows/controller-release.yml:
- Around line 67-73: The checkout step currently uses actions/checkout@v6 with
no tag fetching which makes the subsequent "Create tag" logic (the git rev-parse
check for refs/tags/<tag>) unreliable on reruns; update the Checkout step
(actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd) to fetch tags by
adding the checkout inputs fetch-tags: true (or fetch-depth: 0 to fetch full
history) so remote tags are present locally before the git rev-parse check and
avoid attempting to push an already-existing RC tag.

In @.github/workflows/kubernetes-controller.yml:
- Around line 431-436: Add the missing reusable workflow file named
publish-ocm-component-version.yml referenced by the publish-component job;
create .github/workflows/publish-ocm-component-version.yml implementing the
reusable workflow inputs/outputs and steps required by the callers (used by
publish-component in kubernetes-controller.yml and the release job in
controller-release.yml), ensuring it exposes the should_publish input/output and
the expected secrets/environment so both callers can use uses:
./.github/workflows/publish-ocm-component-version.yml without failing.
- Around line 441-458: The status-check job currently misses upstream publish
failures; add a new step in the status-check job (e.g., "Fail if publish did not
succeed") that runs when needs.publish.result is not "success" (covers "failure"
and "cancelled") and aborts with an error/exit 1, and adjust the existing "Fail
if OCM publish did not succeed" step to only handle the publish-component case
(it can keep its current if: needs.publish.result == 'success' &&
needs.publish-component.result != 'success'). Target the status-check job and
the step names "Fail if E2E did not succeed" and "Fail if OCM publish did not
succeed" to locate where to insert the new conditional step; the new step should
echo an error including the actual needs.publish.result and exit 1.

---

Nitpick comments:
In @.github/scripts/compute-version.js:
- Line 118: Add an optional timestamp override so reruns can be reproducible:
read an env var (e.g., process.env.VERSION_TIMESTAMP or process.env.NOW) into a
new const (e.g., const nowOverride) alongside the existing const gitSha =
process.env.GITHUB_SHA, and pass that value into computeVersionAction (or use it
when building the version) so the action uses the override when present but
falls back to current time when not provided; reference the existing gitSha
variable and the computeVersionAction call to locate where to add the new const
and where to forward the override.

In @.github/scripts/compute-version.test.js:
- Around line 27-33: Extract the repeated test fixtures into shared constants
and update assertions to use them: define top-level constants (e.g., FIXED_NOW =
new Date("2026-03-03T12:34:56Z") and FIXED_GIT_SHA = "abcdef1234567890") in the
test file and replace inline literals in calls to computeVersion(...) with these
constants (referencing computeVersion from the diff); ensure all assertions use
the shared FIXED_NOW and FIXED_GIT_SHA so the fixtures are deterministic and
centrally maintained.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c94f7e60-6d0a-448d-b8b1-2cbd8a89bbdb

📥 Commits

Reviewing files that changed from the base of the PR and between e7f4bce and 7773c58.

📒 Files selected for processing (4)
  • .github/scripts/compute-version.js
  • .github/scripts/compute-version.test.js
  • .github/workflows/controller-release.yml
  • .github/workflows/kubernetes-controller.yml

Comment thread .github/scripts/compute-version.test.js Outdated
Comment thread .github/workflows/controller-release.yml
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
@morri-son

Copy link
Copy Markdown
Contributor Author

@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: 1

♻️ Duplicate comments (1)
.github/workflows/controller-release.yml (1)

68-74: ⚠️ Potential issue | 🟠 Major

Fetch tags in RC checkout to make tag idempotency checks reliable.

The local git rev-parse refs/tags/<tag> check can miss existing remote tags on reruns unless tags are fetched in checkout, which can cause a failing git push for an already-existing RC tag.

Suggested patch
       - name: Checkout
         uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
         with:
           sparse-checkout: ${{ env.COMPONENT_PATH }}
           ref: ${{ github.event.inputs.branch }}
           token: ${{ steps.get_token.outputs.token }}
+          fetch-tags: true
#!/bin/bash
set -euo pipefail
FILE="$(fd -a controller-release.yml .github/workflows | head -n1)"
echo "Inspecting: $FILE"
sed -n '64,106p' "$FILE"
rg -n 'name: Checkout|fetch-tags|fetch-depth|rev-parse|refs/tags' "$FILE"

Expected: checkout in tag_rc currently lacks fetch-tags: true while Create tag relies on local tag refs.

Also applies to: 86-104

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/controller-release.yml around lines 68 - 74, The Checkout
step used in the release workflow doesn't fetch tags, so local checks like `git
rev-parse refs/tags/<tag>` can miss remote tags and cause duplicate-tag pushes
to fail; update the Checkout step (named "Checkout") used by the tag creation
flow (referenced by the `Create tag` step / `git rev-parse` logic) to enable
fetching tags (add the checkout option to fetch tags, e.g., set fetch-tags:
true) so remote tags are available locally before the tag existence/idempotency
check runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/controller-release.yml:
- Around line 405-418: The release creation logic currently calls
github.rest.repos.createRelease unconditionally which fails when rerunning
because the tag already exists; change it to first call
github.rest.repos.getReleaseByTag(finalTag) and if it returns a release use that
release's id (and call github.rest.repos.updateRelease if you need to update
name/body/prerelease/make_latest), otherwise call
github.rest.repos.createRelease to make a new release; before uploading each
chart asset (loop over fs.readdirSync(chartDir).filter(...)) list existing
assets for that release and delete any asset with the same filename
(github.rest.repos.listReleaseAssets + github.rest.repos.deleteReleaseAsset) so
uploads via github.rest.repos.uploadReleaseAsset won’t fail on duplicate names.

---

Duplicate comments:
In @.github/workflows/controller-release.yml:
- Around line 68-74: The Checkout step used in the release workflow doesn't
fetch tags, so local checks like `git rev-parse refs/tags/<tag>` can miss remote
tags and cause duplicate-tag pushes to fail; update the Checkout step (named
"Checkout") used by the tag creation flow (referenced by the `Create tag` step /
`git rev-parse` logic) to enable fetching tags (add the checkout option to fetch
tags, e.g., set fetch-tags: true) so remote tags are available locally before
the tag existence/idempotency check runs.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 60e8135c-8712-4dc6-bd44-e6f6c417c53f

📥 Commits

Reviewing files that changed from the base of the PR and between 7773c58 and 1a44fe6.

📒 Files selected for processing (1)
  • .github/workflows/controller-release.yml

Comment thread .github/workflows/controller-release.yml Outdated

@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: 1

♻️ Duplicate comments (1)
.github/workflows/controller-release.yml (1)

407-419: ⚠️ Potential issue | 🟠 Major

Final release publication is still not rerun-idempotent.

createRelease is unconditional here. On reruns after partial success, this can fail with tag_name already exists, and duplicate asset names can also fail upload. Switch to get-or-create/update release and replace same-name assets before upload.

Suggested patch
-            const isLatest = setLatest === 'true';
-            const created = await github.rest.repos.createRelease({
-              owner: context.repo.owner, repo: context.repo.repo,
-              tag_name: finalTag, name: `Controller ${finalVersion}`,
-              body: notes, prerelease: false, make_latest: isLatest ? 'true' : 'false',
-            });
+            const isLatest = setLatest === 'true';
+            let releaseResp;
+            try {
+              releaseResp = await github.rest.repos.getReleaseByTag({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                tag: finalTag,
+              });
+              releaseResp = await github.rest.repos.updateRelease({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                release_id: releaseResp.data.id,
+                tag_name: finalTag,
+                name: `Controller ${finalVersion}`,
+                body: notes,
+                prerelease: false,
+                make_latest: isLatest ? 'true' : 'false',
+              });
+            } catch (e) {
+              if (e.status !== 404) throw e;
+              releaseResp = await github.rest.repos.createRelease({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                tag_name: finalTag,
+                name: `Controller ${finalVersion}`,
+                body: notes,
+                prerelease: false,
+                make_latest: isLatest ? 'true' : 'false',
+              });
+            }
+            const releaseId = releaseResp.data.id;
+            const existingAssets = (await github.rest.repos.listReleaseAssets({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              release_id: releaseId,
+              per_page: 100,
+            })).data;
             
             // Upload chart from local dist/ directory (no registry pull needed)
             for (const file of fs.readdirSync(chartDir).filter(f => f.endsWith('.tgz'))) {
+              const prior = existingAssets.find(a => a.name === file);
+              if (prior) {
+                await github.rest.repos.deleteReleaseAsset({
+                  owner: context.repo.owner,
+                  repo: context.repo.repo,
+                  asset_id: prior.id,
+                });
+              }
               const data = fs.readFileSync(path.join(chartDir, file));
               await github.rest.repos.uploadReleaseAsset({
-                owner: context.repo.owner, repo: context.repo.repo, release_id: created.data.id,
+                owner: context.repo.owner, repo: context.repo.repo, release_id: releaseId,
                 name: file, data, headers: { 'content-type': 'application/gzip', 'content-length': data.length },
               });
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/controller-release.yml around lines 407 - 419, The current
logic calls github.rest.repos.createRelease unconditionally and then uploads
assets, which breaks on reruns (tag already exists or duplicate asset names);
change this to a get-or-create/update flow: call
github.rest.repos.getReleaseByTag (or list releases) for finalTag, if found use
github.rest.repos.updateRelease to ensure release metadata is up-to-date and set
created to that release, otherwise call createRelease; before each
uploadReleaseAsset for files from fs.readdirSync(chartDir).filter(...), check
the release's existing assets (created.data.assets) and if an asset with the
same name exists call github.rest.repos.deleteReleaseAsset for that asset id to
remove it, then proceed to uploadReleaseAsset as before so reruns are
idempotent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/controller-release.yml:
- Around line 194-195: The comment currently references "controller/release" but
the workflow uses the environment identifier "release" (see occurrences of
environment: release); update the comment to reference "release" so it matches
the configured environment name and avoid confusion—replace "controller/release"
with "release" in the comment block near the environment documentation.

---

Duplicate comments:
In @.github/workflows/controller-release.yml:
- Around line 407-419: The current logic calls github.rest.repos.createRelease
unconditionally and then uploads assets, which breaks on reruns (tag already
exists or duplicate asset names); change this to a get-or-create/update flow:
call github.rest.repos.getReleaseByTag (or list releases) for finalTag, if found
use github.rest.repos.updateRelease to ensure release metadata is up-to-date and
set created to that release, otherwise call createRelease; before each
uploadReleaseAsset for files from fs.readdirSync(chartDir).filter(...), check
the release's existing assets (created.data.assets) and if an asset with the
same name exists call github.rest.repos.deleteReleaseAsset for that asset id to
remove it, then proceed to uploadReleaseAsset as before so reruns are
idempotent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e9ceb83e-8114-4f6c-93f3-09f0c3bbe526

📥 Commits

Reviewing files that changed from the base of the PR and between 1a44fe6 and cfbe257.

📒 Files selected for processing (1)
  • .github/workflows/controller-release.yml

Comment thread .github/workflows/controller-release.yml Outdated

@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: 1

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

Inline comments:
In @.github/workflows/kubernetes-controller.yml:
- Around line 475-477: The current GitHub Actions step named "Fail if
conformance did not succeed" uses the condition if: ${{ needs.conformance.result
!= 'success' && needs.conformance.result != 'skipped' }} which allows
conformance to be skipped even when publish succeeded; update the condition to
explicitly require conformance to have succeeded when publish has succeeded
(i.e. make the step fail if needs.publish.result == 'success' &&
needs.conformance.result != 'success'), replacing the existing if expression so
the workflow enforces conformance success whenever publish succeeds.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f83f167-a4bf-4bf9-8fcd-476734087aac

📥 Commits

Reviewing files that changed from the base of the PR and between bd4c362 and 4c76c6e.

📒 Files selected for processing (1)
  • .github/workflows/kubernetes-controller.yml

Comment thread .github/workflows/kubernetes-controller.yml Outdated

@Skarlso Skarlso 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.

Just a couple of minor comments really.

Comment thread .github/workflows/publish-ocm-component-version.yml Outdated
Comment thread .github/scripts/compute-version.js Outdated
Comment thread .github/scripts/compute-version.js Outdated
Comment thread .github/workflows/cli.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/cli-release.yml Outdated
Comment thread .github/workflows/cli-release.yml Outdated
Comment thread .github/workflows/cli-release.yml Outdated
Comment thread .github/workflows/cli.yml Outdated
Comment thread .github/workflows/cli.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/kubernetes-controller.yml Outdated
Comment thread .github/workflows/publish-ocm-component-version.yml Outdated
@jakobmoellerdev

Copy link
Copy Markdown
Member

@coderabbitai review

@morri-son morri-son force-pushed the enhance-controller-release-v2 branch from 57b6536 to 264577b Compare March 6, 2026 22:26
@morri-son morri-son changed the title chore: Workflow for controller release with component version creation chore: Workflow for controller release Mar 8, 2026
@morri-son

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 2

🧹 Nitpick comments (3)
.github/scripts/create-tag.js (1)

84-102: Async function without await could be simplified.

createRcTag and createFinalTag are declared async but don't use await. While this works (they implicitly return a resolved Promise), it's slightly misleading. Consider removing async or keeping it for consistency if the caller expects a Promise.

This is a minor nitpick and doesn't affect functionality.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/create-tag.js around lines 84 - 102, The functions
createRcTag (and similarly createFinalTag) are declared async but contain no
await; remove the unnecessary async keyword from their declarations to avoid
misleading callers, or alternatively keep async and explicitly return a Promise
(e.g., return void/Promise.resolve) if external code relies on them being async;
update the function signatures for createRcTag and createFinalTag accordingly
and ensure callers (and exports) still work with the new non-async synchronous
return.
.github/scripts/publish-final-release.js (1)

111-119: Asset listing limited to 100 items.

listReleaseAssets uses per_page: 100 without pagination. If a release has more than 100 assets (unlikely but possible), duplicate detection would miss assets beyond page 1.

For controller releases with typically few chart assets, this is low risk.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/scripts/publish-final-release.js around lines 111 - 119, The current
uploadAssets function uses github.rest.repos.listReleaseAssets with per_page:
100 and doesn't paginate, so assets beyond the first page can be missed; update
uploadAssets to paginate and collect all assets (e.g., loop over page numbers or
use Octokit's pagination helper) when calling listReleaseAssets for the given
releaseId, merge all pages into the existing array before doing duplicate
detection, and keep references to uploadAssets, listReleaseAssets, releaseId and
existing to locate and modify the code.
kubernetes/controller/chart/test-values.yaml (1)

6-6: Add a digest render fixture for the new image path.

task helm/template still renders only this tag-based fixture, so the new repository@digest branch in chart/templates/manager/manager.yaml is currently unexercised. A second fixture, or an extra render with manager.image.digest=sha256:..., would keep that path under chart validation.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@kubernetes/controller/chart/test-values.yaml` at line 6, The current
test-values.yaml only exercises the tag-based image path (tag: 0.0.0-main) so
the new repository@digest rendering branch in
chart/templates/manager/manager.yaml is untested; add a second fixture that sets
manager.image.repository and manager.image.digest (e.g.,
manager.image.digest=sha256:...) or modify the test harness to run an additional
helm/template render with manager.image.digest populated so the
repository@digest path in manager.yaml is exercised and validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@kubernetes/controller/Taskfile.yml`:
- Around line 191-198: The helm/package target currently mutates
chart/values.yaml via in-place yq edits (the '{{.YQ}} -i ... chart/values.yaml'
lines), which can leak previous image overrides; instead create a temporary
values file (e.g., copy chart/values.yaml to a temp file), apply yq edits to
that temp file (or use yq to write to stdout redirected into the temp file) and
pass the temp file to helm package with --values, or use helm's --set flags to
override .manager.image.repository/tag/digest without touching the worktree;
update the helm/package cmds to operate on the temp file and ensure cleanup so
the tracked chart/values.yaml is never mutated.
- Around line 247-257: The helm/install Taskfile assumes CONTROLLER_IMG is a
single repo:tag; instead, split the first whitespace-separated token from
CONTROLLER_IMG and handle both :tag and `@digest` forms: set _IMG to the first
token, make _REPO evaluate to the full first-token when it contains '@'
(repo@digest) and otherwise strip the trailing :tag to produce the repository,
and set _TAG to an empty string for digest refs or to the trailing tag for tag
refs; update the _REPO and _TAG sh expressions (used by vars _REPO and _TAG and
the yq commands that set .manager.image.repository and .manager.image.tag)
accordingly so chart/test-values.yaml gets a repo@digest in repository with an
empty tag or a repo and tag for tag refs.

---

Nitpick comments:
In @.github/scripts/create-tag.js:
- Around line 84-102: The functions createRcTag (and similarly createFinalTag)
are declared async but contain no await; remove the unnecessary async keyword
from their declarations to avoid misleading callers, or alternatively keep async
and explicitly return a Promise (e.g., return void/Promise.resolve) if external
code relies on them being async; update the function signatures for createRcTag
and createFinalTag accordingly and ensure callers (and exports) still work with
the new non-async synchronous return.

In @.github/scripts/publish-final-release.js:
- Around line 111-119: The current uploadAssets function uses
github.rest.repos.listReleaseAssets with per_page: 100 and doesn't paginate, so
assets beyond the first page can be missed; update uploadAssets to paginate and
collect all assets (e.g., loop over page numbers or use Octokit's pagination
helper) when calling listReleaseAssets for the given releaseId, merge all pages
into the existing array before doing duplicate detection, and keep references to
uploadAssets, listReleaseAssets, releaseId and existing to locate and modify the
code.

In `@kubernetes/controller/chart/test-values.yaml`:
- Line 6: The current test-values.yaml only exercises the tag-based image path
(tag: 0.0.0-main) so the new repository@digest rendering branch in
chart/templates/manager/manager.yaml is untested; add a second fixture that sets
manager.image.repository and manager.image.digest (e.g.,
manager.image.digest=sha256:...) or modify the test harness to run an additional
helm/template render with manager.image.digest populated so the
repository@digest path in manager.yaml is exercised and validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c4e934c7-1c51-4d51-be9a-1cacbe4612f6

📥 Commits

Reviewing files that changed from the base of the PR and between 4c76c6e and 74208d5.

📒 Files selected for processing (14)
  • .github/scripts/create-tag.js
  • .github/scripts/create-tag.test.js
  • .github/scripts/publish-final-release.js
  • .github/scripts/publish-final-release.test.js
  • .github/workflows/conformance.yml
  • .github/workflows/controller-release.yml
  • .github/workflows/kubernetes-controller.yml
  • kubernetes/controller/Taskfile.yml
  • kubernetes/controller/chart/README.md
  • kubernetes/controller/chart/templates/manager/manager.yaml
  • kubernetes/controller/chart/test-values.yaml
  • kubernetes/controller/chart/values.schema.json
  • kubernetes/controller/chart/values.yaml
  • kubernetes/controller/cliff.toml

Comment thread kubernetes/controller/Taskfile.yml Outdated
Comment thread kubernetes/controller/Taskfile.yml Outdated
@morri-son morri-son force-pushed the enhance-controller-release-v2 branch 2 times, most recently from 31d5914 to 9d20c68 Compare March 9, 2026 11:14
Comment thread kubernetes/controller/cliff.toml Outdated

@frewilhelm frewilhelm 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.

review took a bit longer and some things changed in the meantime. You can just resolve deprecated comments

Comment thread .github/scripts/create-tag.js
Comment thread .github/scripts/create-tag.js
Comment thread .github/scripts/create-tag.js Outdated
Comment thread .github/scripts/publish-final-release.js
Comment thread .github/scripts/publish-final-release.js
Comment thread .github/workflows/controller-release.yml
Comment thread kubernetes/controller/Taskfile.yml Outdated
Comment thread kubernetes/controller/Taskfile.yml Outdated
Comment thread kubernetes/controller/Taskfile.yml Outdated
Comment thread kubernetes/controller/chart/templates/manager/manager.yaml Outdated
Comment thread kubernetes/controller/Taskfile.yml Outdated
@morri-son morri-son force-pushed the enhance-controller-release-v2 branch from cd66ddf to 27c346b Compare March 10, 2026 21:47
- Add dedicated controller-release.yml workflow for RC and final releases
- Refactor kubernetes-controller.yml: simplify build/E2E/publish flow
- Add create-tag.js and publish-final-release.js scripts with tests
- Update release-versioning.js/test for controller support
- Add cliff.toml for controller changelog generation
- Update Taskfile, values.yaml, values.schema.json for controller release
- Update RELEASE_PROCESS.md with controller release documentation

On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
@morri-son morri-son force-pushed the enhance-controller-release-v2 branch from f2d77f8 to 86bc931 Compare March 10, 2026 21:58
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>

@frewilhelm frewilhelm 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.

Just some comments and questions. Thanks for your work!

Comment thread .github/scripts/create-tag.js
Comment thread .github/scripts/publish-final-release.test.js
Comment thread .github/workflows/controller-release.yml
Comment thread .github/workflows/controller-release.yml
Comment thread .github/workflows/controller-release.yml
…re or when switched on with trigger worklow_dispatch

On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
…v**'

On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Skarlso
Skarlso previously approved these changes Mar 11, 2026

@Skarlso Skarlso 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.

Looks okay now! Let's see what it does. :D

On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
morrison-sap and others added 2 commits March 11, 2026 14:17
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>

@jakobmoellerdev jakobmoellerdev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Image

@morri-son morri-son enabled auto-merge (squash) March 11, 2026 14:08
@morri-son morri-son merged commit 54006b4 into open-component-model:main Mar 11, 2026
20 checks passed
frewilhelm pushed a commit to frewilhelm/open-component-model that referenced this pull request Mar 12, 2026
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>

<!-- markdownlint-disable MD041 -->
#### What this PR does / why we need it
This PR improves the existing workflow that builds, tests and publishes
the OCM controller and introduces a new workflow that creates releases
for the controller.

**build workflow:**
- add on workflow_call trigger to be able to call from release workflow
- remove duplicate build in different steps and replace with buidling
just one multi-arch image and extract and reformat single-arch image for
later use in e2e (`kind load`). Since ORAS cannot handle the correct
format, skopeo is used for exactly that purpose. All other steps keep
using ORAS.
- Attestate all published artifacts
- add floating tag "main" on push to main
- Pushes to branches `releases/v*' don't publish images/charts, but only
do E2E tests
- Trigger "workflow_dispatch" that allows to publish/charts if OCI tests
are required

**release workflow:**
- Align with release workflow for cli as much as possible (open-component-model#1755)
- Call build workflow (build, e2e)
- build and publish docker image only once and promote from RC to final
release
- Repackage and re-attest Helm Chart for Final release
- add floating tags 
  - "latest" for highest release (including pre-releases)
  - "stable" for highest final release

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced a two-phase release process (Release Candidate and Final
Release) with automated tag management, artifact promotion, and
provenance attestation.
* Added OCI image digest support to Helm charts for enhanced image
reference flexibility.
* Implemented automated changelog generation and release notes
publishing.

* **Chores**
* Updated default controller image versions from "latest" to
"0.0.0-main".
* Expanded build and release workflows with multi-stage architecture
including build, testing, publishing, and conformance stages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Co-authored-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
morri-son added a commit to morri-son/open-component-model that referenced this pull request Mar 18, 2026
On-behalf-of: Gerald Morrison (SAP) <gerald.morrison@sap.com>

<!-- markdownlint-disable MD041 -->
#### What this PR does / why we need it
This PR improves the existing workflow that builds, tests and publishes
the OCM controller and introduces a new workflow that creates releases
for the controller.

**build workflow:**
- add on workflow_call trigger to be able to call from release workflow
- remove duplicate build in different steps and replace with buidling
just one multi-arch image and extract and reformat single-arch image for
later use in e2e (`kind load`). Since ORAS cannot handle the correct
format, skopeo is used for exactly that purpose. All other steps keep
using ORAS.
- Attestate all published artifacts
- add floating tag "main" on push to main
- Pushes to branches `releases/v*' don't publish images/charts, but only
do E2E tests
- Trigger "workflow_dispatch" that allows to publish/charts if OCI tests
are required

**release workflow:**
- Align with release workflow for cli as much as possible (open-component-model#1755)
- Call build workflow (build, e2e)
- build and publish docker image only once and promote from RC to final
release
- Repackage and re-attest Helm Chart for Final release
- add floating tags
  - "latest" for highest release (including pre-releases)
  - "stable" for highest final release

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Introduced a two-phase release process (Release Candidate and Final
Release) with automated tag management, artifact promotion, and
provenance attestation.
* Added OCI image digest support to Helm charts for enhanced image
reference flexibility.
* Implemented automated changelog generation and release notes
publishing.

* **Chores**
* Updated default controller image versions from "latest" to
"0.0.0-main".
* Expanded build and release workflows with multi-stage architecture
including build, testing, publishing, and conformance stages.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Co-authored-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
Signed-off-by: Gerald Morrison (SAP) <gerald.morrison@sap.com>
@morri-son morri-son deleted the enhance-controller-release-v2 branch April 23, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/github-actions Changes on GitHub Actions or within `.github/` directory kind/chore chore, maintenance, etc. size/l Large

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Create Github workflow for release of kubernetes/controller

7 participants