Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
43eee4d
add new register custom code command
idbentley Sep 23, 2025
7f40e38
add commands for registercustomcode
idbentley Sep 23, 2025
baeb1c9
pass sufficient context to support generation
idbentley Sep 24, 2025
bd331df
feat: implement register custom code functionality
Sep 26, 2025
a245aa6
removed theirs
Sep 29, 2025
2cf8acc
implemented new workflow
Sep 29, 2025
a14a325
update registercustomcode to run generation in a manner more consiste…
idbentley Sep 29, 2025
b386b96
use object oriented interface to workflow file
idbentley Sep 29, 2025
bf1d042
remove pause command, and update generation so applying custom code i…
idbentley Sep 29, 2025
fe95a30
don't fetch new build
idbentley Sep 29, 2025
7c5d20f
added compilation and linting to registercustomcode
Oct 1, 2025
774412a
iter
idbentley Oct 1, 2025
bd1fe40
improved output
idbentley Oct 1, 2025
4934fb4
back out commit upon fialure
idbentley Oct 1, 2025
54c9e97
cleanup
idbentley Oct 1, 2025
9ad5928
disabled versioning
Oct 7, 2025
6921d37
iter
idbentley Oct 3, 2025
1ccd71e
remove unused resolve flag
idbentley Oct 7, 2025
7d4784b
skip version
idbentley Oct 6, 2025
a8836fb
introduce hash
idbentley Oct 7, 2025
1bec3c1
support multi target workflows
idbentley Oct 8, 2025
5f4099f
fix command.go
idbentley Oct 8, 2025
fb00e40
fix multi-build
idbentley Oct 8, 2025
6b307e6
cleanup
idbentley Oct 9, 2025
7a94057
New conflict resolution flow
Oct 9, 2025
518f786
fixes
Oct 10, 2025
3cc0d05
cleanup and prevent common issues
idbentley Oct 10, 2025
40895bb
reintroduce accidental deletion
idbentley Oct 10, 2025
25f4dd1
Saving patches to .diff file instead of gen.lock
Oct 23, 2025
159d06c
Integration test for perfect custom code scenario
Oct 23, 2025
d7de42e
Fixed patch deletion when no custom code is found + integration tests…
Oct 24, 2025
1dc7bcd
test improvement
Oct 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 174 additions & 0 deletions cmd/customcode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
package cmd

import (
"context"
"fmt"

"github.com/speakeasy-api/speakeasy/internal/charm/styles"
"github.com/speakeasy-api/speakeasy/internal/utils"
"github.com/speakeasy-api/speakeasy/internal/model"
"github.com/speakeasy-api/speakeasy/internal/model/flag"
"github.com/speakeasy-api/speakeasy/internal/registercustomcode"
"github.com/speakeasy-api/speakeasy/internal/log"
"github.com/speakeasy-api/speakeasy/internal/env"

"github.com/speakeasy-api/speakeasy/internal/run"
"go.uber.org/zap"
)

type RegisterCustomCodeFlags struct {
Show bool `json:"show"`
Resolve bool `json:"resolve"`
Apply bool `json:"apply-only"`
ApplyReverse bool `json:"apply-reverse"`
LatestHash bool `json:"latest-hash"`
InstallationURL string `json:"installationURL"`
InstallationURLs map[string]string `json:"installationURLs"`
Repo string `json:"repo"`
RepoSubdir string `json:"repo-subdir"`
RepoSubdirs map[string]string `json:"repo-subdirs"`
SkipVersioning bool `json:"skip-versioning"`
Output string `json:"output"`
SetVersion string `json:"set-version"`

}

var registerCustomCodeCmd = &model.ExecutableCommand[RegisterCustomCodeFlags]{
Usage: "customcode",
Short: "Register custom code with the OpenAPI generation system.",
Long: `Register custom code with the OpenAPI generation system.`,
Run: registerCustomCode,
Flags: []flag.Flag{
flag.BooleanFlag{
Name: "show",
Shorthand: "s",
Description: "show custom code patches",
},
flag.BooleanFlag{
Name: "resolve",
Description: "enter conflict resolution mode after a failed generation",
},
flag.BooleanFlag{
Name: "apply-only",
Shorthand: "a",
Description: "apply existing custom code patches without running generation",
},
flag.BooleanFlag{
Name: "latest-hash",
Description: "show the latest commit hash from gen.lock that contains custom code changes",
},
flag.StringFlag{
Name: "installationURL",
Shorthand: "i",
Description: "the language specific installation URL for installation instructions if the SDK is not published to a package manager",
},
flag.MapFlag{
Name: "installationURLs",
Description: "a map from target ID to installation URL for installation instructions if the SDK is not published to a package manager",
},
flag.StringFlag{
Name: "repo",
Shorthand: "r",
Description: "the repository URL for the SDK, if the published (-p) flag isn't used this will be used to generate installation instructions",
},
flag.EnumFlag{
Name: "output",
Shorthand: "o",
Description: "What to output while running",
AllowedValues: []string{"summary", "mermaid", "console"},
DefaultValue: "summary",
},
},
}

