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
31 changes: 29 additions & 2 deletions .github/workflows/functions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,9 @@ jobs:
- test-e2e-podman
- test-e2e-runtimes
- test-e2e-config-ci
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
if: >-
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release-'))
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand Down Expand Up @@ -595,8 +597,31 @@ jobs:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Derive Image Tag
id: image-tag
# Publish the tag the source embeds: the next minor on main, X.Y on
# release-X.Y (see docs/func-utils-image.md). Once release-X.Y is cut,
# main skips the publish until it moves to the next minor, unless its
# commit is the branch head (the cut commit's own run).
run: |
ref="$(make -s --no-print-directory func-utils-image)"
tag="${ref##*:}"
if [[ "${GITHUB_REF_NAME}" == release-* && "${GITHUB_REF_NAME}" != "release-${tag}" ]]; then
echo "::error::${GITHUB_REF_NAME} embeds ${ref}; it must embed its own minor"
exit 1
fi
if [[ "${GITHUB_REF_NAME}" == "main" ]]; then
head="$(git ls-remote origin "refs/heads/release-${tag}")"
head="${head%%$'\t'*}"
if [[ -n "${head}" && "${head}" != "${GITHUB_SHA}" ]]; then
Comment thread
gauron99 marked this conversation as resolved.
echo "::notice::release-${tag} is cut, so only that branch publishes ${ref}; merge the PR that moves main to the next minor"
exit 0
fi
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"
- name: Build and push
id: build-images
if: steps.image-tag.outputs.tag != ''
run: |
for a in amd64 arm64 ppc64le s390x; do
CGO_ENABLED=0 GOARCH="${a}" go build -buildvcs=false -o "func-util-$a" -trimpath -ldflags '-w -s' ./cmd/func-util
Expand All @@ -608,7 +633,7 @@ jobs:
--provenance=false --sbom=false \
--platform=linux/ppc64le,linux/s390x,linux/amd64,linux/arm64 \
--push \
-t "ghcr.io/knative/func-utils:v2" \
-t "ghcr.io/knative/func-utils:${{ steps.image-tag.outputs.tag }}" \
--annotation index:org.opencontainers.image.description="Knative Func Utils Image" \
--annotation index:org.opencontainers.image.source="https://github.com/knative/func" \
--annotation index:org.opencontainers.image.vendor="https://github.com/knative/func" \
Expand All @@ -617,6 +642,7 @@ jobs:
DIGEST="$(jq -r '."containerimage.digest"' build-metadata.json)"
echo "digest=${DIGEST}" >> "${GITHUB_OUTPUT}"
- name: Attest Build Provenance
if: steps.image-tag.outputs.tag != ''
uses: actions/attest-build-provenance@v3
with:
subject-name: "ghcr.io/knative/func-utils"
Expand All @@ -626,6 +652,7 @@ jobs:
publish-image:
name: Publish as Image
needs: build
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
Expand Down
54 changes: 54 additions & 0 deletions .github/workflows/update-func-utils-image.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Update func-utils image to next release

# Main carries the func-utils image of the next minor release, so a branch
# release-X.Y cut from it already embeds func-utils:X.Y, and main's pushes
# have published it (see docs/func-utils-image.md). Cutting release-X.Y opens
# a PR that moves main to the next minor, X.(Y+1). Until it merges, main
# publishes no func-utils image.

on:
# create has no branch filter; the job's if drops every other branch and tag.
create:

permissions:
contents: read

jobs:
bump-utils-image:
name: Bump Utils Image
if: github.ref_type == 'branch' && startsWith(github.ref_name, 'release-')
runs-on: ubuntu-latest
timeout-minutes: 15
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v5
with:
ref: main
- name: Move to Next Minor
id: next
# release-1.24 moves main from func-utils:1.24 to 1.25. If main is on
# another minor (a re-cut or an old branch), sed changes nothing and no
# PR opens.
run: |
cut="${GITHUB_REF_NAME#release-}"
next="${cut%.*}.$(( ${cut#*.} + 1 ))"
sed -i "s|func-utils:${cut}\"|func-utils:${next}\"|" pkg/version/version.go
echo "tag=${next}" >> "$GITHUB_OUTPUT"
- name: Create Pull Request
uses: peter-evans/create-pull-request@v8
with:
token: ${{ github.token }}
commit-message: 'chore: bump func-utils image to ${{ steps.next.outputs.tag }} after new release branch cut'
title: 'Bump func-utils image to ${{ steps.next.outputs.tag }}'
body: |
`${{ github.ref_name }}` was cut, so main moves on to the func-utils image of the next minor release, `ghcr.io/knative/func-utils:${{ steps.next.outputs.tag }}`. Until this merges, main publishes no func-utils image. See [docs/func-utils-image.md](https://github.com/${{ github.repository }}/blob/main/docs/func-utils-image.md).

This PR was automatically generated by the [Update func-utils image workflow](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}).
branch: bump-func-utils-${{ steps.next.outputs.tag }}
delete-branch: true
committer: Knative Automation <automation@knative.team>
author: Knative Automation <automation@knative.team>
assignees: gauron99, matejvasek, lkingland
base: main
12 changes: 11 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,13 @@ KVER ?= $(shell git describe --tags --match 'knative-*' 2>/dev/null)

