Skip to content

Commit 3d93b57

Browse files
committed
feat: add runtime-aware builder config
Generated GitHub Actions workflows from `func config ci` previously used CLI flags for deploy configuration and had no builder selection logic. The deploy step now uses environment variables (FUNC_BUILDER, FUNC_REGISTRY, FUNC_REMOTE, FUNC_VERBOSE) and selects the builder based on the function runtime: host for Go/Python local builds, pack for Node/TypeScript/Rust/Quarkus/Springboot, and s2i for Python remote builds. CIConfig loads the function upfront, encapsulating runtime and root path, removing the need for callers to load separately. Platform validation now rejects empty values and error messages include supported platforms. Adds e2e tests using nektos/act to run generated workflows against a real cluster for each supported runtime, with a corresponding GitHub Actions job, Makefile target, and hack/test-full.sh entry. act is installed via hack/binaries.sh. Fixes TypeScript template imports (build → src) and the HTTP template body parameter type (string → optional IncomingBody). Fixes typos in CI workflow comments (Cluser → Cluster, runtim → runtime). Adds missing .PHONY declarations. Issue #3256 Issue #3256 Signed-off-by: Stanislav Jakuschevskij <sjakusch@redhat.com>
1 parent 27d2405 commit 3d93b57

File tree

21 files changed

+3075
-2623
lines changed

21 files changed

+3075
-2623
lines changed

.github/workflows/functions.yaml

Lines changed: 78 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Functions
33
# To run this workflow's tests locally, see ./hack/test-full.sh
44

55
permissions:
6-
id-token: write # Required for signing
6+
id-token: write # Required for signing
77
contents: read
88
packages: write
99
attestations: write
@@ -18,10 +18,10 @@ on:
1818

1919
# Global version definitions
2020
env:
21-
PYTHON_VERSION: '3.10'
22-
NODE_VERSION: '20'
23-
JAVA_VERSION: '21'
24-
JAVA_DISTRIBUTION: 'temurin'
21+
PYTHON_VERSION: "3.10"
22+
NODE_VERSION: "20"
23+
JAVA_VERSION: "21"
24+
JAVA_DISTRIBUTION: "temurin"
2525

2626
jobs:
2727
# --------
@@ -53,10 +53,10 @@ jobs:
5353
fail-fast: false
5454
matrix:
5555
os:
56-
- "ubuntu-latest" # x86_64
57-
- "ubuntu-24.04-arm" # ARM64
58-
- "macos-latest" # Intel
59-
- "macos-14" # ARM
56+
- "ubuntu-latest" # x86_64
57+
- "ubuntu-24.04-arm" # ARM64
58+
- "macos-latest" # Intel
59+
- "macos-14" # ARM
6060
- "windows-latest"
6161
runs-on: ${{ matrix.os }}
6262
steps:
@@ -88,14 +88,14 @@ jobs:
8888
fail-fast: false
8989
matrix:
9090
os:
91-
- "ubuntu-latest" # x86_64
92-
- "ubuntu-24.04-arm" # ARM64
93-
- "macos-latest" # Intel
94-
- "macos-14" # ARM
91+
- "ubuntu-latest" # x86_64
92+
- "ubuntu-24.04-arm" # ARM64
93+
- "macos-latest" # Intel
94+
- "macos-14" # ARM
9595
- "windows-latest"
9696
runs-on: ${{ matrix.os }}
9797
steps:
98-
# Setup
98+
# Setup
9999
- name: Disable CRLF conversion (Windows)
100100
if: runner.os == 'Windows'
101101
run: git config --global core.autocrlf false
@@ -124,7 +124,6 @@ jobs:
124124
- name: Templates Tests
125125
run: make test-templates
126126

127-
128127
# -----------------
129128
# INTEGRATION TESTS
130129
# -----------------
@@ -175,7 +174,7 @@ jobs:
175174
verbose: true
176175
token: ${{ secrets.CODECOV_TOKEN }}
177176