func registerCustomCode(ctx context.Context, flags RegisterCustomCodeFlags) error {
logger := log.From(ctx).With(zap.String("method", "RegisterCustomCode"))

// If --show flag is provided, show existing customcode
if flags.Show {
wf, _, err := utils.GetWorkflowAndDir()
if err != nil {
return fmt.Errorf("Could not find workflow file")
}
var allErrors []error
for targetName, target := range wf.Targets {
logger.Info("Showing target", zap.String("target_name", targetName))
if err := registercustomcode.ShowCustomCodePatch(ctx, target); err != nil {
allErrors = append(allErrors, fmt.Errorf("target %s: %w", targetName, err))
}
}
if len(allErrors) > 0 {
return fmt.Errorf("errors occurred: %v", allErrors)
}
return nil
}

// If --resolve flag is provided, enter conflict resolution mode
if flags.Resolve {
return registercustomcode.ResolveCustomCodeConflicts(ctx)
}

// If --apply-only flag is provided, only apply existing patches
if flags.Apply {
wf, _, err := utils.GetWorkflowAndDir()
if err != nil {
return fmt.Errorf("Could not find workflow file")
}
for targetName, target := range wf.Targets {
fmt.Println("Applying target ", targetName)
registercustomcode.ApplyCustomCodePatch(ctx, target)
}
return nil
}

// If --latest-hash flag is provided, show the commit hash from gen.lock
if flags.LatestHash {
return registercustomcode.ShowLatestCommitHash(ctx)
}

// Call the registercustomcode functionality
return registercustomcode.RegisterCustomCode(ctx, func(targetName string) error {
opts := []run.Opt{
run.WithTarget(targetName),
run.WithRepo(flags.Repo),
run.WithRepoSubDirs(flags.RepoSubdirs),
run.WithInstallationURLs(flags.InstallationURLs),
run.WithSkipVersioning(true),
run.WithSkipApplyCustomCode(),
}
workflow, err := run.NewWorkflow(
ctx,
opts...,
)
defer func() {
// we should leave temp directories for debugging if run fails
if env.IsGithubAction() {
workflow.Cleanup()
}
}()

switch flags.Output {
case "summary":
err = workflow.RunWithVisualization(ctx)
if err != nil {
return err
}
case "mermaid":
err = workflow.Run(ctx)
workflow.RootStep.Finalize(err == nil)
mermaid, err := workflow.RootStep.ToMermaidDiagram()
if err != nil {
return err
}
log.From(ctx).Println("\n" + styles.MakeSection("Mermaid diagram of workflow", mermaid, styles.Colors.Blue))
case "console":
err = workflow.Run(ctx)
// workflow.RootStep.Finalize(err == nil)
if err != nil {
return err
}
}
return nil
}, )

}
4 changes: 4 additions & 0 deletions cmd/quickstart.go
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ func retryWithSampleSpec(ctx context.Context, workflowFile *workflow.Workflow, i
run.WithTarget(initialTarget),
run.WithShouldCompile(!skipCompile),
)
if err != nil {
return false, err
}
wf.FromQuickstart = true

// Execute the workflow based on output mode
switch output {
Expand Down
3 changes: 3 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ func Init(version, artifactArch string) {

addCommand(rootCmd, AskCmd)
addCommand(rootCmd, reproCmd)
addCommand(rootCmd, registerCustomCodeCmd)
pullInit()
// addCommand(rootCmd, pullCmd)
}

func addCommand(cmd *cobra.Command, command model.Command) {
Expand All @@ -110,6 +112,7 @@ func addCommand(cmd *cobra.Command, command model.Command) {
func CmdForTest(version, artifactArch string) *cobra.Command {
setupRootCmd(version, artifactArch)


return rootCmd
}

Expand Down
13 changes: 13 additions & 0 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ type RunFlags struct {
SkipTesting bool `json:"skip-testing"`
SkipVersioning bool `json:"skip-versioning"`
SkipUploadSpec bool `json:"skip-upload-spec"`
SkipCustomCode bool `json:"skip-custom-code"`
FrozenWorkflowLock bool `json:"frozen-workflow-lockfile"`
Force bool `json:"force"`
Output string `json:"output"`
Expand Down Expand Up @@ -125,6 +126,10 @@ var runCmd = &model.ExecutableCommand[RunFlags]{
Name: "skip-upload-spec",
Description: "skip uploading the spec to the registry",
},
flag.BooleanFlag{
Name: "skip-custom-code",
Description: "skip applying custom code patches during generation",
},
flag.BooleanFlag{
Name: "frozen-workflow-lockfile",
Description: "executes using the stored inputs from the workflow.lock, such that no OAS change occurs",
Expand Down Expand Up @@ -355,6 +360,10 @@ func runNonInteractive(ctx context.Context, flags RunFlags) error {
run.WithSkipCleanup(), // The studio won't work if we clean up before it launches
}

if flags.SkipCustomCode {
opts = append(opts, run.WithSkipApplyCustomCode())
}

if flags.Minimal {
opts = append(opts, minimalOpts...)
}
Expand Down Expand Up @@ -413,6 +422,10 @@ func runInteractive(ctx context.Context, flags RunFlags) error {
run.WithSkipCleanup(), // The studio won't work if we clean up before it launches
}

if flags.SkipCustomCode {
opts = append(opts, run.WithSkipApplyCustomCode())
}

if flags.Minimal {
opts = append(opts, minimalOpts...)
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ replace github.com/pb33f/doctor => github.com/speakeasy-api/doctor v0.20.0-fixva

replace github.com/pb33f/libopenapi => github.com/speakeasy-api/libopenapi v0.21.9-fixhiddencomps-fixed

replace github.com/speakeasy-api/openapi-generation/v2 => ../openapi-generation

require (
github.com/AlekSi/pointer v1.2.0
github.com/KimMachineGun/automemlimit v0.7.1
Expand Down
Loading
Loading