From c7cd47110ef285189259f84b5694ab21a96cb021 Mon Sep 17 00:00:00 2001 From: David Fridrich Date: Tue, 22 Jul 2025 22:53:11 +0200 Subject: [PATCH] drastically simplify the components update - now runs in update-deps.sh - only need to modify json and autogen script --- .github/workflows/update-builder.yaml | 4 +- .github/workflows/update-knative-hack.yaml | 24 -- Makefile | 17 +- hack/cmd/components/main.go | 244 +++++++++++ hack/cmd/components/main_test.go | 140 +++++++ hack/cmd/update-knative-components/main.go | 384 ------------------ .../update-knative-components/main_test.go | 109 ----- hack/component-versions.json | 30 +- hack/component-versions.sh | 8 +- hack/update-deps.sh | 3 + 10 files changed, 422 insertions(+), 541 deletions(-) delete mode 100644 .github/workflows/update-knative-hack.yaml create mode 100644 hack/cmd/components/main.go create mode 100644 hack/cmd/components/main_test.go delete mode 100644 hack/cmd/update-knative-components/main.go delete mode 100644 hack/cmd/update-knative-components/main_test.go diff --git a/.github/workflows/update-builder.yaml b/.github/workflows/update-builder.yaml index 71903742b3..42ae0def2e 100644 --- a/.github/workflows/update-builder.yaml +++ b/.github/workflows/update-builder.yaml @@ -27,5 +27,5 @@ jobs: "$HOME/.config/containers/registries.conf" skopeo login ghcr.io -u gh-action -p "$GITHUB_TOKEN" docker login ghcr.io -u gh-action -p "$GITHUB_TOKEN" - make wf-update-builder - + make __update-builder + diff --git a/.github/workflows/update-knative-hack.yaml b/.github/workflows/update-knative-hack.yaml deleted file mode 100644 index c63fcc52f2..0000000000 --- a/.github/workflows/update-knative-hack.yaml +++ /dev/null @@ -1,24 +0,0 @@ -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-kn-components - diff --git a/Makefile b/Makefile index 50e5a8d60e..69447bbd3d 100644 --- a/Makefile +++ b/Makefile @@ -308,23 +308,16 @@ schema-check: ## Check that func.yaml schema is up-to-date ##@ 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: hack-generate-components +hack-generate-components: ## Regenerate components in hack/ dir + cd hack && go run ./cmd/components .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 +## This is used by workflows .PHONY: update-builder -wf-update-builder: # Used in automation +__update-builder: # Used in automation cd hack && go run ./cmd/update-builder - -### end of automation section diff --git a/hack/cmd/components/main.go b/hack/cmd/components/main.go new file mode 100644 index 0000000000..9d51128646 --- /dev/null +++ b/hack/cmd/components/main.go @@ -0,0 +1,244 @@ +// Package main implements a tool for automatically updating component +// versions for use in the hack/* scripts. +// +// Files interacted with: +// 1. The source-of-truth file at hack/component-versions.json +// 2. Autogenerated script at hack/component-versions.sh +// +// USAGE: +// +// This is running on semi-auto basis where versions are being auto bumped via +// PRs sent to main. Semi-auto because if repo is missing 'owner' or 'repo' fields +// in the .json it will not be automatically bumped (it has no repo to look). +// This is intentional for components we dont want autobumped like this. +// The source-of-truth file is found in this repo @root/hack/component-versions.json +// +// ADD NEW/MODIFY COMPONENTS +// +// 1. Edit source-of-truth .json file +// ! If a component is missing "owner" or "repo" it will not be auto-bumped +// 2. If new component was added: +// - Edit the autogenerated text just below here 'versionsScriptTemplate' +// 3. Regenerate using Makefile - find target 'hack-generate-components' +package main + +import ( + "context" + "encoding/json" + "fmt" + "html/template" + "os" + "os/signal" + "syscall" + + github "github.com/google/go-github/v68/github" +) + +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 want to add/modify these components, please read the how-to steps in +# ./cmd/components/main.go. +# You can regenerate with "make hack-generate-components". + +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.Version}} + + # find source-of-truth in component-versions.json to add/modify components + knative_serving_version="{{.Serving.Version}}" + knative_eventing_version="{{.Eventing.Version}}" + contour_version="{{.Contour.Version}}" + tekton_version="{{.Tekton.Version}}" + pac_version="{{.Pac.Version}}" +} +` +) + +// Individual component info like for "Serving" or "Eventing" +// If you want to add new component, read the comment at the top of the file! +type Component struct { + Version string `json:"version"` + Owner string `json:"owner,omitempty"` + Repo string `json:"repo,omitempty"` +} + +// make iterable struct +type ComponentList map[string]*Component + +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()) + defer cancel() + sigs := make(chan os.Signal, 1) + signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) + go func() { + <-sigs + cancel() + <-sigs + os.Exit(130) + }() + + getClient := func(token string) *github.Client { + if token != "" { + fmt.Println("client with token") + return github.NewClient(nil).WithAuthToken(token) + } + return github.NewClient(nil) + } + client := getClient(os.Getenv("GITHUB_TOKEN")) + + // Read source-of-truth .json + componentList, err := readVersions(fileJson) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + + // update componentList in-situ + updated, err := update(ctx, client, &componentList) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to update %v\n", err) + os.Exit(1) + } + + if !updated { + // nothing was updated, nothing to do + fmt.Println("no newer versions found, re-generating .sh just in case") + // regenerate .sh to keep up to date if changed + err = writeScript(componentList, fileScript) + if err != nil { + err = fmt.Errorf("failed to re-generate script: %v", err) + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Println("all good") + os.Exit(0) + } + + if err := writeFiles(componentList, 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!") +} + +// do the update for each repo defined +func update(ctx context.Context, client *github.Client, cl *ComponentList) (bool, error) { + fmt.Println("Getting latest releases") + updated := false + for _, c := range *cl { + if c.Owner == "" || c.Repo == "" { + //skipping auto updates + continue + } + + newV, err := getLatestVersion(ctx, client, c.Owner, c.Repo) + if err != nil { + err = fmt.Errorf("error while getting latest v of %s/%s: %v", c.Owner, c.Repo, err) + return false, err + } + + if c.Version != newV { + fmt.Printf("bump %v: %v --> %v\n", fmt.Sprintf("%s/%s", c.Owner, c.Repo), c.Version, newV) + c.Version = newV + updated = true + } + } + return updated, nil +} + +// read (unmarshal) component versions from .json +func readVersions(file string) (c ComponentList, err error) { + fmt.Println("Reading versions from source-of-truth") + data, err := os.ReadFile(file) + if err != nil { + return + } + err = json.Unmarshal(data, &c) + if err != nil { + return + } + 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(cl ComponentList, script, json string) error { + fmt.Print("Writing files") + // write to json + err := writeSource(cl, json) + if err != nil { + return fmt.Errorf("failed to write to json: %v", err) + } + // write to script file + err = writeScript(cl, script) + if err != nil { + return fmt.Errorf("failed to generate script: %v", err) + } + return nil +} + +// write to 'source of truth' .json with updated versions (if pulled latest) +func writeSource(cl ComponentList, file string) error { + vB, err := json.MarshalIndent(cl, "", " ") + 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 the autogenerated script based on 'cl' +func writeScript(cl ComponentList, 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, cl); 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) { + 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) + } + return v, nil +} diff --git a/hack/cmd/components/main_test.go b/hack/cmd/components/main_test.go new file mode 100644 index 0000000000..d664392a4e --- /dev/null +++ b/hack/cmd/components/main_test.go @@ -0,0 +1,140 @@ +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 want to add/modify these components, please read the how-to steps in +# ./cmd/components/main.go. +# You can regenerate with "make hack-generate-components". + +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 + + # find source-of-truth in component-versions.json to add/modify components + knative_serving_version="v1.19.0" + knative_eventing_version="v1.19.0" + contour_version="v1.19.0" + tekton_version="v1.1.0" + pac_version="v0.35.2" +} +` + +const expectedJson string = `{ + "Contour": { + "version": "v1.19.0", + "owner": "knative-extensions", + "repo": "net-contour" + }, + "Eventing": { + "version": "v1.19.0", + "owner": "knative", + "repo": "eventing" + }, + "KindNode": { + "version": "v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027" + }, + "Pac": { + "version": "v0.35.2" + }, + "Serving": { + "version": "v1.19.0", + "owner": "knative", + "repo": "serving" + }, + "Tekton": { + "version": "v1.1.0" + } +} +` + +// TestRead should just successfully unmarshal +func TestRead(t *testing.T) { + dir := t.TempDir() + + // just assign this for simplicity, no need to the same variable twice + const jsonContent = expectedJson + + 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") + + // as if we just unmarshalled this + c := ComponentList{ + "Contour": &Component{ + Version: "v1.19.0", + Owner: "knative-extensions", + Repo: "net-contour", + }, + "Eventing": { + Version: "v1.19.0", + Owner: "knative", + Repo: "eventing", + }, + "KindNode": { + Version: "v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027", + }, + "Pac": { + Version: "v0.35.2", + }, + "Serving": { + Version: "v1.19.0", + Owner: "knative", + Repo: "serving", + }, + "Tekton": { + Version: "v1.1.0", + }, + } + + // write to script (generate it) + err := writeScript(c, 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 = writeSource(c, 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) +} diff --git a/hack/cmd/update-knative-components/main.go b/hack/cmd/update-knative-components/main.go deleted file mode 100644 index bd4ad77e09..0000000000 --- a/hack/cmd/update-knative-components/main.go +++ /dev/null @@ -1,384 +0,0 @@ -// Package main implements a tool for automatically updating component -// versions for use in the hack/* scripts. -// -// Files interacted with: -// 1. The source-of-truth file at hack/component-versions.json -// 2. Autogenerated script at hack/component-versions.sh -// -// Usage: -// -// 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 programmatically 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' -package main - -import ( - "context" - "encoding/json" - "fmt" - "html/template" - "os" - "os/exec" - "os/signal" - "syscall" - "time" - - github "github.com/google/go-github/v68/github" -) - -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}}" - tekton_version="{{.Tekton}}" - pac_version="{{.Pac}}" -} -` -) - -// all the components that are kept up to date -type Versions struct { - KindNode string - Serving string - Eventing string - Contour string - Tekton string - Pac 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...") - bodyText := "You might need to close & open this PR so all tests can run" - body := fmt.Sprintf("%s\n%s\n/assign @gauron99", title, bodyText) - - 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 "local". -// 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 -} diff --git a/hack/cmd/update-knative-components/main_test.go b/hack/cmd/update-knative-components/main_test.go deleted file mode 100644 index b16901f6c1..0000000000 --- a/hack/cmd/update-knative-components/main_test.go +++ /dev/null @@ -1,109 +0,0 @@ -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" - tekton_version="v0.56.4" - pac_version="v0.24.6" -} -` - -const expectedJson string = `{ - "KindNode": "v1.30", - "Serving": "v1.2.3", - "Eventing": "v1.4.5", - "Contour": "v1.4.6", - "Tekton": "v0.56.4", - "Pac": "v0.24.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", - "Tekton": "v0.50.0", - "Pac": "v0.20.0" -} -` - 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", - Tekton: "v0.56.4", - Pac: "v0.24.6", - } - - // 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) -} diff --git a/hack/component-versions.json b/hack/component-versions.json index 66771643e8..b5edd4e695 100644 --- a/hack/component-versions.json +++ b/hack/component-versions.json @@ -1,8 +1,26 @@ { - "KindNode": "v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027", - "Serving": "v1.19.0", - "Eventing": "v1.19.0", - "Contour": "v1.19.0", - "Tekton": "v1.1.0", - "Pac": "v0.35.2" + "Contour": { + "version": "v1.19.0", + "owner": "knative-extensions", + "repo": "net-contour" + }, + "Eventing": { + "version": "v1.19.0", + "owner": "knative", + "repo": "eventing" + }, + "KindNode": { + "version": "v1.32.0@sha256:c48c62eac5da28cdadcf560d1d8616cfa6783b58f0d94cf63ad1bf49600cb027" + }, + "Pac": { + "version": "v0.35.2" + }, + "Serving": { + "version": "v1.19.0", + "owner": "knative", + "repo": "serving" + }, + "Tekton": { + "version": "v1.1.0" + } } diff --git a/hack/component-versions.sh b/hack/component-versions.sh index 7484689a1d..faa3faa3ab 100644 --- a/hack/component-versions.sh +++ b/hack/component-versions.sh @@ -1,16 +1,16 @@ #!/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". +# If you want to add/modify these components, please read the how-to steps in +# ./cmd/components/main.go. +# You can regenerate with "make hack-generate-components". 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 + # find source-of-truth in component-versions.json to add/modify components knative_serving_version="v1.19.0" knative_eventing_version="v1.19.0" contour_version="v1.19.0" diff --git a/hack/update-deps.sh b/hack/update-deps.sh index 8111cec4d5..0eb2a4c496 100755 --- a/hack/update-deps.sh +++ b/hack/update-deps.sh @@ -21,3 +21,6 @@ set -o pipefail source "$(go run knative.dev/hack/cmd/script library.sh)" go_update_deps "$@" + +# Update hack components +make hack-generate-components