Add workspace configuration support
This commit is contained in:
@@ -156,10 +156,16 @@ func runPipelineCommand(args []string, stdout, stderr io.Writer, opts Options) i
|
||||
}
|
||||
|
||||
startedAt := opts.Now().UTC()
|
||||
runDir, err := diagnostics.NewRunDirectory(cfg.Diagnostics.WorkDir, cfg.Diagnostics.Retention)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "notarius: %v\n", err)
|
||||
return 1
|
||||
runID := fmt.Sprintf("run-%d", startedAt.UnixNano())
|
||||
var runDir *diagnostics.RunDirectory
|
||||
if cfg.DiagnosticsEnabled() {
|
||||
var err error
|
||||
runDir, err = diagnostics.NewRunDirectory(cfg.Diagnostics.WorkDir, cfg.Diagnostics.Retention)
|
||||
if err != nil {
|
||||
fmt.Fprintf(stderr, "notarius: %v\n", err)
|
||||
return 1
|
||||
}
|
||||
runID = runDir.RunID()
|
||||
}
|
||||
invocation := diagnostics.InvocationMetadata{
|
||||
Operation: "run",
|
||||
@@ -168,10 +174,10 @@ func runPipelineCommand(args []string, stdout, stderr io.Writer, opts Options) i
|
||||
ConfigPath: loadedConfigPath,
|
||||
ConfigSource: configSource(*configPath),
|
||||
OnlyLanes: append([]string(nil), only...),
|
||||
RunID: runDir.RunID(),
|
||||
RunID: runID,
|
||||
StartedAt: startedAt,
|
||||
}
|
||||
if err := runDir.WriteInvocationMetadata(invocation); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteInvocationMetadata(invocation) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics invocation metadata: %w", err))
|
||||
}
|
||||
|
||||
@@ -211,16 +217,18 @@ func runPipelineCommand(args []string, stdout, stderr io.Writer, opts Options) i
|
||||
}
|
||||
effective.ResolvedPipeline = materialized
|
||||
invocation.PipelineDigest = effective.ResolvedPipeline.Digest
|
||||
if err := runDir.WriteInvocationMetadata(invocation); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteInvocationMetadata(invocation) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics invocation metadata: %w", err))
|
||||
}
|
||||
if err := runDir.WriteRedactedEffectiveConfig(effective); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteRedactedEffectiveConfig(effective) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics effective config: %w", err))
|
||||
}
|
||||
if err := runDir.WriteResolvedPipeline(effective.ResolvedPipeline); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteResolvedPipeline(effective.ResolvedPipeline) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics resolved pipeline: %w", err))
|
||||
}
|
||||
if err := runDir.WriteResolvedReferences(pipeline.ReferenceProvenance(effective.ResolvedPipeline)); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error {
|
||||
return runDir.WriteResolvedReferences(pipeline.ReferenceProvenance(effective.ResolvedPipeline))
|
||||
}); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics resolved references: %w", err))
|
||||
}
|
||||
|
||||
@@ -250,45 +258,49 @@ func runPipelineCommand(args []string, stdout, stderr io.Writer, opts Options) i
|
||||
RawInput: rawInput,
|
||||
LLMClient: llmClient,
|
||||
SessionID: strings.TrimSpace(sessionID.value),
|
||||
RunID: runDir.RunID(),
|
||||
RunID: runID,
|
||||
StartedAt: startedAt,
|
||||
LLMProfiles: llmProfiles,
|
||||
Metadata: runMetadata(*outputDir, *diagnosticsDir),
|
||||
Warnings: referenceWarnings,
|
||||
})
|
||||
if err != nil {
|
||||
if output.Manifest.PipelineID != "" {
|
||||
if output.Manifest.PipelineID != "" && runDir != nil {
|
||||
_ = runDir.WriteRunManifest(output.Manifest)
|
||||
}
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("run pipeline %q: %w", pipelineID, err))
|
||||
}
|
||||
|
||||
runOutputDir := filepath.Join(outputRoot(*outputDir), runDir.RunID())
|
||||
if err := runDir.WriteRunManifest(output.Manifest); err != nil {
|
||||
runOutputDir := filepath.Join(outputRoot(*outputDir), runID)
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteRunManifest(output.Manifest) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics run manifest: %w", err))
|
||||
}
|
||||
if err := runDir.WriteWarnings(output.Warnings); err != nil {
|
||||
if err := writeDiagnostics(runDir, func() error { return runDir.WriteWarnings(output.Warnings) }); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics warnings: %w", err))
|
||||
}
|
||||
if err := runDir.WriteRunReport(runReport{
|
||||
RunID: runDir.RunID(),
|
||||
PipelineID: effective.PipelineID,
|
||||
OutputPath: runOutputDir,
|
||||
DiagnosticsPath: runDir.Path(),
|
||||
OutputCount: len(output.NormalizeOutputs),
|
||||
RejectedCount: len(output.Rejected),
|
||||
WarningCount: len(output.Warnings),
|
||||
ValidationStatus: output.Manifest.ValidationStatus,
|
||||
if err := writeDiagnostics(runDir, func() error {
|
||||
return runDir.WriteRunReport(runReport{
|
||||
RunID: runDir.RunID(),
|
||||
PipelineID: effective.PipelineID,
|
||||
OutputPath: runOutputDir,
|
||||
DiagnosticsPath: runDir.Path(),
|
||||
OutputCount: len(output.NormalizeOutputs),
|
||||
RejectedCount: len(output.Rejected),
|
||||
WarningCount: len(output.Warnings),
|
||||
ValidationStatus: output.Manifest.ValidationStatus,
|
||||
})
|
||||
}); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("write diagnostics run report: %w", err))
|
||||
}
|
||||
if err := writeOutputFiles(runOutputDir, output.OutputFiles); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, err)
|
||||
}
|
||||
if err := runDir.ApplyRetention(diagnostics.RetentionDecisionInput{
|
||||
RetentionMode: cfg.Diagnostics.Retention,
|
||||
RunSucceeded: true,
|
||||
HasWarnings: len(output.Warnings) > 0,
|
||||
if err := writeDiagnostics(runDir, func() error {
|
||||
return runDir.ApplyRetention(diagnostics.RetentionDecisionInput{
|
||||
RetentionMode: cfg.Diagnostics.Retention,
|
||||
RunSucceeded: true,
|
||||
HasWarnings: len(output.Warnings) > 0,
|
||||
})
|
||||
}); err != nil {
|
||||
return failPipelineCommand(stderr, runDir, cfg.Diagnostics.Retention, fmt.Errorf("apply diagnostics retention: %w", err))
|
||||
}
|
||||
@@ -327,6 +339,13 @@ func failPipelineCommand(stderr io.Writer, runDir *diagnostics.RunDirectory, ret
|
||||
return 1
|
||||
}
|
||||
|
||||
func writeDiagnostics(runDir *diagnostics.RunDirectory, write func() error) error {
|
||||
if runDir == nil {
|
||||
return nil
|
||||
}
|
||||
return write()
|
||||
}
|
||||
|
||||
func configSource(configPath string) string {
|
||||
if strings.TrimSpace(configPath) != "" {
|
||||
return "flag"
|
||||
|
||||
@@ -2148,6 +2148,29 @@ func TestRunPipelineWritesDiagnosticsArtifactsOnSuccess(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunPipelineSkipsDiagnosticsWhenWorkspaceDiagnosticsDisabled(t *testing.T) {
|
||||
workspaceDir := filepath.Join(t.TempDir(), "workspace")
|
||||
outputDir := t.TempDir()
|
||||
configPath := writeTestConfig(t, mvpConfigYAMLWithWorkspaceDiagnosticsDisabled("dnd-session", workspaceDir))
|
||||
inputPath := writeSeriatimInput(t)
|
||||
var stdout bytes.Buffer
|
||||
var stderr bytes.Buffer
|
||||
|
||||
code := RunWithOptions([]string{"run", "dnd-session", "--config", configPath, "--input", inputPath, "--output-dir", outputDir}, &stdout, &stderr, Options{
|
||||
LLMClientFactory: fakeLLMFactory(newFakeRunLLMClient(false), nil),
|
||||
})
|
||||
|
||||
if code != 0 {
|
||||
t.Fatalf("RunWithOptions() code = %d, stderr=%q", code, stderr.String())
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(workspaceDir, "diagnostics")); !os.IsNotExist(err) {
|
||||
t.Fatalf("workspace diagnostics dir stat err = %v, want not exist", err)
|
||||
}
|
||||
if entries := childDirs(t, outputDir); len(entries) != 1 {
|
||||
t.Fatalf("output run dirs = %v, want one run dir", entries)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunPipelineWritesErrorLogAfterDiagnosticsCreation(t *testing.T) {
|
||||
diagnosticsDir := t.TempDir()
|
||||
configPath := writeTestConfig(t, mvpConfigYAMLWithDiagnostics("dnd-session", diagnosticsDir, "always"))
|
||||
@@ -2732,6 +2755,21 @@ pipelines:
|
||||
`
|
||||
}
|
||||
|
||||
func mvpConfigYAMLWithWorkspaceDiagnosticsDisabled(pipelineID, workspaceDir string) string {
|
||||
return `version: 2
|
||||
workspace:
|
||||
directory: ` + workspaceDir + `
|
||||
diagnostics:
|
||||
enabled: false
|
||||
pipelines:
|
||||
` + pipelineID + `:
|
||||
input: seriatim
|
||||
artifacts:
|
||||
spells:
|
||||
extract: dnd/spells
|
||||
`
|
||||
}
|
||||
|
||||
func writeSeriatimInput(t *testing.T) string {
|
||||
t.Helper()
|
||||
return writeFile(t, "source.json", `{
|
||||
|
||||
Reference in New Issue
Block a user