LDFLAGS := -X knative.dev/func/pkg/version.Vers=$(VERS) -X knative.dev/func/pkg/version.Kver=$(KVER) -X knative.dev/func/pkg/version.Hash=$(HASH)

FUNC_UTILS_IMG ?= ghcr.io/knative/func-utils:v2
# Overrides the func-utils image; the default is version.FuncUtilsImage.
FUNC_UTILS_IMG ?=
ifneq ($(FUNC_UTILS_IMG),)
LDFLAGS += -X knative.dev/func/pkg/k8s.SocatImage=$(FUNC_UTILS_IMG)
LDFLAGS += -X knative.dev/func/pkg/k8s.TarImage=$(FUNC_UTILS_IMG)
LDFLAGS += -X knative.dev/func/pkg/pipelines/tekton.FuncUtilImage=$(FUNC_UTILS_IMG)
endif

GOFLAGS := "-ldflags=$(LDFLAGS)"
export GOFLAGS
Expand Down Expand Up @@ -377,6 +380,13 @@ func-instrumented-bin: # func binary instrumented with coverage reporting
.PHONY: cross-platform
cross-platform: darwin-arm64 darwin-amd64 linux-amd64 linux-arm64 linux-ppc64le linux-s390x windows ## Build all distributable (cross-platform) binaries

.PHONY: func-utils-image
func-utils-image: ## Print the func-utils image reference builds embed
@if [ -n "$(FUNC_UTILS_IMG)" ]; then echo "$(FUNC_UTILS_IMG)"; exit; fi; \
ref="$$(sed -n 's/^const FuncUtilsImage = "\(.*\)"$$/\1/p' pkg/version/version.go)"; \
if [ -z "$$ref" ]; then echo "no FuncUtilsImage constant in pkg/version/version.go" >&2; exit 1; fi; \
echo "$$ref"

