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(cpm): add check-package-manager package #48

Merged
merged 1 commit into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/plenty-bugs-sit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@mheob/check-package-manager': major
---

Initial release of the `check-package-manager` package
1 change: 1 addition & 0 deletions .husky/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
[ -n "$CI" ] && exit 0

pnpm exec changeset status --since main
pnpm exec check-package-manager
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"@changesets/cli": "^2.24.4",
"@commitlint/cli": "^17.1.2",
"@commitlint/config-conventional": "^17.1.0",
"@mheob/check-package-manager": "workspace:*",
"@mheob/eslint-config": "workspace:*",
"@mheob/prettier-config": "workspace:*",
"@types/node": "^18.7.18",
Expand Down
16 changes: 16 additions & 0 deletions packages/check-package-manager/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"rules": {
"no-console": "off",
"unicorn/no-process-exit": "off"
},
"overrides": [
{
"files": ["bin/*"],
"rules": {
"no-undef": "off",
"unicorn/filename-case": ["error", { "case": "kebabCase" }],
"unicorn/prefer-module": "off"
}
}
]
}
86 changes: 86 additions & 0 deletions packages/check-package-manager/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Check for correct package manager

A simple check of the usage of the correct package manager.

## Install

The local installation is optional. It is only needed if you want to have the package inside your project. This could improve
performance, for example.

### With NPM

```sh
npm install -D @mheob/check-package-manager
```

### With YARN

```sh
yarn add -D @mheob/check-package-manager
```

### With PNPM

```sh
pnpm add -D @mheob/check-package-manager
```

## Usage

### As script in `package.json`

Use one of the examples.

```json
"scripts": {
"check-package-manager": "npx check-package-manager npm", // NPM
"check-package-manager": "yarn dlx check-package-manager yarn", // YARN
"check-package-manager": "yarn exec check-package-manager yarn", // YARN - locally installed
"check-package-manager": "pnpm dlx check-package-manager", // PNPM
"check-package-manager": "pnpm dlx check-package-manager pnpm", // PNPM - alternative
"check-package-manager": "pnpm exec check-package-manager", // PNPM - locally installed
"check-package-manager": "pnpm exec check-package-manager pnpm", // PNPM - alternative locally installed
},
```

### As shell script

#### Default (same as `PNPM`)

Use `npx` if you use `NPM` as package manager.\
Otherwise use `exec` if you have installed the package in your project, otherwise use `dlx`.

```sh
npx check-package-manager
```

#### `NPM`

```sh
npx check-package-manager npm
```

#### `YARN`

```sh
yarn dlx check-package-manager yarn
```

#### `PNPM`

```sh
pnpm dlx check-package-manager pnpm
```

### As git hook

For example used in combination with [husky](https://typicode.github.io/husky/).

```sh
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

[ -n "$CI" ] && exit 0

pnpm exec check-package-manager
```
2 changes: 2 additions & 0 deletions packages/check-package-manager/bin/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/usr/bin/env node
require('../dist/index.js');
43 changes: 43 additions & 0 deletions packages/check-package-manager/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"name": "@mheob/check-package-manager",
"version": "0.0.0",
"description": "A simple check of the usage of the correct package manager.",
"keywords": [
"package-manager",
"node",
"config"
],
"homepage": "https://github.com/mheob/config/tree/main/packages/check-package-manager",
"bugs": "https://github.com/mheob/config/issues",
"repository": {
"type": "git",
"url": "https://github.com/mheob/config"
},
"license": "MIT",
"author": "Alexander Böhm <tools@boehm.work>",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"bin": {
"check-package-manager": "./bin/cli.js"
},
"files": [
"bin",
"dist",
"LICENSE",
"README.md"
],
"scripts": {
"build": "tsc",
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
"lint": "eslint **/*.ts --fix",
"sort-package-json": "pnpm dlx sort-package-json"
},
"devDependencies": {
"@mheob/eslint-config": "workspace:*",
"@mheob/tsconfig": "workspace:*",
"eslint": "^8.23.1"
},
"publishConfig": {
"access": "public"
}
}
39 changes: 39 additions & 0 deletions packages/check-package-manager/src/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { existsSync } from 'node:fs';

import {
getInvalidFileMessage,
getInvalidPackageManagerMessage,
getMissingLockFileMessage,
} from './messages';
import type { AvailablePackageManager } from './packageManager';
import { availablePackageManagers, packageManagerDetails } from './packageManager';
import { isCorrectPackageManager } from './utils';

