mirror of https://github.com/pulumi/pulumi.git
Fix codepaths computation when working dir is nested relative to package.json (#15601)
# Description When using `tsc` to precompile typescript in a monorepo, we need to work relative to the location of `package.json`, not where the pulumi program lives (which is usually nested further down). ## Checklist - [x] I have run `make tidy` to update any new dependencies - [x] I have run `make lint` to verify my code passes the lint check - [x] I have formatted my code using `gofumpt` <!--- Please provide details if the checkbox below is to be left unchecked. --> - [ ] I have added tests that prove my fix is effective or that my feature works <!--- User-facing changes require a CHANGELOG entry. --> - [ ] I have run `make changelog` and committed the `changelog/pending/<file>` documenting my change <!-- If the change(s) in this PR is a modification of an existing call to the Pulumi Cloud, then the service should honor older versions of the CLI where this change would not exist. You must then bump the API version in /pkg/backend/httpstate/client/api.go, as well as add it to the service. --> - [ ] Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version <!-- @Pulumi employees: If yes, you must submit corresponding changes in the service repo. -->
This commit is contained in:
parent
d7c4025734
commit
5a19d754d7
changelog/pending
sdk/nodejs
npm
runtime/closure
tests/runtime
tsconfig.jsontests/integration
integration_nodejs_test.go
nodejs
codepaths-tsc
codepaths-workspaces-tsc
|
@ -0,0 +1,4 @@
|
|||
changes:
|
||||
- type: fix
|
||||
scope: sdk/nodejs
|
||||
description: Fix codepaths computation when working dir is nested relative to package.json
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "a-workspace-example-tsc",
|
||||
"description": "A project that uses npm and yarn workspaces.",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"project/"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "some-package",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/* eslint-disable header/header */
|
||||
// This is the pulumi program
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "project",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -25,10 +25,22 @@ import (
|
|||
var ErrNotInWorkspace = errors.New("not in a workspace")
|
||||
|
||||
// FindWorkspaceRoot determines if we are in a yarn/npm workspace setup and
|
||||
// returns the root directory of the workspace. If the programDirectory is
|
||||
// returns the root directory of the workspace. If the startingPath is
|
||||
// not in a workspace, it returns ErrNotInWorkspace.
|
||||
func FindWorkspaceRoot(programDirectory string) (string, error) {
|
||||
currentDir := filepath.Dir(programDirectory)
|
||||
func FindWorkspaceRoot(startingPath string) (string, error) {
|
||||
stat, err := os.Stat(startingPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if !stat.IsDir() {
|
||||
startingPath = filepath.Dir(startingPath)
|
||||
}
|
||||
// We start at the location of the first `package.json` we find.
|
||||
packageJSONDir, err := searchup(startingPath, "package.json")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("did not find package.json in %s: %w", startingPath, err)
|
||||
}
|
||||
currentDir := packageJSONDir
|
||||
nextDir := filepath.Dir(currentDir)
|
||||
for currentDir != nextDir { // We're at the root when the nextDir is the same as the currentDir.
|
||||
p := filepath.Join(currentDir, "package.json")
|
||||
|
@ -52,15 +64,12 @@ func FindWorkspaceRoot(programDirectory string) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if paths != nil && slices.Contains(paths, filepath.Join(programDirectory, "package.json")) {
|
||||
if paths != nil && slices.Contains(paths, filepath.Join(packageJSONDir, "package.json")) {
|
||||
return currentDir, nil
|
||||
}
|
||||
}
|
||||
// None of the workspace globs matched the program directory, so we're
|
||||
// in the slightly weird situation where a parent directory has a
|
||||
// package.json with workspaces set up, but the program directory is
|
||||
// not part of this.
|
||||
return "", ErrNotInWorkspace
|
||||
currentDir = nextDir
|
||||
nextDir = filepath.Dir(currentDir)
|
||||
}
|
||||
return "", ErrNotInWorkspace
|
||||
}
|
||||
|
@ -104,3 +113,14 @@ func parseWorkspaces(p string) ([]string, error) {
|
|||
}
|
||||
return pkgExtended.Workspaces.Packages, nil
|
||||
}
|
||||
|
||||
func searchup(currentDir, fileToFind string) (string, error) {
|
||||
if _, err := os.Stat(filepath.Join(currentDir, fileToFind)); err == nil {
|
||||
return currentDir, nil
|
||||
}
|
||||
parentDir := filepath.Dir(currentDir)
|
||||
if currentDir == parentDir {
|
||||
return "", nil
|
||||
}
|
||||
return searchup(parentDir, fileToFind)
|
||||
}
|
||||
|
|
|
@ -45,3 +45,22 @@ func TestFindWorkspaceRootYarnExtended(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
require.Equal(t, filepath.Join("testdata", "workspace-extended"), root)
|
||||
}
|
||||
|
||||
func TestFindWorkspaceRootNested(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
root, err := FindWorkspaceRoot(filepath.Join("testdata", "workspace-nested", "project", "dist"))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, filepath.Join("testdata", "workspace-nested"), root)
|
||||
}
|
||||
|
||||
func TestFindWorkspaceRootFileArgument(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Use a file as the argument to FindWorkspaceRoot instead of a directory.
|
||||
root, err := FindWorkspaceRoot(filepath.Join("testdata", "workspace-nested", "project", "dist", "index.js"))
|
||||
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, filepath.Join("testdata", "workspace-nested"), root)
|
||||
}
|
||||
|
|
|
@ -182,12 +182,22 @@ function searchUp(currentDir: string, fileToFind: string): string | null {
|
|||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* findWorkspaceRoot detects if we are in a yarn/npm workspace setup, and
|
||||
* returns the root of the workspace. If we are not in a workspace setup, it
|
||||
* returns null.
|
||||
*/
|
||||
async function findWorkspaceRoot(programDirectory: string): Promise<string | null> {
|
||||
let currentDir = upath.dirname(programDirectory);
|
||||
export async function findWorkspaceRoot(startingPath: string): Promise<string | null> {
|
||||
const stat = fs.statSync(startingPath);
|
||||
if (!stat.isDirectory()) {
|
||||
startingPath = upath.dirname(startingPath);
|
||||
}
|
||||
const packageJSONDir = searchUp(startingPath, "package.json");
|
||||
if (packageJSONDir === null) {
|
||||
return null;
|
||||
}
|
||||
// We start at the location of the first `package.json` we find.
|
||||
let currentDir = packageJSONDir;
|
||||
let nextDir = upath.dirname(currentDir);
|
||||
while (currentDir !== nextDir) {
|
||||
const p = upath.join(currentDir, "package.json");
|
||||
|
@ -199,12 +209,13 @@ async function findWorkspaceRoot(programDirectory: string): Promise<string | nul
|
|||
const workspaces = parseWorkspaces(p);
|
||||
for (const workspace of workspaces) {
|
||||
const files = await pGlob(upath.join(currentDir, workspace, "package.json"));
|
||||
const normalized = upath.normalizeTrim(upath.join(programDirectory, "package.json"));
|
||||
const normalized = upath.normalizeTrim(upath.join(packageJSONDir, "package.json"));
|
||||
if (files.map((f) => upath.normalizeTrim(f)).includes(normalized)) {
|
||||
return currentDir;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
currentDir = nextDir;
|
||||
nextDir = upath.dirname(currentDir);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -234,10 +245,7 @@ async function allFoldersForPackages(
|
|||
// searching up from the current directory
|
||||
throw new ResourceError("Failed to find package.json.", logResource);
|
||||
}
|
||||
// Ensure workingDir is a relative path so we get relative paths in the
|
||||
// output. If we have absolute paths, AWS lambda might not find the
|
||||
// dependencies.
|
||||
workingDir = upath.relative(upath.resolve("."), workingDir);
|
||||
workingDir = upath.resolve(workingDir);
|
||||
|
||||
// This is the core starting point of the algorithm. We read the
|
||||
// package.json information for this project, and then we start by walking
|
||||
|
@ -252,7 +260,10 @@ async function allFoldersForPackages(
|
|||
}
|
||||
|
||||
// Find the workspace root, fallback to current working directory if we are not in a workspaces setup.
|
||||
let workspaceRoot = (await findWorkspaceRoot(upath.resolve("."))) || workingDir;
|
||||
let workspaceRoot = (await findWorkspaceRoot(workingDir)) || workingDir;
|
||||
// Ensure workingDir is a relative path so we get relative paths in the
|
||||
// output. If we have absolute paths, AWS lambda might not find the
|
||||
// dependencies.
|
||||
workspaceRoot = upath.relative(upath.resolve("."), workspaceRoot);
|
||||
|
||||
// Read package tree from the workspace root to ensure we can find all
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
// Copyright 2016-2022, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as assert from "assert";
|
||||
import * as path from "path";
|
||||
import { findWorkspaceRoot } from "../../runtime/closure/codePaths";
|
||||
|
||||
const testdata = (...p: string[]) => path.join(__dirname, "..", "..", "..", "tests", "runtime", "testdata", ...p);
|
||||
|
||||
describe("findWorkspaceRoot", () => {
|
||||
it("finds the root of a workspace", async () => {
|
||||
const root = await findWorkspaceRoot(testdata("workspace", "project"));
|
||||
assert.notStrictEqual(root, null);
|
||||
assert.strictEqual(root, testdata("workspace"));
|
||||
});
|
||||
|
||||
it("returns null if we are not in a workspace", async () => {
|
||||
const root = await findWorkspaceRoot(testdata("nested", "project"));
|
||||
assert.strictEqual(root, null);
|
||||
});
|
||||
|
||||
it("finds the root of a workspace when using yarn's extended declaration", async () => {
|
||||
const root = await findWorkspaceRoot(testdata("workspace-extended", "project"));
|
||||
assert.notStrictEqual(root, null);
|
||||
assert.strictEqual(root, testdata("workspace-extended"));
|
||||
});
|
||||
|
||||
it("finds the root of a workspace when in a nested directory", async () => {
|
||||
const root = await findWorkspaceRoot(testdata("workspace-nested", "project", "dist"));
|
||||
assert.notStrictEqual(root, null);
|
||||
assert.strictEqual(root, testdata("workspace-nested"));
|
||||
});
|
||||
|
||||
it("finds the root of a workspace passing a file as argument", async () => {
|
||||
const root = await findWorkspaceRoot(testdata("workspace-nested", "project", "dist", "index.js"));
|
||||
assert.notStrictEqual(root, null);
|
||||
assert.strictEqual(root, testdata("workspace-nested"));
|
||||
});
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "nested-project",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2016-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// This is where the pulumi program lives.
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"name": "a-workspace-example",
|
||||
"description": "A project that uses yarn workspaces using the extended configuration in package.json",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"packages/*",
|
||||
"project/"
|
||||
]
|
||||
}
|
||||
}
|
4
sdk/nodejs/tests/runtime/testdata/workspace-extended/packages/some-package/package.json
vendored
Normal file
4
sdk/nodejs/tests/runtime/testdata/workspace-extended/packages/some-package/package.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "some-package",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "project",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "a-workspace-example-tsc",
|
||||
"description": "A project that uses npm and yarn workspaces.",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"project/"
|
||||
]
|
||||
}
|
4
sdk/nodejs/tests/runtime/testdata/workspace-nested/packages/some-package/package.json
vendored
Normal file
4
sdk/nodejs/tests/runtime/testdata/workspace-nested/packages/some-package/package.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "some-package",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
/* eslint-disable header/header */
|
||||
// This is the pulumi program
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "project",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"name": "a-workspace-example",
|
||||
"description": "A project that uses npm and yarn workspaces.",
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"project/"
|
||||
]
|
||||
}
|
4
sdk/nodejs/tests/runtime/testdata/workspace/packages/some-package/package.json
vendored
Normal file
4
sdk/nodejs/tests/runtime/testdata/workspace/packages/some-package/package.json
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "some-package",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "project",
|
||||
"version": "1.0.0"
|
||||
}
|
|
@ -100,6 +100,7 @@
|
|||
"tests/util.ts",
|
||||
"tests/runtime/asyncIterableUtil.spec.ts",
|
||||
"tests/runtime/closureLoader.spec.ts",
|
||||
"tests/runtime/findWorkspaceRoot.spec.ts",
|
||||
"tests/runtime/registrations.spec.ts",
|
||||
"tests/runtime/tsClosureCases.ts",
|
||||
"tests/runtime/package.spec.ts",
|
||||
|
@ -107,6 +108,7 @@
|
|||
"tests/runtime/settings.spec.ts",
|
||||
"tests/runtime/langhost/run.spec.ts",
|
||||
"tests/runtime/langhost/cases/069.ambiguous_entrypoints/index.ts",
|
||||
"tests/runtime/testdata/nested/project/index.ts",
|
||||
|
||||
"tests/automation/cmd.spec.ts",
|
||||
"tests/automation/localWorkspace.spec.ts",
|
||||
|
|
|
@ -1457,6 +1457,16 @@ func TestCodePaths(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
||||
func TestCodePathsTSC(t *testing.T) {
|
||||
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
||||
Dir: filepath.Join("nodejs", "codepaths-tsc"),
|
||||
Dependencies: []string{"@pulumi/pulumi"},
|
||||
Quick: true,
|
||||
RunBuild: true,
|
||||
})
|
||||
}
|
||||
|
||||
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
||||
func TestCodePathsNested(t *testing.T) {
|
||||
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
||||
|
@ -1477,6 +1487,17 @@ func TestCodePathsWorkspace(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
//nolint:paralleltest // ProgramTest calls t.Parallel()
|
||||
func TestCodePathsWorkspaceTSC(t *testing.T) {
|
||||
integration.ProgramTest(t, &integration.ProgramTestOptions{
|
||||
Dir: filepath.Join("nodejs", "codepaths-workspaces-tsc"),
|
||||
Dependencies: []string{"@pulumi/pulumi"},
|
||||
Quick: true,
|
||||
RunBuild: true,
|
||||
RelativeWorkDir: "infra",
|
||||
})
|
||||
}
|
||||
|
||||
// Test that the resource stopwatch doesn't contain a negative time.
|
||||
func TestNoNegativeTimingsOnRefresh(t *testing.T) {
|
||||
if runtime.GOOS == WindowsOS {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
!/bin
|
|
@ -0,0 +1,7 @@
|
|||
name: codepaths-tsc
|
||||
description: Test case for codepaths using tsc to pre-compile
|
||||
main: bin/index.js
|
||||
runtime:
|
||||
name: nodejs
|
||||
options:
|
||||
typescript: false
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Dummy file to keep ProgramTest happy. We need ProjectInfo.main to exist already.
|
||||
// This will be overwritten by the compiled main file in the test after running
|
||||
// `yarn run build`.
|
||||
|
||||
throw new Error(
|
||||
`This file should not be required in tests. It should be overwritten by the tsc output during testing.`
|
||||
);
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as runtime from "@pulumi/pulumi/runtime"
|
||||
|
||||
(async function () {
|
||||
const deps = await runtime.computeCodePaths() as Map<string, string>;
|
||||
// Deps might include more than just the direct dependencies, but the
|
||||
// precise results depend on how the packages are hoisted within
|
||||
// node_modules. This can change based on the version of the package
|
||||
// manager and the dependencies of @pulumi/pulumi.
|
||||
//
|
||||
// For example for this nesting:
|
||||
//
|
||||
// node_modules
|
||||
// └─┬ semver
|
||||
// └── lru-cache
|
||||
//
|
||||
// deps only includes `node_modules/semver`. However if they are siblings,
|
||||
// it will include both `node_modules/semver` and `node_modules/lru-cache`.
|
||||
//
|
||||
// We only assert that the direct dependencies are included, which are
|
||||
// guaranteed to be stable.
|
||||
const directDependencies = [`../node_modules/semver`]
|
||||
|
||||
const depPaths = [...deps.keys()]
|
||||
for (const expected of directDependencies) {
|
||||
const depPath = depPaths.find((path) => path.includes(expected));
|
||||
if (!depPath) {
|
||||
throw new Error(`Expected to find a path matching ${expected}, got ${depPaths}`)
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "test-codepaths-tsc",
|
||||
"description": "Test case for codepaths using tsc to pre-compile",
|
||||
"main": "bin/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "latest",
|
||||
"typescript": "^3.8.3",
|
||||
"semver": "^7.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.20"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"outDir": "bin",
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"pretty": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": ["index.ts"],
|
||||
"outDir": "bin"
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
!/infra/bin
|
|
@ -0,0 +1,7 @@
|
|||
name: codepaths-workspaces-tsc
|
||||
description: A project that uses npm and yarn workspaces and tsc. CodePaths computation should discover dependencies across the workspaces.
|
||||
main: bin/index.js
|
||||
runtime:
|
||||
name: nodejs
|
||||
options:
|
||||
typescript: false
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
// Dummy file to keep ProgramTest happy. We need ProjectInfo.main to exist already.
|
||||
// This will be overwritten by the compiled main file in the test after running
|
||||
// `yarn run build`.
|
||||
|
||||
throw new Error(
|
||||
`This file should not be required in tests. It should be overwritten by the tsc output during testing.`
|
||||
);
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as runtime from "@pulumi/pulumi/runtime" // @pulumi dependency is not included
|
||||
import * as semver from "semver" // npm dependency
|
||||
import * as myRandom from "my-random" // workspace dependency
|
||||
import * as myDynamicProvider from "my-dynamic-provider" // workspace dependency
|
||||
|
||||
const random = new myRandom.MyRandom("plop", {});
|
||||
|
||||
export const id = random.randomID;
|
||||
|
||||
export const version = semver.parse("1.2.3");
|
||||
|
||||
const dynamicProviderResource = new myDynamicProvider.MyDynamicProviderResource("prov", {});
|
||||
|
||||
(async function () {
|
||||
const deps = await runtime.computeCodePaths() as Map<string, string>;
|
||||
const directDependencies = [`node_modules/semver`, `node_modules/my-random`, `node_modules/my-dynamic-provider`]
|
||||
|
||||
const depPaths = [...deps.keys()]
|
||||
for (const expected of directDependencies) {
|
||||
const depPath = depPaths.find((path) => path.includes(expected));
|
||||
if (!depPath) {
|
||||
throw new Error(`Expected to find a path matching ${expected}, got ${depPaths}`)
|
||||
}
|
||||
}
|
||||
})();
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "infra",
|
||||
"main": "bin/index.js",
|
||||
"version": "1.0.0",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "latest",
|
||||
"my-dynamic-provider": "1.0.0",
|
||||
"my-random": "1.0.0",
|
||||
"semver": "^7.5.2",
|
||||
"typescript": "^3.8.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^14.14.20"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"files": ["index.ts"],
|
||||
"compilerOptions": {
|
||||
"outDir": "bin"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"name": "codepaths-workspaces-tsc",
|
||||
"description": "A project that uses npm and yarn workspaces and tsc. CodePaths computation should discover dependencies across the workspaces.",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "yarn workspaces run build"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*",
|
||||
"infra/"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as pulumi from "@pulumi/pulumi"; // @pulumi dependency is not included;
|
||||
import * as pathExists from "path-exists"; // npm dependency
|
||||
import * as relative from "./relative"; // local dependency
|
||||
|
||||
const dynamicProvider: pulumi.dynamic.ResourceProvider = {
|
||||
async create(inputs) {
|
||||
return {
|
||||
id: `dyn-${Math.ceil(Math.random() * 1000)}`, outs: { isFinite: isFinite(42), magic: relative.fun() }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class MyDynamicProviderResource extends pulumi.dynamic.Resource {
|
||||
constructor(name: string, opts?: pulumi.CustomResourceOptions) {
|
||||
super(dynamicProvider, name, {}, opts);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "my-dynamic-provider",
|
||||
"main": "bin/index.js",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "latest",
|
||||
"path-exists": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.8.3",
|
||||
"@types/node": "^14.14.20"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
const magic = 42;
|
||||
|
||||
export const fun = () => {
|
||||
return magic;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"files": ["index.ts"],
|
||||
"compilerOptions": {
|
||||
"outDir": "bin"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2024-2024, Pulumi Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import * as pulumi from "@pulumi/pulumi";
|
||||
|
||||
export class MyRandom extends pulumi.ComponentResource {
|
||||
public readonly randomID: pulumi.Output<string>;
|
||||
|
||||
constructor(name: string, opts: pulumi.ResourceOptions) {
|
||||
super("pkg:index:MyRandom", name, {}, opts);
|
||||
this.randomID = pulumi.output(`${name}-${Math.floor(Math.random() * 1000)}`);
|
||||
this.registerOutputs({ randomID: this.randomID });
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "my-random",
|
||||
"main": "bin/index.js",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@pulumi/pulumi": "latest"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^3.8.3",
|
||||
"@types/node": "^14.14.20"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"files": ["index.ts"],
|
||||
"compilerOptions": {
|
||||
"outDir": "bin"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"outDir": "bin",
|
||||
"target": "es2016",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"pretty": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noImplicitReturns": true,
|
||||
"forceConsistentCasingInFileNames": true
|
||||
},
|
||||
"files": ["index.ts"],
|
||||
"outDir": "bin"
|
||||
}
|
Loading…
Reference in New Issue