Git Product home page Git Product logo

manypkg's Introduction

An umbrella for your monorepo

weekly downloads from npm


Manypkg

Manypkg is a linter for package.json files in Yarn, Bolt or pnpm monorepos.

Install

yarn add @manypkg/cli

Usage

manypkg check

manypkg check runs all of the checks against your repo, logs any errors and exits with a code

manypkg fix

manypkg fix runs all of the checks against your repo and fixes any of problems that can be fixed.

manypkg run <partial package name or directory> <script>

manypkg run executes scripts for packages within a monorepo.

As an example, let's say there are two packages: @project/package-a at packages/pkg-a and @project/package-b at packages/pkg-b which both have a start script, manypkg run can be used like this:

yarn manypkg run pkg-a start
yarn manypkg run a start
yarn manypkg run package-a start
yarn manypkg run @project/package-a start
yarn manypkg run packages/pkg-a start
yarn manypkg run package-b start
yarn manypkg run b start

The following wouldn't work though because the package and pkg aren't unique among the package names/directories:

yarn manypkg run package start
yarn manypkg run pkg start

In order to target a package with a name that is a substring of another (for example, @project/package-a at packages/pkg-a and @project/package-a-1 at packages/pkg-a-1), use the exact package or directory name:

yarn manypkg run @project/package-a start
yarn manypkg run packages/pkg-a start

manypkg exec <cli command>

manypkg exec executes a command for all packages within a monorepo.

As an example, let's say there are two packages which both have a dist dir, manypkg exec can be used like this:

yarn manypkg exec rm -rf dist

Configuration

Manypkg supports a number of options. Options can be provided using the manypkg key in your root package.json file:

{
  "name": "monorepo-root",
  "private": true,
  "manypkg": {}
}

defaultBranch

Used by the Incorrect repository field rule to determine the correct name for repositories. The default value is master.

{
  "manypkg": {
    "defaultBranch": "master"
  }
}

ignoredRules

Used to determine which checks/fixes should ignored by the Manypkg cli. The default value is [] (all checks/fixes enabled).

{
  "manypkg": {
    "ignoredRules": []
  }
}

To ignore a rule, find the rule in the Checks section below and add its "Key" value to the array. For example, to disable the External mismatch rule:

{
  "manypkg": {
    "ignoredRules": ["EXTERNAL_MISMATCH"]
  }
}

workspaceProtocol

Used to determine whether the workspace: protocol for internal packages is required (require) or allowed (allow). The default value is allow.

{
  "manypkg": {
    "workspaceProtocol": "allow"
  }
}

Dictionary

  • private package - A package that has private: true/is not published. It does not refer to a package published to a private registry here.
  • internal package - A package that is local/in the repo
  • external package - A package that is from a registry like npm
  • range - A node-semver range
  • highest range - The range which has the highest lower bound. If there are multiple ranges with the same highest lower bound, the range with the highest upper bound is the highest range.

Checks

External mismatch

Key: EXTERNAL_MISMATCH

The ranges for all dependencies(excluding peerDependencies) on external packages should exactly match(===). It's important to note that this check does not enforce that only a single version of an external package is installed, only that two versions of an external package will never be installed because they're specified as dependencies of internal packages.

Why it's a rule

So that only a single version of an external package will be installed because having multiple versions of the same package can cause confusion and bundle size problems especially with libraries like React that require there to only be a single copy of the library.

How it's fixed

The most commonly used range of the dependency is set as the range at every non-peer dependency place it is depended on. If for some reason, every range is used the same amount of times, they'll all be fixed to the highest version.

Examples

Incorrect example

NOTE: This example uses Yarn Workspaces but this will work the same with Bolt and pnpm

package.json

{
  "name": "@manypkg-example/repo",
  "version": "1.0.0",
  "workspaces": ["packages/*"]
}

packages/pkg-a/package.json

{
  "name": "@manypkg-example/pkg-a",
  "version": "1.0.0",
  "dependencies": {
    "some-external-package": "1.0.0"
  }
}

packages/pkg-b/package.json

{
  "name": "@manypkg-example/pkg-b",
  "version": "1.0.0",
  "dependencies": {
    "some-external-package": "2.0.0"
  }
}

packages/pkg-c/package.json

{
  "name": "@manypkg-example/pkg-c",
  "version": "1.0.0",
  "dependencies": {
    "some-external-package": "1.0.0"
  }
}