/**
* Check if the lock file is the correct one for the package manager.
*
* @param selectedPackageManager The package manager to check for. Defaults to `PNPM`.
* @returns An array of error messages. If the array is empty, there are no errors.
*/
export function getCheckLockFilesErrors(
selectedPackageManager: string = packageManagerDetails.PNPM.name,
): string[] {
if (!isCorrectPackageManager(selectedPackageManager)) {
return [getInvalidPackageManagerMessage(selectedPackageManager)];
}

const selectedManager = selectedPackageManager.toUpperCase() as AvailablePackageManager;
const errors: string[] = [];

for (const manager of availablePackageManagers) {
const lockFile = packageManagerDetails[manager].lockFile;
if (manager === selectedManager) {
!existsSync(lockFile) && errors.push(getMissingLockFileMessage(lockFile));
} else {
const selectedLockFile = packageManagerDetails[selectedManager].lockFile;
existsSync(lockFile) && errors.push(getInvalidFileMessage(lockFile, selectedLockFile));
}
}

return errors;
}
13 changes: 13 additions & 0 deletions packages/check-package-manager/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getCheckLockFilesErrors } from './check';

const packageManagerArgument = process.argv[2];
const invalidLockFileErrors = getCheckLockFilesErrors(packageManagerArgument);
const hasErrors = invalidLockFileErrors.length > 0;

if (hasErrors) {
console.info('Invalid package manager or lock files found:');
for (const error of invalidLockFileErrors) {
console.warn(error);
}
process.exit(1);
}
38 changes: 38 additions & 0 deletions packages/check-package-manager/src/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { availablePackageManagers } from './packageManager';

/**
* Creates an error message for incorrect package manager.
*
* @param packageManager The package manager to check for.
* @returns The error message.
*/
export function getInvalidPackageManagerMessage(packageManager: string): string {
let message = `- Package manager "${packageManager}" is invalid or not supported.`;
message += ` Please use one of the following: ${availablePackageManagers.join(', ')}`;
return message;
}

/**
* Creates an error message for using an incorrect package manager lock file.
*
* @param lockFile The lock file of the package manager to check for.
* @param lockFileSelected The lock file of the package manager selected by the user.
* @returns The error message.
*/
export function getInvalidFileMessage(lockFile: string, lockFileSelected: string): string {
let message = `- Invalid occurrence of "${lockFile}" file.`;
message += ` Please remove it and use only "${lockFileSelected}".`;
return message;
}

/**
* Creates an error message for missing package manager lock file.
*
* @param lockFile The lock file of the package manager to check for.
* @returns The error message.
*/
export function getMissingLockFileMessage(lockFile: string): string {
let message = `- The "${lockFile}" does not exist or cannot be read.`;
message += ' Please run the installer of your package manager.';
return message;
}
12 changes: 12 additions & 0 deletions packages/check-package-manager/src/packageManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const availablePackageManagers = ['NPM', 'PNPM', 'YARN'] as const;
export type AvailablePackageManager = typeof availablePackageManagers[number];

type PackageManagerDetails = { name: AvailablePackageManager; lockFile: string };
type PackageManager = Record<AvailablePackageManager, PackageManagerDetails>;

/** The available package managers with their name and lock file. */
export const packageManagerDetails: PackageManager = {
NPM: { name: 'NPM', lockFile: 'package-lock.json' },
PNPM: { name: 'PNPM', lockFile: 'pnpm-lock.yaml' },
YARN: { name: 'YARN', lockFile: 'yarn.lock' },
};
12 changes: 12 additions & 0 deletions packages/check-package-manager/src/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { type AvailablePackageManager, availablePackageManagers } from './packageManager';

/**
* Check if the given package manager is correct and available.
*
* @param packageManager The package manager to check for.
* @returns `true` if the package manager is correct and available, `false` otherwise.
*/
export function isCorrectPackageManager(packageManager: string): boolean {
const manager = packageManager.toUpperCase() as AvailablePackageManager;
return availablePackageManagers.includes(manager);
}
9 changes: 9 additions & 0 deletions packages/check-package-manager/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"extends": "@mheob/tsconfig/commonjs.json",
"compilerOptions": {
"declaration": true,
"outDir": "dist",
"rootDir": "src"
},
"include": ["src/**/*"]
}
23 changes: 17 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.