feat: support JS and Go source files in fission package loader
This commit is contained in:
@@ -70,7 +70,7 @@ terraform import fission_http_trigger.hello default/tf-hello-route
|
|||||||
|
|
||||||
## Ограничения MVP
|
## Ограничения MVP
|
||||||
|
|
||||||
- `fission_package.source_dir` в текущей реализации ожидает файл `main.py` в корне указанной директории.
|
- `fission_package.source_dir` в текущей реализации ожидает один из файлов: `main.py`, `main.js`, `main.go`.
|
||||||
- Реализация ориентирована на Python flow через `spec.deployment.literal`.
|
- Реализация ориентирована на Python flow через `spec.deployment.literal`.
|
||||||
- Дополнительные сценарии сборки (`build_command`, многофайловые архивы и т.д.) будут расширены в следующих этапах.
|
- Дополнительные сценарии сборки (`build_command`, многофайловые архивы и т.д.) будут расширены в следующих этапах.
|
||||||
|
|
||||||
|
|||||||
@@ -153,3 +153,14 @@
|
|||||||
|
|
||||||
### Следующий шаг
|
### Следующий шаг
|
||||||
- Добавить в acceptance-тест проверку HTTP latency/perf budget и порогов SLO.
|
- Добавить в acceptance-тест проверку HTTP latency/perf budget и порогов SLO.
|
||||||
|
|
||||||
|
### Обновление этапа (JS/Go source support)
|
||||||
|
- В `fission_package` расширена поддержка `source_dir`:
|
||||||
|
- `main.py`
|
||||||
|
- `main.js`
|
||||||
|
- `main.go`
|
||||||
|
- Добавлены unit-тесты на выбор JS/Go исходников в `package_resource_test.go`.
|
||||||
|
- Прогон `go test ./...` — успешно.
|
||||||
|
|
||||||
|
### Следующий шаг
|
||||||
|
- Добавить отдельные Terraform примеры для Node.js и Go функций.
|
||||||
|
|||||||
@@ -194,3 +194,18 @@
|
|||||||
- fast: 100%
|
- fast: 100%
|
||||||
- cpu: 100%
|
- cpu: 100%
|
||||||
- json: 100%
|
- json: 100%
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Агент: GitHub Copilot
|
||||||
|
Модель: GPT-5.3-Codex
|
||||||
|
|
||||||
|
## План (до действий, этап 11)
|
||||||
|
1. Убрать Python-only ограничение в `fission_package.source_dir`.
|
||||||
|
2. Добавить поддержку JS/Go исходников на уровне package loader.
|
||||||
|
3. Закрыть изменения unit-тестами.
|
||||||
|
|
||||||
|
## Результат (после действий, этап 11)
|
||||||
|
- `fission_package` теперь поддерживает `main.py`, `main.js`, `main.go` в `source_dir`.
|
||||||
|
- Добавлены unit-тесты для JS/Go веток `loadPackageLiteral`.
|
||||||
|
- `go test ./...` проходит.
|
||||||
|
|||||||
@@ -69,11 +69,11 @@ func (r *PackageResource) Schema(_ context.Context, _ resource.SchemaRequest, re
|
|||||||
},
|
},
|
||||||
"source_dir": schema.StringAttribute{
|
"source_dir": schema.StringAttribute{
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "Путь к директории с кодом, которая будет упакована в zip.",
|
Description: "Путь к директории с кодом (поддерживаются main.py, main.js, main.go).",
|
||||||
},
|
},
|
||||||
"code_path": schema.StringAttribute{
|
"code_path": schema.StringAttribute{
|
||||||
Optional: true,
|
Optional: true,
|
||||||
Description: "Путь к готовому zip-архиву с кодом.",
|
Description: "Путь к готовому файлу исходника для literal deployment.",
|
||||||
},
|
},
|
||||||
"code_hash": schema.StringAttribute{
|
"code_hash": schema.StringAttribute{
|
||||||
Optional: true,
|
Optional: true,
|
||||||
@@ -271,10 +271,14 @@ func resolveNamespace(resourceNamespace types.String, providerNamespace string)
|
|||||||
// loadPackageLiteral читает bytes для spec.deployment.literal.
|
// loadPackageLiteral читает bytes для spec.deployment.literal.
|
||||||
func loadPackageLiteral(sourceDir, codePath string) ([]byte, error) {
|
func loadPackageLiteral(sourceDir, codePath string) ([]byte, error) {
|
||||||
if sourceDir != "" {
|
if sourceDir != "" {
|
||||||
mainFilePath := filepath.Join(sourceDir, "main.py")
|
mainFilePath, err := resolveMainSourceFile(sourceDir)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
mainFileBytes, err := os.ReadFile(mainFilePath)
|
mainFileBytes, err := os.ReadFile(mainFilePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read source_dir main.py %q: %w", mainFilePath, err)
|
return nil, fmt.Errorf("read source_dir source file %q: %w", mainFilePath, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return mainFileBytes, nil
|
return mainFileBytes, nil
|
||||||
@@ -288,6 +292,20 @@ func loadPackageLiteral(sourceDir, codePath string) ([]byte, error) {
|
|||||||
return literalBytes, nil
|
return literalBytes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// resolveMainSourceFile выбирает основной файл исходника из source_dir.
|
||||||
|
func resolveMainSourceFile(sourceDir string) (string, error) {
|
||||||
|
candidates := []string{"main.py", "main.js", "main.go"}
|
||||||
|
for _, candidate := range candidates {
|
||||||
|
candidatePath := filepath.Join(sourceDir, candidate)
|
||||||
|
fileInfo, err := os.Stat(candidatePath)
|
||||||
|
if err == nil && !fileInfo.IsDir() {
|
||||||
|
return candidatePath, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", fmt.Errorf("source_dir %q must contain one of: main.py, main.js, main.go", sourceDir)
|
||||||
|
}
|
||||||
|
|
||||||
// packageToUnstructured преобразует Terraform model в Kubernetes CRD payload.
|
// packageToUnstructured преобразует Terraform model в Kubernetes CRD payload.
|
||||||
func packageToUnstructured(model packageResourceModel, namespace string, literalBytes []byte) *unstructured.Unstructured {
|
func packageToUnstructured(model packageResourceModel, namespace string, literalBytes []byte) *unstructured.Unstructured {
|
||||||
literalSource := base64.StdEncoding.EncodeToString(literalBytes)
|
literalSource := base64.StdEncoding.EncodeToString(literalBytes)
|
||||||
|
|||||||
@@ -49,6 +49,40 @@ func TestLoadPackageLiteralFromSourceDir(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLoadPackageLiteralFromSourceDirJS(t *testing.T) {
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
mainPath := filepath.Join(tempDir, "main.js")
|
||||||
|
content := []byte("module.exports = async function() { return 'ok'; }\n")
|
||||||
|
if err := os.WriteFile(mainPath, content, 0o600); err != nil {
|
||||||
|
t.Fatalf("write temp main.js: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded, err := loadPackageLiteral(tempDir, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("loadPackageLiteral returned error: %v", err)
|
||||||
|
}
|
||||||
|
if string(loaded) != string(content) {
|
||||||
|
t.Fatalf("unexpected loaded content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestLoadPackageLiteralFromSourceDirGo(t *testing.T) {
|
||||||
|
tempDir := t.TempDir()
|
||||||
|
mainPath := filepath.Join(tempDir, "main.go")
|
||||||
|
content := []byte("package main\nfunc main() {}\n")
|
||||||
|
if err := os.WriteFile(mainPath, content, 0o600); err != nil {
|
||||||
|
t.Fatalf("write temp main.go: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
loaded, err := loadPackageLiteral(tempDir, "")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("loadPackageLiteral returned error: %v", err)
|
||||||
|
}
|
||||||
|
if string(loaded) != string(content) {
|
||||||
|
t.Fatalf("unexpected loaded content")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestPackageToUnstructured(t *testing.T) {
|
func TestPackageToUnstructured(t *testing.T) {
|
||||||
input := packageResourceModel{
|
input := packageResourceModel{
|
||||||
Name: types.StringValue("pkg-a"),
|
Name: types.StringValue("pkg-a"),
|
||||||
|
|||||||
Reference in New Issue
Block a user