This example will cause an error because the range 2.0.0 for some-external-package specified in @manypkg-example/pkg-b is not equal(===) to the range 1.0.0 specified in @manypkg-example/pkg-a and @manypkg-example/pkg-c.

Correct example

NOTE: This example uses Yarn Workspaces but this will work the same with Bolt and pnpm

package.json

{
  "name": "@manypkg-example/repo",
  "version": "1.0.0",
  "workspaces": ["packages/*"]
}

packages/pkg-a/package.json

{
  "name": "@manypkg-example/pkg-a",
  "version": "1.0.0",
  "dependencies": {
    "some-external-package": "1.0.0"
  }
}

packages/pkg-b/package.json

{
  "name": "@manypkg-example/pkg-b",
  "version": "1.0.0",
  "dependencies": {
    "some-external-package": "1.0.0"
  }
}

This example will not cause an error because the range 1.0.0 for some-external-package specified in @manypkg-example/pkg-a is equal(===) to the range 1.0.0 specified in @manypkg-example/pkg-b.

Ignoring this rule

There are some cases where you might want to intentionally have conflicts between versions. To do this, you can use something that isn't a valid semver range instead of a range such as a git url or etc. If you'd like a conflicting version of an npm package, you can use npm:pkg-name@your-range-here instead of just a range and it will be ignored.

Note: Do this with care, having different versions of the same package can lead to strange bugs

Internal mismatch

Key: INTERNAL_MISMATCH

The ranges for all regular dependencies, devDependencies and optionalDependencies(not peerDependencies) on internal packages should include the version of the internal package.

Why it's a rule

So that an internal package that depends on another internal package will always get the local version of the internal package rather than a version from the registry because installing internal packages from the registry can be very confusing since you generally expect to get the local version when you depend on an internal package.

How it's fixed

If the range is a caret range or a tilde range with no other comparators, the range is set as a caret or tilde range respectively with the version of the internal package. If it is any other range, the range is set to the exact version of the internal package.

Invalid dev and peer dependency relationship

Key: INVALID_DEV_AND_PEER_DEPENDENCY_RELATIONSHIP

All peerDependencies should also be specified in devDependencies and the range specified in devDependencies should be a subset of the range for that dependency in peerDependencies.

Why it's a rule

This is so that peerDependencies are available in the package during development for testing and etc.

How it's fixed

The range for the dependency specified in peerDependencies is added to devDependencies unless the package is already a non-peer dependency elsewhere in the repo in which, that range is used instead.

Root has devDependencies

Key: ROOT_HAS_DEV_DEPENDENCIES

The root package should not have any devDependencies, instead all dependencies should be in dependencies

Why it's a rule

The root package.json of a monorepo is not published so whether a dependency is in devDependencies or dependencies does not make a difference and having one place to put dependencies in the root means that people do not have to arbitrarily decide where a dependency should go every time they install one.

How it's fixed

All devDependencies in the root package.json are moved to dependencies.

Multiple dependency types

Key: MULTIPLE_DEPENDENCY_TYPES

A dependency shouldn't be specified in more than one of dependencies, devDependencies or optionalDependencies.

How it's fixed

The dep is removed from devDependencies or optionalDependencies if it's also in dependencies, if it's in devDependencies and optionalDependencies, it is removed from dependencies.

Invalid package name

Key: INVALID_PACKAGE_NAME

There are rules from npm about what a package name can be and a package will fail to publish if those rules are not met.

Why it's a rule

All packages will be published together so some packages may depend on a package which can't be published. Checking for invalid package names prevents this kind of publish failure.

How it's fixed

This requires manual fixing as automatically fixing this may lead to valid but incorrect package names.

Unsorted dependencies

Key: UNSORTED_DEPENDENCIES

Dependencies in the dependency fields(dependencies, devDependencies, peerDependencies, optionalDependencies) should be sorted alphabetically.

Why it's a rule

When you add a package with yarn add or etc. dependencies are sorted, and this can cause confusing diffs if the dependencies were not previously sorted.

How it's fixed

This is fixed by sorting deps by key alphabetically.

Incorrect repository field

Key: INCORRECT_REPOSITORY_FIELD

If a GitHub repo URL is in the repository field in the root package.json, all of the packages should have a repository field which goes into the directory of the package.

Why it's a rule

Having a repository field is helpful so there is a link to the source of a package on npm but setting that field on every package and making sure it's correct is error prone and time consuming.

How it's fixed

This is fixed by setting the correct URL.

workspace: protocol required

Key: WORKSPACE_REQUIRED

If "workspaceProtocol": "require" is set in the manypkg config in the root package.json, all dependencies on internal packages are required to use the workspace: protocol.

Why it's a rule

If you want to enforce the usage of the workspace: protocol.

How it's fixed

Dependencies are changed to workspace:^. Anything else is also allowed after the workspace: though.

License

Copyright (c) 2023 Thinkmill Labs Pty Ltd. Licensed under the MIT License.

manypkg's People

Contributors

acao avatar andarist avatar askoufis avatar bdkopen avatar benmccann avatar chalkpe avatar clentfort avatar dcousens avatar elliot-nelson avatar emmatown avatar evocateur avatar fbartho avatar fz6m avatar github-actions[bot] avatar jakeboone02 avatar jesstelford avatar katt avatar manzoorwanijk avatar maraisr avatar marcodejongh avatar nateradebaugh avatar noviny avatar salimbensiali avatar steve-taylor avatar tarang9211 avatar with-heart avatar zzarcon avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

manypkg's Issues

Sort out publishing

👋 I just added a new package! It would be great to sort out publishing this repository, and the permissions around that.

"Root has devDependencies"

I would like to raise a concern about this rule mostly due to the problem with npm audit and the general expectation of some underlaying tools that only dependencies should be scanned for vulnerabilities.

Still creates a huge room for some uncertainly of decision which dep should do where, but I would like to have this rule configurable.

support asterix in upgrade

Hello
I have an edge case where I would like to run

manypkg upgrade mypackage *

to run and upgrade all mypackage to * because its part of the monorepo. Its an edge case because the mypackage name collides with the upgrade of another package with the same starting name.

Is that possible?

manypkg run needs better feedback

Just some notes from using it:

Because it just goes and does stuff, I'd like to be told where manypkg is executing the script.
It would be good to be able to as a command print a list of packages so I can copy/paste a package name to run from, rather than needing to open up my editor.

Update INTERNAL_MISMATCH rule for new devDep rule

We made a decisions that internal dev-dependencies should be * at all times, so that updating these does not cause unnecessary releases.

We need to update the internal mismatch rule to cover this.

Proposal: alternative approach to root dependencies

Was talking about root dependencies. Manypkg breaks from its predecessor bolt in using versions within leaf* package.json files, and allowing them to be excluded from root AND that all dependencies in root must be listed under dependencies, not devDependencies

The benefits of the new approach:

  • Calculable source of truth around package versions between packages
  • packages become easier to remove - packages not used anywhere simply vanish
  • shorter root package.jsons

The benefits of the old approach:

  • single source of truth that can be referenced for what packages at what versions are installed

So question 1 then becomes "How important for repository maintainers is having a single source of truth of what packages at what versions exist entirely within the multi-package repository"

I've been talked around that having this single source of truth that is easy to reference is genuinely valuable.

There's an... alternate new approach if we want:

  • single source of truth that can be referenced for what packages at what versions are installed
  • packages become easier to remove - packages not used anywhere simply vanish

The new rules are:

  1. All installed packages used in leaf packages must exist in dependencies in the root package.json
  2. All installed packages not used in leaf packages must exist in devDependencies of the root

Complaints with this approach

This makes the tooling harder to understand, as it has more specific rule about where to place things

True, but we already have a lot of opinions, and things remain as easy to alert and fix as they currently are (thing mentioned in a package but not at root is a new fix, aligning versions changes slightly)

people can throw everything in dev dependencies and then we are no better off

A risk, but also means people unconcerned with removing packages just don't care.

Three possible decisions

  1. Stick with what is in manypkg now, decide single source of truth for package versions is an okay trade-off
    1a. Add a manypkg command to get this list, to counteract the trade-off
  2. Revert to bolt's rules, add everything into dependencies still, decide removing unused packages being harder is an okay trade-off
  3. Implement the new option proposed here, decide the added rules complexity is an okay trade-off.

*New term - picked 'leaf' to match 'root' - may be bad. Technically we only have root and non-root, but that's not ideal either.

Exit code is not working

Hi,