178-
# Preserve Cluser Logs
177+
# Preserve Cluster Logs
179178
- name: Dump Cluster Logs
180179
if: always()
181180
run: ./hack/dump-logs.sh cluster_log.txt
@@ -230,7 +229,7 @@ jobs:
230229
verbose: true
231230
token: ${{ secrets.CODECOV_TOKEN }}
232231

233-
# Preserve Cluser Logs
232+
# Preserve Cluster Logs
234233
- name: Dump Cluster Logs
235234
if: always()
236235
run: ./hack/dump-logs.sh cluster_log.txt
@@ -252,8 +251,8 @@ jobs:
252251
strategy:
253252
matrix:
254253
os:
255-
- "ubuntu-latest" # x86_64
256-
- "ubuntu-24.04-arm" # ARM64
254+
- "ubuntu-latest" # x86_64
255+
- "ubuntu-24.04-arm" # ARM64
257256
env:
258257
FUNC_CLUSTER_RETRIES: 5
259258
FUNC_E2E_PODMAN: true
@@ -284,7 +283,7 @@ jobs:
284283
verbose: true
285284
token: ${{ secrets.CODECOV_TOKEN }}
286285

287-
# Preserve Cluser Logs
286+
# Preserve Cluster Logs
288287
- name: Dump Cluster Logs
289288
if: always()
290289
run: ./hack/dump-logs.sh cluster_log.txt
@@ -296,7 +295,6 @@ jobs:
296295
path: ./cluster_log.txt
297296
retention-days: 7
298297

299-
300298
# -----------------
301299
# E2E RUNTIME TESTS
302300
# -----------------
@@ -315,9 +313,9 @@ jobs:
315313
- "springboot"
316314
runs-on: ubuntu-latest
317315
env:
318-
FUNC_CLUSTER_RETRIES: 5 # Cluster allocation retries
319-
FUNC_E2E_CLEAN: false # Skip deletes (cluster not reused)
320-
FUNC_E2E_MATRIX: true # Enables the language runtim matrix tests
316+
FUNC_CLUSTER_RETRIES: 5 # Cluster allocation retries
317+
FUNC_E2E_CLEAN: false # Skip deletes (cluster not reused)
318+
FUNC_E2E_MATRIX: true # Enables the language runtime matrix tests
321319
FUNC_E2E_VERBOSE: true
322320
FUNC_E2E_MATRIX_RUNTIMES: ${{ matrix.runtime }}
323321
steps:
@@ -374,7 +372,7 @@ jobs:
374372
verbose: true
375373
token: ${{ secrets.CODECOV_TOKEN }}
376374

377-
# Preserve Cluser Logs
375+
# Preserve Cluster Logs
378376
- name: Dump Cluster Logs
379377
if: always()
380378
run: ./hack/dump-logs.sh cluster_log.txt
@@ -386,6 +384,60 @@ jobs:
386384
path: ./cluster_log.txt
387385
retention-days: 7
388386

