667f20a7b3
P0b — Canonical Markdown+frontmatter jobspec parser (R-013/R-014).
Parser (internal/jobspec/markdown.go, REQ-064):
- WorkloadSpec/RuntimeBlock/PortSpec/VolumeSpec types. ParseMarkdown
hand-rolled YAML frontmatter (no yaml.v3 dep). Kind validation (Job/
Service/DaemonSet per R-012). BOM-stripped frontmatter, byte-exact body
preservation (R-015) via the fuzz harness.
Dispatcher (internal/jobspec/dispatch.go, REQ-064):
- ParseFile/Dispatch routes on extension: .md->Markdown, .yaml/.yml->
Markdown-with-empty-body, .hcl->ParseHCL adapter. HCL adapter converts
Spec{Job,Tasks} to *WorkloadSpec (Kind=Job, Runtime.one_of=process).
Backward compat preserved (REQ-090) — orca job run old-spec.hcl works.
- Legacy Parse renamed ParseHCLLegacy, marked // Deprecated per R-013.
Fuzz harness (internal/jobspec/markdown_fuzz_test.go, REQ-067, R-015):
- FuzzParseMarkdownRoundTrip with 10 seed corpus entries (CRLF, BOM,
no-frontmatter, only-closing-separator, code-fence ---, trailing
whitespace, empty body, etc). Asserts byte-exact body round-trip.
Tests: markdown_test.go (19 tests), dispatch_test.go (17 tests), fuzz
(10 seeds). jobspec package 89.2% coverage. cli 81.8% (no regression).
18 packages pass, 20 bats pass, gofmt clean, verify-reqs 90 consistent.
---ci---
project: orca
phase: P0b
milestone: v0.9
status: execute
---/ci---
69 lines
2.0 KiB
Go
69 lines
2.0 KiB
Go
package jobspec
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/gohcl"
|
|
"github.com/hashicorp/hcl/v2/hclsimple"
|
|
)
|
|
|
|
// Spec is the legacy HCL-only jobspec shape. It is retained for the
|
|
// v0.9→v0.10 migration window (REQ-090) and is populated by ParseHCLLegacy.
|
|
//
|
|
// Deprecated: HCL is legacy per R-013; new code should consume the
|
|
// unified *WorkloadSpec returned by ParseFile/Dispatch (see
|
|
// dispatch.go and markdown.go).
|
|
type Spec struct {
|
|
Job JobSpec `hcl:"job,block"`
|
|
Tasks []TaskSpec `hcl:"task,block"`
|
|
}
|
|
|
|
// JobSpec is the legacy HCL job block.
|
|
type JobSpec struct {
|
|
Name string `hcl:"name,label"`
|
|
Type string `hcl:"type,optional"`
|
|
}
|
|
|
|
// TaskSpec is the legacy HCL task block.
|
|
type TaskSpec struct {
|
|
Name string `hcl:"name,label"`
|
|
Command string `hcl:"command"`
|
|
Args []string `hcl:"args,optional"`
|
|
Env []string `hcl:"env,optional"`
|
|
}
|
|
|
|
// hclDecode wraps hclsimple.Decode for testability.
|
|
func hclDecode(filename string, data []byte, spec *Spec) error {
|
|
return hclsimple.Decode(filename, data, nil, spec)
|
|
}
|
|
|
|
// Validate is the legacy HCL Spec validator retained for the migration
|
|
// window (REQ-090). New code should use validateWorkload on a
|
|
// *WorkloadSpec.
|
|
func (s *Spec) Validate() error {
|
|
if strings.TrimSpace(s.Job.Name) == "" {
|
|
return fmt.Errorf("job name is required")
|
|
}
|
|
if len(s.Tasks) == 0 {
|
|
return fmt.Errorf("at least one task is required")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Parse is the original HCL-only entry point retained for backward
|
|
// compatibility with direct HCL callers during the v0.9→v0.10 migration
|
|
// window (REQ-090). New code should call the dispatcher ParseFile (which
|
|
// returns *WorkloadSpec) or ParseHCL (which adapts HCL into
|
|
// *WorkloadSpec).
|
|
//
|
|
// Deprecated: use ParseFile (dispatcher) or ParseHCL (adapter). HCL is
|
|
// legacy per R-013.
|
|
func Parse(data []byte, filename string) (*Spec, error) {
|
|
return ParseHCLLegacy(data, filename)
|
|
}
|
|
|
|
var _ = hcl.Diagnostics{}
|
|
var _ = gohcl.DecodeBody
|