I was trying out manypkg and it's a really nice tool :) But, currently the exit code is not working as expected. I always get 0 when I run manypkg check. I was expecting it to produce a non-zero error code so that we can use it in CI.

Cheers

Prefer workspace protocol when using pnpm

Description

When pnpm encounters a package in a workspace which has a lower version than the most recently published on the npm registry it defaults to using the registry version.

I opened an issue and the proposed solution was to use workspace protocols.

Unfortunately, manypkg fix removes all workspace protocols when run.

My proposal is not just to ignore workspace protocols when using pnpm but actually to prefer them, since it's the recommended way to prevent a hard situation to debug. It took me a while to realize why none of my changes were having an impact.

Configurable fix behaviour

👋 Hey old Thinkmill friends,

We're adopting manypkg in atlassian-frontend as a replacement for Bolt.
The auto-fix behaviour is awesome, but for dependencies, it fixes to the highest version in the repo.
We'd like it to be configurable to fixing the most used version in the repo.

Because the failure mode of this check usually is because of someone running a unversioned dependency add in a workspace:

#inside package/packageA
yarn add react

This would add the latest version of React, whereas they probably just wanted the version in use in the repo. As usually someone adding a dependency to their package does not mean they also want to upgrade the whole repo.

Happy to contribute this back if this is a change the team is willing to accept.

`manypkg check` shouldn't warn to mirror `peerDependencies` into `devDependencies` when they're already available in the root's `dependencies`.

That's a long title, but let me explain.

The broad rule that manypkg warns about, is that anything in peerDependencies, should also be in devDependencies. This is reasonable (and imo also correct).

However, in a monorepo (i.e. something using workspaces), root level dependencies are used as a substitute for package level devDependencies. This keeps it easier to keep the versioning of those deps across workspaces simple, and avoids repeating them across workspaces.

Hence my feature request: You shouldn't warn about mirroring peerDependencies and devDependencies if it's already available in a root's dependencies. It should still do a version check ("External Mistmatch" rule), however.

`manypkg run` to support a glob or workspace

Thanks for this awesome project. We're enjoying it a lot and apply using it across different mono-repos.

By using it we mostly manage to remove lerna which prior served to publish packages also. As we also often use changesets lerna's value for us is not too big anymore for our specific case. It's still a great project regardless!

While migrating away from it we noticed a couple of things we would love to hear you feedback on:

  • manypkg run: runs only on one project
    • Allowing it to run on a workspace or glob would help a lot
    • Generally, some packages are built with preconstruct and some not. Those which are not we would like to target with a glob to have a custom build script

What do you think about this? We're also happy to open a PR if there is general interest on this matter.

Feature Request: Option Flag to always use Highest Semver Range

Currently, manypkg check and manypkg fix decide to resolve dependency versions based on the most commonly witnessed range in the repo. -- Only when there are equal quantities of each range specifier do we select the highest range:

if(acc[1] === value[1]) {
// If all dependency ranges occurances are equal, pick the highest.
// It's impossible to infer intention of the developer
// when all ranges occur an equal amount of times
const highestRange = highest([acc[0], value[0]]);
return [ highestRange, acc[1] ];
}

Would we support a flag --use-highest-range on each command to force this algorithm to select the highest range for a given dependency?

Alternative: add a .manypkg.config.json this and other flags?

I'm happy to contribute this code change if a maintainer can indicate if they'd accept an appropriate PR implementing this.

Error when two packages have same prefix

The issue here is that I have two packages named as @UI/theme and @UI/theme-utils and when I try to use any scripts with @UI/theme the following error is thrown to me:

☔️ error an identifier must only match a single package but "theme" matches the following packages: 
☔️ error @UI/theme
☔️ error @UI/theme-utils

Upon looking at the source code I found the following lines of code that could possibly be causing the issue:

const matchingPackages = packages.filter(pkg => {
return (
pkg.packageJson.name.includes(args[0]) ||
path.relative(root.dir, pkg.dir).includes(args[0])
);
});

This code snippet lies within the runCmd function here.

I suppose that arg[0] might be the package that is calling the CLI command. So, for example, I am currently calling the CLI command for the theme package therefore arg[0] should be @UI/theme.

With that out of the way now I think includes is matching all the packages that have that same name, therefore, causing the issue here. I'll try to make a pull request to fix the issue.

