Skip to content

Commit

Permalink
chore: cleanup run code (#1064)
Browse files Browse the repository at this point in the history
Should be no functional change, just a code cleanup
  • Loading branch information
chase-crumbaugh authored Nov 5, 2024
1 parent 9db21e7 commit a1b1ef3
Show file tree
Hide file tree
Showing 5 changed files with 687 additions and 542 deletions.
91 changes: 91 additions & 0 deletions internal/run/frozenSource.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package run

import (
"context"
"fmt"
"github.com/speakeasy-api/sdk-gen-config/workflow"
"github.com/speakeasy-api/speakeasy/internal/workflowTracking"
"github.com/speakeasy-api/speakeasy/registry"
)

type FrozenSource struct {
workflow *Workflow
parentStep *workflowTracking.WorkflowStep
sourceID string
}

var _ SourceStep = FrozenSource{}

func NewFrozenSource(w *Workflow, parentStep *workflowTracking.WorkflowStep, sourceID string) FrozenSource {
return FrozenSource{
workflow: w,
parentStep: parentStep,
sourceID: sourceID,
}
}

func (f FrozenSource) Do(ctx context.Context, _, _ string) (string, error) {
mergeStep := f.parentStep.NewSubstep("Download OAS from lockfile")

// Check lockfile exists, produce an error if not
if f.workflow.lockfileOld == nil {
return "", fmt.Errorf("workflow lacks a prior lock file: can't use this on first run")
}
lockSource, ok := f.workflow.lockfileOld.Sources[f.sourceID]
if !ok {
return "", fmt.Errorf("workflow lockfile lacks a reference to source %s: can't use this on first run", f.sourceID)
}
if !registry.IsRegistryEnabled(ctx) {
return "", fmt.Errorf("registry is not enabled for this workspace")
}
if lockSource.SourceBlobDigest == "" || lockSource.SourceRevisionDigest == "" || lockSource.SourceNamespace == "" {
return "", fmt.Errorf("invalid workflow lockfile: namespace = %s blobDigest = %s revisionDigest = %s", lockSource.SourceNamespace, lockSource.SourceBlobDigest, lockSource.SourceRevisionDigest)
}

var orgSlug, workspaceSlug, registryNamespace string
var err error

if isSingleRegistrySource(f.workflow.workflow.Sources[f.sourceID]) && f.workflow.workflow.Sources[f.sourceID].Registry == nil {
d := f.workflow.workflow.Sources[f.sourceID].Inputs[0]
registryBreakdown := workflow.ParseSpeakeasyRegistryReference(d.Location.Resolve())
if registryBreakdown == nil {
return "", fmt.Errorf("failed to parse speakeasy registry reference %s", d.Location)
}
orgSlug = registryBreakdown.OrganizationSlug
workspaceSlug = registryBreakdown.WorkspaceSlug
// odd edge case: we are not migrating the registry location when we're a single registry source.
// Unfortunately can't just fix here as it needs a migration
registryNamespace = lockSource.SourceNamespace
} else if !isSingleRegistrySource(f.workflow.workflow.Sources[f.sourceID]) && f.workflow.workflow.Sources[f.sourceID].Registry == nil {
return "", fmt.Errorf("invalid workflow lockfile: no registry location found for source %s", f.sourceID)
} else if f.workflow.workflow.Sources[f.sourceID].Registry != nil {
orgSlug, workspaceSlug, registryNamespace, _, err = f.workflow.workflow.Sources[f.sourceID].Registry.ParseRegistryLocation()
if err != nil {
return "", fmt.Errorf("error parsing registry location %s: %w", string(f.workflow.workflow.Sources[f.sourceID].Registry.Location), err)
}
}

if lockSource.SourceNamespace != registryNamespace {
return "", fmt.Errorf("invalid workflow lockfile: namespace %s != %s", lockSource.SourceNamespace, registryNamespace)
}

registryLocation := fmt.Sprintf(
"%s/%s/%s/%s@%s",
"registry.speakeasyapi.dev",
orgSlug,
workspaceSlug,
lockSource.SourceNamespace,
lockSource.SourceRevisionDigest,
)

d := workflow.Document{Location: workflow.LocationString(registryLocation)}
docPath, err := registry.ResolveSpeakeasyRegistryBundle(ctx, d, workflow.GetTempDir())

if err != nil {
return "", fmt.Errorf("error resolving registry bundle from %s: %w", registryLocation, err)
}

mergeStep.Succeed()

return docPath.LocalFilePath, nil
}
73 changes: 73 additions & 0 deletions internal/run/merge.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package run

import (
"context"
"fmt"
"github.com/speakeasy-api/sdk-gen-config/workflow"
"github.com/speakeasy-api/speakeasy/internal/log"
"github.com/speakeasy-api/speakeasy/internal/schemas"
"github.com/speakeasy-api/speakeasy/internal/workflowTracking"
"github.com/speakeasy-api/speakeasy/pkg/merge"
"os"
"path/filepath"
)

type Merge struct {
workflow *Workflow
parentStep *workflowTracking.WorkflowStep
source workflow.Source
ruleset string
}

var _ SourceStep = Merge{}

func NewMerge(w *Workflow, parentStep *workflowTracking.WorkflowStep, source workflow.Source, ruleset string) Merge {
return Merge{
workflow: w,
parentStep: parentStep,
source: source,
ruleset: ruleset,
}
}

func (m Merge) Do(ctx context.Context, _, outputLocation string) (string, error) {
mergeStep := m.parentStep.NewSubstep("Merge Documents")

mergeLocation := m.source.GetTempMergeLocation()
if len(m.source.Overlays) == 0 {
mergeLocation = outputLocation
}

log.From(ctx).Infof("Merging %d schemas into %s...", len(m.source.Inputs), mergeLocation)

inSchemas := []string{}
for _, input := range m.source.Inputs {
resolvedPath, err := schemas.ResolveDocument(ctx, input, nil, mergeStep)
if err != nil {
return "", err
}
inSchemas = append(inSchemas, resolvedPath)
}

mergeStep.NewSubstep(fmt.Sprintf("Merge %d documents", len(m.source.Inputs)))

if err := mergeDocuments(ctx, inSchemas, mergeLocation, m.ruleset, m.workflow.ProjectDir, m.workflow.SkipGenerateLintReport); err != nil {
return "", err
}

return mergeLocation, nil
}

func mergeDocuments(ctx context.Context, inSchemas []string, outFile, defaultRuleset, workingDir string, skipGenerateLintReport bool) error {
if err := os.MkdirAll(filepath.Dir(outFile), os.ModePerm); err != nil {
return err
}

if err := merge.MergeOpenAPIDocuments(ctx, inSchemas, outFile, defaultRuleset, workingDir, skipGenerateLintReport); err != nil {
return err
}

log.From(ctx).Printf("Successfully merged %d schemas into %s", len(inSchemas), outFile)

return nil
}
135 changes: 135 additions & 0 deletions internal/run/overlay.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package run

import (
"context"
"fmt"
"github.com/speakeasy-api/sdk-gen-config/workflow"
"github.com/speakeasy-api/speakeasy/internal/defaultcodesamples"
"github.com/speakeasy-api/speakeasy/internal/log"
"github.com/speakeasy-api/speakeasy/internal/schemas"
"github.com/speakeasy-api/speakeasy/internal/utils"
"github.com/speakeasy-api/speakeasy/internal/workflowTracking"
"github.com/speakeasy-api/speakeasy/pkg/overlay"
"io"
"os"
"path/filepath"
"strings"
)

type Overlay struct {
workflow *Workflow
parentStep *workflowTracking.WorkflowStep
source workflow.Source
outputLocation string
ruleset string
}

var _ SourceStep = Overlay{}

func NewOverlay(w *Workflow, parentStep *workflowTracking.WorkflowStep, source workflow.Source, outputLocation, ruleset string) Overlay {
return Overlay{
workflow: w,
parentStep: parentStep,
source: source,
outputLocation: outputLocation,
ruleset: ruleset,
}
}

func (o Overlay) Do(ctx context.Context, inputPath, outputPath string) (string, error) {
overlayStep := o.parentStep.NewSubstep("Applying Overlays")

overlayLocation := outputPath

log.From(ctx).Infof("Applying %d overlays into %s...", len(o.source.Overlays), overlayLocation)

var err error
var overlaySchemas []string
for _, overlay := range o.source.Overlays {
overlayFilePath := ""
if overlay.Document != nil {
overlayFilePath, err = schemas.ResolveDocument(ctx, *overlay.Document, nil, overlayStep)
if err != nil {
return "", err
}
} else if overlay.FallbackCodeSamples != nil {
// Make temp file for the overlay output
overlayFilePath = filepath.Join(workflow.GetTempDir(), fmt.Sprintf("fallback_code_samples_overlay_%s.yaml", randStringBytes(10)))
if err := os.MkdirAll(filepath.Dir(overlayFilePath), 0o755); err != nil {
return "", err
}

err = defaultcodesamples.DefaultCodeSamples(ctx, defaultcodesamples.DefaultCodeSamplesFlags{
SchemaPath: inputPath,
Language: overlay.FallbackCodeSamples.FallbackCodeSamplesLanguage,
Out: overlayFilePath,
})
if err != nil {
log.From(ctx).Errorf("failed to generate default code samples: %s", err.Error())
return "", err
}
}

overlaySchemas = append(overlaySchemas, overlayFilePath)
}

overlayStep.NewSubstep(fmt.Sprintf("Apply %d overlay(s)", len(o.source.Overlays)))

if err := overlayDocument(ctx, inputPath, overlaySchemas, overlayLocation); err != nil {
return "", err
}

overlayStep.Succeed()
return overlayLocation, nil
}

func overlayDocument(ctx context.Context, schema string, overlayFiles []string, outFile string) error {
currentBase := schema
if err := os.MkdirAll(workflow.GetTempDir(), os.ModePerm); err != nil {
return err
}

for _, overlayFile := range overlayFiles {
applyPath := getTempApplyPath(outFile)

tempOutFile, err := os.Create(applyPath)
if err != nil {
return err
}

// YamlOut param needs to be based on the eventual output file
if _, err := overlay.Apply(currentBase, overlayFile, utils.HasYAMLExt(outFile), tempOutFile, false, false); err != nil && !strings.Contains(err.Error(), "overlay must define at least one action") {
return err
}

if err := tempOutFile.Close(); err != nil {
return err
}

currentBase = applyPath
}

if err := os.MkdirAll(filepath.Dir(outFile), os.ModePerm); err != nil {
return err
}

finalTempFile, err := os.Open(currentBase)
if err != nil {
return err
}
defer finalTempFile.Close()

outFileWriter, err := os.Create(outFile)
if err != nil {
return err
}
defer outFileWriter.Close()

if _, err := io.Copy(outFileWriter, finalTempFile); err != nil {
return err
}

log.From(ctx).Successf("Successfully applied %d overlays into %s", len(overlayFiles), outFile)

return nil
}
Loading

0 comments on commit a1b1ef3

Please sign in to comment.