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
43 changes: 43 additions & 0 deletions .github/scripts/create_or_update_upstream_pr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/usr/bin/env bash
Comment thread
jancervenka marked this conversation as resolved.

set -euo pipefail
upstream=redhat-openshift-ecosystem/community-operators-prod
branch="openstack-lightspeed-release-$NEW_VERSION"
title="operator openstack-lightspeed-operator ($NEW_VERSION)"
head="${FORK_REPOSITORY%%/*}:$branch"

gh auth setup-git --hostname github.com
git config user.name "$AUTHOR_NAME"
git config user.email "$AUTHOR_EMAIL"
git remote add fork "https://github.com/$FORK_REPOSITORY.git"
remote_head=$(git ls-remote fork "refs/heads/$branch" | cut -f1)
git switch -c "$branch"
git add -- "operators/openstack-lightspeed-operator/$NEW_VERSION"
git commit --signoff -m "$title"
# Only replace the branch if it has not changed since we read it.
git push --force-with-lease="refs/heads/$branch:$remote_head" \
fork "HEAD:refs/heads/$branch"

body_file="$RUNNER_TEMP/community-release-pr.md"
cat > "$body_file" <<EOF
Release OpenStack Lightspeed community operator $NEW_VERSION.

- Image tag: $CONTAINER_IMAGE_TAG
- Bundle image: quay.io/openstack-lightspeed/operator-bundle@$BUNDLE_DIGEST
- Operator image: quay.io/openstack-lightspeed/operator@$OPERATOR_DIGEST

Generated by [this workflow run]($GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID).
EOF

# REST calls through gh support both personal and organization forks.
pr_number=$(gh api --method GET "repos/$upstream/pulls" \
-f state=open -f base=main -f "head=$head" --jq '.[0].number // empty')
if [[ -n "$pr_number" ]]; then
pr_url=$(gh api --method PATCH "repos/$upstream/pulls/$pr_number" \
-f "title=$title" -F "body=@$body_file" --jq .html_url)
else
pr_url=$(gh api --method POST "repos/$upstream/pulls" \
-f base=main -f "head=$head" -f "head_repo=${FORK_REPOSITORY#*/}" \
-f "title=$title" -F "body=@$body_file" --jq .html_url)
fi
echo "pull-request-url=$pr_url" >> "$GITHUB_OUTPUT"
88 changes: 88 additions & 0 deletions .github/scripts/prepare_community_bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
#!/usr/bin/env bash

