Skip to content
Open
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
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:
workflow_dispatch:
inputs:
tag:
description: "New version to release, e.g. 0.4.0 (no 'v' prefix)"
required: true
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.

can we add validation on these format to avoid errors?

type: string
version-replace:
description: "Previously shipped version for the OLM replaces chain, e.g. 0.3.2"
required: true
type: string

permissions:
contents: read

jobs:
prepare-release:
name: Prepare release PR
runs-on: ubuntu-latest
concurrency:
group: release-preparation
cancel-in-progress: true
steps:
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.

Suggested change
steps:
concurrency:
group: release-preparation
cancel-in-progress: true
steps:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Nice one!

- name: Validate inputs
env:
TAG: ${{ inputs.tag }}
VERSION_REPLACE: ${{ inputs.version-replace }}
run: |
SEMVER_REGEX='^[0-9]+\.[0-9]+\.[0-9]+$'
[[ "$TAG" =~ $SEMVER_REGEX ]] || {
echo "::error title=Invalid input::tag='$TAG' must be MAJOR.MINOR.PATCH (e.g. 0.4.0, no 'v' prefix)"
exit 1
}
[[ "$VERSION_REPLACE" =~ $SEMVER_REGEX ]] || {
echo "::error title=Invalid input::version-replace='$VERSION_REPLACE' must be MAJOR.MINOR.PATCH (e.g. 0.3.2)"
exit 1
}

- name: Checkout
uses: actions/checkout@v6
with:
# NOTE: we need to fetch the whole history to be able to generate the changelog
fetch-depth: 0
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.

does the changelog depend on having the commits?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yes I think we need it


- name: Set up Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod

- name: Install tools
uses: ./.github/tools-cache

- name: Update VERSION
run: echo "${{ inputs.tag }}" > VERSION

- name: Generate changelog
run: make generate-changelog

- name: Generate bundle
env:
VERSION_REPLACED: ${{ inputs.version-replace }}
run: make bundle

- name: Generate installer manifest
run: make build-installer

- name: Create pull request
# NOTE: BOT_TOKEN (PAT for persesbot) is required: a PR opened with the default
# GITHUB_TOKEN would not trigger downstream pull_request workflows.
uses: peter-evans/create-pull-request@v8
with:
token: ${{ secrets.BOT_TOKEN }}
branch: chore-version-${{ inputs.tag }}
delete-branch: true
signoff: true
commit-message: "chore: update VERSION to ${{ inputs.tag }}"
title: "chore: update VERSION to ${{ inputs.tag }}"
body: |
Automated release PR for `v${{ inputs.tag }}`
- `VERSION` bumped to `${{ inputs.tag }}`
- Changelog generated (`CHANGELOG.md`) and ready for `UNKNOWN` cleanup in PR review
- Bundle generated with `VERSION_REPLACED=${{ inputs.version-replace }}` (OLM `replaces: perses-operator.v${{ inputs.version-replace }}`)
- Installer manifest `bundle.yaml` generated
184 changes: 114 additions & 70 deletions RELEASE.md
Original file line number Diff line number Diff line change
@@ -1,83 +1,127 @@
# Perses Operator Release

## 1. Prepare your release
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.

Do we need to remove all these steps? These are independent of operator hub, I think like helm chart section we should have a section for operatorhub instead

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes these are all handled by the workflow now


- fetch the latest changes from `main`

- Create a release branch named `release/v<major>.<minor>` from the `main` branch.

> ⚠️ Release candidates and patch releases for any given major or minor release happen in the same `release/v<major>.<minor>` branch. Do not create `release/<version>` for patch or release candidate releases.

- Create a branch based on the release branch you just created in the step above in your fork. The branch should use the naming pattern `<yourname>/release-v<major>.<minor>.<patch>`.
- Update the file `VERSION` with the new version to be created.
- Generate `CHANGELOG.md` updates based on git history:

```bash
make generate-changelog
```

- Regenerate bundle, jsonnet, and installer files, and verify they are up to date:

```bash
make bundle-check
make installer-check
```