387+
# -------------------
388+
# E2E CONFIG CI TESTS
389+
# -------------------
390+
test-e2e-config-ci:
391+
name: E2E - Config CI GitHub Workflows
392+
needs: precheck
393+
runs-on: ubuntu-latest
394+
env:
395+
FUNC_CLUSTER_RETRIES: 5
396+
FUNC_E2E_CLEAN: false
397+
FUNC_E2E_VERBOSE: true
398+
steps:
399+
- uses: actions/checkout@v4
400+
- uses: knative/actions/setup-go@main
401+
- uses: endersonmenezes/free-disk-space@v3
402+
with:
403+
remove_android: true
404+
remove_dotnet: true
405+
remove_haskell: true
406+
remove_swap: true
407+
rm_cmd: "rmz"
408+
409+
- name: Install Binaries
410+
run: ./hack/binaries.sh
411+
- name: Allocate Cluster
412+
run: ./hack/cluster.sh
413+
- name: Start Local Registry
414+
run: ./hack/registry.sh
415+
- name: Prepare Images
416+
run: ./hack/images.sh
417+
418+
- name: Run Config CI E2E Tests
419+
run: make test-e2e-config-ci
420+
421+
- uses: codecov/codecov-action@v5
422+
with:
423+
files: ./coverage.txt
424+
flags: e2e-config-ci
425+
fail_ci_if_error: true
426+
verbose: true
427+
token: ${{ secrets.CODECOV_TOKEN }}
428+
429+
# Preserve Cluster Logs
430+
- name: Dump Cluster Logs
431+
if: always()
432+
run: ./hack/dump-logs.sh cluster_log.txt
433+
- name: Archive Cluster Logs
434+
if: always()
435+
uses: actions/upload-artifact@v4
436+
with:
437+
name: cluster-logs-e2e-config-ci
438+
path: ./cluster_log.txt
439+
retention-days: 7
440+
389441
# Build and Publish
390442
build:
391443
name: Build Release
@@ -396,6 +448,7 @@ jobs:
396448
- test-e2e
397449
- test-e2e-podman
398450
- test-e2e-runtimes
451+
- test-e2e-config-ci
399452
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
400453
runs-on: ubuntu-latest
401454
steps:

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ __pycache__
3636
AGENTS.override.md
3737
.claude/*.local.*
3838
.claude/pr/*
39+
.claude/plans/*
3940
.roo/*
4041

4142
# E2E Tests

Makefile

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,23 +300,29 @@ test-e2e: func-instrumented-bin ## Basic E2E tests (includes core, metadata and
300300
go test -tags e2e -timeout 60m ./e2e -v -run "TestCore_|TestMetadata_|TestRemote_"
301301
go tool covdata textfmt -i=$${FUNC_E2E_GOCOVERDIR:-.coverage} -o coverage.txt
302302

303-
304303
.PHONY: test-e2e-podman
305304
test-e2e-podman: func-instrumented-bin ## Run E2E Podman-specific tests
306305
# see e2e_test.go for available options
307306
FUNC_E2E_PODMAN=true go test -tags e2e -timeout 60m ./e2e -v -run TestPodman_
308307
go tool covdata textfmt -i=$${FUNC_E2E_GOCOVERDIR:-.coverage} -o coverage.txt
309308

309+
.PHONY: test-e2e-matrix
310310
test-e2e-matrix: func-instrumented-bin ## Basic E2E tests (includes core, metadata and remote tests)
311311
# Runtime and other options can be configured using the FUNC_E2E_* environment variables. see e2e_test.go
312312
FUNC_E2E_MATRIX=true go test -tags e2e -timeout 120m ./e2e -v -run TestMatrix_
313313
go tool covdata textfmt -i=$${FUNC_E2E_GOCOVERDIR:-.coverage} -o coverage.txt
314314

315+
.PHONY: test-e2e-config-ci
316+
test-e2e-config-ci: func-instrumented-bin ## CI tests for generated GitHub Workflows
317+
# Runtime and other options can be configured using the FUNC_E2E_* environment variables. see e2e_test.go
318+
FUNC_E2E_CONFIG_CI=true go test -tags e2e -timeout 120m ./e2e -v -run TestConfigCI_
319+
go tool covdata textfmt -i=$${FUNC_E2E_GOCOVERDIR:-.coverage} -o coverage.txt
315320

316321
.PHONY: test-full
317322
test-full: func-instrumented-bin ## Run full test suite with all checks enabled
318323
./hack/test-full.sh
319324

325+
.PHONY: test-full-logged
320326
test-full-logged: func-instrumented-bin ## Run full test and log with timestamps (requires python)
321327
./hack/test-full.sh 2>&1 | python -u -c "import sys; from datetime import datetime; [print(f'[{datetime.now().strftime(\"%H:%M:%S\")}] {line}', end='', flush=True) for line in sys.stdin]" | tee ./test-full.log
322328
@echo '🎉 Full Test Complete. Log stored in test-full.log'

cmd/ci/common.go

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,30 @@ package ci
22

33
import "fmt"
44

5-
func runner(conf CIConfig) string {
6-
if conf.SelfHostedRunner() {
5+
func determineBuilder(runtime string, remote bool) (string, error) {
6+
switch runtime {
7+
case "go":
8+
if remote {
9+
return "pack", nil
10+
}
11+
return "host", nil
12+
13+
case "node", "typescript", "rust", "quarkus", "springboot":
14+
return "pack", nil
15+
16+
case "python":
17+
if remote {
18+
return "s2i", nil
19+
}
20+
return "host", nil
21+
22+
default:
23+
return "", fmt.Errorf("no builder support for runtime: %s", runtime)
24+
}
25+
}
26+
27+
func determineRunner(selfHosted bool) string {
28+
if selfHosted {
729
return "self-hosted"
830
}
931
return "ubuntu-latest"

cmd/ci/config.go

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ const (
6868
type CIConfig struct {
6969
githubWorkflowDir,
7070
githubWorkflowFilename,
71-
path,
7271
branch,
7372
workflowName,
7473
kubeconfigSecret,
@@ -83,9 +82,12 @@ type CIConfig struct {
8382
testStep,
8483
force,
8584
verbose bool
85+
fnRuntime,
86+
fnRoot string
8687
}
8788

8889
func NewCIConfig(
90+
fnLoader common.FunctionLoader,
8991
currentBranch common.CurrentBranchFunc,
9092
workingDir common.WorkDirFunc,
9193
workflowNameExplicit bool,
@@ -106,10 +108,14 @@ func NewCIConfig(
106108

107109
workflowName := resolveWorkflowName(workflowNameExplicit)
108110

111+
f, err := fnLoader.Load(path)
112+
if err != nil {
113+
return CIConfig{}, err
114+
}
115+
109116
return CIConfig{
110117
githubWorkflowDir: DefaultGitHubWorkflowDir,
111118
githubWorkflowFilename: DefaultGitHubWorkflowFilename,
112-
path: path,
113119
branch: branch,
114120
workflowName: workflowName,
115121
kubeconfigSecret: viper.GetString(KubeconfigSecretNameFlag),
@@ -124,13 +130,18 @@ func NewCIConfig(
124130
testStep: viper.GetBool(TestStepFlag),
125131
force: viper.GetBool(ForceFlag),
126132
verbose: viper.GetBool(VerboseFlag),
133+
fnRuntime: f.Runtime,
134+
fnRoot: f.Root,
127135
}, nil
128136
}
129137

130138
func resolvePlatform() error {
131139
platform := viper.GetString(PlatformFlag)
140+
if platform == "" {
141+
return fmt.Errorf("platform must not be empty, supported: %s", DefaultPlatform)
142+
}
132143
if strings.ToLower(platform) != DefaultPlatform {
133-
return fmt.Errorf("%s support is not implemented", platform)
144+
return fmt.Errorf("%s support is not implemented, supported: %s", platform, DefaultPlatform)
134145
}
135146

136147
return nil
@@ -177,22 +188,15 @@ func resolveWorkflowName(explicit bool) string {
177188
return DefaultWorkflowName
178189
}
179190

180-
func (cc CIConfig) fnGitHubWorkflowDir(fnRoot string) string {
181-
return filepath.Join(fnRoot, cc.githubWorkflowDir)
182-
}
183-
184-
func (cc CIConfig) FnGitHubWorkflowFilepath(fnRoot string) string {
185-
return filepath.Join(cc.fnGitHubWorkflowDir(fnRoot), cc.githubWorkflowFilename)
191+
func (cc CIConfig) FnGitHubWorkflowFilepath() string {
192+
fnGitHubWorkflowDir := filepath.Join(cc.fnRoot, cc.githubWorkflowDir)
193+
return filepath.Join(fnGitHubWorkflowDir, cc.githubWorkflowFilename)
186194
}
187195

188196
func (cc CIConfig) OutputPath() string {
189197
return filepath.Join(cc.githubWorkflowDir, cc.githubWorkflowFilename)
190198
}
191199

192-
func (cc CIConfig) Path() string {
193-
return cc.path
194-
}
195-
196200
func (cc CIConfig) Branch() string {
197201
return cc.branch
198202
}
@@ -248,3 +252,7 @@ func (cc CIConfig) Force() bool {
248252
func (cc CIConfig) Verbose() bool {
249253
return cc.verbose
250254
}
255+
256+
func (cc CIConfig) FnRuntime() string {
257+
return cc.fnRuntime
258+
}

0 commit comments

Comments
 (0)