Skip to content

Commit 38fcfc8

Browse files
committed
ADD: two-phase release process
Automates the release of limitador, including the manual steps from before. Also aligns the release process with the up-and-coming RFC. Signed-off-by: Jim Fitzpatrick <jfitzpat@redhat.com>
1 parent f280c20 commit 38fcfc8

11 files changed

Lines changed: 891 additions & 101 deletions

File tree

.github/scripts/README.md

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Release Scripts
2+
3+
Helper scripts used by the release workflows. Both require [yq](https://github.com/mikefarah/yq) to be installed.
4+
5+
## parse-version.sh
6+
7+
Reads `release.yaml`, validates that both `version` and `crate-version` are valid semver, and outputs version components. In CI it writes to `$GITHUB_OUTPUT`; locally it prints to stdout.
8+
9+
### Usage
10+
11+
```sh
12+
.github/scripts/parse-version.sh [path-to-release-yaml]
13+
```
14+
15+
### Examples
16+
17+
Using the default `release.yaml` at the repo root:
18+
19+
```sh
20+
.github/scripts/parse-version.sh
21+
```
22+
23+
Using a custom file:
24+
25+
```sh
26+
cat > /tmp/test-release.yaml <<'EOF'
27+
limitador:
28+
version: "2.5.0"
29+
crate-version: "0.13.0"
30+
31+
dependencies: {}
32+
EOF
33+
34+
.github/scripts/parse-version.sh /tmp/test-release.yaml
35+
```
36+
37+
Expected output:
38+
39+
```
40+
version=2.5.0
41+
major=2
42+
minor=5
43+
patch=0
44+
release-branch=release-2.5
45+
crate-version=0.13.0
46+
crate-major=0
47+
crate-minor=13
48+
crate-patch=0
49+
```
50+
51+
### Error cases
52+
53+
Invalid semver:
54+
55+
```sh
56+
cat > /tmp/bad.yaml <<'EOF'
57+
limitador:
58+
version: "not-a-version"
59+
crate-version: "0.13.0"
60+
dependencies: {}
61+
EOF
62+
63+
.github/scripts/parse-version.sh /tmp/bad.yaml
64+
# ::error::Invalid semver for version: not-a-version
65+
# exit code: 1
66+
```
67+
68+
## validate-release-yaml.sh
69+
70+
Validates version gating rules for the version-gate CI check. On release branches it rejects `0.0.0` sentinel values and `-dev` suffixed versions. For any declared dependencies, it verifies the corresponding GitHub Release exists.
71+
72+
### Usage
73+
74+
```sh
75+
.github/scripts/validate-release-yaml.sh <branch-name> [org] [path-to-release-yaml]
76+
```
77+
78+
| Argument | Required | Default | Description |
79+
|----------|----------|---------|-------------|
80+
| `branch-name` | yes | | The branch name to validate against (e.g. `main`, `release-2.5`) |
81+
| `org` | no | `Kuadrant` | GitHub organization for dependency release lookups |
82+
| `path-to-release-yaml` | no | `release.yaml` | Path to the release.yaml file |
83+
84+
### Examples
85+
86+
Validating on `main` (sentinel `0.0.0` is allowed):
87+
88+
```sh
89+
.github/scripts/validate-release-yaml.sh main
90+
# release.yaml validation passed
91+
```
92+
93+
Validating on a release branch with the default `release.yaml` (should fail because versions are `0.0.0` on main):
94+
95+
```sh
96+
.github/scripts/validate-release-yaml.sh release-2.5
97+
# ::error::release.yaml version is 0.0.0 on branch 'release-2.5' ...
98+
# exit code: 1
99+
```
100+
101+
Validating on a release branch with proper versions:
102+
103+
```sh
104+
cat > /tmp/release-test.yaml <<'EOF'
105+
limitador:
106+
version: "2.5.0"
107+
crate-version: "0.13.0"
108+
109+
dependencies: {}
110+
EOF
111+
112+
.github/scripts/validate-release-yaml.sh release-2.5 Kuadrant /tmp/release-test.yaml
113+
# release.yaml validation passed
114+
```
115+
116+
### Error cases
117+
118+
Dev version on a release branch:
119+
120+
```sh
121+
cat > /tmp/dev.yaml <<'EOF'
122+
limitador:
123+
version: "2.5.0-dev"
124+
crate-version: "0.13.0"
125+
dependencies: {}
126+
EOF
127+
128+
.github/scripts/validate-release-yaml.sh release-2.5 Kuadrant /tmp/dev.yaml
129+
# ::error::release.yaml version '2.5.0-dev' is a dev version on branch 'release-2.5' ...
130+
# exit code: 1
131+
```
132+
133+
Missing dependency release (requires `gh` CLI and authentication):
134+
135+
```sh
136+
cat > /tmp/deps.yaml <<'EOF'
137+
limitador:
138+
version: "2.5.0"
139+
crate-version: "0.13.0"
140+
141+
dependencies:
142+
some-repo: "99.99.99"
143+
EOF
144+
145+
.github/scripts/validate-release-yaml.sh release-2.5 Kuadrant /tmp/deps.yaml
146+
# ::error::Dependency 'some-repo' targets version '99.99.99', but release v99.99.99 does not exist in Kuadrant/some-repo
147+
# exit code: 1
148+
```

.github/scripts/parse-version.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
RELEASE_YAML="${1:-release.yaml}"
5+
6+
if [[ ! -f "$RELEASE_YAML" ]]; then
7+
echo "::error::File not found: $RELEASE_YAML"
8+
exit 1
9+
fi
10+
11+
VERSION=$(yq '.limitador.version' "$RELEASE_YAML")
12+
if [[ -z "$VERSION" || "$VERSION" == "null" ]]; then
13+
echo "::error::No version found in $RELEASE_YAML under limitador.version"
14+
exit 1
15+
fi
16+
17+
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
18+
echo "::error::Invalid semver for version: $VERSION"
19+
exit 1
20+
fi
21+
22+
CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML")
23+
if [[ -z "$CRATE_VERSION" || "$CRATE_VERSION" == "null" ]]; then
24+
echo "::error::No crate-version found in $RELEASE_YAML under limitador.crate-version"
25+
exit 1
26+
fi
27+
28+
if ! [[ "$CRATE_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
29+
echo "::error::Invalid semver for crate-version: $CRATE_VERSION"
30+
exit 1
31+
fi
32+
33+
MAJOR=$(echo "$VERSION" | cut --delimiter=. --fields=1)
34+
MINOR=$(echo "$VERSION" | cut --delimiter=. --fields=2)
35+
PATCH=$(echo "$VERSION" | cut --delimiter=. --fields=3 | cut --delimiter=- --fields=1)
36+
RELEASE_BRANCH="release-${MAJOR}.${MINOR}"
37+
38+
CRATE_MAJOR=$(echo "$CRATE_VERSION" | cut --delimiter=. --fields=1)
39+
CRATE_MINOR=$(echo "$CRATE_VERSION" | cut --delimiter=. --fields=2)
40+
CRATE_PATCH=$(echo "$CRATE_VERSION" | cut --delimiter=. --fields=3 | cut --delimiter=- --fields=1)
41+
42+
echo "version=$VERSION" >> "${GITHUB_OUTPUT:-/dev/stdout}"
43+
echo "major=$MAJOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
44+
echo "minor=$MINOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
45+
echo "patch=$PATCH" >> "${GITHUB_OUTPUT:-/dev/stdout}"
46+
echo "release-branch=$RELEASE_BRANCH" >> "${GITHUB_OUTPUT:-/dev/stdout}"
47+
echo "crate-version=$CRATE_VERSION" >> "${GITHUB_OUTPUT:-/dev/stdout}"
48+
echo "crate-major=$CRATE_MAJOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
49+
echo "crate-minor=$CRATE_MINOR" >> "${GITHUB_OUTPUT:-/dev/stdout}"
50+
echo "crate-patch=$CRATE_PATCH" >> "${GITHUB_OUTPUT:-/dev/stdout}"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
4+
BRANCH="${1:?Branch name required}"
5+
ORG="${2:-Kuadrant}"
6+
RELEASE_YAML="${3:-release.yaml}"
7+
8+
if [[ ! -f "$RELEASE_YAML" ]]; then
9+
echo "::error::File not found: $RELEASE_YAML"
10+
exit 1
11+
fi
12+
13+
VERSION=$(yq '.limitador.version' "$RELEASE_YAML")
14+
CRATE_VERSION=$(yq '.limitador."crate-version"' "$RELEASE_YAML")
15+
16+
if [[ "$BRANCH" =~ ^release- ]]; then
17+
if [[ "$VERSION" == "0.0.0" ]]; then
18+
echo "::error::release.yaml version is 0.0.0 on branch '$BRANCH' -- must specify a release version on release branches"
19+
exit 1
20+
fi
21+
22+
if [[ "$VERSION" == *-dev* ]]; then
23+
echo "::error::release.yaml version '${VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'"
24+
exit 1
25+
fi
26+
27+
if [[ "$CRATE_VERSION" == "0.0.0" ]]; then
28+
echo "::error::release.yaml crate-version is 0.0.0 on branch '$BRANCH' -- must specify a crate version on release branches"
29+
exit 1
30+
fi
31+
32+
if [[ "$CRATE_VERSION" == *-dev* ]]; then
33+
echo "::error::release.yaml crate-version '${CRATE_VERSION}' is a dev version on branch '$BRANCH' -- release versions must not contain '-dev'"
34+
exit 1
35+
fi
36+
fi
37+
38+
DEPS=$(yq '.dependencies | keys | .[]' "$RELEASE_YAML" 2>/dev/null || true)
39+
for dep in $DEPS; do
40+
dep_version=$(yq ".dependencies.${dep}" "$RELEASE_YAML")
41+
if [[ "$dep_version" != "0.0.0" && "$dep_version" != "null" && -n "$dep_version" ]]; then
42+
if ! gh release view "v${dep_version}" --repo "${ORG}/${dep}" &>/dev/null; then
43+
echo "::error::Dependency '${dep}' targets version '${dep_version}', but release v${dep_version} does not exist in ${ORG}/${dep}"
44+
exit 1
45+
fi
46+
fi
47+
done
48+
49+
echo "release.yaml validation passed"

.github/workflows/build-image.yaml

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@
22
name: Build Image
33

44
on:
5+
workflow_call:
6+
inputs:
7+
ref:
8+
description: "Git ref to check out"
9+
required: true
10+
type: string
11+
tag:
12+
description: "Image tag to apply"
13+
required: true
14+
type: string
515
workflow_dispatch:
616
push:
717
branches:
818
- main
9-
tags:
10-
- "*"
1119

1220
env:
1321
IMG_REGISTRY_HOST: quay.io
@@ -37,6 +45,8 @@ jobs:
3745
steps:
3846
- name: Check out code
3947
uses: actions/checkout@v6
48+
with:
49+
ref: ${{ inputs.ref || github.ref }}
4050
- name: Set up Docker Buildx
4151
uses: docker/setup-buildx-action@v3
4252
- name: Docker meta
@@ -99,12 +109,14 @@ jobs:
99109
images: |
100110
${{ env.IMG_REGISTRY_HOST }}/${{ env.IMG_REGISTRY_ORG }}/limitador
101111
tags: |
112+
# When called from release workflow, use the provided tag
113+
type=raw,value=${{ inputs.tag }},enable=${{ inputs.tag != '' }}
102114
# SHA tag for main branch
103-
type=raw,value=${{ github.sha }},enable=${{ github.ref_name == env.MAIN_BRANCH_NAME }}
115+
type=raw,value=${{ github.sha }},enable=${{ inputs.tag == '' && github.ref_name == env.MAIN_BRANCH_NAME }}
104116
# set latest tag for main branch
105-
type=raw,value=latest,enable=${{ github.ref_name == env.MAIN_BRANCH_NAME }}
117+
type=raw,value=latest,enable=${{ inputs.tag == '' && github.ref_name == env.MAIN_BRANCH_NAME }}
106118
# set ref name tag for non-main branches
107-
type=raw,value=${{ github.ref_name }},enable=${{ github.ref_name != env.MAIN_BRANCH_NAME }}
119+
type=raw,value=${{ github.ref_name }},enable=${{ inputs.tag == '' && github.ref_name != env.MAIN_BRANCH_NAME }}
108120
- name: Login to container registry
109121
uses: docker/login-action@v2
110122
with:

0 commit comments

Comments
 (0)