Skip to content

feat: add sub folder support for git url#7487

Merged
zkochan merged 16 commits intopnpm:mainfrom
RexSkz:git-sub-folder
Jan 24, 2024
Merged

feat: add sub folder support for git url#7487
zkochan merged 16 commits intopnpm:mainfrom
RexSkz:git-sub-folder

Conversation

@RexSkz
Copy link
Copy Markdown
Contributor

@RexSkz RexSkz commented Jan 4, 2024

Close #4765

@RexSkz RexSkz requested a review from zkochan as a code owner January 4, 2024 10:20
@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 8, 2024

@zkochan I have two questions according to your comment:

we'll have to probably detect if the workspace feature is used and if so, then run install in the root of the repository before taking the subdirectory.

The "workspace" feature in NPM, Yarn and PNPM is different. PNPM uses WORKSPACE_MANIFEST_FILENAME (pnpm-workspace.yaml) while the others use workspaces field in package.json. Should I support both two scenarios?

It seems the only work is to add logic to the packageShouldBeBuilt function; if it returns true, PNPM will run ${pm} install then.

git+https://host/user/repo#next#path:<relative path>

I found that Yarn's "workspace clone" is actually placed on the docs Git Protocol, which gives a syntax that uses & to split multiple params:

git@github.com:yarnpkg/berry.git#workspace=@yarnpkg/shell&tag=@yarnpkg/shell/2.1.0

Should I change the separator to &?

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 8, 2024

The "workspace" feature in NPM, Yarn and PNPM is different. PNPM uses WORKSPACE_MANIFEST_FILENAME (pnpm-workspace.yaml) while the others use workspaces field in package.json. Should I support both two scenarios?

It seems the only work is to add logic to the packageShouldBeBuilt function; if it returns true, PNPM will run ${pm} install then.

The current logic might already work for the monorepo scenario. pnpm checks what lockfile is used and runs the right package manager.

which gives a syntax that uses & to split multiple params

I'm fine with this approach just use path instead of workspace

@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 8, 2024

The current logic might already work for the monorepo scenario.

The current logic does not handle the pnpm-workspace.yaml or workspaces field - if there's no scripts, prepare, index.js etc., the preparePackage just returns false without executing any command.

I'll add a check for this that only runs when path is present.

@RexSkz RexSkz changed the title feat: add sub folder query support for git url feat: add sub folder support for git url Jan 8, 2024
@RexSkz RexSkz force-pushed the git-sub-folder branch 4 times, most recently from cb0c93e to fcba8dc Compare January 10, 2024 19:43
@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 11, 2024

@zkochan I've finished all changes; please take a look~

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 12, 2024

add changesets.

Also, this is a new feature, so I'd like more members to review it.

@zkochan zkochan requested a review from a team January 12, 2024 00:27
@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 12, 2024

What to do with packages that have the workspace:* in dependencies? For instance, I want to install @pnpm/fetch directly from the pnpm repository. It has these dependencies:

"@pnpm/core-loggers": "workspace:*",
"@pnpm/fetching-types": "workspace:*",

Installation will fail because workspace:* can be resolved only inside a workspace.

I guess the "right" solution would be to convert those dependencies to something like:

 "@pnpm/core-loggers": "github:pnpm/pnpm#main&path:packages/core-loggers", 
 "@pnpm/fetching-types": "github:pnpm/pnpm#main&path:network/fetching-types", 

@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 12, 2024

Using workspace:* is currently impossible even without specifying a path. There's only a .bin folder inside the node_modules of each subpackage because soft links become invalid when moving files.

The scenario may need to be supported, but maybe not by this PR?

@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 12, 2024

Currently, pnpm works fine only for the following scenarios (without workspace:*):

  • The repo has a prepublish script and will bundle a dist file during prepublish to let users import.
  • Users want to use the source code (maybe in src) in this repo, and there are dependencies that will be used by the source code.
  • Users want to use the source code (maybe in src) in this repo, and there is no dependencies at all.

After this PR, pnpm will also work fine in these scenarios if users specify path. I think maybe it's enough.

Copy link
Copy Markdown
Member

@zkochan zkochan left a comment

Choose a reason for hiding this comment

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

You need to make changes to https://github.com/pnpm/pnpm/blob/main/fetching/tarball-fetcher/src/gitHostedTarballFetcher.ts too.

Some git-hosting providers (e.g. Github) have API for downloading the tarball through an HTTP request.

@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 13, 2024

I've added support for tarball fetcher, and changed pkgDir param of preparePackage to be required to prevent potential errors caused by missing the param in future.

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 14, 2024

It still doesn't work as far as I can tell. Will check later why. Also, it is stored currently in the store by git URL, so it will work only for the first package from the given git repo, the next one will be broken.

@RexSkz
Copy link
Copy Markdown
Contributor Author

RexSkz commented Jan 14, 2024

It should be okay to store only by Git URL - just 1 item in packages and multiple items in dependencies.

But I found it strange that pnpm somehow uses both tarball fetcher and git fetcher even if the Git URLs are the same. Please see the following package.json and the generated pnpm-lock.yaml:

