npm-update-package 0.1.0

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 (140) 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 +19 -0
  6. package/.husky/pre-commit +4 -0
  7. package/.nvmrc +1 -0
  8. package/LICENSE +22 -0
  9. package/README.md +43 -0
  10. package/dist/app.js +8 -0
  11. package/dist/bin.js +18 -0
  12. package/dist/enums/LogLevel.js +10 -0
  13. package/dist/enums/PackageManagerName.js +10 -0
  14. package/dist/enums/UpdateType.js +11 -0
  15. package/dist/enums/index.js +12 -0
  16. package/dist/git/Committer.js +31 -0
  17. package/dist/git/Git.js +48 -0
  18. package/dist/git/GitRepository.js +41 -0
  19. package/dist/git/index.js +7 -0
  20. package/dist/github/Branch.js +2 -0
  21. package/dist/github/GitHub.js +22 -0
  22. package/dist/github/PullRequest.js +2 -0
  23. package/dist/github/PullRequestCreator.js +31 -0
  24. package/dist/github/RemoteBranchExistenceChecker.js +17 -0
  25. package/dist/github/Repository.js +2 -0
  26. package/dist/github/createGitHub.js +14 -0
  27. package/dist/github/createOctokit.js +24 -0
  28. package/dist/github/createPullRequestBody.js +19 -0
  29. package/dist/github/createPullRequestTitle.js +10 -0
  30. package/dist/github/index.js +11 -0
  31. package/dist/logger/Logger.js +2 -0
  32. package/dist/logger/createLogger.js +11 -0
  33. package/dist/logger/index.js +5 -0
  34. package/dist/main.js +83 -0
  35. package/dist/ncu/Ncu.js +38 -0
  36. package/dist/ncu/NcuOutdatedPackages.js +2 -0
  37. package/dist/ncu/NcuOutdatedPackagesConverter.js +26 -0
  38. package/dist/ncu/index.js +5 -0
  39. package/dist/ncu/isNcuOutdatedPackages.js +8 -0
  40. package/dist/ncu/toUpdateType.js +17 -0
  41. package/dist/options/Options.js +16 -0
  42. package/dist/options/index.js +5 -0
  43. package/dist/options/initOptions.js +27 -0
  44. package/dist/outdated-package-processor/OutdatedPackageProcessor.js +56 -0
  45. package/dist/outdated-package-processor/createBranchName.js +9 -0
  46. package/dist/outdated-package-processor/createCommitMessage.js +10 -0
  47. package/dist/outdated-package-processor/index.js +5 -0
  48. package/dist/outdated-packages-processor/OutdatedPackagesProcessor.js +19 -0
  49. package/dist/outdated-packages-processor/index.js +5 -0
  50. package/dist/package-manager/Npm.js +20 -0
  51. package/dist/package-manager/PackageManager.js +2 -0
  52. package/dist/package-manager/Yarn.js +20 -0
  53. package/dist/package-manager/createPackageManager.js +15 -0
  54. package/dist/package-manager/index.js +9 -0
  55. package/dist/read-package-json/Package.js +18 -0
  56. package/dist/read-package-json/PackageDependencies.js +6 -0
  57. package/dist/read-package-json/index.js +5 -0
  58. package/dist/read-package-json/parsePackageJson.js +15 -0
  59. package/dist/read-package-json/readFile.js +12 -0
  60. package/dist/read-package-json/readPackageJson.js +11 -0
  61. package/dist/terminal/Terminal.js +29 -0
  62. package/dist/terminal/index.js +5 -0
  63. package/dist/terminal/isExecaReturnValue.js +24 -0
  64. package/dist/types/OutdatedPackage.js +2 -0
  65. package/dist/types/Result.js +2 -0
  66. package/dist/types/index.js +2 -0
  67. package/dist/values/PackageVersion.js +25 -0
  68. package/dist/values/index.js +5 -0
  69. package/jest.config.ts +11 -0
  70. package/lint-staged.config.js +4 -0
  71. package/package.json +59 -0
  72. package/src/app.ts +5 -0
  73. package/src/bin.ts +19 -0
  74. package/src/enums/LogLevel.ts +8 -0
  75. package/src/enums/PackageManagerName.ts +8 -0
  76. package/src/enums/UpdateType.ts +9 -0
  77. package/src/enums/index.ts +12 -0
  78. package/src/git/Committer.ts +49 -0
  79. package/src/git/Git.ts +55 -0
  80. package/src/git/GitRepository.test.ts +61 -0
  81. package/src/git/GitRepository.ts +57 -0
  82. package/src/git/index.ts +3 -0
  83. package/src/github/Branch.ts +4 -0
  84. package/src/github/GitHub.ts +27 -0
  85. package/src/github/PullRequest.ts +3 -0
  86. package/src/github/PullRequestCreator.ts +57 -0
  87. package/src/github/RemoteBranchExistenceChecker.ts +15 -0
  88. package/src/github/Repository.ts +3 -0
  89. package/src/github/createGitHub.ts +18 -0
  90. package/src/github/createOctokit.ts +28 -0
  91. package/src/github/createPullRequestBody.test.ts +62 -0
  92. package/src/github/createPullRequestBody.ts +17 -0
  93. package/src/github/createPullRequestTitle.test.ts +43 -0
  94. package/src/github/createPullRequestTitle.ts +8 -0
  95. package/src/github/index.ts +7 -0
  96. package/src/logger/Logger.ts +1 -0
  97. package/src/logger/createLogger.ts +10 -0
  98. package/src/logger/index.ts +2 -0
  99. package/src/main.ts +105 -0
  100. package/src/ncu/Ncu.ts +41 -0
  101. package/src/ncu/NcuOutdatedPackages.ts +6 -0
  102. package/src/ncu/NcuOutdatedPackagesConverter.ts +25 -0
  103. package/src/ncu/index.ts +1 -0
  104. package/src/ncu/isNcuOutdatedPackages.ts +6 -0
  105. package/src/ncu/toUpdateType.test.ts +21 -0
  106. package/src/ncu/toUpdateType.ts +18 -0
  107. package/src/options/Options.ts +24 -0
  108. package/src/options/index.ts +2 -0
  109. package/src/options/initOptions.ts +34 -0
  110. package/src/outdated-package-processor/OutdatedPackageProcessor.ts +101 -0
  111. package/src/outdated-package-processor/createBranchName.test.ts +14 -0
  112. package/src/outdated-package-processor/createBranchName.ts +7 -0
  113. package/src/outdated-package-processor/createCommitMessage.test.ts +43 -0
  114. package/src/outdated-package-processor/createCommitMessage.ts +8 -0
  115. package/src/outdated-package-processor/index.ts +1 -0
  116. package/src/outdated-packages-processor/OutdatedPackagesProcessor.ts +34 -0
  117. package/src/outdated-packages-processor/index.ts +1 -0
  118. package/src/package-manager/Npm.ts +19 -0
  119. package/src/package-manager/PackageManager.ts +4 -0
  120. package/src/package-manager/Yarn.ts +19 -0
  121. package/src/package-manager/createPackageManager.ts +21 -0
  122. package/src/package-manager/index.ts +4 -0
  123. package/src/read-package-json/Package.ts +24 -0
  124. package/src/read-package-json/PackageDependencies.ts +10 -0
  125. package/src/read-package-json/index.ts +2 -0
  126. package/src/read-package-json/parsePackageJson.ts +13 -0
  127. package/src/read-package-json/readFile.ts +6 -0
  128. package/src/read-package-json/readPackageJson.ts +9 -0
  129. package/src/terminal/Terminal.ts +30 -0
  130. package/src/terminal/index.ts +1 -0
  131. package/src/terminal/isExecaReturnValue.ts +30 -0
  132. package/src/types/OutdatedPackage.ts +9 -0
  133. package/src/types/Result.ts +7 -0
  134. package/src/types/index.ts +2 -0
  135. package/src/values/PackageVersion.test.ts +25 -0
  136. package/src/values/PackageVersion.ts +40 -0
  137. package/src/values/index.ts +1 -0
  138. package/tsconfig.base.json +3 -0
  139. package/tsconfig.build.json +13 -0
  140. package/tsconfig.json +9 -0
package/src/main.ts ADDED
@@ -0,0 +1,105 @@
1
+ import {
2
+ Committer,
3
+ Git
4
+ } from './git'
5
+ import {
6
+ createGitHub,
7
+ PullRequestCreator,
8
+ RemoteBranchExistenceChecker
9
+ } from './github'
10
+ import type { Logger } from './logger'
11
+ import { Ncu } from './ncu'
12
+ import type { Options } from './options'
13
+ import { OutdatedPackageProcessor } from './outdated-package-processor'
14
+ import { OutdatedPackagesProcessor } from './outdated-packages-processor'
15
+ import { createPackageManager } from './package-manager'
16
+ import { Terminal } from './terminal'
17
+
18
+ // TODO: add test
19
+ export const main = async ({
20
+ options,
21
+ logger
22
+ }: {
23
+ options: Options
24
+ logger: Logger
25
+ }): Promise<void> => {
26
+ logger.debug(`options=${JSON.stringify(options)}`)
27
+
28
+ const ncu = new Ncu()
29
+ const outdatedPackages = await ncu.check()
30
+ logger.debug(`outdatedPackages=${JSON.stringify(outdatedPackages)}`)
31
+
32
+ if (outdatedPackages.length === 0) {
33
+ logger.info('All packages are up-to-date.')
34
+ return
35
+ }
36
+
37
+ logger.info(`There are ${outdatedPackages.length} outdated packages.`)
38
+
39
+ const terminal = new Terminal()
40
+ const git = new Git(terminal)
41
+ const gitRepo = await git.getRepository()
42
+ logger.debug(`gitRepo=${JSON.stringify(gitRepo)}`)
43
+
44
+ const github = createGitHub({
45
+ repository: gitRepo,
46
+ token: options.githubToken
47
+ })
48
+ const githubRepo = await github.fetchRepository({
49
+ owner: gitRepo.owner,
50
+ repo: gitRepo.name
51
+ })
52
+ logger.debug(`githubRepo=${JSON.stringify(githubRepo)}`)
53
+
54
+ const remoteBranches = await github.fetchBranches({
55
+ owner: gitRepo.owner,
56
+ repo: gitRepo.name
57
+ })
58
+ logger.debug(`remoteBranches=${JSON.stringify(remoteBranches)}`)
59
+
60
+ const remoteBranchExistenceChecker = RemoteBranchExistenceChecker.of(remoteBranches)
61
+ const committer = new Committer({
62
+ git,
63
+ user: {
64
+ name: options.gitUserName,
65
+ email: options.gitUserEmail
66
+ }
67
+ })
68
+ const packageManager = createPackageManager({
69
+ terminal,
70
+ packageManager: options.packageManager
71
+ })
72
+ const pullRequestCreator = new PullRequestCreator({
73
+ github,
74
+ gitRepo,
75
+ githubRepo,
76
+ logger
77
+ })
78
+ const outdatedPackageProcessor = new OutdatedPackageProcessor({
79
+ committer,
80
+ git,
81
+ ncu,
82
+ packageManager,
83
+ pullRequestCreator,
84
+ remoteBranchExistenceChecker,
85
+ logger
86
+ })
87
+ const outdatedPackagesProcessor = new OutdatedPackagesProcessor({
88
+ outdatedPackageProcessor,
89
+ logger
90
+ })
91
+ const results = await outdatedPackagesProcessor.process(outdatedPackages)
92
+ logger.debug(`results=${JSON.stringify(results)}`)
93
+
94
+ const updatedPackages = results
95
+ .filter(({ updated }) => updated)
96
+ .map(({ outdatedPackage }) => outdatedPackage)
97
+ logger.debug(`updatedPackages=${JSON.stringify(updatedPackages)}`)
98
+
99
+ const skippedPackages = results
100
+ .filter(({ skipped }) => skipped)
101
+ .map(({ outdatedPackage }) => outdatedPackage)
102
+ logger.debug(`skippedPackages=${JSON.stringify(skippedPackages)}`)
103
+
104
+ logger.info(`${updatedPackages.length} packages has updated. ${skippedPackages.length} packages has skipped.`)
105
+ }
package/src/ncu/Ncu.ts ADDED
@@ -0,0 +1,41 @@
1
+ import { run } from 'npm-check-updates'
2
+ import type { Options } from 'npm-check-updates/build/src/types'
3
+ import { readPackageJson } from '../read-package-json'
4
+ import type { OutdatedPackage } from '../types'
5
+ import { isNcuOutdatedPackages } from './isNcuOutdatedPackages'
6
+ import { NcuOutdatedPackagesConverter } from './NcuOutdatedPackagesConverter'
7
+
8
+ // TODO: add test
9
+ export class Ncu {
10
+ async check (): Promise<OutdatedPackage[]> {
11
+ return await this.run({
12
+ jsonUpgraded: true
13
+ })
14
+ }
15
+
16
+ async update (outdatedPackage: OutdatedPackage): Promise<OutdatedPackage[]> {
17
+ return await this.run({
18
+ jsonUpgraded: true,
19
+ filter: outdatedPackage.name,
20
+ upgrade: true
21
+ })
22
+ }
23
+
24
+ private async run (options: Options): Promise<OutdatedPackage[]> {
25
+ const pkg = await readPackageJson('./package.json')
26
+ const currentDependencies = {
27
+ ...pkg.dependencies,
28
+ ...pkg.devDependencies,
29
+ ...pkg.peerDependencies,
30
+ ...pkg.optionalDependencies
31
+ }
32
+ const result = await run(options)
33
+
34
+ if (!isNcuOutdatedPackages(result)) {
35
+ throw new Error('result is not NcuOutdatedPackages')
36
+ }
37
+
38
+ const ncuOutdatedPackagesConverter = new NcuOutdatedPackagesConverter(currentDependencies)
39
+ return ncuOutdatedPackagesConverter.toOutdatedPackages(result)
40
+ }
41
+ }
@@ -0,0 +1,6 @@
1
+ import type {
2
+ Index,
3
+ VersionSpec
4
+ } from 'npm-check-updates/build/src/types'
5
+
6
+ export type NcuOutdatedPackages = Index<VersionSpec>
@@ -0,0 +1,25 @@
1
+ import type { PackageDependencies } from '../read-package-json'
2
+ import type { OutdatedPackage } from '../types'
3
+ import { PackageVersion } from '../values'
4
+ import type { NcuOutdatedPackages } from './NcuOutdatedPackages'
5
+ import { toUpdateType } from './toUpdateType'
6
+
7
+ // TODO: add test
8
+ export class NcuOutdatedPackagesConverter {
9
+ constructor (private readonly currentDependencies: PackageDependencies) {}
10
+
11
+ toOutdatedPackages (outdatedPackages: NcuOutdatedPackages): OutdatedPackage[] {
12
+ return Object.entries(outdatedPackages)
13
+ .map(([name, newVersion]) => ({
14
+ name,
15
+ currentVersion: PackageVersion.of(this.currentDependencies[name]),
16
+ newVersion: PackageVersion.of(newVersion)
17
+ }))
18
+ .map(({ name, currentVersion, newVersion }) => ({
19
+ name,
20
+ currentVersion,
21
+ newVersion,
22
+ type: toUpdateType(currentVersion, newVersion)
23
+ }))
24
+ }
25
+ }
@@ -0,0 +1 @@
1
+ export { Ncu } from './Ncu'
@@ -0,0 +1,6 @@
1
+ import type { NcuOutdatedPackages } from './NcuOutdatedPackages'
2
+
3
+ // TODO: add test
4
+ export const isNcuOutdatedPackages = (value: unknown): value is NcuOutdatedPackages => {
5
+ return typeof value === 'object' && value !== null && Object.values(value).every(value => typeof value === 'string')
6
+ }
@@ -0,0 +1,21 @@
1
+ import { UpdateType } from '../enums'
2
+ import { PackageVersion } from '../values'
3
+ import { toUpdateType } from './toUpdateType'
4
+
5
+ describe('toUpdateType', () => {
6
+ const currentVersion = PackageVersion.of('1.0.0')
7
+
8
+ describe('if both versions are different', () => {
9
+ it('returns UpdateType', () => {
10
+ expect(toUpdateType(currentVersion, PackageVersion.of('1.0.1'))).toBe(UpdateType.Patch)
11
+ expect(toUpdateType(currentVersion, PackageVersion.of('1.1.1'))).toBe(UpdateType.Minor)
12
+ expect(toUpdateType(currentVersion, PackageVersion.of('2.1.1'))).toBe(UpdateType.Major)
13
+ })
14
+ })
15
+
16
+ describe('if both versions are same', () => {
17
+ it('throws error', () => {
18
+ expect(() => toUpdateType(currentVersion, PackageVersion.of('1.0.0'))).toThrow(Error)
19
+ })
20
+ })
21
+ })
@@ -0,0 +1,18 @@
1
+ import { UpdateType } from '../enums'
2
+ import type { PackageVersion } from '../values'
3
+
4
+ export const toUpdateType = (currentVersion: PackageVersion, newVersion: PackageVersion): UpdateType => {
5
+ if (currentVersion.major !== newVersion.major) {
6
+ return UpdateType.Major
7
+ }
8
+
9
+ if (currentVersion.minor !== newVersion.minor) {
10
+ return UpdateType.Minor
11
+ }
12
+
13
+ if (currentVersion.patch !== newVersion.patch) {
14
+ return UpdateType.Patch
15
+ }
16
+
17
+ throw new Error('Both versions are same.')
18
+ }
@@ -0,0 +1,24 @@
1
+ import {
2
+ intersection,
3
+ literal,
4
+ partial,
5
+ string,
6
+ type,
7
+ union
8
+ } from 'io-ts'
9
+ import type { TypeOf } from 'io-ts'
10
+
11
+ export const Options = intersection([
12
+ type({
13
+ githubToken: string,
14
+ logLevel: union([literal('info'), literal('debug')]),
15
+ packageManager: union([literal('npm'), literal('yarn')])
16
+ }),
17
+ partial({
18
+ gitUserEmail: string,
19
+ gitUserName: string
20
+ })
21
+ ])
22
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
23
+ export type Options = TypeOf<typeof Options>
24
+ export const isOptions = Options.is
@@ -0,0 +1,2 @@
1
+ export { initOptions } from './initOptions'
2
+ export type { Options } from './Options'
@@ -0,0 +1,34 @@
1
+ import {
2
+ Option,
3
+ program
4
+ } from 'commander'
5
+ import { app } from '../app'
6
+ import { isOptions } from './Options'
7
+ import type { Options } from './Options'
8
+
9
+ // TODO: add test
10
+ export const initOptions = (): Options => {
11
+ program
12
+ .version(app.version)
13
+ .option('--git-user-email <value>', 'User email of commit')
14
+ .option('--git-user-name <value>', 'User name of commit')
15
+ .requiredOption('--github-token <value>', 'GitHub token')
16
+ .addOption(
17
+ new Option('--log-level <value>', 'Log level to show')
18
+ .choices(['info', 'debug'])
19
+ .default('info')
20
+ )
21
+ .addOption(
22
+ new Option('--package-manager <value>', 'Package manager of your project')
23
+ .choices(['npm', 'yarn'])
24
+ .default('npm')
25
+ )
26
+ program.parse(process.argv)
27
+ const options = program.opts()
28
+
29
+ if (!isOptions(options)) {
30
+ throw new Error(`Failed to parse command-line options. options=${JSON.stringify(options)}`)
31
+ }
32
+
33
+ return options
34
+ }
@@ -0,0 +1,101 @@
1
+ import type {
2
+ Committer,
3
+ Git
4
+ } from '../git'
5
+ import type {
6
+ PullRequestCreator,
7
+ RemoteBranchExistenceChecker
8
+ } from '../github'
9
+ import type { Logger } from '../logger'
10
+ import type { Ncu } from '../ncu'
11
+ import type { PackageManager } from '../package-manager'
12
+ import type {
13
+ OutdatedPackage,
14
+ Result
15
+ } from '../types'
16
+ import { createBranchName } from './createBranchName'
17
+ import { createCommitMessage } from './createCommitMessage'
18
+
19
+ // TODO: add test
20
+ export class OutdatedPackageProcessor {
21
+ private readonly committer: Committer
22
+ private readonly git: Git
23
+ private readonly ncu: Ncu
24
+ private readonly packageManager: PackageManager
25
+ private readonly pullRequestCreator: PullRequestCreator
26
+ private readonly remoteBranchExistenceChecker: RemoteBranchExistenceChecker
27
+ private readonly logger: Logger
28
+
29
+ constructor ({
30
+ committer,
31
+ git,
32
+ ncu,
33
+ packageManager,
34
+ pullRequestCreator,
35
+ remoteBranchExistenceChecker,
36
+ logger
37
+ }: {
38
+ committer: Committer
39
+ git: Git
40
+ ncu: Ncu
41
+ packageManager: PackageManager
42
+ pullRequestCreator: PullRequestCreator
43
+ remoteBranchExistenceChecker: RemoteBranchExistenceChecker
44
+ logger: Logger
45
+ }) {
46
+ this.committer = committer
47
+ this.git = git
48
+ this.ncu = ncu
49
+ this.packageManager = packageManager
50
+ this.pullRequestCreator = pullRequestCreator
51
+ this.remoteBranchExistenceChecker = remoteBranchExistenceChecker
52
+ this.logger = logger
53
+ }
54
+
55
+ /**
56
+ * Don't run in parallel because it includes file operations.
57
+ */
58
+ async process (outdatedPackage: OutdatedPackage): Promise<Result> {
59
+ const branchName = createBranchName(outdatedPackage)
60
+ this.logger.debug(`branchName=${branchName}`)
61
+
62
+ if (this.remoteBranchExistenceChecker.check(branchName)) {
63
+ this.logger.info(`Skip ${outdatedPackage.name} because ${branchName} branch already exists on remote.`)
64
+ return {
65
+ outdatedPackage,
66
+ skipped: true
67
+ }
68
+ }
69
+
70
+ await this.git.createBranch(branchName)
71
+ this.logger.info(`${branchName} branch has created.`)
72
+
73
+ const updatedPackages = await this.ncu.update(outdatedPackage)
74
+
75
+ if (updatedPackages.length !== 1) {
76
+ throw new Error(`Failed to update ${outdatedPackage.name}.`)
77
+ }
78
+
79
+ await this.packageManager.install()
80
+ this.logger.info(`${outdatedPackage.name} has updated from v${outdatedPackage.currentVersion.version} to v${outdatedPackage.newVersion.version}`)
81
+
82
+ await this.git.add(...this.packageManager.packageFiles)
83
+ const message = createCommitMessage(outdatedPackage)
84
+ this.logger.debug(`message=${message}`)
85
+
86
+ await this.committer.commit(message)
87
+ await this.git.push(branchName)
88
+ await this.pullRequestCreator.create({
89
+ outdatedPackage,
90
+ branchName
91
+ })
92
+ await this.git.checkout('-')
93
+ await this.git.removeBranch(branchName)
94
+ this.logger.info(`${branchName} branch has removed.`)
95
+
96
+ return {
97
+ outdatedPackage,
98
+ updated: true
99
+ }
100
+ }
101
+ }
@@ -0,0 +1,14 @@
1
+ import { PackageVersion } from '../values'
2
+ import { createBranchName } from './createBranchName'
3
+
4
+ describe('createBranchName', () => {
5
+ it('returns branch name', () => {
6
+ const actual = createBranchName({
7
+ name: '@typescript-eslint/eslint-plugin',
8
+ currentVersion: PackageVersion.of('1.0.0'),
9
+ newVersion: PackageVersion.of('1.2.3'),
10
+ type: 'major'
11
+ })
12
+ expect(actual).toBe('npm-update-package/@typescript-eslint/eslint-plugin/v1.2.3')
13
+ })
14
+ })
@@ -0,0 +1,7 @@
1
+ import type { OutdatedPackage } from '../types'
2
+
3
+ export const createBranchName = (outdatedPackage: OutdatedPackage): string => {
4
+ const packageName = outdatedPackage.name
5
+ const newVersion = outdatedPackage.newVersion.version
6
+ return `npm-update-package/${packageName}/v${newVersion}`
7
+ }
@@ -0,0 +1,43 @@
1
+ import { UpdateType } from '../enums'
2
+ import { PackageVersion } from '../values'
3
+ import { createCommitMessage } from './createCommitMessage'
4
+
5
+ describe('createCommitMessage', () => {
6
+ const currentVersion = PackageVersion.of('1.0.0')
7
+
8
+ describe('if update type is patch', () => {
9
+ it('returns commit message', () => {
10
+ const actual = createCommitMessage({
11
+ name: '@typescript-eslint/eslint-plugin',
12
+ currentVersion,
13
+ newVersion: PackageVersion.of('1.0.1'),
14
+ type: UpdateType.Patch
15
+ })
16
+ expect(actual).toBe('chore(deps): patch update @typescript-eslint/eslint-plugin to v1.0.1')
17
+ })
18
+ })
19
+
20
+ describe('if update type is minor', () => {
21
+ it('returns commit message', () => {
22
+ const actual = createCommitMessage({
23
+ name: '@typescript-eslint/eslint-plugin',
24
+ currentVersion,
25
+ newVersion: PackageVersion.of('1.1.0'),
26
+ type: UpdateType.Minor
27
+ })
28
+ expect(actual).toBe('chore(deps): minor update @typescript-eslint/eslint-plugin to v1.1.0')
29
+ })
30
+ })
31
+
32
+ describe('if update type is major', () => {
33
+ it('returns commit message', () => {
34
+ const actual = createCommitMessage({
35
+ name: '@typescript-eslint/eslint-plugin',
36
+ currentVersion,
37
+ newVersion: PackageVersion.of('2.0.0'),
38
+ type: UpdateType.Major
39
+ })
40
+ expect(actual).toBe('chore(deps): major update @typescript-eslint/eslint-plugin to v2.0.0')
41
+ })
42
+ })
43
+ })
@@ -0,0 +1,8 @@
1
+ import type { OutdatedPackage } from '../types'
2
+
3
+ export const createCommitMessage = (outdatedPackage: OutdatedPackage): string => {
4
+ const packageName = outdatedPackage.name
5
+ const newVersion = outdatedPackage.newVersion.version
6
+ const updateType = outdatedPackage.type
7
+ return `chore(deps): ${updateType} update ${packageName} to v${newVersion}`
8
+ }
@@ -0,0 +1 @@
1
+ export { OutdatedPackageProcessor } from './OutdatedPackageProcessor'
@@ -0,0 +1,34 @@
1
+ import type { Logger } from '../logger'
2
+ import type { OutdatedPackageProcessor } from '../outdated-package-processor'
3
+ import type {
4
+ OutdatedPackage,
5
+ Result
6
+ } from '../types'
7
+
8
+ export class OutdatedPackagesProcessor {
9
+ private readonly outdatedPackageProcessor: OutdatedPackageProcessor
10
+ private readonly logger: Logger
11
+
12
+ constructor ({
13
+ outdatedPackageProcessor,
14
+ logger
15
+ }: {
16
+ outdatedPackageProcessor: OutdatedPackageProcessor
17
+ logger: Logger
18
+ }) {
19
+ this.outdatedPackageProcessor = outdatedPackageProcessor
20
+ this.logger = logger
21
+ }
22
+
23
+ async process (outdatedPackages: OutdatedPackage[]): Promise<Result[]> {
24
+ const results: Result[] = []
25
+
26
+ for (const outdatedPackage of outdatedPackages) {
27
+ this.logger.debug(`outdatedPackage=${JSON.stringify(outdatedPackage)}`)
28
+ const result = await this.outdatedPackageProcessor.process(outdatedPackage)
29
+ results.push(result)
30
+ }
31
+
32
+ return results
33
+ }
34
+ }
@@ -0,0 +1 @@
1
+ export { OutdatedPackagesProcessor } from './OutdatedPackagesProcessor'
@@ -0,0 +1,19 @@
1
+ import type { Terminal } from '../terminal'
2
+ import type { PackageManager } from './PackageManager'
3
+
4
+ // TODO: add test
5
+ export class Npm implements PackageManager {
6
+ readonly packageFiles = [
7
+ 'package.json',
8
+ 'package-lock.json'
9
+ ]
10
+
11
+ constructor (private readonly terminal: Terminal) {}
12
+
13
+ /**
14
+ * @see https://docs.npmjs.com/cli/v8/commands/npm-install
15
+ */
16
+ async install (): Promise<void> {
17
+ await this.terminal.run('npm', 'install')
18
+ }
19
+ }
@@ -0,0 +1,4 @@
1
+ export interface PackageManager {
2
+ packageFiles: string[]
3
+ install: () => Promise<void>
4
+ }
@@ -0,0 +1,19 @@
1
+ import type { Terminal } from '../terminal'
2
+ import type { PackageManager } from './PackageManager'
3
+
4
+ // TODO: add test
5
+ export class Yarn implements PackageManager {
6
+ readonly packageFiles = [
7
+ 'package.json',
8
+ 'yarn.lock'
9
+ ]
10
+
11
+ constructor (private readonly terminal: Terminal) {}
12
+
13
+ /**
14
+ * @see https://classic.yarnpkg.com/en/docs/cli/install
15
+ */
16
+ async install (): Promise<void> {
17
+ await this.terminal.run('yarn', 'install')
18
+ }
19
+ }
@@ -0,0 +1,21 @@
1
+ import type { PackageManagerName } from '../enums'
2
+ import type { Terminal } from '../terminal'
3
+ import { Npm } from './Npm'
4
+ import type { PackageManager } from './PackageManager'
5
+ import { Yarn } from './Yarn'
6
+
7
+ // TODO: add test
8
+ export const createPackageManager = ({
9
+ terminal,
10
+ packageManager
11
+ }: {
12
+ terminal: Terminal
13
+ packageManager: PackageManagerName
14
+ }): PackageManager => {
15
+ switch (packageManager) {
16
+ case 'npm':
17
+ return new Npm(terminal)
18
+ case 'yarn':
19
+ return new Yarn(terminal)
20
+ }
21
+ }
@@ -0,0 +1,4 @@
1
+ export { createPackageManager } from './createPackageManager'
2
+ export { Npm } from './Npm'
3
+ export type { PackageManager } from './PackageManager'
4
+ export { Yarn } from './Yarn'
@@ -0,0 +1,24 @@
1
+ import {
2
+ intersection,
3
+ partial,
4
+ string,
5
+ type
6
+ } from 'io-ts'
7
+ import type { TypeOf } from 'io-ts'
8
+ import { PackageDependencies } from './PackageDependencies'
9
+
10
+ export const Package = intersection([
11
+ type({
12
+ name: string,
13
+ version: string
14
+ }),
15
+ partial({
16
+ dependencies: PackageDependencies,
17
+ devDependencies: PackageDependencies,
18
+ peerDependencies: PackageDependencies,
19
+ optionalDependencies: PackageDependencies
20
+ })
21
+ ])
22
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
23
+ export type Package = TypeOf<typeof Package>
24
+ export const isPackage = Package.is
@@ -0,0 +1,10 @@
1
+ import {
2
+ record,
3
+ string
4
+ } from 'io-ts'
5
+ import type { TypeOf } from 'io-ts'
6
+
7
+ export const PackageDependencies = record(string, string)
8
+ // eslint-disable-next-line @typescript-eslint/no-redeclare
9
+ export type PackageDependencies = TypeOf<typeof PackageDependencies>
10
+ export const isPackageDependencies = PackageDependencies.is
@@ -0,0 +1,2 @@
1
+ export type { PackageDependencies } from './PackageDependencies'
2
+ export { readPackageJson } from './readPackageJson'
@@ -0,0 +1,13 @@
1
+ import { isPackage } from './Package'
2
+ import type { Package } from './Package'
3
+
4
+ // TODO: add test
5
+ export const parsePackageJson = (json: string): Package => {
6
+ const parsed: unknown = JSON.parse(json)
7
+
8
+ if (isPackage(parsed)) {
9
+ return parsed
10
+ } else {
11
+ throw new Error(`Failed to parse package.json. json=${json}`)
12
+ }
13
+ }
@@ -0,0 +1,6 @@
1
+ import fs from 'fs'
2
+
3
+ // TODO: add test
4
+ export const readFile = async (filePath: string): Promise<string> => {
5
+ return await fs.promises.readFile(filePath, 'utf8')
6
+ }
@@ -0,0 +1,9 @@
1
+ import type { Package } from './Package'
2
+ import { parsePackageJson } from './parsePackageJson'
3
+ import { readFile } from './readFile'
4
+
5
+ // TODO: add test
6
+ export const readPackageJson = async (filePath: string): Promise<Package> => {
7
+ const json = await readFile(filePath)
8
+ return parsePackageJson(json)
9
+ }