- Review the generated `CHANGELOG.md` for valid output. Things to check include:
- Entries in the `CHANGELOG.md` are meant to be in this order:
* `[FEATURE]`
* `[ENHANCEMENT]`
* `[BUGFIX]`
* `[BREAKINGCHANGE]`
* `[DOC]`
- Entries that map to a pull request should include a pull request number.
- As we have many libraries we publish, it's better if you also put a clear indication about what library is affected by
these changes.
- Consumers understand how to handle breaking changes either through the messaging in the changelog or through the linked pull requests.
- Push the branch to Github and create a pull request with the release branch as the base. This gives others the opportunity to chime in on the release,
in general, and on the addition to the changelog, in particular.
- It's also helpful to drop a link to the release PR in #perses-dev on the CNCF Slack to get extra visibility.
- Address any necessary feedback.
- Once the pull request is approved, merge it into the release branch.

## 2. Create release tag and validate release

- Pull down the latest updates to the release branch on your local machine to ensure you have the updates from the previous step.
- Tag the new release via the following commands:

```bash
git checkout release/v<major>.<minor>
export GIT_REMOTE_UPSTREAM=origin # change if your upstream remote differs
make tag
git push $GIT_REMOTE_UPSTREAM v<major>.<minor>.<patch>
```

Once a tag is created, an automated release process for this tag is triggered via Github Actions. This automated process includes:

- Building new go binaries and docker images.
- Publishing the docker images to Docker Hub.
- Creating a new Github release that uses the changelog as the release notes and provides tarballs with the latest go binaries.

## 3. Merge the release into `main`

It can be helpful to leave the release branch up for a little while in case we need to create a patch release to address bugs or minor issues with the release you just made.

Once the release branch is no longer needed, you should open a new PR based on `main` to merge those changes. When this PR is approved, merge it into `main` :warning: **using the "merge pull request" option, not "squash and merge"** (the latter would delete the commit needed for the release tag, which can lead to problems).
The release is driven by the **Release** GitHub Actions workflow
(`.github/workflows/release.yaml`). It opens a PR against `main` that bumps
`VERSION`, regenerates `CHANGELOG.md`, regenerates the OLM bundle with the
correct `replaces` chain, and regenerates the installer manifest. Publishing
runs after the PR is merged and the new `v*` tag is pushed.

## Flow overview

```
1. User: Actions ▸ Release ▸ Run workflow (tag, version-replace)
2. release.yaml → opens PR: chore: update VERSION to <tag>
│ (VERSION + CHANGELOG.md + bundle/ + bundle.yaml)
3. User: review & merge PR into main
4. User: push v<tag> tag on main
5. ci.yaml (on v* tag) → images (operator/bundle/catalog) + GitHub release
6. publish-operator-hub.yaml (on release: published)
→ PR against k8s-operatorhub/community-operators
```

## 1. Trigger the release workflow

In GitHub: **Actions** → **Release** → **Run workflow**.

Inputs:

| Input | Example | Meaning |
|-------------------|---------|--------------------------------------------------------------------|
| `tag` | `0.4.0` | New version to release (no `v` prefix). |
| `version-replace` | `0.3.2` | Previously shipped version. Drives OLM `spec.replaces` in the CSV. |

The workflow:

- Writes `<tag>` to `VERSION`.
- Runs `make generate-changelog` — regenerates `CHANGELOG.md` for the new
release version.
- Runs `make bundle VERSION_REPLACED=<version-replace>` — regenerates `bundle/manifests/*`
(CSV `spec.version`, `spec.replaces: perses-operator.v<version-replace>`) and the
jsonnet files under `jsonnet/generated` and `jsonnet/examples`.
- Runs `make build-installer` — regenerates the root `bundle.yaml` installer.
- Opens a PR titled `chore: update VERSION to <tag>` against `main` on branch
`chore-version-<tag>`

Re-running the workflow with the same `tag` updates the existing PR branch.

> ⚠️ `version-replace` must equal the version currently shipped on OperatorHub

## 2. Review and merge the PR

