@npmcli/template-oss 2.9.2 → 3.1.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 +77 -68
- package/bin/apply.js +22 -0
- package/bin/check.js +26 -0
- package/lib/apply/apply-files.js +31 -0
- package/lib/apply/index.js +5 -0
- package/lib/check/check-apply.js +73 -0
- package/lib/check/check-changelog.js +31 -0
- package/lib/check/check-gitignore.js +67 -0
- package/lib/check/check-required.js +55 -0
- package/lib/check/check-unwanted.js +23 -0
- package/lib/check/index.js +9 -0
- package/lib/config.js +151 -40
- package/lib/content/CODEOWNERS +1 -1
- package/lib/content/LICENSE.md +0 -2
- package/lib/content/SECURITY.md +0 -2
- package/lib/content/audit.yml +5 -12
- package/lib/content/bug.yml +45 -46
- package/lib/content/ci.yml +35 -38
- package/lib/content/codeql-analysis.yml +11 -9
- package/lib/content/commitlintrc.js +1 -4
- package/lib/content/config.yml +0 -2
- package/lib/content/dependabot.yml +13 -14
- package/lib/content/eslintrc.js +0 -2
- package/lib/content/gitignore +8 -14
- package/lib/content/index.js +92 -0
- package/lib/content/npmrc +0 -2
- package/lib/content/pkg.json +27 -0
- package/lib/content/post-dependabot.yml +12 -15
- package/lib/content/pull-request.yml +11 -13
- package/lib/content/release-please.yml +18 -11
- package/lib/content/setup-git.yml +11 -0
- package/lib/content/setup-node.yml +25 -0
- package/lib/index.js +100 -0
- package/lib/util/files.js +43 -0
- package/lib/util/get-git-url.js +24 -0
- package/lib/util/has-package.js +83 -0
- package/lib/util/json-diff.js +33 -0
- package/lib/util/output.js +35 -0
- package/lib/util/parse-ci-versions.js +78 -0
- package/lib/util/parser.js +280 -0
- package/lib/util/template.js +41 -0
- package/package.json +27 -25
- package/bin/.gitattributes +0 -3
- package/bin/npm-template-check.js +0 -44
- package/bin/postinstall.js +0 -31
- package/lib/content/ci-no-windows.yml +0 -48
- package/lib/content/ci-workspace.yml +0 -63
- package/lib/content/release-please-workspace.yml +0 -29
- package/lib/postinstall/copy-content.js +0 -133
- package/lib/postinstall/update-package.js +0 -100
- package/lib/postlint/check-gitignore.js +0 -59
- package/lib/postlint/check-package.js +0 -90
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const { dirname, join, resolve } = require('path')
|
|
2
|
-
const fs = require('@npmcli/fs')
|
|
3
|
-
const PackageJson = require('@npmcli/package-json')
|
|
4
|
-
|
|
5
|
-
const contentDir = resolve(__dirname, '..', 'content')
|
|
6
|
-
|
|
7
|
-
// keys are destination paths in the target project
|
|
8
|
-
// values are paths to contents relative to '../content/'
|
|
9
|
-
const moduleFiles = {
|
|
10
|
-
'.eslintrc.js': './eslintrc.js',
|
|
11
|
-
'.gitignore': './gitignore',
|
|
12
|
-
'.npmrc': './npmrc',
|
|
13
|
-
'SECURITY.md': './SECURITY.md',
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const repoFiles = {
|
|
17
|
-
'.commitlintrc.js': './commitlintrc.js',
|
|
18
|
-
'.github/workflows/ci.yml': './ci.yml',
|
|
19
|
-
'.github/ISSUE_TEMPLATE/bug.yml': './bug.yml',
|
|
20
|
-
'.github/ISSUE_TEMPLATE/config.yml': './config.yml',
|
|
21
|
-
'.github/CODEOWNERS': './CODEOWNERS',
|
|
22
|
-
'.github/dependabot.yml': './dependabot.yml',
|
|
23
|
-
'.github/workflows/audit.yml': './audit.yml',
|
|
24
|
-
'.github/workflows/codeql-analysis.yml': './codeql-analysis.yml',
|
|
25
|
-
'.github/workflows/post-dependabot.yml': './post-dependabot.yml',
|
|
26
|
-
'.github/workflows/pull-request.yml': './pull-request.yml',
|
|
27
|
-
'.github/workflows/release-please.yml': './release-please.yml',
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// currently no workspace module files
|
|
31
|
-
// const workspaceModuleFiles = {}
|
|
32
|
-
|
|
33
|
-
const workspaceRepoFiles = {
|
|
34
|
-
'.github/workflows/release-please-%%pkgfsname%%.yml': './release-please-workspace.yml',
|
|
35
|
-
'.github/workflows/ci-%%pkgfsname%%.yml': './ci-workspace.yml',
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const filesToDelete = [
|
|
39
|
-
// remove any eslint config files that aren't local to the project
|
|
40
|
-
/^\.eslintrc\.(?!(local\.)).*/,
|
|
41
|
-
]
|
|
42
|
-
|
|
43
|
-
const defaultConfig = {
|
|
44
|
-
applyRootRepoFiles: true,
|
|
45
|
-
applyWorkspaceRepoFiles: true,
|
|
46
|
-
applyRootModuleFiles: true,
|
|
47
|
-
windowsCI: true,
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const findReplace = (str, replace = {}) => {
|
|
51
|
-
for (const [f, r] of Object.entries(replace)) {
|
|
52
|
-
str = str.replace(new RegExp(f, 'g'), r)
|
|
53
|
-
}
|
|
54
|
-
return str
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const copyFile = async (source, target, replacements) => {
|
|
58
|
-
if (replacements) {
|
|
59
|
-
const content = await fs.readFile(source, { encoding: 'utf-8' })
|
|
60
|
-
return fs.writeFile(target, findReplace(content, replacements), { owner: 'inherit' })
|
|
61
|
-
}
|
|
62
|
-
return fs.copyFile(source, target, { owner: 'inherit' })
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const copyFiles = async (targetDir, files, replacements) => {
|
|
66
|
-
for (let [target, source] of Object.entries(files)) {
|
|
67
|
-
target = findReplace(join(targetDir, target), replacements)
|
|
68
|
-
source = join(contentDir, source)
|
|
69
|
-
// if the target is a subdirectory of the path, mkdirp it first
|
|
70
|
-
if (dirname(target) !== targetDir) {
|
|
71
|
-
await fs.mkdir(dirname(target), {
|
|
72
|
-
owner: 'inherit',
|
|
73
|
-
recursive: true,
|
|
74
|
-
force: true,
|
|
75
|
-
})
|
|
76
|
-
}
|
|
77
|
-
await copyFile(source, target, replacements)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// given a root directory, copy all files in the content map
|
|
82
|
-
// after purging any files we need to delete
|
|
83
|
-
const copyContent = async (path, rootPath, config) => {
|
|
84
|
-
config = { ...defaultConfig, ...config }
|
|
85
|
-
const isWorkspace = path !== rootPath
|
|
86
|
-
|
|
87
|
-
const contents = await fs.readdir(path)
|
|
88
|
-
|
|
89
|
-
if (isWorkspace || config.applyRootModuleFiles) {
|
|
90
|
-
// delete files and copy moduleFiles if it's a workspace
|
|
91
|
-
// or if we enabled doing so for the root
|
|
92
|
-
for (const file of contents) {
|
|
93
|
-
if (filesToDelete.some((p) => p.test(file))) {
|
|
94
|
-
await fs.rm(join(path, file))
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
await copyFiles(path, moduleFiles)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (!isWorkspace) {
|
|
101
|
-
if (config.applyRootRepoFiles) {
|
|
102
|
-
await copyFiles(rootPath, repoFiles)
|
|
103
|
-
if (!config.windowsCI) {
|
|
104
|
-
// copyFiles already did the mkdir so we can just fs.copyFile now
|
|
105
|
-
await fs.copyFile(
|
|
106
|
-
join(contentDir, 'ci-no-windows.yml'),
|
|
107
|
-
join(rootPath, '.github', 'workflows', 'ci.yml')
|
|
108
|
-
)
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
return
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// only workspace now
|
|
115
|
-
|
|
116
|
-
// TODO: await copyFiles(path, workspaceModuleFiles)
|
|
117
|
-
// if we ever have workspace specific files
|
|
118
|
-
|
|
119
|
-
// transform and copy all workspace repo files
|
|
120
|
-
if (config.applyWorkspaceRepoFiles) {
|
|
121
|
-
const workspacePkg = (await PackageJson.load(path)).content
|
|
122
|
-
await copyFiles(rootPath, workspaceRepoFiles, {
|
|
123
|
-
'%%pkgname%%': workspacePkg.name,
|
|
124
|
-
'%%pkgfsname%%': workspacePkg.name.replace(/\//g, '-').replace(/@/g, ''),
|
|
125
|
-
'%%pkgpath%%': path.substring(rootPath.length + 1),
|
|
126
|
-
})
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
copyContent.moduleFiles = moduleFiles
|
|
131
|
-
copyContent.repoFiles = repoFiles
|
|
132
|
-
|
|
133
|
-
module.exports = copyContent
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
const PackageJson = require('@npmcli/package-json')
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
version: TEMPLATE_VERSION,
|
|
5
|
-
name: TEMPLATE_NAME,
|
|
6
|
-
} = require('../../package.json')
|
|
7
|
-
|
|
8
|
-
const changes = {
|
|
9
|
-
author: 'GitHub Inc.',
|
|
10
|
-
files: ['bin', 'lib'],
|
|
11
|
-
scripts: {
|
|
12
|
-
lint: `eslint '**/*.js'`,
|
|
13
|
-
postlint: 'npm-template-check',
|
|
14
|
-
'template-copy': 'npm-template-copy --force',
|
|
15
|
-
lintfix: 'npm run lint -- --fix',
|
|
16
|
-
preversion: 'npm test',
|
|
17
|
-
postversion: 'npm publish',
|
|
18
|
-
prepublishOnly: 'git push origin --follow-tags',
|
|
19
|
-
snap: 'tap',
|
|
20
|
-
test: 'tap',
|
|
21
|
-
posttest: 'npm run lint',
|
|
22
|
-
},
|
|
23
|
-
engines: {
|
|
24
|
-
node: '^12.13.0 || ^14.15.0 || >=16',
|
|
25
|
-
},
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const patchPackage = async (path, root, config) => {
|
|
29
|
-
const pkg = await PackageJson.load(path)
|
|
30
|
-
config = config || {}
|
|
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
|
-
const currentVersion = (pkg.content.templateOSS === undefined) ?
|
|
38
|
-
pkg.content.templateVersion : pkg.content.templateOSS.version
|
|
39
|
-
|
|
40
|
-
// if the target package.json has a templateVersion field matching our own
|
|
41
|
-
// current version, we return false here so the postinstall script knows to
|
|
42
|
-
// exit early instead of running everything again
|
|
43
|
-
if (!config.force
|
|
44
|
-
&& currentVersion === TEMPLATE_VERSION
|
|
45
|
-
&& !isDogfood) {
|
|
46
|
-
return false
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const templateConfig = {
|
|
50
|
-
templateOSS: {
|
|
51
|
-
...pkg.content.templateOSS,
|
|
52
|
-
...{ version: TEMPLATE_VERSION },
|
|
53
|
-
},
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
let update
|
|
57
|
-
|
|
58
|
-
if (path === root && !config.applyRootModuleFiles) {
|
|
59
|
-
// only update templateVersion if we're skipping root module files
|
|
60
|
-
update = {
|
|
61
|
-
...templateConfig,
|
|
62
|
-
}
|
|
63
|
-
} else {
|
|
64
|
-
// we build a new object here so our exported set of changes is not modified
|
|
65
|
-
update = {
|
|
66
|
-
...changes,
|
|
67
|
-
scripts: {
|
|
68
|
-
...pkg.content.scripts,
|
|
69
|
-
...changes.scripts,
|
|
70
|
-
},
|
|
71
|
-
...templateConfig,
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (isDogfood) {
|
|
76
|
-
delete update.templateVersion
|
|
77
|
-
delete update.templateOSS
|
|
78
|
-
} else {
|
|
79
|
-
if (pkg.content.templateVersion) {
|
|
80
|
-
update.templateVersion = undefined
|
|
81
|
-
}
|
|
82
|
-
if (pkg.content.scripts && pkg.content.scripts['lint:fix']) {
|
|
83
|
-
// some old packages using standard had a lint:fix script
|
|
84
|
-
delete update.scripts['lint:fix']
|
|
85
|
-
}
|
|
86
|
-
if (pkg.content.standard) {
|
|
87
|
-
// remove standard configuration if it exists
|
|
88
|
-
update.standard = undefined
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
pkg.update(update)
|
|
93
|
-
|
|
94
|
-
await pkg.save()
|
|
95
|
-
return true
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
patchPackage.changes = changes
|
|
99
|
-
|
|
100
|
-
module.exports = patchPackage
|
|
@@ -1,59 +0,0 @@
|
|
|
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,90 +0,0 @@
|
|
|
1
|
-
const PackageJson = require('@npmcli/package-json')
|
|
2
|
-
const patchPackage = require('../postinstall/update-package.js')
|
|
3
|
-
|
|
4
|
-
const unwantedPackages = [
|
|
5
|
-
'@npmcli/lint',
|
|
6
|
-
'eslint-plugin-promise',
|
|
7
|
-
'eslint-plugin-standard',
|
|
8
|
-
'eslint-plugin-import',
|
|
9
|
-
'standard',
|
|
10
|
-
]
|
|
11
|
-
|
|
12
|
-
const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key)
|
|
13
|
-
|
|
14
|
-
const check = async (root) => {
|
|
15
|
-
const pkg = (await PackageJson.load(root)).content
|
|
16
|
-
const changes = Object.entries(patchPackage.changes)
|
|
17
|
-
const problems = []
|
|
18
|
-
const incorrectFields = []
|
|
19
|
-
// 1. ensure package.json changes have been applied
|
|
20
|
-
for (const [key, value] of changes) {
|
|
21
|
-
if (!hasOwn(pkg, key)) {
|
|
22
|
-
incorrectFields.push({
|
|
23
|
-
name: key,
|
|
24
|
-
found: pkg[key],
|
|
25
|
-
expected: value,
|
|
26
|
-
})
|
|
27
|
-
} else if (value && typeof value === 'object') {
|
|
28
|
-
for (const [subKey, subValue] of Object.entries(value)) {
|
|
29
|
-
if (!hasOwn(pkg[key], subKey) ||
|
|
30
|
-
pkg[key][subKey] !== subValue) {
|
|
31
|
-
incorrectFields.push({
|
|
32
|
-
name: `${key}.${subKey}`,
|
|
33
|
-
found: pkg[key][subKey],
|
|
34
|
-
expected: subValue,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
} else {
|
|
39
|
-
if (pkg[key] !== patchPackage.changes[key]) {
|
|
40
|
-
incorrectFields.push({
|
|
41
|
-
name: key,
|
|
42
|
-
found: pkg[key],
|
|
43
|
-
expected: value,
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (incorrectFields.length) {
|
|
50
|
-
problems.push({
|
|
51
|
-
message: [
|
|
52
|
-
`The following package.json fields are incorrect:`,
|
|
53
|
-
...incorrectFields.map((field) => {
|
|
54
|
-
const message = [
|
|
55
|
-
'Field:',
|
|
56
|
-
`${JSON.stringify(field.name)}`,
|
|
57
|
-
'Expected:',
|
|
58
|
-
`${JSON.stringify(field.expected)}`,
|
|
59
|
-
'Found:',
|
|
60
|
-
`${JSON.stringify(field.found)}`,
|
|
61
|
-
].join(' ')
|
|
62
|
-
return ` ${message}`
|
|
63
|
-
}),
|
|
64
|
-
].join('\n'),
|
|
65
|
-
solution: 'npm rm @npmcli/template-oss && npm i -D @npmcli/template-oss',
|
|
66
|
-
})
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 2. ensure packages that should not be present are removed
|
|
70
|
-
const mustRemove = unwantedPackages.filter((name) => {
|
|
71
|
-
return hasOwn(pkg.dependencies || {}, name) ||
|
|
72
|
-
hasOwn(pkg.devDependencies || {}, name)
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
if (mustRemove.length) {
|
|
76
|
-
problems.push({
|
|
77
|
-
message: [
|
|
78
|
-
'The following unwanted packages were found:',
|
|
79
|
-
...mustRemove.map((p) => ` ${p}`),
|
|
80
|
-
].join('\n'),
|
|
81
|
-
solution: `npm rm ${mustRemove.join(' ')}`,
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return problems
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
check.unwantedPackages = unwantedPackages
|
|
89
|
-
|
|
90
|
-
module.exports = check
|