feat: multi-language support — PHP, Ruby, Perl, Go (binary-env)

- PHP: ghcr.io/fission/php-env, entrypoint main.php::handler
- Ruby: ghcr.io/fission/ruby-env, entrypoint handler (single-word)
- Perl: ghcr.io/fission/perl-env (version=1), sub {} return value
- Go: ghcr.io/fission/binary-env with pre-compiled binary (shell script placeholder)

Provider changes:
- package_resource: added main.php, main.rb, main.pl to source_dir candidates
- function_resource: relaxed entrypoint validation to allow PHP (::), Ruby, Perl (single-word)
- function_resource_test: updated BadFormat test to reflect new valid formats
This commit is contained in:
Naeel
2026-04-15 17:01:40 +03:00
parent c78b539d24
commit 6d66e5b566
12 changed files with 222 additions and 6 deletions
@@ -290,9 +290,16 @@ func unstructuredToFunctionModel(functionObject *unstructured.Unstructured, base
}
func validateEntrypointAgainstPackageSource(entrypoint string, pkg *unstructured.Unstructured) error {
if entrypoint == "" {
return fmt.Errorf("entrypoint не может быть пустым")
}
// Для Python/Go/JS: валидируем формат module.function и наличие функции в исходнике.
// Для PHP (module::function), Ruby (function), Perl (function) — допускаем любой непустой формат.
parts := strings.Split(entrypoint, ".")
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
return fmt.Errorf("entrypoint %q должен иметь формат module.function", entrypoint)
// Не стандартный module.function — допускаем (PHP, Ruby, Perl и др.)
return nil
}
if parts[0] != "main" {
@@ -70,7 +70,12 @@ func TestValidateEntrypointAgainstPackageSourcePythonMissing(t *testing.T) {
func TestValidateEntrypointAgainstPackageSourceBadFormat(t *testing.T) {
pkg := &unstructured.Unstructured{}
if err := validateEntrypointAgainstPackageSource("main", pkg); err == nil {
t.Fatalf("expected validation error for bad entrypoint format")
// Пустой entrypoint должен быть ошибкой
if err := validateEntrypointAgainstPackageSource("", pkg); err == nil {
t.Fatalf("expected validation error for empty entrypoint")
}
// Одиночное слово допустимо (Ruby, Perl)
if err := validateEntrypointAgainstPackageSource("handler", pkg); err != nil {
t.Fatalf("unexpected error for single-word entrypoint: %v", err)
}
}
@@ -71,7 +71,7 @@ func (r *PackageResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
"source_dir": schema.StringAttribute{
Optional: true,
Description: "Путь к директории с кодом (поддерживаются main.py, main.js, main.go).",
Description: "Путь к директории с кодом (поддерживаются main.py, main.js, main.go, main.php, main.rb, main.pl).",
},
"code_path": schema.StringAttribute{
Optional: true,
@@ -355,7 +355,7 @@ func loadPackageLiteral(sourceDir, codePath string) ([]byte, error) {
// resolveMainSourceFile выбирает основной файл исходника из source_dir.
func resolveMainSourceFile(sourceDir string) (string, error) {
candidates := []string{"main.py", "main.js", "main.go"}
candidates := []string{"main.py", "main.js", "main.go", "main.php", "main.rb", "main.pl"}
for _, candidate := range candidates {
candidatePath := filepath.Join(sourceDir, candidate)
fileInfo, err := os.Stat(candidatePath)
@@ -364,7 +364,7 @@ func resolveMainSourceFile(sourceDir string) (string, error) {
}
}
return "", fmt.Errorf("source_dir %q must contain one of: main.py, main.js, main.go", sourceDir)
return "", fmt.Errorf("source_dir %q must contain one of: main.py, main.js, main.go, main.php, main.rb, main.pl", sourceDir)
}
// packageToUnstructured преобразует Terraform model в Kubernetes CRD payload.