- Review the diff — specifically:
- `VERSION`
- `CHANGELOG.md` (clean up/categorize any `UNKNOWN` entries)
- `bundle/manifests/perses-operator.clusterserviceversion.yaml`
(`spec.version`, `spec.replaces`)
- CRDs and jsonnet generated files (if CRDs changed)
- `bundle.yaml` (root installer manifest)
- Approve and merge the PR into `main`.

> Note: the PR is created using the `BOT_TOKEN` PAT (the same token used by
> `publish-operator-hub.yaml`). This is required so downstream `pull_request`
> workflows (`go.yaml`, `ci.yaml`) fire on the auto-created PR. `BOT_TOKEN`
> is a configuration prerequisite (see
> [One-time setup prerequisites](#one-time-setup-prerequisites)).

## 3. Tag the release

Pull the merged `main` and push the tag:

```bash
git fetch origin
git checkout main
git pull
git tag -a v<tag> -m "v<tag>"
git push origin v<tag>
```

> ⚠️ Do **not** use GitHub's "Create release" UI. `ci.yaml` drives `goreleaser`
> which publishes the GitHub release itself — creating one manually would race.

Pushing the `v*` tag triggers `ci.yaml`, which:

- Builds and pushes the operator container image to Docker Hub and Quay.
- Builds and pushes the bundle and catalog images (`v<tag>` tag on both registries).
- Runs `goreleaser` to publish the GitHub release with the Go binaries.

## 4. Publish to OperatorHub (automated)

When the GitHub release is published, a workflow automatically creates a pull request to submit the new operator version to [k8s-operatorhub/community-operators](https://github.com/k8s-operatorhub/community-operators/pulls) (OperatorHub.io).
When the GitHub release is published, `publish-operator-hub.yaml` fires and
calls the reusable `operator-hub-release.yaml` workflow. It:

- Checks out the `persesbot` fork of `k8s-operatorhub/community-operators` (synced with upstream).
- Checks out `perses-operator` at the released tag and runs `make bundle`.
- Copies `bundle/{manifests,metadata,tests}` into `operators/perses-operator/<tag>/`.
- Pushes the branch to the `persesbot` fork and opens a PR against
[`k8s-operatorhub/community-operators`](https://github.com/k8s-operatorhub/community-operators/pulls).

A maintainer should monitor the PR and address any CI feedback from the community-operators repository.
Monitor that PR and address any feedback from the community-operators CI.

### One-time setup prerequisites

Before the automation can run, the following must be configured once:
Before the OperatorHub automation can run, the following must be configured once:

1. **Bot account**: The `persesbot` GitHub account must have a fork of [k8s-operatorhub/community-operators](https://github.com/k8s-operatorhub/community-operators).
2. **GitHub secret**: A Personal Access Token with `repo` scope for the bot account must be added as `PERSESBOT_GITHUB_TOKEN` in the repository settings.
3. **CLA/DCO**: The bot account should sign the CNCF CLA or Linux Foundation DCO if required.
1. **Bot account**: the `persesbot` GitHub account must have a fork of
[`k8s-operatorhub/community-operators`](https://github.com/k8s-operatorhub/community-operators).
2. **GitHub secret**: a Personal Access Token (`repo` scope) for the bot account
must be added as `BOT_TOKEN` in the repository settings.
3. **CLA/DCO**: the bot account should sign the CNCF CLA or Linux Foundation DCO
if required.

## 5. Update the Helm chart

After the release is published, update the [Perses Operator Helm chart](https://github.com/perses/helm-charts/tree/main/charts/perses-operator) in the [perses/helm-charts](https://github.com/perses/helm-charts) repository. Follow the [Bumping perses-operator Version](https://github.com/perses/helm-charts/blob/main/DEVELOPER_GUIDE.md#bumping-perses-operator-version) guide.
After the release is published, update the
[Perses Operator Helm chart](https://github.com/perses/helm-charts/tree/main/charts/perses-operator)
in the [`perses/helm-charts`](https://github.com/perses/helm-charts) repository.
Follow the
[Bumping perses-operator Version](https://github.com/perses/helm-charts/blob/main/DEVELOPER_GUIDE.md#bumping-perses-operator-version)
guide.
Loading