.PHONY: darwin-arm64
darwin-arm64: $(BIN_DARWIN_ARM64) ## Build for mac M1

Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Functions can be deployed on the following platforms:
[Function Developer's Guide](https://knative.dev/docs/functions/)
[Function Integrator's Guide](integrators_guide.md).
[CLI Command Reference](reference/func.md)
[The func-utils Image](func-utils-image.md)

## Contributing

Expand Down
42 changes: 42 additions & 0 deletions docs/func-utils-image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# The func-utils image

`ghcr.io/knative/func-utils` holds `cmd/func-util`, which func runs in the
cluster: Tekton build steps, the socat dialer and the volume upload. Each
func CLI embeds one tag of it.

## Tags

| Tag | Used by |
| --- | --- |
| `latest` | CLIs before 2025. Frozen. |
| `v2` | CLIs up to 1.23. Frozen. |
| `X.Y` | CLIs `vX.Y.*`. Published from `release-X.Y`, and from `main` while `X.Y` is in development. |

Ideally we would not backport to `release-X.Y` a change that breaks how the CLI
calls the image: arguments, exit codes, parsed output or shared files.
In most cases the latest `X.Y` image will work with every `vX.Y.*` CLI.

## Where the tag lives

`FuncUtilsImage` in `pkg/version/version.go`. `make func-utils-image`
prints what a build embeds. To embed another image, set `FUNC_UTILS_IMG`.

## Release cut

`main` embeds the minor in development, say `1.24`, and every green push
publishes `:1.24`. When `release-1.24` is cut:

1. The branch already embeds `:1.24`, and the image exists, so the
release can go. `hack/release.sh` refuses a `v1.24.z` release
otherwise.
2. `.github/workflows/update-func-utils-image.yaml` opens a PR that moves
`main` to `1.25`. Until it merges, `main` stops publishing `:1.24`,
except for the cut commit itself.
3. Every green push to `release-1.24` (a backport) publishes `:1.24`.

If `:1.24` holds the wrong image, re-run the Functions run for the
newest commit on `release-1.24`.

If `main` still embeds `1.24` when `release-1.25` is cut, set
`FuncUtilsImage` to `ghcr.io/knative/func-utils:1.25` on `release-1.25`
and to `:1.26` on `main`.
7 changes: 6 additions & 1 deletion hack/images.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ set -o errexit
set -o nounset
set -o pipefail

FUNC_UTILS_IMG="registry.localtest.me/knative/func-utils:v2"
# Push the locally built func-util image under the reference the func binary
# embeds (see docs/func-utils-image.md), with the local registry in place of
# the registry host. The kind cluster mirrors ghcr.io and quay.io to the local
# registry (hack/cluster.sh), so in-cluster pulls of that reference find it.
EMBEDDED_IMG="$(make -C "$(dirname "$0")/.." -s --no-print-directory func-utils-image)"
FUNC_UTILS_IMG="registry.localtest.me/${EMBEDDED_IMG#*/}"

CGO_ENABLED=0 go build -o "func-util" -trimpath -ldflags '-w -s' ./cmd/func-util

Expand Down
16 changes: 16 additions & 0 deletions hack/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ VALIDATION_TESTS="make test"

source "$(go run knative.dev/hack/cmd/script release.sh)"

# A vX.Y.Z release must embed the func-utils image pinned for X.Y, and that
# image must exist. Both hold when release-X.Y is cut from main: main embeds
# the minor in development and its green pushes publish that image (see
# docs/func-utils-image.md).
function check_func_utils_image() {
local want actual
want="ghcr.io/knative/func-utils:$(major_minor_version "$1")"
Comment thread
gauron99 marked this conversation as resolved.
actual="$(make -s --no-print-directory func-utils-image)"
[[ "${actual}" == "${want}" ]] \
|| abort "release $1 would embed func-utils image '${actual}', want '${want}'; see docs/func-utils-image.md"
go run github.com/google/go-containerregistry/cmd/crane digest "${want}" > /dev/null \
|| abort "func-utils image '${want}' does not exist"
echo "🧰 func-utils image: ${want}"
}

function build_release() {
echo "🚧 🐧 Building cross platform binaries: Linux 🐧 (amd64 / arm64 / ppc64le / s390x), MacOS 🍏, and Windows 🎠"

Expand All @@ -35,6 +50,7 @@ function build_release() {
else
# Release build: convert knative version to go module version
go_module_version="v0.$(( $(minor_version "$TAG") + 27 )).$(patch_version "$TAG")"
check_func_utils_image "${TAG}"
fi
else
knative_version="$(git describe --tags --match 'knative-*')"
Expand Down
4 changes: 3 additions & 1 deletion pkg/k8s/dialer.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import (
restclient "k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/tools/remotecommand"

"knative.dev/func/pkg/version"
)

var SocatImage = "ghcr.io/knative/func-utils:v2"
var SocatImage = version.FuncUtilsImage

// NewInClusterDialer creates context dialer that will dial TCP connections via POD running in k8s cluster.
// This is useful when accessing k8s services that are not exposed outside cluster (e.g. openshift image registry).
Expand Down
4 changes: 3 additions & 1 deletion pkg/k8s/persistent_volumes.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (
"k8s.io/client-go/kubernetes"
restclient "k8s.io/client-go/rest"
k8sclientcmd "k8s.io/client-go/tools/clientcmd"

"knative.dev/func/pkg/version"
)

func GetPersistentVolumeClaim(ctx context.Context, name, namespaceOverride string) (*corev1.PersistentVolumeClaim, error) {
Expand Down Expand Up @@ -72,7 +74,7 @@ func DeletePersistentVolumeClaims(ctx context.Context, namespaceOverride string,
return client.CoreV1().PersistentVolumeClaims(namespace).DeleteCollection(ctx, metav1.DeleteOptions{}, listOptions)
}

var TarImage = "ghcr.io/knative/func-utils:v2"
var TarImage = version.FuncUtilsImage

// UploadToVolume uploads files (passed in form of tar stream) into volume.
func UploadToVolume(ctx context.Context, content io.Reader, claimName, namespace string) error {
Expand Down
4 changes: 3 additions & 1 deletion pkg/pipelines/tekton/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import (
_ "embed"
"strings"
"text/template"

"knative.dev/func/pkg/version"
)

var (
FuncUtilImage = "ghcr.io/knative/func-utils:v2"
FuncUtilImage = version.FuncUtilsImage
DeployerImage string
ScaffoldImage string
S2IImage string
Expand Down
7 changes: 7 additions & 0 deletions pkg/version/version.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
package version

var Vers, Kver, Hash string

// FuncUtilsImage is the func-utils image that func runs in the cluster: the
// minor in development on main, X.Y on release-X.Y. Builds can override it
// (FUNC_UTILS_IMG in the Makefile). When release-X.Y is cut, the workflow
// update-func-utils-image.yaml moves main to the next minor; see
// docs/func-utils-image.md.
const FuncUtilsImage = "ghcr.io/knative/func-utils:1.24"
Loading