Edit: args[0] doesn't equal to @UI/theme but just theme. I had overlooked some parts of the code

Respository field set to invalid URL by @manypkg/cli

After running manypkg fix the repository field was set to a URL will nulls in it.

Git diff:

-  "repository": "[email protected]:dpisani/gengarden.git",
+  "repository": "null//github.com/null/github.com",

This also happened in child workspaces

-  "repository": "[email protected]:dpisani/gengarden.git",
+  "repository": "null//github.com/null/github.com/tree/master/packages/examples",

@manypkg/cli version: 0.17.0
node version: v10.14.2
OS: Linux (KDE Neon)

Eslint-ifying manypkg

Manypkg is currently very opinionated. It's a sort of 'linter for your workspace configurations' (aka your package.jsons) with easy context awareness.

To write new rules for it you can follow a clear template and get them added very quickly.

Currently it's effectively enforcing the our styleguide, with no customisation, but the shape of writing rules would be useful for others. We should make it 'customisable'.

NB: This moves it very much into a linter-ish space, with pluggable rules, etc, so thinking about this probably involves going 'what is good in eslint' vs 'what is bad/annoying'.

poor cli support

running npx manypkg --help throws an error that sort of lists the possible commands, but doesn't give any description of how to use any of them:

> npx manypkg --help
☔️ error command --help not found, only check, exec, run, upgrade, npm-tag and fix exist

Similarly, running --help with any of the manypkg commands throws spawn errors:

> npx manypkg exec --help
☔️ error Error: spawn --help ENOENT
☔️ error     at Process.ChildProcess._handle.onexit (internal/child_process.js:274:19)
☔️ error     at onErrorNT (internal/child_process.js:469:16)
☔️ error     at processTicksAndRejections (internal/process/task_queues.js:82:21) {
☔️ error   errno: -2,
☔️ error   code: 'ENOENT',
☔️ error   syscall: 'spawn --help',
☔️ error   path: '--help',
☔️ error   spawnargs: []
☔️ error }

I expect a cli tool to give me basic information about itself when I run it with a --help flag; it would be great if manypkg could provide that experience!

How should you add packages?

Before looking at this, please review #10.

Adding packages isn't a great experience with these constraints right now.

I've got a kinda mostly working implementation to solve part of this right now but I want to think about this more because I think it's more of a nuanced thing than my implementation looks like right now.

I think there are two things that a user wants at different times when they add a dependency in a monorepo.

  1. Add a package as a dep to a package at the same version if it is already a dependency elsewhere in the monorepo, otherwise add the latest version of the package
  2. Add the latest version of a package, if it is a dependency elsewhere in the monorepo, update it there

The question is, how should people do this?
Bolt did 1 and that seemed to work mostly well so maybe the answer is to only have 1 and then maybe also a way to upgrade packages? The thing that's implemented right now(which I think is broken) works like this yarn m add <theThing>and does 1

Slightly related but also a bit separate thing that's not really a problem because I think the solution is pretty good: Adding peerDependencies

In Yarn and npm(I think), when using the --peer flag adds a package as a peerDependency but you generally also want it as a devDependency. Because of the peer and dev dependency relationship check, we already enforce that. This means that Manypkg's --peer flag on whatever add command might exist should also add the dep as a devDependency.

"Invalid dev and peer dependency relationship" errors when devDependency is "*"

In our monorepo, we have a package (A) with a peerDependency declared on another internal package (B).

The "Internal devDependencies are not " implies the devDependency of A on B should be "". manypkg fix enforces this.

However, the "Invalid dev and peer dependency relationship" does not accept "*" to be valid when a peerDependency is declared.

Expected behaviour: Any peerDependency is compatible with a devDependency of "*".

version: @manypkg/cli@^0.8.0

@Noviny has the context on this.

Can't specify URL Tarball, instead of semver range, for dependencies

Background

We have a dependency entry in our root package.json, and package-a/package.json, that directly links to a tarball, e.g.:

{
  ...
  "dependencies": {
    ...
    "bootstrap": "https://github.com/twbs/bootstrap/archive/v3.3.5.tar.gz"
    ...
  }
}

Actual Behaviour

When running yarn manypkg check we see it fail with the following error

