diff --git a/core/core.go b/core/core.go index c2ec2d655..5556dc0b9 100644 --- a/core/core.go +++ b/core/core.go @@ -115,6 +115,10 @@ func GenerateBuildPlan(app *app.App, env *app.Environment, options *GenerateBuil return &BuildResult{Success: false, Logs: logger.Logs} } + if err := addAdditionalMiseToolsToPackages(ctx, ctx.GetMiseStepBuilder(), resolvedPackages); err != nil { + logger.LogWarn("Failed to include additional tools from mise.toml in package output: %s", err.Error()) + } + if providerToUse != nil { providerToUse.CleansePlan(buildPlan) } @@ -311,3 +315,46 @@ func getProviders(ctx *generate.GenerateContext, config *c.Config) (providers.Pr return providerToUse, detectedProvider } + +// Adds app-local mise.toml tools to the package output table. +func addAdditionalMiseToolsToPackages( + ctx *generate.GenerateContext, + miseStep *generate.MiseStepBuilder, + resolvedPackages map[string]*resolver.ResolvedPackage, +) error { + misePackages, err := miseStep.GetMisePackageVersionsCached(ctx) + if err != nil { + return err + } + + addAdditionalMiseToolsFromPackages(misePackages, resolvedPackages) + return nil +} + +// Merges non-provider mise.toml tools into resolved package rows. +func addAdditionalMiseToolsFromPackages( + misePackages map[string]*generate.MisePackageInfo, + resolvedPackages map[string]*resolver.ResolvedPackage, +) { + for _, name := range slices.Sorted(maps.Keys(misePackages)) { + pkg := misePackages[name] + if pkg == nil || pkg.Source != "mise.toml" { + continue + } + if _, exists := resolvedPackages[name]; exists { + continue + } + + version := pkg.Version + var requestedVersion *string + if pkg.RequestedVersion != "" { + requestedVersion = &pkg.RequestedVersion + } + resolvedPackages[name] = &resolver.ResolvedPackage{ + Name: name, + RequestedVersion: requestedVersion, + ResolvedVersion: &version, + Source: "mise.toml", + } + } +} diff --git a/core/core_test.go b/core/core_test.go index d5c73a32e..cd3217b8f 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -7,7 +7,9 @@ import ( "github.com/gkampitakis/go-snaps/snaps" "github.com/railwayapp/railpack/core/app" + "github.com/railwayapp/railpack/core/generate" "github.com/railwayapp/railpack/core/logger" + "github.com/railwayapp/railpack/core/resolver" "github.com/stretchr/testify/require" ) @@ -105,3 +107,42 @@ func TestGenerateBuildPlan_DockerignoreMetadata(t *testing.T) { require.NotNil(t, buildResult.Metadata) require.Equal(t, "true", buildResult.Metadata["dockerIgnore"]) } + +func TestAddAdditionalMiseToolsToPackages(t *testing.T) { + nodeVersion := "24.0.0" + bunVersion := "1.3.10" + + // Simulate what provider already resolved (node + bun already in table) + resolvedPackages := map[string]*resolver.ResolvedPackage{ + "node": {Name: "node", ResolvedVersion: &nodeVersion, Source: "mise.toml"}, + "bun": {Name: "bun", ResolvedVersion: &bunVersion, Source: "mise.toml"}, + } + + // Simulate what mise returns from app mise.toml + misePackages := map[string]*generate.MisePackageInfo{ + "node": {Version: "24.0.0", RequestedVersion: "24", Source: "mise.toml"}, + "bun": {Version: "1.3.10", RequestedVersion: "latest", Source: "mise.toml"}, + "python": {Version: "3.13.0", RequestedVersion: "3.13", Source: "mise.toml"}, + "go": {Version: "1.23.0", RequestedVersion: "1.23", Source: "mise.toml"}, + } + + addAdditionalMiseToolsFromPackages(misePackages, resolvedPackages) + + // node and bun should remain unchanged + require.Equal(t, "mise.toml", resolvedPackages["node"].Source) + require.Equal(t, "mise.toml", resolvedPackages["bun"].Source) + + // python and go should be added with requested versions from app mise.toml + require.Contains(t, resolvedPackages, "python") + require.Equal(t, "mise.toml", resolvedPackages["python"].Source) + require.Equal(t, "3.13.0", *resolvedPackages["python"].ResolvedVersion) + require.Equal(t, "3.13", *resolvedPackages["python"].RequestedVersion) + + require.Contains(t, resolvedPackages, "go") + require.Equal(t, "mise.toml", resolvedPackages["go"].Source) + require.Equal(t, "1.23.0", *resolvedPackages["go"].ResolvedVersion) + require.Equal(t, "1.23", *resolvedPackages["go"].RequestedVersion) + + // total should now be 4 + require.Len(t, resolvedPackages, 4) +} diff --git a/core/generate/mise_step_builder.go b/core/generate/mise_step_builder.go index 46ed57887..84cf6f65f 100644 --- a/core/generate/mise_step_builder.go +++ b/core/generate/mise_step_builder.go @@ -26,8 +26,9 @@ var ( // represents a app-local mise package type MisePackageInfo struct { - Version string - Source string + Version string + RequestedVersion string + Source string } // MiseListSource represents the source of a mise tool installation @@ -61,6 +62,7 @@ type MiseStepBuilder struct { Variables map[string]string app *a.App env *a.Environment + cachedMisePackages map[string]*MisePackageInfo } func (c *GenerateContext) NewMiseStepBuilder(displayName string) *MiseStepBuilder { @@ -161,7 +163,8 @@ func (b *MiseStepBuilder) GetMisePackageVersions(ctx *GenerateContext) (map[stri if len(appDirTools) > 0 { firstTool := appDirTools[0] packages[toolName] = &MisePackageInfo{ - Version: firstTool.Version, + Version: firstTool.Version, + RequestedVersion: firstTool.RequestedVersion, // include the source so we can surface this to the user so they understand where the package version came from Source: firstTool.Source.Type, } @@ -171,9 +174,24 @@ func (b *MiseStepBuilder) GetMisePackageVersions(ctx *GenerateContext) (map[stri return packages, nil } +// Reuses the mise package list to avoid duplicate mise invocations. +func (b *MiseStepBuilder) GetMisePackageVersionsCached(ctx *GenerateContext) (map[string]*MisePackageInfo, error) { + if b.cachedMisePackages != nil { + return b.cachedMisePackages, nil + } + + misePackages, err := b.GetMisePackageVersions(ctx) + if err != nil { + return nil, err + } + + b.cachedMisePackages = misePackages + return misePackages, nil +} + // Use mise-specified versions for all packages in the input list func (b *MiseStepBuilder) UseMiseVersions(ctx *GenerateContext, packages []string) { - miseVersions, err := b.GetMisePackageVersions(ctx) + miseVersions, err := b.GetMisePackageVersionsCached(ctx) if err != nil { ctx.Logger.LogWarn("Failed to get package versions from mise: %s", err.Error()) return