(projectInfo pulumiProjectInfo, dir, monitorAddr, engineAddr string, logWriter io.Writer)
| 637 | } |
| 638 | |
| 639 | func runUserProgramTo(projectInfo pulumiProjectInfo, dir, monitorAddr, engineAddr string, logWriter io.Writer) error { |
| 640 | env := append(os.Environ(), |
| 641 | "PULUMI_MONITOR="+monitorAddr, |
| 642 | "PULUMI_ENGINE="+engineAddr, |
| 643 | "PULUMI_PROJECT="+projectInfo.Name, |
| 644 | "PULUMI_STACK="+projectInfo.Stack, |
| 645 | "PULUMI_ROOT_DIRECTORY="+dir, |
| 646 | "PULUMI_DRY_RUN=true", |
| 647 | "PULUMI_PARALLEL=1", |
| 648 | "PULUMI_ORGANIZATION=cloudcent", |
| 649 | // Prevent Docker SDK from connecting to a real daemon — point it at |
| 650 | // a non-existent socket so docker.Image fails fast instead of hanging. |
| 651 | "DOCKER_HOST=tcp://127.0.0.1:0", |
| 652 | ) |
| 653 | if len(projectInfo.Config) > 0 { |
| 654 | configJSON, err := json.Marshal(projectInfo.Config) |
| 655 | if err != nil { |
| 656 | return fmt.Errorf("marshaling Pulumi config: %w", err) |
| 657 | } |
| 658 | env = append(env, "PULUMI_CONFIG="+string(configJSON)) |
| 659 | } |
| 660 | |
| 661 | var c *exec.Cmd |
| 662 | switch projectInfo.Runtime { |
| 663 | case "go": |
| 664 | c = exec.Command("go", "run", ".") |
| 665 | case "nodejs", "node": |
| 666 | // Use the Pulumi Node.js runner (node_modules/@pulumi/pulumi/cmd/run/index.js) |
| 667 | // instead of ts-node directly. The runner calls settings.configure() with the |
| 668 | // monitor/engine addresses before executing user code — running ts-node directly |
| 669 | // leaves the monitor unset, causing resource/invoke calls to fail. |
| 670 | nodeRunner := filepath.Join(dir, "node_modules", "@pulumi", "pulumi", "cmd", "run", "index.js") |
| 671 | // Resolve the TypeScript entry point. The runner needs an explicit .ts file |
| 672 | // (not ".") so it can register ts-node before attempting to load the module. |
| 673 | // Without this, it tries require(".") → no index.js → fails before ts-node runs. |
| 674 | tsEntry, err := resolveNodeEntry(dir) |
| 675 | if err != nil { |
| 676 | return err |
| 677 | } |
| 678 | c = exec.Command("node", nodeRunner, |
| 679 | "--monitor", monitorAddr, |
| 680 | "--engine", engineAddr, |
| 681 | "--project", projectInfo.Name, |
| 682 | "--stack", projectInfo.Stack, |
| 683 | "--parallel", "1", |
| 684 | "--dry-run", "true", |
| 685 | "--organization", "cloudcent", |
| 686 | "--pwd", dir, |
| 687 | tsEntry, |
| 688 | ) |
| 689 | // Tell the runner this is a TypeScript project so it registers ts-node. |
| 690 | env = append(env, "PULUMI_NODEJS_TYPESCRIPT=true") |
| 691 | case "python": |
| 692 | venvDir := pythonVenvDir(projectInfo.Virtualenv) |
| 693 | // pulumi-language-python-exec is a system binary (installed with the Pulumi CLI, |
| 694 | // not the Python SDK). It calls pulumi.runtime.configure(settings) before running |
| 695 | // user code, which wires up the monitor/engine gRPC stubs. Running __main__.py |
| 696 | // directly skips this and leaves monitor=None, causing invoke calls to crash. |
no test coverage detected