☔️ error TypeError: Invalid comparator: https://github.com/twbs/bootstrap/archive/v3.3.5.tar.gz
☔️ error     at Comparator.parse (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:794:11)
☔️ error     at new Comparator (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:777:8)
☔️ error     at Range.<anonymous> (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:975:12)
☔️ error     at Array.map (<anonymous>)
☔️ error     at Range.parseRange (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:974:13)
☔️ error     at Range.<anonymous> (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:917:17)
☔️ error     at Array.map (<anonymous>)
☔️ error     at new Range (/my-monorepo/node_modules/sembear/node_modules/semver/semver.js:916:40)
☔️ error     at upperBound (/my-monorepo/node_modules/sembear/dist/sembear.cjs.dev.js:19:11)
☔️ error     at /my-monorepo/node_modules/sembear/dist/sembear.cjs.dev.js:138:19

Expected Behaviour

manypkg check should gladly accept tarball urls if they are consistent across the package.jsons in the repo.

In the case where there is a mix of tarball urls or semver ranges, it should return a warning that it couldn't reconcile the versions in the repo.

Hypothesis

It looks like sembear is assuming that it will be able to coerce the range into a valid value. I'm guessing we should do a check as to whether a dependency version is valid semver or not, and avoid trying to coerce it.

INTERNAL_DEV_DEP_NOT_STAR rule breaks repo when using prerelease versions

Just tried this lib for the first time, and it's awesome, except for one issue: setting local dev dependency versions to '*' makes it so that yarn won't install anything. Instead I get variations of the following error about a million times:

Error: Couldn't find package "my_package_a@*" required by "[email protected]" on the "npm" registry.

This happens because '*' doesn't match prerelease versions.

I think that when the dependency's current version is a prerelease version, it should be set to that version; otherwise, use the wildcard.

See yarnpkg/yarn#6719

In the meantime, is there a way to selectively disable rules so that I can continue to use manypkg?

sembear fails when trying to compare a git version type

When a package dep references github directly, the checker fails. I believe its got something to do with:

highest([highestExternalRange, deps[depName]]) === deps[depName]

That being said - I have started to raise a pr that simply ignores git: but then it dawned on me that this'll also be an issue for file: etc... So I'm opening up the issue to discuss a best approach.

I believe that perhaps we can simply wrap that highest call in a try catch, so if it throws we could simply move on? Perhaps there is a way to first detect if its a semver version string, and if so only then check it.

I do accept that this is probably not best practice in using git, file and so on - references but there have been times where I'd want to still have the level of strictness manypkg offer, but not semever. Also I'd say that this wouldnt be verifiying that the strings are greater or less than - perhaps manypkg could error if the strings it finds aren't equal, ie: "packageA": "git://github.com/abc/xyz.git#master" is not the same as "packageA": "git://github.com/abc/xyz.git#random-hash".

feature request: some way to ignore warnings.

Great package, thank you. Conceptually I like to think of this as an analogue to eslint, but for monorepos. However, there are times when I want to be able to ignore warnings and not have them show up, much like // eslint-ignore. Specific usecase - I'm working on a codebase that needs to load multiple versions of react/react-dom on a page. (very similar to as described in https://reactjs.org/blog/2020/08/10/react-v17-rc.html#gradual-upgrades / https://github.com/reactjs/react-gradual-upgrade-demo/). As you can imagine, @manypkg/cli check gives an error in this circumstance, because it expects only a single version of a package to be used in a monrepo. I'd like to somehow silence this warning on a case by case basis. I'm not sure what this exception would look like. Maybe a field in that workspace's package.json like -

"manypkg-ignore: {
  "ignore": ["react", "react-dom"]
}

Please and thank you!

Does this work with npm?

Hello,
We don't use yarn, rather npm, and for the most part this works. However, at times when I run manypkg fix, I get the following:

> manypkg fix

☔️ error Error: spawn yarn ENOENT
☔️ error     at Process.ChildProcess._handle.onexit (node:internal/child_process:282:19)
☔️ error     at onErrorNT (node:internal/child_process:480:16)
☔️ error     at processTicksAndRejections (node:internal/process/task_queues:83:21) {
☔️ error   errno: -2,
☔️ error   code: 'ENOENT',
☔️ error   syscall: 'spawn yarn',
☔️ error   path: 'yarn',
☔️ error   spawnargs: []
☔️ error }

It seems that under the hood this wants to use yarn but since I don't have it installed its erroring. Is it possible to get away from this?

feature request: (optionally) enforce the same versions of dependencies across all packages + root

Hi and thanks for this tool!

I'm trying to use manypkg to replace bolt.

Bolt has an opinionated feature where it enforces that every package in the monorepo should have the exact same versions of the same dependency. For example we can't have a package A depending on lodash@3 while package B depends on lodash@4

I agree that it's a design choice so it should be optional.

Bolt also enforces that dependencies of sub-packages should also appear in the root package.json.

Are those ideas something that manypkg could check / warn about?

[`run` command] Add a way to differentiate between packages when one package name is a substring of another

Hi there! Thanks for the great tool. We're using it as part of our tools for managing https://github.com/chakra-ui/chakra-ui to great effect!

One of the problems we've run into is that we have packages where one package name is a substring of another, and as far as I can tell, there isn't a way to force manypkg to target the substring name. The packages are named @chakra-ui/theme and @chakra-ui/theme-tools, so we're stuck without a way to target @chakra-ui/theme.

The README notes that this can be the case with an example of the pkg and package directories not being unique, but in this case, the only way around this would be for us to rename one of the packages, since we end up with the same issue in their directory names: packages/theme/packages/theme-tools.

My first thought was to treat the "partial package name or directory" argument as a regex string, where we'd compare the package name/directory using match instead of includes. This should allow users to continue using run as they did previously, but would also allow us to do something like manypkg run theme$ to target only @chakra-ui/theme.

Please restore Bolt support

I realise Bolt didn't win the monorepo package manager war, but there are still people using it (e.g. me). For me, its killer features are enforcement of uniform dependency versions, speed and simplicity. I've tried them all and settled on a toolkit that included Bolt, Changesets and Manypkg.

Unfortunately, Changesets uses Manypkg to get workspaces, so Bolt support in Changesets is going away soon.

Can you please restore Bolt support? Alternatively, will you accept a well-crafted pull request that restores Bolt support?

getPackages method not working on cwd absolute path matches the pnpm workspace exclude rules

Now pnpm workspace support workspace exclude rules.

pnpm-workspace.yaml case:

packages:
  # all packages in subdirs of packages/ and components/
  - 'packages/**'
  # exclude packages that are inside test directories
  - '!**/test/**'

so. if cwd absolute path matches the exclude rules, glob will exclude all workspaces.

case (expected results in parentheses) :

  - test
    - packages
      - pkg-1   # (need)
      - pkg-2  # (need)
      - test   # (not need)
    - pnpm-workspace.yaml

the parent cwd path has test string matches the exclude rule, getPackages result is [] (empty) .

`repository` validation fails in some cases

For this:

{ "rootRepositoryField": "https://github.com/Thinkmill/manypkg" }

we get this back from parse-github-url:

{
  "protocol": "https:",
  "slashes": true,
  "auth": null,
  "host": "github.com",
  "port": null,
  "hostname": "github.com",
  "hash": null,
  "search": null,
  "query": null,
  "pathname": "Thinkmill/manypkg",
  "path": "Thinkmill/manypkg",
  "href": "https://github.com/Thinkmill/manypkg",
  "filepath": null,
  "owner": "Thinkmill",
  "name": "manypkg",
  "repo": "Thinkmill/manypkg",
  "branch": "master",
  "repository": "Thinkmill/manypkg"
}

As we might notice the branch has defaulted to master which in turn makes per-package repository field like https://github.com/Thinkmill/manypkg/tree/main/packages/cli incorrect and results in the error:

☔️ error @manypkg/cli has a repository field of "https://github.com/Thinkmill/manypkg/tree/main/packages/cli" when it should be "https://github.com/Thinkmill/manypkg/tree/master/packages/cli"

The quickest fix for me was to just remove the root "repository" field but I think that the situation here should be improved so nobody would face that in the future.

Incompatibility with Yarn 2's workspace protocol?

Hello,

Thanks for this great CLI tool!

What I see
I've just started using it, and it seems manypkg reports an error when the root of a monorepo uses Yarn 2's workspace protocol :workspace

This an example error report:

☔️ error root has a dependency on @private/library@workspace:libraries/library
but the version of @private/library in the repo is 3.16.13
which is not within range of the depended on version,
please update the dependency version

Expected
In this case, I would expect manypkg not to report an error, since the root will naturally use the latest available version.

What do you think?

Feature request: --only for isolating fix to current directory

We're building a system for incrementally upgrading our monorep (for which we'll also need #13).
After a user runs yarn add, we run manypkg fix to make sure the right version was added. But if a dependency is under incremental upgrade that can have unexpected consequences.

If a developer runs yarn add react in pkgD, manypkg fix will updated all the other React dependencies down to 1.0.0, undoing the incremental upgrade. By adding a --only (open to better names), we want to have manypkg fix only update the current directory, in this case pkgD, so that only pkgD's package.json is fixed.

We're more than happy to contribute this back

INCORRECT_REPOSITORY_FIELD requires github repos

My company doesn't use github, so we're seeing INCORRECT_REPOSITORY_FIELD errors with the new check.

This check should either be updated to handle other repositories, or at least disabled for non-github URLs.

`manypkg exec` should be documented

The "official" monorepo-starter uses manypkg exec but there's nothing in this project that mentions this command or the power it enables.

Enables things like this:

"clean": "manypkg exec rm -rf node_modules && manypkg exec rm -rf dist && rm -rf node_modules",

Run command

const getWorkspaces = require("get-workspaces");
const spawnDamnit = require("spawn-damnit");
async function execInOnePkg(matchString, command) {
  const workspaces = await getWorkspaces();
  // regex match or globby match
  // against name for actual matches, or dir in case they are different
  let matchingWorkspaces = workspaces.filter(({ name, dir }) =>
    name.includes(matchString, command)
  );
  if (matchingWorkspaces.length > 1) {
    console.error(
      "This matched multiple workspaces:",
      matchingWorkspaces.map(({ name }) => name).join(", ")
    );
    console.error("please narrow your search so only one workspace is matched");
    throw new Error("stahp");
  } else if (matchingWorkspaces.length === 0) {
    console.warn("no matching packages");
  } else {
    let [workspace] = matchingWorkspaces;
    // I do not know this API at all
    // We want to spawn a new shell at the workspace.dir and execute whatever was passed as 'command'
    await spawnDamnit(workspace.dir, command);
  }
}
execInOnePkg();
`manypkg next-app run start`;
// Runs yarn start in the package

Missing LICENSE

You mention "license": "MIT", in your package.json(s), but there is no LICENSE file

Configurable fixes?

Hi,

Very useful tool, I wanted to know if there is a plan to add a bit of configuration to the fix decisions? One in particular is dependency discrepancy resolution, I would love to be able to set highest instead of most-common

Thanks

Globby dependency outdated and contains NPM audit vulnerability

In projects using @manypkg/[email protected] (latest), npm audit flags a vulnerability. In tracing the dependency tree, @manypkg/get-packages is a full version behind on it's dependency declaration for globby@^11.0.0. By updating this to ^12.0.1, the vulnerability will be fixed.

This update would require releasing a patch for @manypkg/get-packages then a subsequent patch to @manypkg/cli updating the dependency on get-packages to the new version.

Feat: add prompt command/option to select a command to run within a package

Hi 👋

Background

In our team we use and rely a lot on the @manypkg/cli for both our open source and private projects.

In one of our private monorepos, there are multiple application packages and we have a custom script that we run from the workspace root to prompt the developer to choose which application to start.

It's pretty simple. In fact we use @manypkg/get-packages to get the list of application names/dirs to be prompted.

Proposal

I think it might make sense to have this option built into the @manypkg/cli, so that other people can also benefit from that.

Essentially the end result would be the same as manypkg run pkg-a start, except that the pkg-a is selected from the prompt options.

Whether it would be a separate command (e.g. prompt) or a flag of the run command, that's up to discussion.

For example:

# Usage: manypkg prompt --match <glob> <script>

manypkg prompt --match @my-scope/* start

? Select the package to run the command "start" from › - Use arrow-keys. Return to submit.
❯   @my-scope/a
    @my-scope/b
    @my-scope/c
    @my-scope/d

or

# Usage: manypkg run <glob> <script> --prompt

manypkg run @my-scope/* start --prompt

? Select the package to run the command "start" from › - Use arrow-keys. Return to submit.
❯   @my-scope/a
    @my-scope/b
    @my-scope/c
    @my-scope/d

If you like the idea and are willing to accept this, I'm happy to contribute with the implementation.

Looking forward to your feedback.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.