Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(deploy): apply publishConfig to all packages during deploy #6943

Merged
merged 4 commits into from Aug 24, 2023

Conversation

JacobLey
Copy link
Contributor

When deploying packages, the package.json of the deployed package (as well as any other locally defined dependencies) should be treated as if it published, and mutate the package.json according to publishConfig and local workspace: dependencies.

Issue: #6693

@JacobLey JacobLey requested a review from zkochan as a code owner August 15, 2023 21:40
@welcome
Copy link

welcome bot commented Aug 15, 2023

💖 Thanks for opening this pull request! 💖
Please be patient and we will get back to you as soon as we can.

@@ -46,6 +59,10 @@ test('deploy', async () => {
fs.writeFileSync(`${name}/index.js`, '', 'utf8')
})

await writeYamlFile('pnpm-workspace.yaml', { packages: ['*'] })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In order to createExportableManifest we need metadata only available after an install.

Presently, deploy does not actually require an install previously.

This could be considered a breaking change. Although I would assume most users already have the relevant packages installed, and expected this behavior. This is inline with how commands like publish work.

deploy could be considered a "local" publish.

@@ -46,6 +59,10 @@ test('deploy', async () => {
fs.writeFileSync(`${name}/index.js`, '', 'utf8')
})

await writeYamlFile('pnpm-workspace.yaml', { packages: ['*'] })
crossSpawn.sync(pnpmBin, ['install', '--ignore-scripts', '--store-dir=../store', `--registry=http://localhost:${REGISTRY_MOCK_PORT}`])
fs.rmSync('pnpm-lock.yaml')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little bit of a hack for testing purposes... an assertion below checks that this file does not exist (as a side effect of the install called internally to deploy) and wanted to maintain that assertion.

Comment on lines 32 to 29
if (opts.makeExportableManifest) {
const manifest = await readProjectManifest(newDir)
const exportableManifest = await createExportableManifest(
path.dirname(filenames[manifest.fileName]),
manifest.manifest
)
await manifest.writeProjectManifest(exportableManifest)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is going to be used only by the deploy command, so I don't see any reason to put this code to importIndexedDir. Just place it in deploy.ts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to put all createExportableManifest logic in deploy.ts.

Removed all changes to other packages (adding createExportableManifest option)

@JacobLey
Copy link
Contributor Author

Build is currently only failing on ubuntu+v16 on this test: https://github.com/pnpm/pnpm/blob/main/pnpm/test/filterProd.test.ts#L9

This PR does not touch filtering, install, or recursive execution, so I would be surprised if I explicitly broke something.

Will defer to maintainer for guidance if there is something I can do to fix? Or perhaps just retry the test (flaky)?

@zkochan
Copy link
Member

zkochan commented Aug 16, 2023

The issue with this solution is that now createExportableManifest will be executed on all the dependencies. Even though we only need to run it on dependencies linked from local directories.

I suggest a different solution. Make the change in directory-fetcher. It create an index file that is passed to the linker. You can write the "exportable manifest" into node_modules/.pnpm/package.json and provide the path to it to the files index map. This way the package.json file that you create will be linked, not the original one.

@JacobLey
Copy link
Contributor Author

will be executed on all the dependencies

Agreed, should only be executed on local packages.

Looking into directory-fetcher, but we are back to the original issue that we will need to start passing some flag around to other packages for this single use case. Which I am ok implementing, but calling it out.

Another possible solution is to look up the list of all packages in the workspace pre-install (via something like findWorkspacePackages). Then reference that list for each hook and check "is this package a local workspace package". If true -> createExportableManifest.
There may even be an existing utility that does that check?

write the "exportable manifest" into node_modules/.pnpm/package.json

That sounds safe to me. Do we want to clean up the file after we are done with it?
Such as

process.on('exit', () => fs.rm('node_modules/.pnpm/package.json')

@zkochan
Copy link
Member

zkochan commented Aug 17, 2023

Looking into directory-fetcher, but we are back to the original issue that we will need to start passing some flag around to other packages for this single use case. Which I am ok implementing, but calling it out.

No, I think we can make this the default behaviour for all local directory dependencies. No need to pass options.

@JacobLey
Copy link
Contributor Author

JacobLey commented Aug 17, 2023

Updated, but not ready to merge.

Tests are now (rightfully) failing on PnP recursion https://github.com/pnpm/pnpm/blob/main/exec/plugin-commands-script-runners/test/exec.e2e.ts#L487

Not entirely sure how I broke that, but there must be some expectation that the package.json link remains unaltered.
Looks like this is related to my local setup somehow. Not seeing similar failure in CI build.

type WriteProjectManifest = (manifest: ProjectManifest, force?: boolean) => Promise<void>
interface WriteProjectManifestOptions {
force?: boolean
manifestPathOverride?: string
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The existing behavior was to re-write the file in same location it was loaded from. That is unwanted for our use case, so provided this override option.

This "breaks" existing options syntax, although I did not find any usage of the force option... so actually worked in-repo.

If this method is considered part of pnpm's public API though, I can tweak to accept a boolean or this options object for backwards compatibility.

Alternatively, I can use the writeProjectManifest function directly in directory-fetcher, but I did appreciate that the manifest.writeProjectManifest came with sensible defaults

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add this option. Just use a function that accepts the path to the manifest for saving the manifest.

filesIndex[fileName] = manifestPathOverride
}

return manifest?.manifest ?? null
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure exactly what behavior depends on it, but would it be preferable to return exportableManifest here instead?

FWIW that did not solve my current failing tests anyways.

manifest.manifest
)
const manifestPathOverride = path.join(dir, 'node_modules', '.pnpm', fileName)
await manifest.writeProjectManifest(exportableManifest, { manifestPathOverride })
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is the use case of manifestPathOverride. As mentioned in other comment, could replace this call with raw writeProjectManifest (rather than the one built into the safeRead response)


if (manifest) {
const { fileName } = manifest
const exportableManifest = await createExportableManifest(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's actually check if the exportableManifest differs from the original one. If it doesn't differ, there's no. need to write it to the file system and the path to the original file may be used.

type WriteProjectManifest = (manifest: ProjectManifest, force?: boolean) => Promise<void>
interface WriteProjectManifestOptions {
force?: boolean
manifestPathOverride?: string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't add this option. Just use a function that accepts the path to the manifest for saving the manifest.

When deploying packages, the package.json of the deployed package
(as well as any other locally defined dependencies)
should be treated as if it published, and mutate the package.json
according to `publishConfig` and local `workspace:` dependencies.

Issue: pnpm#6693
@JacobLey
Copy link
Contributor Author

Updated to use separate write function, so doesn't alter existing parameters.
Also check for diff before writing, to hopefully optimize file write.

One (trivial) call out is that the package will not necessarily be formatted the same way as before. Which I guess wasn't ever a guarantee (e.g. multi-newline in JSON file is removed) but now we would also lose comments in a JSON5, or change the indent settings.

@zkochan zkochan merged commit d57e4de into pnpm:main Aug 24, 2023
3 of 8 checks passed
@welcome
Copy link

welcome bot commented Aug 24, 2023

Congrats on merging your first pull request! 🎉🎉🎉

zkochan added a commit that referenced this pull request Sep 5, 2023
…loy (#6943)" (#7058)

This reverts commit d57e4de.

This reverts #6943

This will solve:

- #7040
- #6994
zkochan added a commit that referenced this pull request Feb 13, 2024
When deploying packages, the package.json of the deployed package
(as well as any other locally defined dependencies)
should be treated as if it published, and mutate the package.json
according to `publishConfig` and local `workspace:` dependencies.

close #6693

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants