npm-update-package 0.30.0 → 0.31.3

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 (179) hide show
  1. package/.eslintignore +3 -0
  2. package/.eslintrc.js +23 -0
  3. package/.github/renovate.json +15 -0
  4. package/.github/workflows/eslint.yml +14 -0
  5. package/.github/workflows/test.yml +20 -0
  6. package/.husky/pre-commit +4 -0
  7. package/.nvmrc +1 -0
  8. package/dist/package.json +65 -0
  9. package/dist/{bin.js → src/bin.js} +6 -3
  10. package/dist/{core → src/core}/FailedResult.js +0 -0
  11. package/dist/{core → src/core}/OutdatedPackage.js +0 -0
  12. package/dist/{core → src/core}/OutdatedPackageProcessor.js +0 -0
  13. package/dist/{core → src/core}/OutdatedPackagesProcessor.js +0 -0
  14. package/dist/{core → src/core}/SucceededResult.js +0 -0
  15. package/dist/{core → src/core}/index.js +0 -0
  16. package/dist/{file → src/file}/index.js +0 -0
  17. package/dist/{file → src/file}/readFile.js +0 -0
  18. package/dist/{git → src/git}/CommitMessageCreator.js +0 -0
  19. package/dist/{git → src/git}/Git.js +0 -0
  20. package/dist/{git → src/git}/GitRepository.js +0 -0
  21. package/dist/{git → src/git}/createBranchName.js +0 -0
  22. package/dist/{git → src/git}/index.js +0 -0
  23. package/dist/{github → src/github}/GitHub.js +0 -0
  24. package/dist/{github → src/github}/branch/finder/BranchFinder.js +0 -0
  25. package/dist/{github → src/github}/branch/finder/index.js +0 -0
  26. package/dist/{github → src/github}/branch/index.js +0 -0
  27. package/dist/{github → src/github}/createGitHub.js +0 -0
  28. package/dist/{github → src/github}/createOctokit.js +5 -2
  29. package/dist/{github → src/github}/errors/NotFoundError.js +0 -0
  30. package/dist/{github → src/github}/errors/index.js +0 -0
  31. package/dist/{github → src/github}/index.js +0 -0
  32. package/dist/{github → src/github}/label/creator/LabelCreator.js +0 -0
  33. package/dist/{github → src/github}/label/creator/index.js +0 -0
  34. package/dist/{github → src/github}/label/index.js +0 -0
  35. package/dist/{github → src/github}/pull-request/closer/PullRequestCloser.js +0 -0
  36. package/dist/{github → src/github}/pull-request/closer/index.js +0 -0
  37. package/dist/{github → src/github}/pull-request/creator/PullRequestCreator.js +0 -0
  38. package/dist/{github → src/github}/pull-request/creator/PullRequestTitleCreator.js +0 -0
  39. package/dist/{github → src/github}/pull-request/creator/createPullRequestBody.js +5 -5
  40. package/dist/{github → src/github}/pull-request/creator/index.js +0 -0
  41. package/dist/{github → src/github}/pull-request/finder/PullRequestFinder.js +0 -0
  42. package/dist/{github → src/github}/pull-request/finder/index.js +0 -0
  43. package/dist/{github → src/github}/pull-request/finder/isPullRequestByNpmUpdatePackage.js +0 -0
  44. package/dist/{github → src/github}/pull-request/index.js +0 -0
  45. package/dist/{github → src/github}/pull-request/metadata/PullRequestMetadata.js +0 -0
  46. package/dist/{github → src/github}/pull-request/metadata/createPullRequestMetadata.js +5 -2
  47. package/dist/{github → src/github}/pull-request/metadata/extractPullRequestMetadata.js +0 -0
  48. package/dist/{github → src/github}/pull-request/metadata/index.js +0 -0
  49. package/dist/{json → src/json}/index.js +0 -0
  50. package/dist/{json → src/json}/toJSON.js +0 -0
  51. package/dist/{logger → src/logger}/LogLevel.js +0 -0
  52. package/dist/{logger → src/logger}/Logger.js +0 -0
  53. package/dist/{logger → src/logger}/createLogger.js +0 -0
  54. package/dist/{logger → src/logger}/index.js +0 -0
  55. package/dist/{main.js → src/main.js} +0 -0
  56. package/dist/{ncu → src/ncu}/Ncu.js +0 -0
  57. package/dist/{ncu → src/ncu}/NcuResult.js +0 -0
  58. package/dist/{ncu → src/ncu}/index.js +0 -0
  59. package/dist/{options → src/options}/CLIOption.js +0 -0
  60. package/dist/{options → src/options}/OptionType.js +0 -0
  61. package/dist/{options → src/options}/Options.js +0 -0
  62. package/dist/{options → src/options}/cliOptions.js +0 -0
  63. package/dist/{options → src/options}/index.js +0 -0
  64. package/dist/{options → src/options}/initOptions.js +5 -2
  65. package/dist/{options → src/options}/toCommanderOption.js +0 -0
  66. package/dist/{package-json → src/package-json}/PackageMetadata.js +0 -0
  67. package/dist/{package-json → src/package-json}/PackageMetadataDependencies.js +0 -0
  68. package/dist/{package-json → src/package-json}/index.js +0 -0
  69. package/dist/{package-json → src/package-json}/parsePackageJson.js +0 -0
  70. package/dist/{package-manager → src/package-manager}/Npm.js +0 -0
  71. package/dist/{package-manager → src/package-manager}/PackageManager.js +0 -0
  72. package/dist/{package-manager → src/package-manager}/PackageManagerName.js +0 -0
  73. package/dist/{package-manager → src/package-manager}/Yarn.js +0 -0
  74. package/dist/{package-manager → src/package-manager}/createPackageManager.js +0 -0
  75. package/dist/{package-manager → src/package-manager}/index.js +0 -0
  76. package/dist/{semver → src/semver}/SemVer.js +0 -0
  77. package/dist/{semver → src/semver}/SemVerLevel.js +0 -0
  78. package/dist/{semver → src/semver}/compareSemVers.js +0 -0
  79. package/dist/{semver → src/semver}/index.js +0 -0
  80. package/dist/{terminal → src/terminal}/Terminal.js +0 -0
  81. package/dist/{terminal → src/terminal}/index.js +0 -0
  82. package/jest.config.ts +12 -0
  83. package/lint-staged.config.js +4 -0
  84. package/npm-update-package.code-workspace +10 -0
  85. package/package.json +2 -5
  86. package/src/bin.ts +22 -0
  87. package/src/core/FailedResult.ts +6 -0
  88. package/src/core/OutdatedPackage.ts +11 -0
  89. package/src/core/OutdatedPackageProcessor.ts +136 -0
  90. package/src/core/OutdatedPackagesProcessor.ts +35 -0
  91. package/src/core/SucceededResult.ts +7 -0
  92. package/src/core/index.ts +5 -0
  93. package/src/file/index.ts +1 -0
  94. package/src/file/readFile.ts +6 -0
  95. package/src/git/CommitMessageCreator.test.ts +17 -0
  96. package/src/git/CommitMessageCreator.ts +19 -0
  97. package/src/git/Git.ts +59 -0
  98. package/src/git/GitRepository.test.ts +82 -0
  99. package/src/git/GitRepository.ts +57 -0
  100. package/src/git/createBranchName.test.ts +14 -0
  101. package/src/git/createBranchName.ts +7 -0
  102. package/src/git/index.ts +4 -0
  103. package/src/github/GitHub.ts +198 -0
  104. package/src/github/branch/finder/BranchFinder.test.ts +21 -0
  105. package/src/github/branch/finder/BranchFinder.ts +9 -0
  106. package/src/github/branch/finder/index.ts +1 -0
  107. package/src/github/branch/index.ts +1 -0
  108. package/src/github/createGitHub.test.ts +16 -0
  109. package/src/github/createGitHub.ts +17 -0
  110. package/src/github/createOctokit.test.ts +27 -0
  111. package/src/github/createOctokit.ts +27 -0
  112. package/src/github/errors/NotFoundError.ts +11 -0
  113. package/src/github/errors/index.ts +1 -0
  114. package/src/github/index.ts +5 -0
  115. package/src/github/label/creator/LabelCreator.ts +71 -0
  116. package/src/github/label/creator/index.ts +1 -0
  117. package/src/github/label/index.ts +1 -0
  118. package/src/github/pull-request/closer/PullRequestCloser.test.ts +53 -0
  119. package/src/github/pull-request/closer/PullRequestCloser.ts +21 -0
  120. package/src/github/pull-request/closer/index.ts +1 -0
  121. package/src/github/pull-request/creator/PullRequestCreator.test.ts +98 -0
  122. package/src/github/pull-request/creator/PullRequestCreator.ts +84 -0
  123. package/src/github/pull-request/creator/PullRequestTitleCreator.test.ts +17 -0
  124. package/src/github/pull-request/creator/PullRequestTitleCreator.ts +19 -0
  125. package/src/github/pull-request/creator/createPullRequestBody.test.ts +47 -0
  126. package/src/github/pull-request/creator/createPullRequestBody.ts +35 -0
  127. package/src/github/pull-request/creator/index.ts +2 -0
  128. package/src/github/pull-request/finder/PullRequestFinder.ts +27 -0
  129. package/src/github/pull-request/finder/index.ts +1 -0
  130. package/src/github/pull-request/finder/isPullRequestByNpmUpdatePackage.test.ts +24 -0
  131. package/src/github/pull-request/finder/isPullRequestByNpmUpdatePackage.ts +5 -0
  132. package/src/github/pull-request/index.ts +3 -0
  133. package/src/github/pull-request/metadata/PullRequestMetadata.ts +22 -0
  134. package/src/github/pull-request/metadata/createPullRequestMetadata.test.ts +31 -0
  135. package/src/github/pull-request/metadata/createPullRequestMetadata.ts +21 -0
  136. package/src/github/pull-request/metadata/extractPullRequestMetadata.test.ts +53 -0
  137. package/src/github/pull-request/metadata/extractPullRequestMetadata.ts +21 -0
  138. package/src/github/pull-request/metadata/index.ts +3 -0
  139. package/src/json/index.ts +1 -0
  140. package/src/json/toJSON.test.ts +65 -0
  141. package/src/json/toJSON.ts +13 -0
  142. package/src/logger/LogLevel.ts +13 -0
  143. package/src/logger/Logger.ts +1 -0
  144. package/src/logger/createLogger.ts +10 -0
  145. package/src/logger/index.ts +3 -0
  146. package/src/main.ts +149 -0
  147. package/src/ncu/Ncu.ts +84 -0
  148. package/src/ncu/NcuResult.ts +10 -0
  149. package/src/ncu/index.ts +1 -0
  150. package/src/options/CLIOption.ts +19 -0
  151. package/src/options/OptionType.ts +8 -0
  152. package/src/options/Options.ts +40 -0
  153. package/src/options/cliOptions.ts +60 -0
  154. package/src/options/index.ts +2 -0
  155. package/src/options/initOptions.ts +24 -0
  156. package/src/options/toCommanderOption.ts +35 -0
  157. package/src/package-json/PackageMetadata.ts +24 -0
  158. package/src/package-json/PackageMetadataDependencies.ts +10 -0
  159. package/src/package-json/index.ts +2 -0
  160. package/src/package-json/parsePackageJson.ts +15 -0
  161. package/src/package-manager/Npm.ts +17 -0
  162. package/src/package-manager/PackageManager.ts +5 -0
  163. package/src/package-manager/PackageManagerName.ts +8 -0
  164. package/src/package-manager/Yarn.ts +17 -0
  165. package/src/package-manager/createPackageManager.test.ts +27 -0
  166. package/src/package-manager/createPackageManager.ts +20 -0
  167. package/src/package-manager/index.ts +5 -0
  168. package/src/semver/SemVer.test.ts +17 -0
  169. package/src/semver/SemVer.ts +40 -0
  170. package/src/semver/SemVerLevel.ts +9 -0
  171. package/src/semver/compareSemVers.test.ts +21 -0
  172. package/src/semver/compareSemVers.ts +16 -0
  173. package/src/semver/index.ts +3 -0
  174. package/src/terminal/Terminal.ts +12 -0
  175. package/src/terminal/index.ts +1 -0
  176. package/tsconfig.base.json +7 -0
  177. package/tsconfig.build.json +12 -0
  178. package/tsconfig.json +9 -0
  179. package/dist/app.js +0 -8
@@ -0,0 +1,31 @@
1
+
2
+ import pkg from '../../../../package.json'
3
+ import type { OutdatedPackage } from '../../../core'
4
+ import { SemVer } from '../../../semver'
5
+ import { createPullRequestMetadata } from './createPullRequestMetadata'
6
+
7
+ describe('createPullRequestMetadata', () => {
8
+ it('returns PullRequestMetadata', () => {
9
+ const outdatedPackages: OutdatedPackage[] = [
10
+ {
11
+ name: '@npm-update-package/example',
12
+ currentVersion: SemVer.of('1.0.0'),
13
+ newVersion: SemVer.of('2.0.0'),
14
+ level: 'major'
15
+ }
16
+ ]
17
+ const metadata = createPullRequestMetadata(outdatedPackages)
18
+
19
+ expect(metadata).toEqual({
20
+ version: pkg.version,
21
+ packages: [
22
+ {
23
+ name: '@npm-update-package/example',
24
+ currentVersion: '1.0.0',
25
+ newVersion: '2.0.0',
26
+ level: 'major'
27
+ }
28
+ ]
29
+ })
30
+ })
31
+ })
@@ -0,0 +1,21 @@
1
+
2
+ import pkg from '../../../../package.json'
3
+ import type { OutdatedPackage } from '../../../core'
4
+ import type { PullRequestMetadata } from './PullRequestMetadata'
5
+
6
+ export const createPullRequestMetadata = (outdatedPackages: OutdatedPackage[]): PullRequestMetadata => {
7
+ return {
8
+ version: pkg.version,
9
+ packages: outdatedPackages.map(({
10
+ name,
11
+ currentVersion,
12
+ newVersion,
13
+ level
14
+ }) => ({
15
+ name,
16
+ currentVersion: currentVersion.version,
17
+ newVersion: newVersion.version,
18
+ level
19
+ }))
20
+ }
21
+ }
@@ -0,0 +1,53 @@
1
+ import { extractPullRequestMetadata } from './extractPullRequestMetadata'
2
+
3
+ describe('extractPullRequestMetadata', () => {
4
+ it('returns PullRequestMetadata if body contains metadata', () => {
5
+ const body = `<div id="npm-update-package-metadata">
6
+
7
+ \`\`\`json
8
+ {
9
+ "version": "1.0.0",
10
+ "packages": [
11
+ {
12
+ "name": "@npm-update-package/example",
13
+ "level": "major",
14
+ "currentVersion": "1.0.0",
15
+ "newVersion": "2.0.0"
16
+ }
17
+ ]
18
+ }
19
+ \`\`\`
20
+
21
+ </div>`
22
+ const metadata = extractPullRequestMetadata(body)
23
+ expect(metadata).toEqual({
24
+ version: '1.0.0',
25
+ packages: [
26
+ {
27
+ name: '@npm-update-package/example',
28
+ level: 'major',
29
+ currentVersion: '1.0.0',
30
+ newVersion: '2.0.0'
31
+ }
32
+ ]
33
+ })
34
+ })
35
+
36
+ it('returns undefined if body does not contain metadata', () => {
37
+ const body = ''
38
+ const metadata = extractPullRequestMetadata(body)
39
+ expect(metadata).toBeUndefined()
40
+ })
41
+
42
+ it('returns undefined if metadata is invalid', () => {
43
+ const body = `<div id="npm-update-package-metadata">
44
+
45
+ \`\`\`json
46
+ {}
47
+ \`\`\`
48
+
49
+ </div>`
50
+ const metadata = extractPullRequestMetadata(body)
51
+ expect(metadata).toBeUndefined()
52
+ })
53
+ })
@@ -0,0 +1,21 @@
1
+ import {
2
+ isPullRequestMetadata,
3
+ type PullRequestMetadata
4
+ } from './PullRequestMetadata'
5
+
6
+ export const extractPullRequestMetadata = (pullRequestBody: string): PullRequestMetadata | undefined => {
7
+ const matched = pullRequestBody.match(/<div id="npm-update-package-metadata">\s*```json\s*([\s\S]+?)\s*```\s*<\/div>/)
8
+ const json = matched?.[1]
9
+
10
+ if (json === undefined) {
11
+ return undefined
12
+ }
13
+
14
+ const metadata: unknown = JSON.parse(json)
15
+
16
+ if (!isPullRequestMetadata(metadata)) {
17
+ return undefined
18
+ }
19
+
20
+ return metadata
21
+ }
@@ -0,0 +1,3 @@
1
+ export * from './createPullRequestMetadata'
2
+ export * from './extractPullRequestMetadata'
3
+ export * from './PullRequestMetadata'
@@ -0,0 +1 @@
1
+ export * from './toJSON'
@@ -0,0 +1,65 @@
1
+ import { toJSON } from './toJSON'
2
+
3
+ type TestCase = [unknown, string]
4
+
5
+ describe('toJSON', () => {
6
+ describe('returns not indented JSON string if pretty option is false', () => {
7
+ const cases: TestCase[] = [
8
+ [
9
+ {
10
+ number: 1,
11
+ string: 'string'
12
+ },
13
+ '{"number":1,"string":"string"}'
14
+ ],
15
+ [
16
+ [
17
+ {
18
+ number: 1,
19
+ string: 'string'
20
+ }
21
+ ],
22
+ '[{"number":1,"string":"string"}]'
23
+ ]
24
+ ]
25
+
26
+ it.each<TestCase>(cases)('value=%j', (value, expected) => {
27
+ const json = toJSON(value)
28
+ expect(json).toBe(expected)
29
+ })
30
+ })
31
+
32
+ describe('returns indented JSON string if pretty option is true', () => {
33
+ const cases: TestCase[] = [
34
+ [
35
+ {
36
+ number: 1,
37
+ string: 'string'
38
+ },
39
+ `{
40
+ "number": 1,
41
+ "string": "string"
42
+ }`
43
+ ],
44
+ [
45
+ [
46
+ {
47
+ number: 1,
48
+ string: 'string'
49
+ }
50
+ ],
51
+ `[
52
+ {
53
+ "number": 1,
54
+ "string": "string"
55
+ }
56
+ ]`
57
+ ]
58
+ ]
59
+
60
+ it.each<TestCase>(cases)('value=%j', (value, expected) => {
61
+ const json = toJSON(value, { pretty: true })
62
+ expect(json).toBe(expected)
63
+ })
64
+ })
65
+ })
@@ -0,0 +1,13 @@
1
+ interface Options {
2
+ pretty?: boolean
3
+ }
4
+
5
+ export const toJSON = (value: unknown, options?: Options): string => {
6
+ const pretty = options?.pretty ?? false
7
+
8
+ if (pretty) {
9
+ return JSON.stringify(value, null, 2)
10
+ } else {
11
+ return JSON.stringify(value)
12
+ }
13
+ }
@@ -0,0 +1,13 @@
1
+ export const LogLevel = {
2
+ Debug: 'debug',
3
+ Error: 'error',
4
+ Fatal: 'fatal',
5
+ Info: 'info',
6
+ Off: 'off',
7
+ Trace: 'trace',
8
+ Warn: 'warn'
9
+ } as const
10
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
11
+ export type LogLevel = typeof LogLevel[keyof typeof LogLevel]
12
+ const logLevels = Object.values(LogLevel)
13
+ export const isLogLevel = (value: any): value is LogLevel => logLevels.includes(value)
@@ -0,0 +1 @@
1
+ export type { Logger } from 'log4js'
@@ -0,0 +1,10 @@
1
+ import { getLogger } from 'log4js'
2
+ import type { Logger } from './Logger'
3
+ import type { LogLevel } from './LogLevel'
4
+
5
+ // TODO: add test
6
+ export const createLogger = (logLevel: LogLevel): Logger => {
7
+ const logger = getLogger()
8
+ logger.level = logLevel
9
+ return logger
10
+ }
@@ -0,0 +1,3 @@
1
+ export * from './createLogger'
2
+ export * from './Logger'
3
+ export * from './LogLevel'
package/src/main.ts ADDED
@@ -0,0 +1,149 @@
1
+ import {
2
+ isLeft,
3
+ isRight
4
+ } from 'fp-ts/lib/Either'
5
+ import {
6
+ OutdatedPackageProcessor,
7
+ OutdatedPackagesProcessor
8
+ } from './core'
9
+ import {
10
+ CommitMessageCreator,
11
+ Git
12
+ } from './git'
13
+ import {
14
+ BranchFinder,
15
+ createGitHub,
16
+ LabelCreator,
17
+ PullRequestCloser,
18
+ PullRequestCreator,
19
+ PullRequestFinder,
20
+ PullRequestTitleCreator
21
+ } from './github'
22
+ import type { Logger } from './logger'
23
+ import { Ncu } from './ncu'
24
+ import type { Options } from './options'
25
+ import { createPackageManager } from './package-manager'
26
+ import { Terminal } from './terminal'
27
+
28
+ // TODO: add test
29
+ export const main = async ({
30
+ options,
31
+ logger
32
+ }: {
33
+ options: Options
34
+ logger: Logger
35
+ }): Promise<void> => {
36
+ logger.debug(`options=${JSON.stringify({
37
+ ...options,
38
+ githubToken: options.githubToken !== '' ? '***' : ''
39
+ })}`)
40
+
41
+ const ncu = new Ncu(logger)
42
+ const outdatedPackages = await ncu.check()
43
+ logger.debug(`outdatedPackages=${JSON.stringify(outdatedPackages)}`)
44
+
45
+ if (outdatedPackages.length === 0) {
46
+ logger.info('All packages are up-to-date.')
47
+ return
48
+ }
49
+
50
+ logger.info(`There are ${outdatedPackages.length} outdated packages.`)
51
+
52
+ const terminal = new Terminal()
53
+ const git = new Git(terminal)
54
+ const gitRepo = await git.getRepository()
55
+ logger.debug(`gitRepo=${JSON.stringify(gitRepo)}`)
56
+
57
+ const github = createGitHub({
58
+ repository: gitRepo,
59
+ token: options.githubToken
60
+ })
61
+ const githubRepo = await github.fetchRepository({
62
+ owner: gitRepo.owner,
63
+ repo: gitRepo.name
64
+ })
65
+ logger.debug(`githubRepo=${JSON.stringify(githubRepo)}`)
66
+
67
+ const branches = await github.fetchBranches({
68
+ owner: gitRepo.owner,
69
+ repo: gitRepo.name
70
+ })
71
+ logger.debug(`branches=${JSON.stringify(branches)}`)
72
+
73
+ const pullRequests = await github.fetchPullRequests({
74
+ owner: gitRepo.owner,
75
+ repo: gitRepo.name
76
+ })
77
+ logger.debug(`pullRequests=${JSON.stringify(pullRequests)}`)
78
+
79
+ const labelCreator = new LabelCreator({
80
+ github,
81
+ gitRepo,
82
+ logger
83
+ })
84
+ await labelCreator.create({
85
+ name: 'npm-update-package',
86
+ description: 'Created by npm-update-package',
87
+ color: 'A00F21'
88
+ })
89
+
90
+ const branchFinder = new BranchFinder(branches)
91
+ const packageManager = createPackageManager({
92
+ terminal,
93
+ packageManager: options.packageManager
94
+ })
95
+ const pullRequestTitleCreator = new PullRequestTitleCreator(options.pullRequestTitle)
96
+ const pullRequestCreator = new PullRequestCreator({
97
+ github,
98
+ gitRepo,
99
+ githubRepo,
100
+ pullRequestTitleCreator,
101
+ logger,
102
+ reviewers: options.reviewers
103
+ })
104
+ const commitMessageCreator = new CommitMessageCreator(options.commitMessage)
105
+ const pullRequestFinder = new PullRequestFinder(pullRequests)
106
+ const pullRequestCloser = new PullRequestCloser(github)
107
+ const outdatedPackageProcessor = new OutdatedPackageProcessor({
108
+ git,
109
+ ncu,
110
+ packageManager,
111
+ pullRequestCreator,
112
+ branchFinder,
113
+ logger,
114
+ commitMessageCreator,
115
+ pullRequestFinder,
116
+ pullRequestCloser
117
+ })
118
+ const outdatedPackagesProcessor = new OutdatedPackagesProcessor({
119
+ outdatedPackageProcessor,
120
+ logger
121
+ })
122
+ const results = await outdatedPackagesProcessor.process(outdatedPackages)
123
+ logger.debug(`results=${JSON.stringify(results)}`)
124
+
125
+ const succeededResults = results.filter(isRight).map(({ right }) => right)
126
+ logger.debug(`succeededResults=${JSON.stringify(succeededResults)}`)
127
+
128
+ const createdPackages = succeededResults
129
+ .filter(({ created }) => created)
130
+ .map(({ outdatedPackage }) => outdatedPackage)
131
+ logger.debug(`createdPackages=${JSON.stringify(createdPackages)}`)
132
+
133
+ const skippedPackages = succeededResults
134
+ .filter(({ skipped }) => skipped)
135
+ .map(({ outdatedPackage }) => outdatedPackage)
136
+ logger.debug(`skippedPackages=${JSON.stringify(skippedPackages)}`)
137
+
138
+ const failedResults = results.filter(isLeft).map(({ left }) => left)
139
+ logger.debug(`failedResults=${JSON.stringify(failedResults)}`)
140
+
141
+ const failedPackages = failedResults.map(({ outdatedPackage }) => outdatedPackage)
142
+ logger.debug(`failedPackages=${JSON.stringify(failedPackages)}`)
143
+
144
+ // TODO: show as table
145
+ logger.info(`Processed ${succeededResults.length + failedPackages.length} packages:
146
+ - ${createdPackages.length} packages: created (${createdPackages.map(({ name }) => name).join(',')})
147
+ - ${skippedPackages.length} packages: skipped: (${skippedPackages.map(({ name }) => name).join(',')})
148
+ - ${failedPackages.length} packages: failed: (${failedPackages.map(({ name }) => name).join(',')})`)
149
+ }
package/src/ncu/Ncu.ts ADDED
@@ -0,0 +1,84 @@
1
+ import { run } from 'npm-check-updates'
2
+ import type { RunOptions } from 'npm-check-updates/build/src/types'
3
+ import { isNotUndefined } from 'type-guards'
4
+ import type { OutdatedPackage } from '../core'
5
+ import { readFile } from '../file'
6
+ import type { Logger } from '../logger'
7
+ import { parsePackageJson } from '../package-json'
8
+ import {
9
+ compareSemVers,
10
+ SemVer
11
+ } from '../semver'
12
+ import { isNcuResult } from './NcuResult'
13
+
14
+ // TODO: add test
15
+ export class Ncu {
16
+ constructor (private readonly logger: Logger) {}
17
+
18
+ async check (): Promise<OutdatedPackage[]> {
19
+ return await this.run({
20
+ jsonUpgraded: true
21
+ })
22
+ }
23
+
24
+ async update (outdatedPackage: OutdatedPackage): Promise<OutdatedPackage[]> {
25
+ return await this.run({
26
+ jsonUpgraded: true,
27
+ filter: outdatedPackage.name,
28
+ upgrade: true
29
+ })
30
+ }
31
+
32
+ private async run (options: RunOptions): Promise<OutdatedPackage[]> {
33
+ // Read package.json before running ncu
34
+ const json = await readFile('./package.json')
35
+ const pkg = parsePackageJson(json)
36
+ this.logger.debug(`pkg=${JSON.stringify(pkg)}`)
37
+
38
+ const result = await run(options)
39
+ this.logger.debug(`result=${JSON.stringify(result)}`)
40
+
41
+ if (!isNcuResult(result)) {
42
+ throw new Error('Failed to running ncu.')
43
+ }
44
+
45
+ const currentDependencies = {
46
+ ...pkg.dependencies,
47
+ ...pkg.devDependencies,
48
+ ...pkg.peerDependencies,
49
+ ...pkg.optionalDependencies
50
+ }
51
+ const resultEntries = Object.entries(result)
52
+ const outdatedPackages: OutdatedPackage[] = resultEntries
53
+ .map(([name, newVersionString]) => {
54
+ const currentVersionString = currentDependencies[name]
55
+
56
+ if (currentVersionString === undefined) {
57
+ return undefined
58
+ }
59
+
60
+ const currentVersion = SemVer.of(currentVersionString)
61
+ const newVersion = SemVer.of(newVersionString)
62
+ const level = compareSemVers(currentVersion, newVersion)
63
+
64
+ if (level === undefined) {
65
+ return undefined
66
+ }
67
+
68
+ const outdatedPackage: OutdatedPackage = {
69
+ name,
70
+ currentVersion,
71
+ newVersion,
72
+ level
73
+ }
74
+ return outdatedPackage
75
+ })
76
+ .filter(isNotUndefined)
77
+
78
+ if (resultEntries.length !== outdatedPackages.length) {
79
+ throw new Error('Failed to running ncu.')
80
+ }
81
+
82
+ return outdatedPackages
83
+ }
84
+ }
@@ -0,0 +1,10 @@
1
+ import {
2
+ record,
3
+ string,
4
+ type TypeOf
5
+ } from 'io-ts'
6
+
7
+ export const NcuResult = record(string, string)
8
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
9
+ export type NcuResult = TypeOf<typeof NcuResult>
10
+ export const isNcuResult = NcuResult.is
@@ -0,0 +1 @@
1
+ export * from './Ncu'
@@ -0,0 +1,19 @@
1
+ import type { OptionType } from './OptionType'
2
+
3
+ interface OptionBase {
4
+ name: string
5
+ description: string
6
+ type: OptionType
7
+ choices?: string[]
8
+ }
9
+
10
+ interface RequiredOption extends OptionBase {
11
+ required: true
12
+ }
13
+
14
+ interface OptionalOption extends OptionBase {
15
+ required: false
16
+ default?: string
17
+ }
18
+
19
+ export type CLIOption = RequiredOption | OptionalOption
@@ -0,0 +1,8 @@
1
+ export const OptionType = {
2
+ String: 'string',
3
+ StringArray: 'string[]'
4
+ } as const
5
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
6
+ export type OptionType = typeof OptionType[keyof typeof OptionType]
7
+ const optionTypes = Object.values(OptionType)
8
+ export const isOptionType = (value: any): value is OptionType => optionTypes.includes(value)
@@ -0,0 +1,40 @@
1
+ import {
2
+ array,
3
+ intersection,
4
+ literal,
5
+ partial,
6
+ string,
7
+ type,
8
+ union,
9
+ type TypeOf
10
+ } from 'io-ts'
11
+ import { LogLevel } from '../logger'
12
+ import { PackageManagerName } from '../package-manager'
13
+
14
+ const Options = intersection([
15
+ type({
16
+ commitMessage: string,
17
+ githubToken: string,
18
+ logLevel: union([
19
+ literal(LogLevel.Off),
20
+ literal(LogLevel.Fatal),
21
+ literal(LogLevel.Error),
22
+ literal(LogLevel.Warn),
23
+ literal(LogLevel.Info),
24
+ literal(LogLevel.Debug),
25
+ literal(LogLevel.Trace)
26
+ ]),
27
+ packageManager: union([
28
+ literal(PackageManagerName.Npm),
29
+ literal(PackageManagerName.Yarn)
30
+ ]),
31
+ pullRequestTitle: string
32
+ }),
33
+ partial({
34
+ reviewers: array(string)
35
+ })
36
+ ])
37
+
38
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
39
+ export type Options = TypeOf<typeof Options>
40
+ export const isOptions = Options.is
@@ -0,0 +1,60 @@
1
+ import { LogLevel } from '../logger'
2
+ import { PackageManagerName } from '../package-manager'
3
+ import type { CLIOption } from './CLIOption'
4
+ import { OptionType } from './OptionType'
5
+
6
+ export const cliOptions: CLIOption[] = [
7
+ {
8
+ name: 'commit-message',
9
+ description: 'Commit message template',
10
+ type: OptionType.String,
11
+ required: false,
12
+ default: 'chore(deps): {{level}} update {{{packageName}}} to v{{newVersion}}'
13
+ },
14
+ {
15
+ name: 'github-token',
16
+ description: 'GitHub token',
17
+ type: OptionType.String,
18
+ required: true
19
+ },
20
+ {
21
+ name: 'log-level',
22
+ description: 'Log level to show',
23
+ type: OptionType.String,
24
+ required: false,
25
+ choices: [
26
+ LogLevel.Off,
27
+ LogLevel.Fatal,
28
+ LogLevel.Error,
29
+ LogLevel.Warn,
30
+ LogLevel.Info,
31
+ LogLevel.Debug,
32
+ LogLevel.Trace
33
+ ],
34
+ default: LogLevel.Info
35
+ },
36
+ {
37
+ name: 'package-manager',
38
+ description: 'Package manager of your project',
39
+ type: OptionType.String,
40
+ required: false,
41
+ choices: [
42
+ PackageManagerName.Npm,
43
+ PackageManagerName.Yarn
44
+ ],
45
+ default: PackageManagerName.Npm
46
+ },
47
+ {
48
+ name: 'pull-request-title',
49
+ description: 'Pull request title template',
50
+ type: OptionType.String,
51
+ required: false,
52
+ default: 'chore(deps): {{level}} update {{{packageName}}} to v{{newVersion}}'
53
+ },
54
+ {
55
+ name: 'reviewers',
56
+ description: 'User names to request reviews',
57
+ type: OptionType.StringArray,
58
+ required: false
59
+ }
60
+ ]
@@ -0,0 +1,2 @@
1
+ export * from './initOptions'
2
+ export * from './Options'
@@ -0,0 +1,24 @@
1
+ import { program } from 'commander'
2
+ import pkg from '../../package.json'
3
+ import { cliOptions } from './cliOptions'
4
+ import {
5
+ isOptions,
6
+ type Options
7
+ } from './Options'
8
+ import { toCommanderOption } from './toCommanderOption'
9
+
10
+ // TODO: add test
11
+ export const initOptions = (): Options => {
12
+ program.version(pkg.version)
13
+ cliOptions
14
+ .map(toCommanderOption)
15
+ .forEach(option => program.addOption(option))
16
+ program.parse(process.argv)
17
+ const options = program.opts()
18
+
19
+ if (!isOptions(options)) {
20
+ throw new Error(`Failed to parse command-line options. options=${JSON.stringify(options)}`)
21
+ }
22
+
23
+ return options
24
+ }