From e30851b44349e89f4b5092d3e05a4b0943e5d08a Mon Sep 17 00:00:00 2001 From: David Fridrich Date: Mon, 29 Dec 2025 11:23:57 +0100 Subject: [PATCH 1/2] fix template readmes --- .github/workflows/invoke-all.yaml | 4 ++-- .github/workflows/manual-workflow.yml | 4 ++-- go/blog/README.md | 12 ++---------- go/blog/hugo/content/posts/hust-builder.md | 9 ++++----- python/hello/README.md | 2 +- python/mcp/README.md | 2 +- 6 files changed, 12 insertions(+), 21 deletions(-) diff --git a/.github/workflows/invoke-all.yaml b/.github/workflows/invoke-all.yaml index 1e49926..ed4c1ac 100644 --- a/.github/workflows/invoke-all.yaml +++ b/.github/workflows/invoke-all.yaml @@ -48,8 +48,8 @@ jobs: ACTIONS_STEP_DEBUG: true language_paths: ${{needs.prepare.outputs.language_paths}} HEADREF: ${{github.head_ref}} - # TODO: UPDATE THIS IF HOST BUILDER IS ENABLED FOR MORE LANGUAGES SO WE - # DEFAULT TO THE HOST BUILDER + # Host builder is currently the default for Go and Python. + # Update this list if host builder support is added for more languages. HOST_ENABLED_LANGUAGES: '["go","python"]' steps: - name: Checkout code diff --git a/.github/workflows/manual-workflow.yml b/.github/workflows/manual-workflow.yml index cbf91fa..437cd23 100644 --- a/.github/workflows/manual-workflow.yml +++ b/.github/workflows/manual-workflow.yml @@ -9,7 +9,7 @@ jobs: languages: ${{ steps.prep-matrix.outputs.languages }} language_paths: ${{ steps.prep-matrix.outputs.language_paths }} env: - FUNC_VERSION: "knative-v1.16.1" + FUNC_VERSION: "knative-v1.19.1" steps: - name: Checkout code uses: actions/checkout@v4 @@ -65,5 +65,5 @@ jobs: template=$(basename "$template_dir_abs") echo "f create $language-$template -r=$url -l=$language -t=$template" f create $language-$template -r "$url" -l "$language" -t "$template" - #FUNC_ENABLE_HOST_BUILDER=1 FUNC_BUILDER=host FUNC_CONTAINER=false FUNC_REGISTRY=docker.io/4141gauron3268 f + #FUNC_REGISTRY=quay.io/dfridric f build --builder=host done \ No newline at end of file diff --git a/go/blog/README.md b/go/blog/README.md index edffa3b..5c17e58 100644 --- a/go/blog/README.md +++ b/go/blog/README.md @@ -36,20 +36,12 @@ hugo build --destination ../dist Now you can simply `func run` or `func deploy` with the host builder to either expose your Function locally or on your cluster respectively. -Example of these commands (note that host builder is hidden behind a flag, you -need to enable -it first - this will become the default builder in the future) +Example commands: ```bash -export FUNC_ENABLE_HOST_BUILDER=1 -func run --container=false --builder=host +func run --builder=host ``` -Note: We are running without a container because the host builder builds on the -OS system -without a docker containarization app (func bundles up your Function in a -specific way as an archive file to make it into an image). ```bash -export FUNC_ENABLE_HOST_BUILDER=1 func deploy --builder=host ``` diff --git a/go/blog/hugo/content/posts/hust-builder.md b/go/blog/hugo/content/posts/hust-builder.md index 2901277..abc026f 100644 --- a/go/blog/hugo/content/posts/hust-builder.md +++ b/go/blog/hugo/content/posts/hust-builder.md @@ -8,12 +8,11 @@ summary: This post explains what the new Host Builder is and why its our new def --- ## The Host Builder -We have introduced the Host Builder (currently in active developement) some months -ago and its already been available behind a flag *FUNC_ENABLE_HOST_BUILDER* which -needs to be set to truthy value in order to use it. +The Host Builder is now the default builder for Go and Python functions. +Simply use `--builder=host` to take advantage of it. # Why use it? -It's way faster to build your Functions!. Func will package your Functions +It's way faster to build your Functions! Func will package your Functions directory as an archive in a specific way into an image ready to be 'run' locally on your machine, within seconds! @@ -22,7 +21,7 @@ locally on your machine, within seconds! {{< details summary="with time" >}} Example of a go Function build using the Host Builder ``` -❯ FUNC_ENABLE_HOST_BUILDER=1 time func build --builder=host +❯ time func build --builder=host Building function image f.linux.amd64 f.linux.arm64 diff --git a/python/hello/README.md b/python/hello/README.md index f9fc9a0..0786772 100644 --- a/python/hello/README.md +++ b/python/hello/README.md @@ -19,7 +19,7 @@ management, including configurable startup and shutdown hooks. func deploy --builder=host # Local development and testing -func run --builder=host --container=false +func run --builder=host ``` ## Customization diff --git a/python/mcp/README.md b/python/mcp/README.md index dd28fad..d349fa2 100644 --- a/python/mcp/README.md +++ b/python/mcp/README.md @@ -83,7 +83,7 @@ For testing the MCP functionality, you can use the included client at `client/cl ```bash # run your mcp server locally -func run --builder=host --container=false +func run --builder=host # in different terminal: run mcp client python client/client.py From f147da059a0f8be3c1a28af5b061079ff7ce2f93 Mon Sep 17 00:00:00 2001 From: David Fridrich Date: Mon, 29 Dec 2025 12:27:00 +0100 Subject: [PATCH 2/2] local testing invoke:all --- .../{hust-builder.md => host-builder.md} | 0 invoke-local.sh | 263 ++++++++++++++++++ 2 files changed, 263 insertions(+) rename go/blog/hugo/content/posts/{hust-builder.md => host-builder.md} (100%) create mode 100755 invoke-local.sh diff --git a/go/blog/hugo/content/posts/hust-builder.md b/go/blog/hugo/content/posts/host-builder.md similarity index 100% rename from go/blog/hugo/content/posts/hust-builder.md rename to go/blog/hugo/content/posts/host-builder.md diff --git a/invoke-local.sh b/invoke-local.sh new file mode 100755 index 0000000..2277b53 --- /dev/null +++ b/invoke-local.sh @@ -0,0 +1,263 @@ +#!/bin/bash +# +# invoke-local.sh - Test all function templates locally +# +# This script replicates the invoke-all.yaml GitHub workflow for local testing. +# It discovers all language/template combinations, builds, runs, and invokes each one. +# +# Usage: ./invoke-local.sh +# +# Environment variables: +# FUNC_BIN - Path to func binary (default: func) +# FUNC_REGISTRY - Container registry to use (default: quay.io/test) +# +# Requirements: +# - func CLI installed +# - hugo (for go/blog template) +# - npm (for typescript templates) +# - cargo (for rust templates) + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +WORKDIR=$(mktemp -d) +HOST_ENABLED_LANGUAGES=("go" "python") +REGISTRY="${FUNC_REGISTRY:-quay.io/test}" +FUNC_BIN="${FUNC_BIN:-func}" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Track results +declare -a PASSED=() +declare -a FAILED=() +declare -a FAILED_DIRS=() + +log_info() { + echo -e "${GREEN}[INFO]${NC} $1" +} + +log_warn() { + echo -e "${YELLOW}[WARN]${NC} $1" +} + +log_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +cleanup_on_success() { + local dir=$1 + if [[ -d "$dir" ]]; then + rm -rf "$dir" + log_info "Cleaned up: $dir" + fi +} + +is_host_enabled() { + local lang=$1 + for enabled in "${HOST_ENABLED_LANGUAGES[@]}"; do + if [[ "$lang" == "$enabled" ]]; then + return 0 + fi + done + return 1 +} + +run_prerequisites() { + local language=$1 + local template=$2 + + log_info "Running prerequisites for $language/$template" + + case "$language/$template" in + go/blog) + log_info "Building hugo static files" + make + ;; + typescript/*) + log_info "Running npm install" + npm install + ;; + rust/*) + log_info "Running cargo build" + cargo build + ;; + *) + log_info "No prerequisites needed" + ;; + esac +} + +test_template() { + local language=$1 + local template=$2 + local func_name="$language-$template" + local func_dir="$WORKDIR/$func_name" + local run_pid="" + + log_info "==========================================" + log_info "Testing: $language/$template" + log_info "==========================================" + + # Determine builder + local builder="pack" + if is_host_enabled "$language"; then + builder="host" + fi + log_info "Using builder: $builder" + + # Create function using func create with local repository (file:// protocol) + local repo_uri="file://$SCRIPT_DIR" + log_info "Creating function with: $FUNC_BIN create $func_name -r $repo_uri -l $language -t $template" + cd "$WORKDIR" + + if ! $FUNC_BIN create "$func_name" -r "$repo_uri" -l "$language" -t "$template"; then + log_error "func create failed for $language/$template" + return 1 + fi + + cd "$func_dir" + + if [[ ! -f "func.yaml" ]]; then + log_error "No func.yaml found after func create" + return 1 + fi + + # Run prerequisites + run_prerequisites "$language" "$template" + + # Build + log_info "Building function" + if ! FUNC_REGISTRY="$REGISTRY" $FUNC_BIN build --builder="$builder"; then + log_error "Build failed for $language/$template" + return 1 + fi + + # Run in background + log_info "Starting function" + $FUNC_BIN run --build=false & + run_pid=$! + + # Check if process started + sleep 2 + if ! ps -p $run_pid > /dev/null 2>&1; then + log_error "Failed to start function" + return 1 + fi + + # Wait for function to be ready + log_info "Waiting for function to be ready..." + sleep 10 + + # Invoke with retries + local max_retries=5 + local retry_count=0 + local success=false + + while [[ $retry_count -lt $max_retries ]]; do + log_info "Invoke attempt $((retry_count + 1)) of $max_retries" + if $FUNC_BIN invoke --request-type=GET 2>/dev/null; then + log_info "Invoke succeeded!" + success=true + break + else + log_warn "Invoke failed, retrying..." + retry_count=$((retry_count + 1)) + sleep 5 + fi + done + + # Cleanup: kill the running function + if [[ -n "$run_pid" ]] && ps -p $run_pid > /dev/null 2>&1; then + kill $run_pid 2>/dev/null || true + wait $run_pid 2>/dev/null || true + fi + + if [[ "$success" == "true" ]]; then + return 0 + else + return 1 + fi +} + +print_summary() { + echo "" + echo "==========================================" + echo " SUMMARY" + echo "==========================================" + echo "" + + if [[ ${#PASSED[@]} -gt 0 ]]; then + echo -e "${GREEN}PASSED (${#PASSED[@]}):${NC}" + for item in "${PASSED[@]}"; do + echo " - $item" + done + fi + + echo "" + + if [[ ${#FAILED[@]} -gt 0 ]]; then + echo -e "${RED}FAILED (${#FAILED[@]}):${NC}" + for i in "${!FAILED[@]}"; do + echo " - ${FAILED[$i]}" + echo " Preserved at: ${FAILED_DIRS[$i]}" + done + fi + + echo "" + echo "Total: $((${#PASSED[@]} + ${#FAILED[@]})) | Passed: ${#PASSED[@]} | Failed: ${#FAILED[@]}" + + if [[ ${#FAILED[@]} -gt 0 ]]; then + return 1 + fi + return 0 +} + +main() { + log_info "Starting local template testing" + log_info "Script directory: $SCRIPT_DIR" + log_info "Work directory: $WORKDIR" + echo "" + + # Find all language directories + for lang_dir in "$SCRIPT_DIR"/*/; do + # Skip hidden directories and non-directories + [[ ! -d "$lang_dir" ]] && continue + [[ "$(basename "$lang_dir")" == .* ]] && continue + + local language=$(basename "$lang_dir") + + # Skip non-language directories + if [[ "$language" == "docs" ]] || [[ "$language" == ".github" ]]; then + continue + fi + + # Find all templates in this language + for template_dir in "$lang_dir"/*/; do + [[ ! -d "$template_dir" ]] && continue + + local template=$(basename "$template_dir") + local test_name="$language/$template" + local func_dir="$WORKDIR/$language-$template" + + if test_template "$language" "$template"; then + PASSED+=("$test_name") + cleanup_on_success "$func_dir" + else + FAILED+=("$test_name") + FAILED_DIRS+=("$func_dir") + log_error "FAILED: $test_name (preserved at $func_dir)" + fi + + echo "" + done + done + + print_summary +} + +# Run main +main "$@"