mirror of https://github.com/knative/func.git
Have static knative component versions in hack/, update in automatic PR (#2677)
* gomod Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * create hack/main.go, delegate, init dynamic updatic of version in allocate.sh, bump github version, unify those versions to v68 Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * new file, fix, more updates Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * bump Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * simplify Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * pr exists, check Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * simplify, fix some stuff Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * simplify further Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix sed error, more comments Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * return to main, dont exit Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * single execute, dont force push, return Run() Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix printing because no 'ready' is at the end Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * misspell Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * context moved to main Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * updt-builder Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * update-knative-components fixes, pagination, simplify using go templates, json file as source of truth Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix error check Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * add json, add kind version, comments Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix versions json Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * add newline Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * add tests, fix structs, locally generate files Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * fix comment inline Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * redo the structure to use cmd/ instead of big hack/main, separate, add \n to generated .json Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * simplify test, fix linter errors Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * small additions, comments Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * update autogen comment Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * gomod Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * localize const to test Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * suggestions Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * makefile Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * makefile, update builder target Signed-off-by: David Fridrich <fridrich.david19@gmail.com> * prefix target with wf Signed-off-by: David Fridrich <fridrich.david19@gmail.com> --------- Signed-off-by: David Fridrich <fridrich.david19@gmail.com>
This commit is contained in:
parent
c28d5ba441
commit
a9cb5b7a93
|
@ -16,4 +16,4 @@ jobs:
|
||||||
- name: Build and Push
|
- name: Build and Push
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ github.token }}
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
run: go run ./hack/update-builder.go
|
run: make wf-update-builder
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
name: Update Kn components in hack/ scripts
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# every 4 hours
|
||||||
|
- cron: '0 */4 * * *'
|
||||||
|
jobs:
|
||||||
|
update:
|
||||||
|
name: Update components
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version: 1.23.0
|
||||||
|
- name: Run script
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ github.token }}
|
||||||
|
run: make wf-generate-knative-components
|
||||||
|
|
24
Makefile
24
Makefile
|
@ -269,3 +269,27 @@ schema-check: ## Check that func.yaml schema is up-to-date
|
||||||
(echo "\n\nFunction config schema 'schema/func_yaml-schema.json' is obsolete, please run 'make schema-generate'.\n\n"; rm -rf schema/func_yaml-schema-previous.json; exit 1)
|
(echo "\n\nFunction config schema 'schema/func_yaml-schema.json' is obsolete, please run 'make schema-generate'.\n\n"; rm -rf schema/func_yaml-schema-previous.json; exit 1)
|
||||||
rm -rf schema/func_yaml-schema-previous.json
|
rm -rf schema/func_yaml-schema-previous.json
|
||||||
|
|
||||||
|
######################
|
||||||
|
##@ Hack scripting
|
||||||
|
######################
|
||||||
|
|
||||||
|
### Local section - Can be run locally!
|
||||||
|
|
||||||
|
.PHONY: generate-kn-components-local
|
||||||
|
generate-kn-components-local: ## Generate knative components locally
|
||||||
|
cd hack && go run ./cmd/update-knative-components "local"
|
||||||
|
|
||||||
|
.PHONY: test-hack
|
||||||
|
test-hack:
|
||||||
|
cd hack && go test ./... -v
|
||||||
|
|
||||||
|
### Automated section - This gets run in workflows, scripts etc.
|
||||||
|
.PHONY: wf-generate-kn-components
|
||||||
|
wf-generate-kn-components: # Generate kn components - used in automation
|
||||||
|
cd hack && go run ./cmd/update-knative-components
|
||||||
|
|
||||||
|
.PHONY: update-builder
|
||||||
|
wf-update-builder: # Used in automation
|
||||||
|
cd hack && go run ./cmd/update-builder
|
||||||
|
|
||||||
|
### end of automation section
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -27,7 +27,7 @@ require (
|
||||||
github.com/go-git/go-git/v5 v5.13.1
|
github.com/go-git/go-git/v5 v5.13.1
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/google/go-containerregistry v0.20.3
|
github.com/google/go-containerregistry v0.20.3
|
||||||
github.com/google/go-github/v49 v49.1.0
|
github.com/google/go-github/v68 v68.0.0
|
||||||
github.com/google/uuid v1.6.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
|
github.com/hectane/go-acl v0.0.0-20190604041725-da78bae5fc95
|
||||||
github.com/heroku/color v0.0.6
|
github.com/heroku/color v0.0.6
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -533,10 +533,10 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
|
||||||
github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI=
|
github.com/google/go-containerregistry v0.20.3 h1:oNx7IdTI936V8CQRveCjaxOiegWwvM7kqkbXTpyiovI=
|
||||||
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
|
github.com/google/go-containerregistry v0.20.3/go.mod h1:w00pIgBRDVUDFM6bq+Qx8lwNWK+cxgCuX1vd3PIBDNI=
|
||||||
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
|
||||||
github.com/google/go-github/v49 v49.1.0 h1:LFkMgawGQ8dfzWLH/rNE0b3u1D3n6/dw7ZmrN3b+YFY=
|
|
||||||
github.com/google/go-github/v49 v49.1.0/go.mod h1:MUUzHPrhGniB6vUKa27y37likpipzG+BXXJbG04J334=
|
|
||||||
github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M=
|
github.com/google/go-github/v66 v66.0.0 h1:ADJsaXj9UotwdgK8/iFZtv7MLc8E8WBl62WLd/D/9+M=
|
||||||
github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4=
|
github.com/google/go-github/v66 v66.0.0/go.mod h1:+4SO9Zkuyf8ytMj0csN1NR/5OTR+MfqPp8P8dVlcvY4=
|
||||||
|
github.com/google/go-github/v68 v68.0.0 h1:ZW57zeNZiXTdQ16qrDiZ0k6XucrxZ2CGmoTvcCyQG6s=
|
||||||
|
github.com/google/go-github/v68 v68.0.0/go.mod h1:K9HAUBovM2sLwM408A18h+wd9vqdLOEqTUCbnRIcx68=
|
||||||
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
github.com/google/go-intervals v0.0.2 h1:FGrVEiUnTRKR8yE04qzXYaJMtnIYqobR5QbblK3ixcM=
|
||||||
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
github.com/google/go-intervals v0.0.2/go.mod h1:MkaR3LNRfeKLPmqgJYs4E66z5InYjmCjbbr4TQlcT6Y=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
|
|
|
@ -21,16 +21,8 @@ set -o nounset
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
source "$(dirname "$(realpath "$0")")/common.sh"
|
source "$(dirname "$(realpath "$0")")/common.sh"
|
||||||
|
# this is where versions of common components are (like knative)
|
||||||
|
source "$(dirname "$(realpath "$0")")/component-versions.sh"
|
||||||
set_versions() {
|
|
||||||
# Note: Kubernetes Version node image per Kind releases (full hash is suggested):
|
|
||||||
# https://github.com/kubernetes-sigs/kind/releases
|
|
||||||
kind_node_version=v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027
|
|
||||||
knative_serving_version="v$(get_latest_release_version "knative" "serving")"
|
|
||||||
knative_eventing_version="v$(get_latest_release_version "knative" "eventing")"
|
|
||||||
contour_version="v$(get_latest_release_version "knative-extensions" "net-contour")"
|
|
||||||
}
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
echo "${blue}Allocating${reset}"
|
echo "${blue}Allocating${reset}"
|
||||||
|
@ -62,46 +54,6 @@ main() {
|
||||||
echo -e "\n${green}🎉 DONE${reset}\n"
|
echo -e "\n${green}🎉 DONE${reset}\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Retrieve latest version from given Knative repository tags
|
|
||||||
# On 'main' branch the latest released version is returned
|
|
||||||
# On 'release-x.y' branch the latest patch version for 'x.y.*' is returned
|
|
||||||
# Similar to hack/library.sh get_latest_knative_yaml_source()
|
|
||||||
function get_latest_release_version() {
|
|
||||||
local org_name="$1"
|
|
||||||
local repo_name="$2"
|
|
||||||
local major_minor=""
|
|
||||||
if is_release_branch; then
|
|
||||||
local branch_name
|
|
||||||
branch_name="$(current_branch)"
|
|
||||||
major_minor="${branch_name##release-}"
|
|
||||||
fi
|
|
||||||
local version
|
|
||||||
version="$(git ls-remote --tags --ref https://github.com/"${org_name}"/"${repo_name}".git \
|
|
||||||
| grep "${major_minor}" \
|
|
||||||
| cut -d '-' -f2 \
|
|
||||||
| cut -d 'v' -f2 \
|
|
||||||
| sort -Vr \
|
|
||||||
| head -n 1)"
|
|
||||||
echo "${version}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns whether the current branch is a release branch.
|
|
||||||
function is_release_branch() {
|
|
||||||
[[ $(current_branch) =~ ^release-[0-9\.]+$ ]]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Returns the current branch.
|
|
||||||
# Taken from knative/hack. The function covers Knative CI use cases and local variant.
|
|
||||||
function current_branch() {
|
|
||||||
local branch_name=""
|
|
||||||
# Get the branch name from Prow's env var, see https://github.com/kubernetes/test-infra/blob/master/prow/jobs.md.
|
|
||||||
# Otherwise, try getting the current branch from git.
|
|
||||||
(( ${IS_PROW:-} )) && branch_name="${PULL_BASE_REF:-}"
|
|
||||||
[[ -z "${branch_name}" ]] && branch_name="${GITHUB_BASE_REF:-}"
|
|
||||||
[[ -z "${branch_name}" ]] && branch_name="$(git rev-parse --abbrev-ref HEAD)"
|
|
||||||
echo "${branch_name}"
|
|
||||||
}
|
|
||||||
|
|
||||||
kubernetes() {
|
kubernetes() {
|
||||||
cat <<EOF | $KIND create cluster --name=func --kubeconfig="${KUBECONFIG}" --wait=60s --config=-
|
cat <<EOF | $KIND create cluster --name=func --kubeconfig="${KUBECONFIG}" --wait=60s --config=-
|
||||||
kind: Cluster
|
kind: Cluster
|
||||||
|
|
|
@ -41,12 +41,15 @@ import (
|
||||||
"github.com/google/go-containerregistry/pkg/v1/partial"
|
"github.com/google/go-containerregistry/pkg/v1/partial"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/remote"
|
"github.com/google/go-containerregistry/pkg/v1/remote"
|
||||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||||
"github.com/google/go-github/v49/github"
|
"github.com/google/go-github/v68/github"
|
||||||
"github.com/paketo-buildpacks/libpak/carton"
|
"github.com/paketo-buildpacks/libpak/carton"
|
||||||
"github.com/pelletier/go-toml"
|
"github.com/pelletier/go-toml"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
// Set up context for possible signal inputs to not disrupt cleanup process.
|
||||||
|
// This is not gonna do much for workflows since they finish and shutdown
|
||||||
|
// but in case of local testing - dont leave left over resources on disk/RAM.
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel()
|
defer cancel()
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
|
@ -69,6 +72,7 @@ func main() {
|
||||||
fmt.Println("::endgroup::")
|
fmt.Println("::endgroup::")
|
||||||
}
|
}
|
||||||
if hadError {
|
if hadError {
|
||||||
|
fmt.Fprintln(os.Stderr, "failed to update builder")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,384 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"html/template"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
github "github.com/google/go-github/v68/github"
|
||||||
|
)
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
// ---------------------------- File description ---------------------------- \\
|
||||||
|
//
|
||||||
|
// #update-knative-components/main.go -- This file takes care of updating
|
||||||
|
// knative components programatically.
|
||||||
|
//
|
||||||
|
// Files interacted with:
|
||||||
|
// 1) The source-of-truth file and its content can be found at
|
||||||
|
// root/hack/component-versions.json
|
||||||
|
// 2) autogenerated script in root/hack/component-versions.sh (2 directories up)
|
||||||
|
//
|
||||||
|
// How to use this file:
|
||||||
|
// Most of the time this file will be used in a workflow that will run
|
||||||
|
// on scheduled basis checking if a new latest version of corresponding
|
||||||
|
// components exists (check components in 'Versions' struct). Please note that
|
||||||
|
// KindNode is NOT being updated programatically at this time.
|
||||||
|
// When new latest version is detected, the program will create a PR in
|
||||||
|
// knative/func repository with the latest changes allowing the CI/CD workflows
|
||||||
|
// to run automatically before using the latest in main branch.
|
||||||
|
// Alternative use: You can run this file from hack/ directory to locally
|
||||||
|
// regenerate 2 files mentioned above (if you made some changes etc.) - you can
|
||||||
|
// use the root Makefile for your convenience -- 'make regenerate-kn-components'
|
||||||
|
//
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
|
||||||
|
const (
|
||||||
|
fileScript string = "component-versions.sh"
|
||||||
|
fileJson string = "component-versions.json"
|
||||||
|
|
||||||
|
versionsScriptTemplate string = `#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# AUTOGENERATED FILE - edit versions in ./component-versions.json.
|
||||||
|
# If you are adding components, modify this scripts' template in
|
||||||
|
# ./cmd/update-knative-components/main.go.
|
||||||
|
# You can regenerate locally with "make generate-kn-components-local".
|
||||||
|
|
||||||
|
set_versions() {
|
||||||
|
# Note: Kubernetes Version node image per Kind releases (full hash is suggested):
|
||||||
|
# https://github.com/kubernetes-sigs/kind/releases
|
||||||
|
kind_node_version={{.KindNode}}
|
||||||
|
|
||||||
|
# gets updated programatically via workflow -> PR creation
|
||||||
|
knative_serving_version="{{.Serving}}"
|
||||||
|
knative_eventing_version="{{.Eventing}}"
|
||||||
|
contour_version="{{.Contour}}"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
// all the components that are kept up to date
|
||||||
|
type Versions struct {
|
||||||
|
KindNode string
|
||||||
|
Serving string
|
||||||
|
Eventing string
|
||||||
|
Contour string
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// there is an optional "local" argument
|
||||||
|
if len(os.Args) == 2 && os.Args[1] == "local" { //leveraging lazy evals
|
||||||
|
fmt.Println("Generate argument received! Regenerating files locally...")
|
||||||
|
err := generateComponentVersions()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "error: %v", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
fmt.Println("done")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set up context for possible signal inputs to not disrupt cleanup process.
|
||||||
|
// This is not gonna do much for workflows since they finish and shutdown
|
||||||
|
// but in case of local testing - dont leave left over resources on disk/RAM.
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
go func() {
|
||||||
|
<-sigs
|
||||||
|
cancel()
|
||||||
|
<-sigs
|
||||||
|
os.Exit(130)
|
||||||
|
}()
|
||||||
|
|
||||||
|
const prTitle = "chore: Update components' versions to latest"
|
||||||
|
client := github.NewClient(nil).WithAuthToken(os.Getenv("GITHUB_TOKEN"))
|
||||||
|
|
||||||
|
e, err := prExists(ctx, client, prTitle)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
if e {
|
||||||
|
fmt.Printf("PR already exists, nothing to do, exiting")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
projects := []struct {
|
||||||
|
owner, repo string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
owner: "knative",
|
||||||
|
repo: "serving",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: "knative",
|
||||||
|
repo: "eventing",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
owner: "knative-extensions",
|
||||||
|
repo: "net-contour",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get current versions used.
|
||||||
|
v, err := readVersions(fileJson)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
updated := false
|
||||||
|
// cycle through all versions of components listed above, fetch their
|
||||||
|
// latest from github releases - cmp them - create PR for update if necessary
|
||||||
|
for _, p := range projects {
|
||||||
|
newV, err := getLatestVersion(ctx, client, p.owner, p.repo)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error while getting latest v of %s/%s: %v", p.owner, p.repo, err)
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to overwrite with possibly new versions
|
||||||
|
if updateVersion(&v, p.repo, newV) {
|
||||||
|
// if any of the files are updated, set true
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !updated {
|
||||||
|
// nothing was updated, nothing to do
|
||||||
|
fmt.Printf("all good, no newer component releases, exiting\n")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := writeFiles(v, fileScript, fileJson); err != nil {
|
||||||
|
err = fmt.Errorf("failed to write files: %v", err)
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("files updated!")
|
||||||
|
|
||||||
|
branchName := "update-components" + time.Now().Format(time.DateOnly)
|
||||||
|
err = prepareBranch(branchName)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("failed to prep the branch: %v", err)
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
err = createPR(ctx, client, prTitle, branchName)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// read (unmarshal) component versions from .json
|
||||||
|
func readVersions(file string) (v Versions, err error) {
|
||||||
|
fmt.Print("> Reading versions from file...")
|
||||||
|
data, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(data, &v)
|
||||||
|
if err != nil {
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
fmt.Println("done")
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// attempt to update 'v' Versions to new 'val' for specific 'repo'
|
||||||
|
// 'v' - structure that holds versions of components
|
||||||
|
// 'repo' - points to a component repo that is being updated (example: serving)
|
||||||
|
// 'val' - value of the latest release of that repo (pulled via GH API)
|
||||||
|
func updateVersion(v *Versions, repo, val string) (updated bool) {
|
||||||
|
fmt.Printf("check for %s update...", repo)
|
||||||
|
if repo == "serving" && v.Serving != val {
|
||||||
|
v.Serving = val
|
||||||
|
updated = true
|
||||||
|
} else if repo == "eventing" && v.Eventing != val {
|
||||||
|
v.Eventing = val
|
||||||
|
updated = true
|
||||||
|
} else if repo == "net-contour" && v.Contour != val {
|
||||||
|
v.Contour = val
|
||||||
|
updated = true
|
||||||
|
}
|
||||||
|
if updated {
|
||||||
|
fmt.Printf("found! new:'%s'\n", val)
|
||||||
|
} else {
|
||||||
|
fmt.Println("nothing to do")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Overwrite the 'source of truth' file - .json and regenerate new script
|
||||||
|
// with new versions from 'v'.
|
||||||
|
// Arguments 'script' & 'json' are paths to files for autogenerated script and
|
||||||
|
// source (json) file respectively.
|
||||||
|
func writeFiles(v Versions, script, json string) error {
|
||||||
|
fmt.Print("> Writing into files...")
|
||||||
|
// write to json
|
||||||
|
err := writeVersionsSource(v, json)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write to json: %v", err)
|
||||||
|
}
|
||||||
|
// write to script file
|
||||||
|
err = writeVersionsScript(v, script)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to generate script: %v", err)
|
||||||
|
}
|
||||||
|
fmt.Println("done")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to 'source of truth' file (json) with updated versions
|
||||||
|
func writeVersionsSource(v Versions, file string) error {
|
||||||
|
vB, err := json.MarshalIndent(v, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cant Marshal versions: %v", err)
|
||||||
|
}
|
||||||
|
f, err := os.Create(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
_, err = f.Write(append(vB, '\n')) // append newline for reviewdog
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to autogenerated script file with newest Versions via templates pkg
|
||||||
|
func writeVersionsScript(v Versions, file string) error {
|
||||||
|
tmpl, err := template.New("versions").Parse(versionsScriptTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
f, err := os.Create(file)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
if err := tmpl.Execute(f, v); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// get latest version of owner/repo via GH API
|
||||||
|
func getLatestVersion(ctx context.Context, client *github.Client, owner string, repo string) (v string, err error) {
|
||||||
|
fmt.Printf("> get latest '%s/%s'...", owner, repo)
|
||||||
|
rr, res, err := client.Repositories.GetLatestRelease(ctx, owner, repo)
|
||||||
|
if err != nil {
|
||||||
|
err = fmt.Errorf("error: request for latest %s release: %v", owner+"/"+repo, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.StatusCode < 200 && res.StatusCode > 299 {
|
||||||
|
err = fmt.Errorf("error: Return status code of request for latest %s release is %d", owner+"/"+repo, res.StatusCode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
v = *rr.Name
|
||||||
|
if v == "" {
|
||||||
|
return "", fmt.Errorf("internal error: returned latest release name is empty for '%s'", repo)
|
||||||
|
}
|
||||||
|
fmt.Println("done")
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// prepare branch for PR via git commands
|
||||||
|
// config user as knative bot -> create branch -> add changes -> commit -> push
|
||||||
|
func prepareBranch(branchName string) error {
|
||||||
|
fmt.Println("> preparing branch")
|
||||||
|
cmd := exec.Command("bash", "-c", fmt.Sprintf(`
|
||||||
|
git config --local user.email "automation@knative.team" &&
|
||||||
|
git config --local user.name "Knative Automation" &&
|
||||||
|
git switch -c %s &&
|
||||||
|
git add %s %s &&
|
||||||
|
git commit -m "update components" &&
|
||||||
|
git push origin %s
|
||||||
|
`, branchName, fileScript, fileJson, branchName))
|
||||||
|
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
return cmd.Run()
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a PR via GH API on the func repo with those new versions
|
||||||
|
func createPR(ctx context.Context, client *github.Client, title string, branchName string) error {
|
||||||
|
fmt.Print("> creating PR...")
|
||||||
|
body := fmt.Sprintf("%s\n/assign @gauron99", title)
|
||||||
|
|
||||||
|
newPR := github.NewPullRequest{
|
||||||
|
Title: github.Ptr(title),
|
||||||
|
Base: github.Ptr("main"),
|
||||||
|
Head: github.Ptr(branchName),
|
||||||
|
Body: github.Ptr(body),
|
||||||
|
MaintainerCanModify: github.Ptr(true),
|
||||||
|
}
|
||||||
|
pr, _, err := client.PullRequests.Create(ctx, "knative", "func", &newPR)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("PR looks like this:\n%#v\n", pr)
|
||||||
|
fmt.Printf("err: %s\n", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
fmt.Println("ready")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true when PR with given title already exists in knative/func repo
|
||||||
|
// otherwise false.
|
||||||
|
// Returns an error if occurred, otherwise nil.
|
||||||
|
func prExists(ctx context.Context, c *github.Client, title string) (bool, error) {
|
||||||
|
perPage := 10
|
||||||
|
opt := &github.PullRequestListOptions{State: "open", ListOptions: github.ListOptions{PerPage: perPage}}
|
||||||
|
for {
|
||||||
|
list, resp, err := c.PullRequests.List(ctx, "knative", "func", opt)
|
||||||
|
if err != nil {
|
||||||
|
return false, fmt.Errorf("errror pulling PRs in knative/func: %s", err)
|
||||||
|
}
|
||||||
|
for _, pr := range list {
|
||||||
|
if pr.GetTitle() == title {
|
||||||
|
// gauron99 - currently cannot update already existing PR
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp.NextPage == 0 {
|
||||||
|
// hit end of list
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
// otherwise, continue to the next page
|
||||||
|
opt.Page = resp.NextPage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
// -------------------------------------------------------------------------- \\
|
||||||
|
|
||||||
|
// This is used when running this file with 1st argument "generate".
|
||||||
|
// Regenerate written files (source (.json) & autogenerated .sh file)
|
||||||
|
// Generally you wont use this, but in case you make local changes to the
|
||||||
|
// files, you can simply regenerate them with this
|
||||||
|
func generateComponentVersions() error {
|
||||||
|
v, err := readVersions(fileJson)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to read Versions from json: %v", err)
|
||||||
|
}
|
||||||
|
// generate
|
||||||
|
err = writeFiles(v, fileScript, fileJson)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to write Versions: %v", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/fs"
|
||||||
|
"os"
|
||||||
|
"path"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"gotest.tools/v3/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
const expectedScript string = `#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# AUTOGENERATED FILE - edit versions in ./component-versions.json.
|
||||||
|
# If you are adding components, modify this scripts' template in
|
||||||
|
# ./cmd/update-knative-components/main.go.
|
||||||
|
# You can regenerate locally with "make generate-kn-components-local".
|
||||||
|
|
||||||
|
set_versions() {
|
||||||
|
# Note: Kubernetes Version node image per Kind releases (full hash is suggested):
|
||||||
|
# https://github.com/kubernetes-sigs/kind/releases
|
||||||
|
kind_node_version=v1.30
|
||||||
|
|
||||||
|
# gets updated programatically via workflow -> PR creation
|
||||||
|
knative_serving_version="v1.2.3"
|
||||||
|
knative_eventing_version="v1.4.5"
|
||||||
|
contour_version="v1.4.6"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
const expectedJson string = `{
|
||||||
|
"KindNode": "v1.30",
|
||||||
|
"Serving": "v1.2.3",
|
||||||
|
"Eventing": "v1.4.5",
|
||||||
|
"Contour": "v1.4.6"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
// TestRead should just successfully unmarshal ('v' struct & json compatibility)
|
||||||
|
func TestRead(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
const jsonContent string = `{
|
||||||
|
"Serving": "v1.14",
|
||||||
|
"Eventing": "v1.15",
|
||||||
|
"Contour": "v1.61",
|
||||||
|
"KindNode": "1.3456"
|
||||||
|
}
|
||||||
|
`
|
||||||
|
tmpJson := path.Join(dir, "json.json")
|
||||||
|
err := os.WriteFile(tmpJson, []byte(jsonContent), fs.ModePerm)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = readVersions(tmpJson)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read json: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestWrite ensures that writing both files succeeds with the correct file
|
||||||
|
// contents
|
||||||
|
func TestWrite(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
|
tmpJson := path.Join(dir, "f.json")
|
||||||
|
tmpSh := path.Join(dir, "f.sh")
|
||||||
|
|
||||||
|
v := Versions{
|
||||||
|
Serving: "v1.2.3",
|
||||||
|
Eventing: "v1.4.5",
|
||||||
|
Contour: "v1.4.6",
|
||||||
|
KindNode: "v1.30",
|
||||||
|
}
|
||||||
|
|
||||||
|
// write to script (generate it)
|
||||||
|
err := writeVersionsScript(v, tmpSh)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to generate script: %v", err)
|
||||||
|
}
|
||||||
|
// assert
|
||||||
|
fsh, err := os.ReadFile(tmpSh)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read file: %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, string(fsh), expectedScript)
|
||||||
|
|
||||||
|
// write to json
|
||||||
|
err = writeVersionsSource(v, tmpJson)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to write json: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// assert
|
||||||
|
fjson, err := os.ReadFile(tmpJson)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read json: %v", err)
|
||||||
|
}
|
||||||
|
assert.Equal(t, string(fjson), expectedJson)
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"KindNode": "v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027",
|
||||||
|
"Serving": "v1.17.0",
|
||||||
|
"Eventing": "v1.17.0",
|
||||||
|
"Contour": "v1.17.0"
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# AUTOGENERATED FILE - edit versions in ./component-versions.json.
|
||||||
|
# If you are adding components, modify this scripts' template in
|
||||||
|
# ./cmd/update-knative-components/main.go.
|
||||||
|
# You can regenerate locally with "make generate-kn-components-local".
|
||||||
|
|
||||||
|
set_versions() {
|
||||||
|
# Note: Kubernetes Version node image per Kind releases (full hash is suggested):
|
||||||
|
# https://github.com/kubernetes-sigs/kind/releases
|
||||||
|
kind_node_version=v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027
|
||||||
|
|
||||||
|
# gets updated programatically via workflow -> PR creation
|
||||||
|
knative_serving_version="v1.17.0"
|
||||||
|
knative_eventing_version="v1.17.0"
|
||||||
|
contour_version="v1.17.0"
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/google/go-github/v49/github"
|
"github.com/google/go-github/v68/github"
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -16,18 +16,18 @@ type Client struct {
|
||||||
|
|
||||||
func (c Client) CreateWebHook(ctx context.Context, repoOwner, repoName, payloadURL, webhookSecret string) error {
|
func (c Client) CreateWebHook(ctx context.Context, repoOwner, repoName, payloadURL, webhookSecret string) error {
|
||||||
hook := &github.Hook{
|
hook := &github.Hook{
|
||||||
Name: github.String("web"),
|
Name: github.Ptr("web"),
|
||||||
Active: github.Bool(true),
|
Active: github.Ptr(true),
|
||||||
Events: []string{
|
Events: []string{
|
||||||
"issue_comment",
|
"issue_comment",
|
||||||
"pull_request",
|
"pull_request",
|
||||||
"push",
|
"push",
|
||||||
},
|
},
|
||||||
Config: map[string]interface{}{
|
Config: &github.HookConfig{
|
||||||
"url": payloadURL,
|
URL: github.Ptr(payloadURL),
|
||||||
"content_type": "json",
|
ContentType: github.Ptr("json"),
|
||||||
"insecure_ssl": "1", // TODO fix insecure (default should be 0)
|
InsecureSSL: github.Ptr("1"), // TODO fix insecure (default should be 0)
|
||||||
"secret": webhookSecret,
|
Secret: github.Ptr(webhookSecret),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue