@npmcli/template-oss 2.0.0 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -36
- package/bin/.gitattributes +3 -0
- package/bin/npm-template-check.js +7 -2
- package/bin/postinstall.js +4 -6
- package/lib/content/CODEOWNERS +1 -0
- package/lib/content/SECURITY.md +2 -0
- package/lib/content/ci.yml +1 -2
- package/lib/content/gitignore +4 -0
- package/lib/{content/index.js → postinstall/copy-content.js} +15 -6
- package/lib/{package.js → postinstall/update-package.js} +20 -4
- package/lib/postlint/check-gitignore.js +59 -0
- package/lib/{check.js → postlint/check-package.js} +25 -19
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -9,22 +9,26 @@ single devDependency.
|
|
|
9
9
|
|
|
10
10
|
These fields will be set in the project's `package.json`:
|
|
11
11
|
|
|
12
|
-
```
|
|
12
|
+
```js
|
|
13
13
|
{
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
author: 'GitHub Inc.',
|
|
15
|
+
files: ['bin', 'lib'],
|
|
16
|
+
license: 'ISC',
|
|
17
|
+
templateVersion: $TEMPLATE_VERSION,
|
|
18
|
+
scripts: {
|
|
19
|
+
lint: `eslint '**/*.js'`,
|
|
20
|
+
postlint: 'npm-template-check',
|
|
21
|
+
lintfix: 'npm run lint -- --fix',
|
|
22
|
+
preversion: 'npm test',
|
|
23
|
+
postversion: 'npm publish',
|
|
24
|
+
prepublishOnly: 'git push origin --follow-tags',
|
|
25
|
+
snap: 'tap',
|
|
26
|
+
test: 'tap',
|
|
27
|
+
posttest: 'npm run lint',
|
|
28
|
+
},
|
|
29
|
+
engines: {
|
|
30
|
+
node: '^12.13.0 || ^14.15.0 || >=16',
|
|
31
|
+
},
|
|
28
32
|
}
|
|
29
33
|
```
|
|
30
34
|
|
|
@@ -34,9 +38,9 @@ action.
|
|
|
34
38
|
|
|
35
39
|
#### Extending
|
|
36
40
|
|
|
37
|
-
The `changes` constant located in `lib/package.js` should contain
|
|
38
|
-
for the `package.json` file. Be sure to correctly expand any object/array
|
|
39
|
-
values with the original package content.
|
|
41
|
+
The `changes` constant located in `lib/postinstall/update-package.js` should contain
|
|
42
|
+
all patches for the `package.json` file. Be sure to correctly expand any object/array
|
|
43
|
+
based values with the original package content.
|
|
40
44
|
|
|
41
45
|
### Static files
|
|
42
46
|
|
|
@@ -47,8 +51,12 @@ These files will be copied, overwriting any existing files:
|
|
|
47
51
|
|
|
48
52
|
- `.eslintrc.js`
|
|
49
53
|
- `.github/workflows/ci.yml`
|
|
54
|
+
- `.github/ISSUE_TEMPLATE/bug.yml`
|
|
55
|
+
- `.github/ISSUE_TEMPLATE/config.yml`
|
|
56
|
+
- `.github/CODEOWNERS`
|
|
50
57
|
- `.gitignore`
|
|
51
58
|
- `LICENSE.md`
|
|
59
|
+
- `SECURITY.md`
|
|
52
60
|
|
|
53
61
|
#### Extending
|
|
54
62
|
|
|
@@ -56,27 +64,16 @@ Place files in the `lib/content/` directory, use only the file name and remove
|
|
|
56
64
|
any leading `.` characters (i.e. `.github/workflows/ci.yml` becomes `ci.yml`
|
|
57
65
|
and `.gitignore` becomes `gitignore`).
|
|
58
66
|
|
|
59
|
-
Modify the `content` object at the top of `lib/content
|
|
67
|
+
Modify the `content` object at the top of `lib/postinstall/copy-content.js` to include
|
|
60
68
|
your new file. The object keys are destination paths, and values are source.
|
|
61
69
|
|
|
70
|
+
### `package.json` checks
|
|
62
71
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
These packages will be removed:
|
|
66
|
-
|
|
67
|
-
- `eslint-plugin-import`
|
|
68
|
-
- `eslint-plugin-promise`
|
|
69
|
-
- `eslint-plugin-standard`
|
|
70
|
-
- `@npmcli/lint`
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
Afterwards, these packages will be installed as devDependencies:
|
|
74
|
-
|
|
75
|
-
- `eslint`
|
|
76
|
-
- `eslint-plugin-node`
|
|
77
|
-
- `@npmcli/eslint-config`
|
|
78
|
-
- `tap`
|
|
72
|
+
`npm-template-check` is run by `postlint` and will error if the `package.json`
|
|
73
|
+
is not configured properly, with steps to run to correct any problems.
|
|
79
74
|
|
|
80
75
|
#### Extending
|
|
81
76
|
|
|
82
|
-
|
|
77
|
+
Add any unwanted packages to `unwantedPackages` in `lib/check.js`. Currently
|
|
78
|
+
the best way to install any packages is to include them as `peerDependencies`
|
|
79
|
+
in this repo.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const checkPackage = require('../lib/postlint/check-package.js')
|
|
4
|
+
const checkGitIgnore = require('../lib/postlint/check-gitignore.js')
|
|
4
5
|
|
|
5
6
|
const main = async () => {
|
|
6
7
|
const {
|
|
@@ -11,7 +12,11 @@ const main = async () => {
|
|
|
11
12
|
throw new Error('This package requires npm >7.21.1')
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const problems =
|
|
15
|
+
const problems = [
|
|
16
|
+
...(await checkPackage(root)),
|
|
17
|
+
...(await checkGitIgnore(root)),
|
|
18
|
+
]
|
|
19
|
+
|
|
15
20
|
if (problems.length) {
|
|
16
21
|
console.error('Some problems were detected:')
|
|
17
22
|
console.error()
|
package/bin/postinstall.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const copyContent = require('../lib/content
|
|
4
|
-
const patchPackage = require('../lib/package.js')
|
|
3
|
+
const copyContent = require('../lib/postinstall/copy-content.js')
|
|
4
|
+
const patchPackage = require('../lib/postinstall/update-package.js')
|
|
5
5
|
|
|
6
6
|
const main = async () => {
|
|
7
7
|
const {
|
|
@@ -19,12 +19,10 @@ const main = async () => {
|
|
|
19
19
|
return
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
|
|
22
|
+
await copyContent(root)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
// for the catch handler because it does so little it's not worth testing
|
|
27
|
-
module.exports = main().catch(/* istanbul ignore next */ (err) => {
|
|
25
|
+
module.exports = main().catch((err) => {
|
|
28
26
|
console.error(err.stack)
|
|
29
27
|
process.exitCode = 1
|
|
30
28
|
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @npm/cli-team
|
package/lib/content/SECURITY.md
CHANGED
package/lib/content/ci.yml
CHANGED
|
@@ -26,7 +26,7 @@ jobs:
|
|
|
26
26
|
strategy:
|
|
27
27
|
fail-fast: false
|
|
28
28
|
matrix:
|
|
29
|
-
node-version: [12.13.0, 12.x, 14.15.0, 14.x, 16.x]
|
|
29
|
+
node-version: [12.13.0, 12.x, 14.15.0, 14.x, 16.13.0, 16.x]
|
|
30
30
|
platform:
|
|
31
31
|
- os: ubuntu-latest
|
|
32
32
|
shell: bash
|
|
@@ -51,4 +51,3 @@ jobs:
|
|
|
51
51
|
- run: npm i --prefer-online -g npm@latest
|
|
52
52
|
- run: npm ci
|
|
53
53
|
- run: npm test --ignore-scripts
|
|
54
|
-
- run: npm ls -a
|
package/lib/content/gitignore
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
|
-
const { dirname, join } = require('path')
|
|
1
|
+
const { dirname, join, resolve } = require('path')
|
|
2
2
|
const fs = require('@npmcli/fs')
|
|
3
3
|
|
|
4
|
+
const contentDir = resolve(__dirname, '..', 'content')
|
|
5
|
+
|
|
4
6
|
// keys are destination paths in the target project
|
|
5
|
-
// values are paths to contents relative to
|
|
7
|
+
// values are paths to contents relative to '../content/'
|
|
6
8
|
const content = {
|
|
7
9
|
'.eslintrc.js': './eslintrc.js',
|
|
8
10
|
'.github/workflows/ci.yml': './ci.yml',
|
|
9
11
|
'.github/ISSUE_TEMPLATE/bug.yml': './bug.yml',
|
|
10
12
|
'.github/ISSUE_TEMPLATE/config.yml': './config.yml',
|
|
13
|
+
'.github/CODEOWNERS': './CODEOWNERS',
|
|
11
14
|
'.gitignore': './gitignore',
|
|
12
15
|
'LICENSE.md': './LICENSE.md',
|
|
13
16
|
'SECURITY.md': './SECURITY.md',
|
|
14
17
|
}
|
|
15
18
|
|
|
19
|
+
const filesToDelete = [
|
|
20
|
+
// remove any other license files
|
|
21
|
+
/^LICENSE*/,
|
|
22
|
+
// remove any eslint config files that aren't local to the project
|
|
23
|
+
/^\.eslintrc\.(?!(local\.)).*/,
|
|
24
|
+
]
|
|
25
|
+
|
|
16
26
|
// given a root directory, copy all files in the content map
|
|
17
|
-
// after purging any
|
|
27
|
+
// after purging any files we need to delete
|
|
18
28
|
const copyContent = async (root) => {
|
|
19
29
|
const contents = await fs.readdir(root)
|
|
20
30
|
|
|
21
31
|
for (const file of contents) {
|
|
22
|
-
|
|
23
|
-
if (file.startsWith('.eslintrc.') && !file.startsWith('.eslintrc.local.')) {
|
|
32
|
+
if (filesToDelete.some((p) => p.test(file))) {
|
|
24
33
|
await fs.rm(join(root, file))
|
|
25
34
|
}
|
|
26
35
|
}
|
|
27
36
|
|
|
28
37
|
for (let [target, source] of Object.entries(content)) {
|
|
29
|
-
source = join(
|
|
38
|
+
source = join(contentDir, source)
|
|
30
39
|
target = join(root, target)
|
|
31
40
|
// if the target is a subdirectory of the root, mkdirp it first
|
|
32
41
|
if (dirname(target) !== root) {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
const PackageJson = require('@npmcli/package-json')
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const {
|
|
4
|
+
version: TEMPLATE_VERSION,
|
|
5
|
+
name: TEMPLATE_NAME,
|
|
6
|
+
} = require('../../package.json')
|
|
4
7
|
|
|
5
8
|
const changes = {
|
|
6
9
|
author: 'GitHub Inc.',
|
|
@@ -26,25 +29,38 @@ const changes = {
|
|
|
26
29
|
const patchPackage = async (root) => {
|
|
27
30
|
const pkg = await PackageJson.load(root)
|
|
28
31
|
|
|
32
|
+
// If we are running this on itself, we always run the script.
|
|
33
|
+
// We also don't set templateVersion in package.json because
|
|
34
|
+
// its not relavent and would cause git churn after running
|
|
35
|
+
// `npm version`.
|
|
36
|
+
const isDogfood = pkg.content.name === TEMPLATE_NAME
|
|
37
|
+
|
|
29
38
|
// if the target package.json has a templateVersion field matching our own
|
|
30
39
|
// current version, we return false here so the postinstall script knows to
|
|
31
40
|
// exit early instead of running everything again
|
|
32
|
-
if (pkg.content.templateVersion === TEMPLATE_VERSION) {
|
|
41
|
+
if (pkg.content.templateVersion === TEMPLATE_VERSION && !isDogfood) {
|
|
33
42
|
return false
|
|
34
43
|
}
|
|
35
44
|
|
|
36
45
|
// we build a new object here so our exported set of changes is not modified
|
|
37
|
-
|
|
46
|
+
const update = {
|
|
38
47
|
...changes,
|
|
39
48
|
scripts: {
|
|
40
49
|
...pkg.content.scripts,
|
|
41
50
|
...changes.scripts,
|
|
42
51
|
},
|
|
43
|
-
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (isDogfood) {
|
|
55
|
+
delete update.templateVersion
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
pkg.update(update)
|
|
44
59
|
|
|
45
60
|
await pkg.save()
|
|
46
61
|
return true
|
|
47
62
|
}
|
|
63
|
+
|
|
48
64
|
patchPackage.changes = changes
|
|
49
65
|
|
|
50
66
|
module.exports = patchPackage
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
const path = require('path')
|
|
2
|
+
const fs = require('fs')
|
|
3
|
+
const { sync: which } = require('which')
|
|
4
|
+
const { spawnSync } = require('child_process')
|
|
5
|
+
|
|
6
|
+
// The problem we are trying to solve is when a new .gitignore file
|
|
7
|
+
// is copied into an existing repo, there could be files already checked in
|
|
8
|
+
// to git that are now ignored by new gitignore rules. We want to warn
|
|
9
|
+
// about these files.
|
|
10
|
+
const check = async (root) => {
|
|
11
|
+
const git = path.resolve(root, '.git')
|
|
12
|
+
const gitignore = path.resolve(root, '.gitignore')
|
|
13
|
+
|
|
14
|
+
if (!fs.existsSync(git)) {
|
|
15
|
+
return []
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (!fs.existsSync(gitignore)) {
|
|
19
|
+
throw new Error(`${gitignore} must exist to run npm-template-check`)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const res = spawnSync(which('git'), [
|
|
23
|
+
'ls-files',
|
|
24
|
+
'--cached',
|
|
25
|
+
'--ignored',
|
|
26
|
+
// The .gitignore file has already been placed by now with the postinstall
|
|
27
|
+
// script so when this script runs via postlint, it can use that file
|
|
28
|
+
`--exclude-from=${gitignore}`,
|
|
29
|
+
], { encoding: 'utf-8', cwd: root })
|
|
30
|
+
|
|
31
|
+
const files = res.stdout
|
|
32
|
+
.trim()
|
|
33
|
+
.split('\n')
|
|
34
|
+
.filter(Boolean)
|
|
35
|
+
|
|
36
|
+
if (!files.length) {
|
|
37
|
+
return []
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const relativeGitignore = path.relative(root, gitignore)
|
|
41
|
+
const ignores = fs.readFileSync(gitignore)
|
|
42
|
+
.toString()
|
|
43
|
+
.split('\n')
|
|
44
|
+
.filter((l) => l && !l.trim().startsWith('#'))
|
|
45
|
+
|
|
46
|
+
const message = [
|
|
47
|
+
`The following files are tracked by git but matching a pattern in ${relativeGitignore}:`,
|
|
48
|
+
...files.map((f) => ` ${f}`),
|
|
49
|
+
].join('\n')
|
|
50
|
+
|
|
51
|
+
const solution = [
|
|
52
|
+
'Move files to not match one of these patterns:',
|
|
53
|
+
...ignores.map((i) => ` ${i}`),
|
|
54
|
+
].join('\n')
|
|
55
|
+
|
|
56
|
+
return [{ message, solution }]
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
module.exports = check
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
const fs = require('@npmcli/fs')
|
|
1
|
+
const PackageJson = require('@npmcli/package-json')
|
|
3
2
|
|
|
4
|
-
const
|
|
3
|
+
const { name: TEMPLATE_NAME } = require('../../package.json')
|
|
4
|
+
const patchPackage = require('../postinstall/update-package.js')
|
|
5
5
|
|
|
6
6
|
const unwantedPackages = [
|
|
7
7
|
'@npmcli/lint',
|
|
@@ -13,30 +13,29 @@ const unwantedPackages = [
|
|
|
13
13
|
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
|
|
14
14
|
|
|
15
15
|
const check = async (root) => {
|
|
16
|
-
const
|
|
17
|
-
try {
|
|
18
|
-
var contents = await fs.readFile(pkgPath, { encoding: 'utf8' })
|
|
19
|
-
} catch (err) {
|
|
20
|
-
throw new Error('No package.json found')
|
|
21
|
-
}
|
|
16
|
+
const pkg = (await PackageJson.load(root)).content
|
|
22
17
|
|
|
23
|
-
|
|
18
|
+
// templateVersion doesn't apply if we're on this repo
|
|
19
|
+
// since we always run the scripts here
|
|
20
|
+
const changes = Object.entries(patchPackage.changes).filter(([key]) => {
|
|
21
|
+
if (pkg.name === TEMPLATE_NAME && key === 'templateVersion') {
|
|
22
|
+
return false
|
|
23
|
+
}
|
|
24
|
+
return true
|
|
25
|
+
})
|
|
24
26
|
|
|
25
27
|
const problems = []
|
|
26
28
|
|
|
27
29
|
const incorrectFields = []
|
|
28
30
|
// 1. ensure package.json changes have been applied
|
|
29
|
-
for (const [key, value] of
|
|
31
|
+
for (const [key, value] of changes) {
|
|
30
32
|
if (!hasOwn(pkg, key)) {
|
|
31
33
|
incorrectFields.push({
|
|
32
34
|
name: key,
|
|
33
35
|
found: pkg[key],
|
|
34
36
|
expected: value,
|
|
35
37
|
})
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (value && typeof value === 'object') {
|
|
38
|
+
} else if (value && typeof value === 'object') {
|
|
40
39
|
for (const [subKey, subValue] of Object.entries(value)) {
|
|
41
40
|
if (!hasOwn(pkg[key], subKey) ||
|
|
42
41
|
pkg[key][subKey] !== subValue) {
|
|
@@ -63,8 +62,15 @@ const check = async (root) => {
|
|
|
63
62
|
message: [
|
|
64
63
|
`The following package.json fields are incorrect:`,
|
|
65
64
|
...incorrectFields.map((field) => {
|
|
66
|
-
const
|
|
67
|
-
|
|
65
|
+
const message = [
|
|
66
|
+
'Field:',
|
|
67
|
+
`${JSON.stringify(field.name)}`,
|
|
68
|
+
'Expected:',
|
|
69
|
+
`${JSON.stringify(field.expected)}`,
|
|
70
|
+
'Found:',
|
|
71
|
+
`${JSON.stringify(field.found)}`,
|
|
72
|
+
].join(' ')
|
|
73
|
+
return ` ${message}`
|
|
68
74
|
}),
|
|
69
75
|
].join('\n'),
|
|
70
76
|
solution: 'npm rm @npmcli/template-oss && npm i -D @npmcli/template-oss',
|
|
@@ -81,8 +87,8 @@ const check = async (root) => {
|
|
|
81
87
|
problems.push({
|
|
82
88
|
message: [
|
|
83
89
|
'The following unwanted packages were found:',
|
|
84
|
-
...mustRemove,
|
|
85
|
-
].join('
|
|
90
|
+
...mustRemove.map((p) => ` ${p}`),
|
|
91
|
+
].join('\n'),
|
|
86
92
|
solution: `npm rm ${mustRemove.join(' ')}`,
|
|
87
93
|
})
|
|
88
94
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@npmcli/template-oss",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "templated files used in npm CLI team oss projects",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"postlint": "npm-template-check",
|
|
14
14
|
"posttest": "npm run lint",
|
|
15
15
|
"postversion": "npm publish",
|
|
16
|
-
"prelint": "ln -sf ../../bin/npm-template-check.js node_modules/.bin/npm-template-check",
|
|
17
16
|
"prepublishOnly": "git push origin --follow-tags",
|
|
18
17
|
"preversion": "npm test",
|
|
19
18
|
"snap": "tap",
|
|
@@ -32,7 +31,7 @@
|
|
|
32
31
|
"dependencies": {
|
|
33
32
|
"@npmcli/fs": "^1.0.0",
|
|
34
33
|
"@npmcli/package-json": "^1.0.1",
|
|
35
|
-
"
|
|
34
|
+
"which": "^2.0.2"
|
|
36
35
|
},
|
|
37
36
|
"files": [
|
|
38
37
|
"bin",
|
|
@@ -40,7 +39,9 @@
|
|
|
40
39
|
],
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@npmcli/eslint-config": "*",
|
|
43
|
-
"
|
|
42
|
+
"@npmcli/promise-spawn": "^2.0.0",
|
|
43
|
+
"@npmcli/template-oss": "file:./",
|
|
44
|
+
"eslint": "^8.1.0",
|
|
44
45
|
"eslint-plugin-node": "^11.1.0",
|
|
45
46
|
"tap": "*"
|
|
46
47
|
},
|
|
@@ -48,7 +49,9 @@
|
|
|
48
49
|
"@npmcli/eslint-config": "^1.0.0",
|
|
49
50
|
"tap": "^15.0.9"
|
|
50
51
|
},
|
|
51
|
-
"
|
|
52
|
+
"tap": {
|
|
53
|
+
"coverage-map": "map.js"
|
|
54
|
+
},
|
|
52
55
|
"engines": {
|
|
53
56
|
"node": "^12.13.0 || ^14.15.0 || >=16"
|
|
54
57
|
}
|