{
  "name": "test",
  "version": "1.0.0",
  "dependencies": {
    "simple-react-app": "github:RexSkz/test-git-subfolder-fetch.git#path:/packages/simple-react-app",
    "simple-express-server": "github:RexSkz/test-git-subfolder-fetch.git#path:/packages/simple-express-server"
  }
}
dependencies:
  simple-express-server:
    specifier: github:RexSkz/test-git-subfolder-fetch.git#path:/packages/simple-express-server
    version: git@github.com+RexSkz/test-git-subfolder-fetch/2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22
  simple-react-app:
    specifier: github:RexSkz/test-git-subfolder-fetch.git#path:/packages/simple-react-app
    version: github.com/RexSkz/test-git-subfolder-fetch/2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22

packages:

  git@github.com+RexSkz/test-git-subfolder-fetch/2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22:
    resolution: {commit: 2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22, path: /packages/simple-express-server, repo: git@github.com:RexSkz/test-git-subfolder-fetch.git, type: git}
    name: '@my-namespace/simple-express-server'
    version: 1.0.0
    dependencies:
      express: 4.18.2
      lodash: 4.17.21
    transitivePeerDependencies:
      - supports-color
    dev: false

  github.com/RexSkz/test-git-subfolder-fetch/2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22:
    resolution: {tarball: https://codeload.github.com/RexSkz/test-git-subfolder-fetch/tar.gz/2b42a57a945f19f8ffab8ecbd2021fdc2c58ee22}
    name: monorepo-example
    version: 1.0.0
    dev: false

The simple-express-server is installed correctly, but it seems that pnpm resolves simple-react-app to a tarball URL, and the path param is lost.

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 14, 2024

I will look into it only after I finish with #7407

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Jan 22, 2024

TODO:

  • add an integration test to @pnpm/core. The test should install two packages from the same monorepo
  • consider changing the way index files for git-hosted dependencies are saved in the store. Right now it will be increasingly long, which will cause issues on Windows. Maybe use a hash instead?

@zkochan zkochan merged commit b13d2dc into pnpm:main Jan 24, 2024
@RexSkz RexSkz deleted the git-sub-folder branch January 24, 2024 08:25
@shinebayar-g
Copy link
Copy Markdown

Hi, Is it going to be a part of 8.x?

@qiutian00
Copy link
Copy Markdown

qiutian00 commented Jan 31, 2024

It seems a part of 9.x. https://github.com/pnpm/pnpm/releases/tag/v9.0.0-alpha.1

const joined = path.join(root, sub)
// prevent the dir traversal attack
const relative = path.relative(root, joined)
if (relative.startsWith('..')) {
Copy link
Copy Markdown

@levrik levrik Feb 5, 2024

Choose a reason for hiding this comment

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

Doesn't this still allow passing subdir/../../../ and a relative.includes('..') would be safer?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

relative is a calculated relative path between two ABSOLUTE paths: root and joined. If you pass subdir/../../../, the relative will definitely start with ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Oh. I missed the call to path.relative before.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We should always use path.relative to let Node.js calculate whether the user input path is outside the project root. Disallowing .. or / might not be a safe way since the resolving rules may change in future, and our block list may not be effective then :)

@alvis
Copy link
Copy Markdown
Contributor

alvis commented Feb 8, 2024

What to do with packages that have the workspace:* in dependencies? For instance, I want to install @pnpm/fetch directly from the pnpm repository. It has these dependencies:

"@pnpm/core-loggers": "workspace:*",
"@pnpm/fetching-types": "workspace:*",

Installation will fail because workspace:* can be resolved only inside a workspace.

I guess the "right" solution would be to convert those dependencies to something like:

 "@pnpm/core-loggers": "github:pnpm/pnpm#main&path:packages/core-loggers", 
 "@pnpm/fetching-types": "github:pnpm/pnpm#main&path:network/fetching-types", 

The capability to install packages with workspace:* dependencies is fundamentally important for enabling efficient cross-project referencing. In my experience of maintaining multiple monorepos, the current workflow of propagating changes exclusively through new package releases is both painfully frustrating and inefficient 😭 I truly hope we can find a resolution to this issue in the near future, as it would significantly enhance our development processes 🚀

@zkochan
Copy link
Copy Markdown
Member

zkochan commented Feb 8, 2024

Hi, Is it going to be a part of 8.x?

No, it will only be part of v9. v8 will probably have only bug fixes from now on.

The capability to install packages with workspace:* dependencies is fundamentally important for enabling efficient cross-project referencing. In my experience of maintaining multiple monorepos, the current workflow of propagating changes exclusively through new package releases is both painfully frustrating and inefficient 😭 I truly hope we can find a resolution to this issue in the near future, as it would significantly enhance our development processes 🚀

It is not an easy task. It isn't high in my own priority list.

In general, I don't think installing from git is a good idea although I do see that many people do it.

I would recommend looking into bit.dev as an alternative to monorepo(s) usage. With bit every component is independent but can be developed together in a singe workspace. So, you don't need to maintain monorepos. When you want to change some components, you just import them to a workspace. When the changes are done, you export them. This workflow is much better than monorepos, especially than multiple monorepos.

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.

Add from github source, in a specific subfolder

7 participants