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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
88 changes: 88 additions & 0 deletions .github/workflows/automated-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
name: Automated Release

on:
workflow_dispatch:
inputs:
gitRef:
description: Commit SHA, tag or branch name (usually main branch)
required: true
default: "main"
type: string
version:
description: Release version (semver without v prefix, e.g. 0.1.0)
required: true
type: string

jobs:
prepare-release:
name: Prepare release
runs-on: ubuntu-latest
steps:
- name: Checkout code at git ref
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.gitRef }}
token: ${{ secrets.KUADRANT_DEV_PAT }}

- name: Validate version format
run: |
VERSION="${{ github.event.inputs.version }}"
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "Error: Version '$VERSION' is not valid semver format (expected: X.Y.Z or X.Y.Z-suffix)"
exit 1
fi
echo "Version $VERSION is valid"

- name: Create release branch
id: create-release-branch
run: |
base_branch=release-v$(echo "${{ github.event.inputs.version }}" | sed 's/[+-].*//; s/\.[0-9]*$//')
echo "BASE_BRANCH=$base_branch" >> $GITHUB_ENV

if git ls-remote --exit-code --heads origin $base_branch; then
echo "Base branch $base_branch already exists"
git fetch origin $base_branch
git checkout $base_branch
else
echo "Creating branch $base_branch"
git checkout -b "$base_branch"
git push --set-upstream origin "$base_branch"
fi

- name: Update VERSION in Makefile
run: |
VERSION="${{ github.event.inputs.version }}"
sed -i "s/^VERSION ?= .*/VERSION ?= $VERSION/" Makefile

echo "Updated Makefile VERSION to $VERSION"
grep "^VERSION" Makefile

- name: Create Pull Request
if: ${{ !env.ACT }}
uses: peter-evans/create-pull-request@v7
with:
token: ${{ secrets.KUADRANT_DEV_PAT }}
commit-message: "Release v${{ github.event.inputs.version }}"
committer: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
author: ${{ github.actor }} <${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com>
signoff: true
base: ${{ env.BASE_BRANCH }}
branch: release-v${{ github.event.inputs.version }}
delete-branch: true
title: "[Release] Developer Portal Controller v${{ github.event.inputs.version }}"
body: |
Prepare release v${{ github.event.inputs.version }}

## Changes
- Updated VERSION in Makefile to ${{ github.event.inputs.version }}

## Post-merge
After this PR is merged, a workflow will automatically:
- Create git tag v${{ github.event.inputs.version }}
- Create GitHub release
- Build and push image to quay.io

Auto-generated by [create-pull-request](https://github.com/peter-evans/create-pull-request)
team-reviewers: |
Kuadrant/developers
draft: false
85 changes: 85 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
name: Release

on:
pull_request:
types:
- closed
branches:
- 'release-v[0-9]+.[0-9]+'
workflow_dispatch: {}

jobs:
release:
if: github.event.pull_request.merged == true
name: Create release
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.KUADRANT_DEV_PAT }}
fetch-depth: 0

- name: Get version from Makefile
id: get_version
run: |
VERSION=$(grep "^VERSION ?=" Makefile | sed 's/VERSION ?= //')
echo "VERSION=$VERSION" >> $GITHUB_OUTPUT
echo "TAG=v$VERSION" >> $GITHUB_OUTPUT
echo "Releasing version: $VERSION (tag: v$VERSION)"

- name: Check if tag already exists
id: check_tag
run: |
TAG="${{ steps.get_version.outputs.TAG }}"
CURRENT_SHA="${{ github.sha }}"
if git rev-parse "$TAG" >/dev/null 2>&1; then
TAG_SHA=$(git rev-parse "$TAG^{}")
if [ "$TAG_SHA" = "$CURRENT_SHA" ]; then
echo "Tag $TAG already exists and points to current commit"
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "::error::Tag $TAG already exists but points to a different commit"
echo "Tag SHA: $TAG_SHA"
echo "Current SHA: $CURRENT_SHA"
exit 1
fi
else
echo "Tag $TAG does not exist"
echo "exists=false" >> $GITHUB_OUTPUT
fi

- name: Create and push tag
if: steps.check_tag.outputs.exists == 'false'
run: |
TAG="${{ steps.get_version.outputs.TAG }}"
git tag "$TAG"
git push origin "$TAG"
echo "Created and pushed tag: $TAG"

- name: Determine if prerelease
id: prerelease
run: |
VERSION="${{ steps.get_version.outputs.VERSION }}"
if [[ "$VERSION" =~ -(alpha|beta|rc) ]]; then
echo "prerelease=true" >> $GITHUB_OUTPUT
else
echo "prerelease=false" >> $GITHUB_OUTPUT
fi

- name: Generate release notes
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
RELEASE_TAG: ${{ steps.get_version.outputs.TAG }}
run: bash ./utils/release/github-release-changelog.sh

- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: ${{ steps.get_version.outputs.TAG }}
tag_name: ${{ steps.get_version.outputs.TAG }}
body: ${{ env.releaseBody }}
target_commitish: ${{ github.ref_name }}
prerelease: ${{ steps.prerelease.outputs.prerelease }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# To re-generate a bundle for another specific version without changing the standard setup, you can:
# - use the VERSION as arg of the bundle target (e.g make bundle VERSION=0.0.2)
# - use environment variables to overwrite this value (e.g export VERSION=0.0.2)
VERSION ?= 0.0.1
VERSION ?= 0.0.0

# IMAGE_TAG_BASE defines the docker.io namespace and part of the image name for remote images.
# This variable is used to construct full image tags for bundle and catalog images.
Expand Down
101 changes: 101 additions & 0 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# How to Release Developer Portal Controller

## Versioning

This project follows [Semantic Versioning](https://semver.org/) (X.Y.Z).

The version is defined in the `Makefile`:
```makefile
VERSION ?= X.Y.Z
```

**Important:** The `main` branch always has `VERSION ?= 0.0.0` as a placeholder. The actual version is only set on release branches (e.g., `release-v0.1`). This follows the same pattern as [kuadrant-operator](https://github.com/Kuadrant/kuadrant-operator). When building release images, the version is read from the release branch where the automated workflow updated it.

## Automated Workflow (Recommended)

_**IMPORTANT:**_
For RC2+ or patch releases, set `gitRef` to the existing release branch (e.g., `release-v0.1`), not `main`.
The workflow picks up all history from the specified gitRef - cherry-pick any required fixes to the release branch before triggering the workflow.

### Notes
* The automated workflow is best suited for RC1 of a new point release from `main`.
* For patch releases (e.g., 0.1.1): Cherry-pick only the bug fix to the release branch, then run the workflow with `gitRef: release-v0.1`.
* It's not possible to cherry-pick commits within the workflow - it will include all history from the gitRef.

### Steps

1. **Run the [Automated Release](https://github.com/Kuadrant/developer-portal-controller/actions/workflows/automated-release.yaml) workflow** filling the following fields:
- **gitRef**: Select the branch/tag/commit where you want to cut a release from (usually `main`)
- **version**: The version to release (e.g., `0.1.0` or `0.1.0-alpha-1`)

2. **Review and merge the PR**:
- The workflow creates a PR that updates the VERSION in the Makefile
- Review the changes and merge the PR

3. **Automatic post-merge actions**:
- Once merged, the Release workflow automatically:
- Creates a git tag (e.g., `v0.1.0`)
- Creates a GitHub release with auto-generated release notes
- Triggers the image build workflow

4. **Verify the release**:
- Check the [GitHub Actions](https://github.com/Kuadrant/developer-portal-controller/actions) workflows completed successfully
- Verify the image is available at [quay.io](https://quay.io/repository/kuadrant/developer-portal-controller?tab=tags)

## Patch Releases

To release a patch (e.g., `0.1.1` after `0.1.0` with a bug fix from `main`):

1. **Cherry-pick the fix to the release branch**:
```bash
git checkout release-v0.1
git pull origin release-v0.1
git cherry-pick <commit-sha> # Only the bug fix, not new features
git push origin release-v0.1
```

2. **Run the Automated Release workflow**:
- **gitRef**: `release-v0.1` (the release branch, NOT main)
- **version**: `0.1.1`

3. **Review and merge the PR**, then the release will be created automatically.

> **Note**: Patch releases should only include bug fixes, not new features. New features go into the next minor release (e.g., `0.2.0`).

## Manual Workflow

If the automated workflow is not suitable, you can release manually:

1. **Update the VERSION** in the [Makefile](./Makefile):
```makefile
VERSION ?= X.Y.Z
```

2. **Commit the version change**:
```bash
git commit -m "Release vX.Y.Z"
```

3. **Create and push a git tag**:
```bash
git tag vX.Y.Z
git push origin main --tags
```

4. **[GitHub Actions](https://github.com/Kuadrant/developer-portal-controller/actions/workflows/build-image.yaml) will automatically**:
- Build image
- Push the image to `quay.io/kuadrant/developer-portal-controller:vX.Y.Z`

5. **Verify the release**:
- Check the [GitHub Actions](https://github.com/Kuadrant/developer-portal-controller/actions) workflow completed successfully
- Verify the image is available at [quay.io](https://quay.io/repository/kuadrant/developer-portal-controller?tab=tags)

## Post-Release

After releasing a new version, notify the [kuadrant-operator](https://github.com/Kuadrant/kuadrant-operator) maintainers to update the `developer-portal-controller` dependency version in `release.yaml` for the next kuadrant-operator release.

## Bundled Releases

The developer-portal-controller is bundled as part of the kuadrant-operator release. When a new kuadrant-operator version is released, it includes a specific version of this controller.

For details on the kuadrant-operator release process, see the [kuadrant-operator RELEASE.md](https://github.com/Kuadrant/kuadrant-operator/blob/main/RELEASE.md).
33 changes: 33 additions & 0 deletions utils/release/github-release-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#!/usr/bin/env bash

if [[ -z "$GITHUB_TOKEN" ]]; then
echo "GITHUB_TOKEN must be set"
exit 1
fi

# Get previous tag (latest release)
previous_tag=$(curl -sL "https://api.github.com/repos/Kuadrant/developer-portal-controller/releases/latest" \
-H "Accept: application/vnd.github+json" | jq -r '.tag_name // empty')

if [[ -z "$previous_tag" ]]; then
echo "No previous release found, generating notes from scratch"
previous_tag=""
fi

# Generate notes via API
if [[ -n "$previous_tag" ]]; then
payload="{\"tag_name\": \"$RELEASE_TAG\", \"previous_tag_name\": \"$previous_tag\"}"
else
payload="{\"tag_name\": \"$RELEASE_TAG\"}"
fi

body=$(curl -sL "https://api.github.com/repos/Kuadrant/developer-portal-controller/releases/generate-notes" \
-X POST \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
-d "$payload" | jq -r '.body')

# Export to GitHub Actions environment
echo "releaseBody<<EOF" >> $GITHUB_ENV
echo "$body" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV