add e2e and alias for npx, pnpx (#105)

* add e2e and alias for npx, pnpx

* Update .github/workflows/pmg-e2e.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Sahil Bansal
2026-01-10 16:47:43 +05:30
committed by GitHub
co-authored by Copilot
parent ca224f523c
commit f50d296935
4 changed files with 81 additions and 6 deletions
+50
View File
@@ -217,6 +217,56 @@ jobs:
test -d node_modules/lodash
cd .. && rm -rf yarn-test
- name: Test NPX - Package Execution
run: |
echo "Testing NPX package execution..."
mkdir npx-test && cd npx-test
echo "Testing npx with a simple package..."
pmg npx cowsay@1.6.0 "Hello from pmg npx" | tee npx-output.txt
# Verification: cowsay output contains our message
grep -q "Hello from pmg npx" npx-output.txt
echo "Testing npx with --package flag..."
pmg npx --package cowsay@1.6.0 -- cowsay "Hello with package flag" | tee npx-pkg-output.txt
# Verification: package flag execution produces expected output
grep -q "Hello with package flag" npx-pkg-output.txt
echo "Testing npx dry-run mode..."
pmg --dry-run npx cowsay@1.6.0 "This should not execute" | tee npx-dry-output.txt
# Verification: dry-run should NOT produce cowsay ASCII art (cow face ^__^ should not appear)
! grep -q '\^__\^' npx-dry-output.txt
cd .. && rm -rf npx-test
- name: Test PNPX - Package Execution
run: |
echo "Testing PNPX package execution..."
mkdir pnpx-test && cd pnpx-test
echo "Testing pnpx with a simple package..."
pmg pnpx cowsay@1.6.0 "Hello from pmg pnpx" | tee pnpx-output.txt
# Verification: cowsay output contains our message
grep -q "Hello from pmg pnpx" pnpx-output.txt
echo "Testing pnpx with --package flag..."
pmg pnpx --package cowsay@1.6.0 -- cowsay "Hello with package flag" | tee pnpx-pkg-output.txt
# Verification: package flag execution produces expected output
grep -q "Hello with package flag" pnpx-pkg-output.txt
echo "Testing pnpx dry-run mode..."
pmg --dry-run pnpx cowsay@1.6.0 "This should not execute" | tee pnpx-dry-output.txt
# Verification: dry-run should NOT produce cowsay ASCII art (cow face ^__^ should not appear)
! grep -q '\^__\^' pnpx-dry-output.txt
cd .. && rm -rf pnpx-test
- name: Test Pip - Single Package & Manifest
run: |
echo "Testing Pip single package installation..."
+1 -1
View File
@@ -95,7 +95,7 @@ func DefaultConfig() AliasConfig {
return AliasConfig{
RcFileName: ".pmg.rc",
PackageManagers: []string{"npm", "pip", "pip3", "pnpm", "bun", "uv", "yarn", "poetry"},
PackageManagers: []string{"npm", "pip", "pip3", "pnpm", "bun", "uv", "yarn", "poetry", "npx", "pnpx"},
Shells: shells,
}
}
+5 -3
View File
@@ -82,9 +82,11 @@ func (n *npmPackageExecutor) ParseCommand(args []string) (*ParsedCommand, error)
}
}
// Unlike npx, pnpx does not separate package and binary;
// the first arg is always an install target.
if n.Config.CommandName == "pnpx" && len(flagSet.Args()) > 0 {
// For both npx and pnpx, the first positional argument is typically
// the package to execute (e.g., `npx cowsay@1.6.0` or `pnpx cowsay@1.6.0`).
// However, if -p/--package flags are provided, the first positional arg
// is the binary to run, not the package (e.g., `npx -p typescript tsc`).
if len(flagSet.Args()) > 0 && len(packages) == 0 {
pkg := flagSet.Args()[0]
if !slices.Contains(packages, pkg) {
packages = append(packages, pkg)
+25 -2
View File
@@ -43,14 +43,37 @@ func TestNpxExecutorParseCommand(t *testing.T) {
},
},
{
name: "non-package npx command",
name: "package as first positional arg",
command: "npx create-react-app my-app",
assert: func(t *testing.T, parsed *ParsedCommand, err error) {
assert.NoError(t, err)
assert.Equal(t, 0, len(parsed.InstallTargets))
assert.Equal(t, 1, len(parsed.InstallTargets))
assert.Equal(t, "create-react-app", parsed.InstallTargets[0].PackageVersion.Package.Name)
assert.Equal(t, []string{"create-react-app", "my-app"}, parsed.Command.Args)
},
},
{
name: "package with version as first positional arg",
command: "npx cowsay@1.6.0 hello",
assert: func(t *testing.T, parsed *ParsedCommand, err error) {
assert.NoError(t, err)
assert.Equal(t, 1, len(parsed.InstallTargets))
assert.Equal(t, "cowsay", parsed.InstallTargets[0].PackageVersion.Package.Name)
assert.Equal(t, "1.6.0", parsed.InstallTargets[0].PackageVersion.Version)
},
},
{
name: "package via -p flag with different binary",
command: "npx -p typescript tsc --version",
assert: func(t *testing.T, parsed *ParsedCommand, err error) {
assert.NoError(t, err)
assert.Equal(t, 1, len(parsed.InstallTargets))
assert.Equal(t, "typescript", parsed.InstallTargets[0].PackageVersion.Package.Name)
assert.Empty(t, parsed.InstallTargets[0].PackageVersion.Version)
// tsc is the binary, not a package
assert.Equal(t, []string{"-p", "typescript", "tsc", "--version"}, parsed.Command.Args)
},
},
{
name: "single package using -p flag npx command with binary",
command: "npx -p tsx my-app",