@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.
Files changed (52) hide show
  1. package/README.md +77 -68
  2. package/bin/apply.js +22 -0
  3. package/bin/check.js +26 -0
  4. package/lib/apply/apply-files.js +31 -0
  5. package/lib/apply/index.js +5 -0
  6. package/lib/check/check-apply.js +73 -0
  7. package/lib/check/check-changelog.js +31 -0
  8. package/lib/check/check-gitignore.js +67 -0
  9. package/lib/check/check-required.js +55 -0
  10. package/lib/check/check-unwanted.js +23 -0
  11. package/lib/check/index.js +9 -0
  12. package/lib/config.js +151 -40
  13. package/lib/content/CODEOWNERS +1 -1
  14. package/lib/content/LICENSE.md +0 -2
  15. package/lib/content/SECURITY.md +0 -2
  16. package/lib/content/audit.yml +5 -12
  17. package/lib/content/bug.yml +45 -46
  18. package/lib/content/ci.yml +35 -38
  19. package/lib/content/codeql-analysis.yml +11 -9
  20. package/lib/content/commitlintrc.js +1 -4
  21. package/lib/content/config.yml +0 -2
  22. package/lib/content/dependabot.yml +13 -14
  23. package/lib/content/eslintrc.js +0 -2
  24. package/lib/content/gitignore +8 -14
  25. package/lib/content/index.js +92 -0
  26. package/lib/content/npmrc +0 -2
  27. package/lib/content/pkg.json +27 -0
  28. package/lib/content/post-dependabot.yml +12 -15
  29. package/lib/content/pull-request.yml +11 -13
  30. package/lib/content/release-please.yml +18 -11
  31. package/lib/content/setup-git.yml +11 -0
  32. package/lib/content/setup-node.yml +25 -0
  33. package/lib/index.js +100 -0
  34. package/lib/util/files.js +43 -0
  35. package/lib/util/get-git-url.js +24 -0
  36. package/lib/util/has-package.js +83 -0
  37. package/lib/util/json-diff.js +33 -0
  38. package/lib/util/output.js +35 -0
  39. package/lib/util/parse-ci-versions.js +78 -0
  40. package/lib/util/parser.js +280 -0
  41. package/lib/util/template.js +41 -0
  42. package/package.json +27 -25
  43. package/bin/.gitattributes +0 -3
  44. package/bin/npm-template-check.js +0 -44
  45. package/bin/postinstall.js +0 -31
  46. package/lib/content/ci-no-windows.yml +0 -48
  47. package/lib/content/ci-workspace.yml +0 -63
  48. package/lib/content/release-please-workspace.yml +0 -29
  49. package/lib/postinstall/copy-content.js +0 -133
  50. package/lib/postinstall/update-package.js +0 -100
  51. package/lib/postlint/check-gitignore.js +0 -59
  52. 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