set -euo pipefail
if [[ "$HAS_TOKEN" != true ]]; then
echo "::error::Set the COMMUNITY_OPERATORS_TOKEN repository secret."
exit 1
fi
: "${AUTHOR_NAME:?Set the RELEASE_AUTHOR_NAME repository variable.}"
: "${AUTHOR_EMAIL:?Set the RELEASE_AUTHOR_EMAIL repository variable.}"
version_pattern='^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$'
if [[ ! "$NEW_VERSION" =~ $version_pattern ]]; then
echo "::error::new_version must have the form X.Y.Z."
exit 1
fi
if [[ ! "$FORK_REPOSITORY" =~ ^[a-zA-Z0-9-]+/[a-zA-Z0-9_.-]+$ ]]; then
echo "::error::Set the COMMUNITY_OPERATORS_FORK repository variable to owner/repository."
exit 1
fi
if [[ ! "$CONTAINER_IMAGE_TAG" =~ ^[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$ ]]; then
echo "::error::container_image_tag must be a valid container image tag."
exit 1
fi

operator_dir=operators/openstack-lightspeed-operator
release_dir="$operator_dir/$NEW_VERSION"
if [[ -e "$release_dir" ]]; then
echo "::error::Version $NEW_VERSION already exists on upstream main."
exit 1
fi
PREVIOUS_VERSION=$(
{ find "$operator_dir" -mindepth 1 -maxdepth 1 -type d -printf '%f\n'; printf '%s\n' "$NEW_VERSION"; } |
grep -E "$version_pattern" | sort -Vu |
awk -v version="$NEW_VERSION" '$0 == version { print previous } { previous = $0 }'
)
: "${PREVIOUS_VERSION:?No existing community release precedes this version.}"

declare -A image_digests
for repository in operator operator-bundle; do
digest=$(curl --fail --silent --show-error --max-time 30 \
--get --data-urlencode "specificTag=$CONTAINER_IMAGE_TAG" \
--data-urlencode 'onlyActiveTags=true' \
"https://quay.io/api/v1/repository/openstack-lightspeed/$repository/tag/" |
jq -r --arg tag "$CONTAINER_IMAGE_TAG" \
'[.tags[]? | select(.name == $tag) | .manifest_digest][0] // empty')
if [[ ! "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]; then
echo "::error::No active $repository image with a valid digest for $CONTAINER_IMAGE_TAG."
exit 1
fi
image_digests[$repository]="$digest"
done
OPERATOR_IMAGE_DIGEST=${image_digests[operator]}
BUNDLE_IMAGE_DIGEST=${image_digests[operator-bundle]}
export PREVIOUS_VERSION OPERATOR_IMAGE_DIGEST

image="quay.io/openstack-lightspeed/operator-bundle@$BUNDLE_IMAGE_DIGEST"
podman pull "$image"
image_id=$(podman image inspect --format '{{.Id}}' "$image")
# Podman 4 requires a command even though this container is never started.
container_id=$(podman create "$image_id" /bin/true)
trap 'podman rm "$container_id" >/dev/null || true' EXIT
mkdir -p "$release_dir"
for directory in manifests metadata tests; do
podman cp "$container_id:/$directory" "$release_dir/$directory"
done

yq -i '
.metadata.name = ("openstack-lightspeed-operator.v" + strenv(NEW_VERSION)) |
.metadata.annotations.containerImage = ("quay.io/openstack-lightspeed/operator@" + strenv(OPERATOR_IMAGE_DIGEST)) |
.metadata.annotations.support = "Community" |
.spec.displayName = "OpenStack Lightspeed (Community)" |
.spec.replaces = ("openstack-lightspeed-operator.v" + strenv(PREVIOUS_VERSION)) |
.spec.version = strenv(NEW_VERSION)
' "$release_dir/manifests/openstack-lightspeed-operator.clusterserviceversion.yaml"

cat > "$release_dir/release-config.yaml" <<EOF
catalog_templates:
- template_name: v4.16.yaml
channels: [alpha]
replaces: openstack-lightspeed-operator.v$PREVIOUS_VERSION
- template_name: v4.18.yaml
channels: [alpha]
replaces: openstack-lightspeed-operator.v$PREVIOUS_VERSION
- template_name: v4.22.yaml
channels: [alpha]
replaces: openstack-lightspeed-operator.v$PREVIOUS_VERSION
EOF
echo "operator_digest=$OPERATOR_IMAGE_DIGEST" >> "$GITHUB_OUTPUT"
echo "bundle_digest=$BUNDLE_IMAGE_DIGEST" >> "$GITHUB_OUTPUT"
99 changes: 99 additions & 0 deletions .github/workflows/propose-community-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: Propose community operator release
Comment thread
jancervenka marked this conversation as resolved.

on:
workflow_dispatch:
inputs:
new_version:
description: 'Community release version (X.Y.Z)'
required: true
type: string
container_image_tag:
description: 'Published operator and bundle image tag'
required: true
default: latest
type: string

permissions:
contents: read

concurrency:
group: community-release-${{ vars.COMMUNITY_OPERATORS_FORK }}-${{ inputs.new_version }}
cancel-in-progress: false

jobs:
propose-release:
runs-on: ubuntu-24.04
timeout-minutes: 30
defaults:
run:
shell: bash
env:
NEW_VERSION: ${{ inputs.new_version }}
CONTAINER_IMAGE_TAG: ${{ inputs.container_image_tag }}
FORK_REPOSITORY: ${{ vars.COMMUNITY_OPERATORS_FORK }} # owner/repo-name
AUTHOR_NAME: ${{ vars.RELEASE_AUTHOR_NAME }}
AUTHOR_EMAIL: ${{ vars.RELEASE_AUTHOR_EMAIL }}

steps:
- name: Check out release scripts
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
sparse-checkout: .github
persist-credentials: false

- name: Check out community operators
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
repository: redhat-openshift-ecosystem/community-operators-prod
ref: main
path: community-operators-prod
# Keep history for pushing to forks that are behind upstream.
fetch-depth: 0
sparse-checkout: operators/openstack-lightspeed-operator
persist-credentials: false

- name: Prepare community bundle
id: bundle
working-directory: community-operators-prod
env:
# The preparation script only needs to know whether the PAT is configured.
HAS_TOKEN: ${{ secrets.COMMUNITY_OPERATORS_TOKEN != '' }}
run: bash "$GITHUB_WORKSPACE/.github/scripts/prepare_community_bundle.sh"

- name: Install operator-sdk
uses: redhat-actions/openshift-tools-installer@37eb3cfb20ac2df6f0511ffa71cd917e4d49cabf # v3
with:
source: github
operator-sdk: 1.42.3

- name: Validate community bundle
working-directory: community-operators-prod
run: operator-sdk bundle validate "./operators/openstack-lightspeed-operator/$NEW_VERSION"

# Scorecard executes its tests in Kubernetes pods.
- name: Create cluster for scorecard
uses: helm/kind-action@1544676c07bb3570fcb70166beaa07c4528fd4aa # v1.15.1
with:
cluster_name: community-scorecard
wait: 120s

- name: Run community bundle scorecard
working-directory: community-operators-prod
run: operator-sdk scorecard "./operators/openstack-lightspeed-operator/$NEW_VERSION" --wait-time 5m

- name: Create or update upstream pull request
id: pr
working-directory: community-operators-prod
env:
GH_TOKEN: ${{ secrets.COMMUNITY_OPERATORS_TOKEN }}
Comment thread
lpiwowar marked this conversation as resolved.
GH_PROMPT_DISABLED: "1"
GIT_TERMINAL_PROMPT: "0"
OPERATOR_DIGEST: ${{ steps.bundle.outputs.operator_digest }}
BUNDLE_DIGEST: ${{ steps.bundle.outputs.bundle_digest }}
run: bash "$GITHUB_WORKSPACE/.github/scripts/create_or_update_upstream_pr.sh"

- name: Show pull request
env:
PR_URL: ${{ steps.pr.outputs.pull-request-url }}
run: |
printf 'Release pull request: %s\n' "$PR_URL" >> "$GITHUB_STEP_SUMMARY"
38 changes: 38 additions & 0 deletions docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,44 @@ cd ../..
`PULL_SECRET` is the same pull secret described in the
[installation guide](install_guide.md#access-to-registry-images).

## Releasing to the community catalog

The **Propose community operator release** GitHub Actions workflow uses
already-published operator and bundle images from Quay. It resolves the selected
tag to image digests, extracts the bundle, and updates its version, community
metadata, and upgrade link to the preceding release. It runs bundle validation
and scorecard tests (in a temporary Kind cluster), then opens or updates a PR in
[community-operators-prod](https://github.com/redhat-openshift-ecosystem/community-operators-prod).
The current targets are the `alpha` channel on OpenShift 4.16, 4.18, 4.22 configured
in `.github/scripts/prepare_community_bundle.sh`.

Before the first release, a repository administrator must configure these
Actions secrets and variables:

- Secret `COMMUNITY_OPERATORS_TOKEN`: a bot account token that can push to the
fork and create or update upstream PRs.
- Variable `COMMUNITY_OPERATORS_FORK`: the existing fork, in `owner/repository`
format (for example, `openstack-lightspeed-bot/community-operators-prod`).
- Variables `RELEASE_AUTHOR_NAME` and `RELEASE_AUTHOR_EMAIL`: the bot's Git
commit identity.

To make a release:

1. Wait for **Build and push operator container image** to finish successfully
for the code you want to release.
2. In the `lightspeed-operator` repository, open **Actions → Propose community
operator release → Run workflow**.
3. Set `new_version` to the next community version, such as `0.0.3` (without a
`v` prefix). It must not already exist in the catalog. Set
`container_image_tag` to `latest` (the default, from the latest main build),
or a specific build tag such as `v0.1.0-<short-commit-sha>`.
4. Click **Run workflow**. If validation and scorecard pass, the run summary
contains the upstream PR link. Follow that PR's checks and review through
merge; the upstream pipeline handles publication to the catalog.

After publication, verify installation and a Lightspeed query on an OpenShift
cluster using the [installation guide](install_guide.md).

## Architecture

```mermaid
Expand Down
Loading