Skip to content

Commit 10a77dc

Browse files
committed
Add a tool to generate the release name
Signed-off-by: Andrea Frittoli <[email protected]>
1 parent 5b082b1 commit 10a77dc

File tree

2 files changed

+239
-23
lines changed

2 files changed

+239
-23
lines changed

tekton/release-cheat-sheet.md

+37-23
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,54 @@ the pipelines repo, a terminal window and a text editor.
1212

1313
1. [Install kustomize](https://kubectl.docs.kubernetes.io/installation/kustomize) if you haven't already.
1414

15-
1. Ensure the correct version of the release pipeline is installed on the cluster:
15+
1. Select the commit you would like to build the release from (NOTE: the commit is full (40-digit) hash.)
16+
- Select the most recent commit on the ***main branch*** if you are cutting a major or minor release i.e. `x.0.0` or `0.x.0`
17+
- Select the most recent commit on the ***`release-<version number>x` branch***, e.g. [`release-v0.47.x`](https://github.com/tektoncd/pipeline/tree/release-v0.47.x) if you are patching a release i.e. `v0.47.2`.
18+
19+
1. Ensure the correct version of the release pipeline is installed on the cluster.
20+
To do that, the selected commit should be checked-out locally
1621

1722
```bash
1823
kustomize build tekton | kubectl --context dogfooding replace -f -
1924
```
2025

21-
1. Create environment variables for bash scripts in later steps.
26+
1. Choose a name for the new release! The usual pattern is "< cat breed > < famous robot >" e.g. "Ragdoll Norby". For LTS releases, add a suffix "LTS" in the name such as "< cat breed > < famous robot > LTS" e.g. "Ragdoll Norby LTS". Use this command to generate a name that has not yet been used:
2227

2328
```bash
24-
TEKTON_VERSION=# Example: v0.21.0
29+
go run tekton/release_names.go
30+
```
31+
32+
It returns something like:
33+
34+
```json
35+
{
36+
"release_name": "Khao Manee KARR",
37+
"cat_breed_url": "https://en.wikipedia.org/wiki/Khao_Manee",
38+
"robot_url": "https://en.wikipedia.org/wiki/KARR"
39+
}
40+
```
41+
42+
The URLs can be used to find out more about the cat breed and robot selected by the tool.
43+
Previous release names can also be found with the following command:
44+
45+
```bash
46+
curl \
47+
-H "Accept: application/vnd.github.v3+json" \
48+
https://api.github.com/repos/tektoncd/pipeline/releases\?per_page=100 \
49+
| jq ".[].name" | cut -d'"' -f 3 | tr -d '\' | sort -u
2550
```
2651

27-
- Select the commit you would like to build the release from (NOTE: the commit is full (40-digit) hash.)
28-
- Select the most recent commit on the ***main branch*** if you are cutting a major or minor release i.e. `x.0.0` or `0.x.0`
29-
- Select the most recent commit on the ***`release-<version number>x` branch***, e.g. [`release-v0.47.x`](https://github.com/tektoncd/pipeline/tree/release-v0.47.x) if you are patching a release i.e. `v0.47.2`.
52+
1. Create a `release.env` file with environment variables for bash scripts in later steps, and source it:
3053

3154
```bash
32-
TEKTON_RELEASE_GIT_SHA=# SHA of the release to be released
55+
cat <<EOF > release.env
56+
TEKTON_VERSION= # Example: v0.69.0
57+
TEKTON_RELEASE_GIT_SHA= # SHA of the release to be released, e.g. 5b082b1106753e093593d12152c82e1c4b0f37e5
58+
TEKTON_OLD_VERSION= # Example: v0.68.0
59+
TEKTON_RELEASE_NAME="Oriental Longhair Omnibot" # Name of the release
60+
TEKTON_PACKAGE=tektoncd/pipeline
61+
EOF
62+
. ./release.env
3363
```
3464
3565
1. Confirm commit SHA matches what you want to release.
@@ -103,15 +133,6 @@ the pipelines repo, a terminal window and a text editor.
103133
104134
1. The YAMLs are now released! Anyone installing Tekton Pipelines will get the new version. Time to create a new GitHub release announcement:
105135
106-
1. Choose a name for the new release! The usual pattern is "< cat breed > < famous robot >" e.g. "Ragdoll Norby". For LTS releases, add a suffix "LTS" in the name such as "< cat breed > < famous robot > LTS" e.g. "Ragdoll Norby LTS". Browse [the releases page](https://github.com/tektoncd/pipeline/releases) or run this command to check which names have already been used:
107-
108-
```bash
109-
curl \
110-
-H "Accept: application/vnd.github.v3+json" \
111-
https://api.github.com/repos/tektoncd/pipeline/releases\?per_page=100 \
112-
| jq ".[].name"
113-
```
114-
115136
1. Find the Rekor UUID for the release
116137
117138
```bash
@@ -121,13 +142,6 @@ the pipelines repo, a terminal window and a text editor.
121142
echo -e "CONTROLLER_IMAGE_SHA: ${CONTROLLER_IMAGE_SHA}\nREKOR_UUID: ${REKOR_UUID}"
122143
```
123144
124-
1. Create additional environment variables
125-
126-
```bash
127-
TEKTON_OLD_VERSION=# Example: v0.11.1
128-
TEKTON_RELEASE_NAME=# The release name you just chose, e.g.: "Ragdoll Norby"
129-
```
130-
131145
1. Execute the Draft Release Pipeline.
132146
133147
```bash

tekton/release_names.go

+202
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
/*
2+
Copyright 2020 The Tekton Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
/*
18+
This utility can be used to generate a new release name in the format:
19+
<cat breed> <robot name>
20+
21+
to be used for a Tekton Pipelines release.
22+
It looks for cat breeds from CatAPIURL and it parses robot names out
23+
of Wikipedia WikiURL. It filters names that have been used already,
24+
based on the GitHub API GitHubReleasesURL
25+
26+
To use, run:
27+
go run release_names.go
28+
29+
30+
Example output:
31+
{
32+
"release_name": "California Spangled Clank",
33+
"cat_breed_url": "https://en.wikipedia.org/wiki/California_Spangled",
34+
"robot_url": "https://en.wikipedia.org/wiki/Clank"
35+
}
36+
*/
37+
38+
package main
39+
40+
import (
41+
"encoding/json"
42+
"errors"
43+
"fmt"
44+
"io"
45+
"math/rand"
46+
"net/http"
47+
"regexp"
48+
"strings"
49+
)
50+
51+
// API Endpoints
52+
const (
53+
CatAPIURL = "https://api.thecatapi.com/v1/breeds"
54+
WikiURL = "https://en.wikipedia.org/wiki/List_of_fictional_robots_and_androids"
55+
GitHubReleasesURL = "https://api.github.com/repos/tektoncd/pipeline/releases"
56+
)
57+
58+
// Structs to hold API responses
59+
type CatBreed struct {
60+
Name string `json:"name"`
61+
}
62+
63+
type Release struct {
64+
Name string `json:"name"`
65+
}
66+
67+
// Fetch cat breeds and organize them by first letter
68+
func getCatBreeds() (map[string][][2]string, error) {
69+
resp, err := http.Get(CatAPIURL)
70+
if err != nil {
71+
return nil, err
72+
}
73+
defer resp.Body.Close()
74+
75+
var breeds []CatBreed
76+
if err := json.NewDecoder(resp.Body).Decode(&breeds); err != nil {
77+
return nil, err
78+
}
79+
80+
catDict := make(map[string][][2]string)
81+
for _, breed := range breeds {
82+
firstLetter := strings.ToUpper(string(breed.Name[0]))
83+
wikiURL := "https://en.wikipedia.org/wiki/" + strings.ReplaceAll(breed.Name, " ", "_")
84+
catDict[firstLetter] = append(catDict[firstLetter], [2]string{breed.Name, wikiURL})
85+
}
86+
87+
return catDict, nil
88+
}
89+
90+
// Scrape Wikipedia for robot names
91+
func getRobotNames() (map[string][][2]string, error) {
92+
resp, err := http.Get(WikiURL)
93+
if err != nil {
94+
return nil, err
95+
}
96+
defer resp.Body.Close()
97+
98+
body, err := io.ReadAll(resp.Body)
99+
if err != nil {
100+
return nil, err
101+
}
102+
103+
robotDict := make(map[string][][2]string)
104+
105+
// Regex to extract robot names from <li><b>Robot Name</b>
106+
re := regexp.MustCompile(`<li>\s*<b>\s*<a[^>]*>([^<]+)</a>\s*</b>`)
107+
matches := re.FindAllStringSubmatch(string(body), -1)
108+
109+
for _, match := range matches {
110+
if len(match) > 1 {
111+
name := strings.TrimSpace(match[1])
112+
firstLetter := strings.ToUpper(string(name[0]))
113+
wikiURL := "https://en.wikipedia.org/wiki/" + strings.ReplaceAll(name, " ", "_")
114+
robotDict[firstLetter] = append(robotDict[firstLetter], [2]string{name, wikiURL})
115+
}
116+
}
117+
118+
return robotDict, nil
119+
}
120+
121+
// Fetch past releases from GitHub
122+
func getPastReleases() (map[string]bool, error) {
123+
resp, err := http.Get(GitHubReleasesURL + "?per_page=100")
124+
if err != nil {
125+
return nil, err
126+
}
127+
defer resp.Body.Close()
128+
129+
var releases []Release
130+
if err := json.NewDecoder(resp.Body).Decode(&releases); err != nil {
131+
return nil, err
132+
}
133+
134+
pastReleases := make(map[string]bool)
135+
for _, release := range releases {
136+
pastReleases[release.Name] = true
137+
}
138+
139+
return pastReleases, nil
140+
}
141+
142+
// Generate a unique release name
143+
func generateUniqueName() (string, string, string, error) {
144+
catBreeds, err := getCatBreeds()
145+
if err != nil {
146+
return "", "", "", err
147+
}
148+
149+
robotNames, err := getRobotNames()
150+
if err != nil {
151+
return "", "", "", err
152+
}
153+
154+
pastReleases, err := getPastReleases()
155+
if err != nil {
156+
return "", "", "", err
157+
}
158+
159+
// Find common letters
160+
commonLetters := []string{}
161+
for letter := range catBreeds {
162+
if _, exists := robotNames[letter]; exists {
163+
commonLetters = append(commonLetters, letter)
164+
}
165+
}
166+
167+
if len(commonLetters) == 0 {
168+
return "", "", "", errors.New("no matching names found")
169+
}
170+
171+
maxAttempts := 10
172+
for i := 0; i < maxAttempts; i++ {
173+
chosenLetter := commonLetters[rand.Intn(len(commonLetters))]
174+
175+
cat := catBreeds[chosenLetter][rand.Intn(len(catBreeds[chosenLetter]))]
176+
robot := robotNames[chosenLetter][rand.Intn(len(robotNames[chosenLetter]))]
177+
178+
newName := cat[0] + " " + robot[0]
179+
if !pastReleases[newName] {
180+
return newName, cat[1], robot[1], nil
181+
}
182+
}
183+
184+
return "", "", "", errors.New("could not generate a unique name after multiple attempts")
185+
}
186+
187+
func main() {
188+
name, catURL, robotURL, err := generateUniqueName()
189+
if err != nil {
190+
fmt.Println(`{"error": "` + err.Error() + `"}`)
191+
return
192+
}
193+
194+
output := map[string]string{
195+
"release_name": name,
196+
"cat_breed_url": catURL,
197+
"robot_url": robotURL,
198+
}
199+
200+
jsonOutput, _ := json.MarshalIndent(output, "", " ")
201+
fmt.Println(string(jsonOutput))
202+
}

0 commit comments

Comments
 (0)