@@ -6,16 +6,30 @@ import path from "path";
6
6
import parseGitHubUrl from "parse-github-url" ;
7
7
import * as t from "io-ts" ;
8
8
9
+ /** Determine if the current directory is an NPM package */
10
+ const isNpmPackage = ( dir ?: string ) =>
11
+ fs . existsSync ( dir ? path . join ( dir , "package.json" ) : "package.json" ) ;
12
+
13
+ /** Determine if the current directory is an lerna monorepo */
14
+ const isLernaMonorepo = ( dir ?: string ) =>
15
+ fs . existsSync ( dir ? path . join ( dir , "package.json" ) : "package.json" ) ;
16
+
17
+ /** Read a NPM package.json */
18
+ const readPackageJson = ( dir ?: string ) =>
19
+ JSON . parse (
20
+ fs . readFileSync ( dir ? path . join ( dir , "package.json" ) : "package.json" , {
21
+ encoding : "utf-8" ,
22
+ } )
23
+ ) ;
24
+
9
25
/** Update package in an npm package */
10
26
const updateNpmPackage = (
11
27
dir : string ,
12
28
name : string ,
13
29
version : string ,
14
30
isYarn : boolean
15
31
) => {
16
- const { dependencies, devDependencies } = JSON . parse (
17
- fs . readFileSync ( path . join ( dir , "package.json" ) , { encoding : "utf-8" } )
18
- ) ;
32
+ const { dependencies, devDependencies } = readPackageJson ( dir ) ;
19
33
20
34
const isDep = Boolean ( dependencies [ name ] ) ;
21
35
const isDevDep = Boolean ( devDependencies [ name ] ) ;
@@ -30,21 +44,65 @@ const updateNpmPackage = (
30
44
}
31
45
} ;
32
46
47
+ /** Update a dependency in a monorepo */
48
+ const updateLernaMonorepo = ( dir : string , name : string , version : string ) =>
49
+ execSync (
50
+ `npx lernaupdate --non-interactive --dependency ${ name } @${ version } ` ,
51
+ { cwd : dir }
52
+ ) ;
53
+
54
+ /** Update a dependency in a JS project */
55
+ const updateJsProject = ( dir : string , name : string , version : string ) => {
56
+ if ( isLernaMonorepo ( ) ) {
57
+ updateLernaMonorepo ( dir , name , version ) ;
58
+ } else {
59
+ const hasLock = fs . existsSync ( "yarn.lock" ) ;
60
+ updateNpmPackage ( dir , name , version , hasLock ) ;
61
+ }
62
+ } ;
63
+
64
+ interface LernaPackage {
65
+ /** The name of the package */
66
+ name : string ;
67
+ /** The current version of the package */
68
+ version : string ;
69
+ /** Whether the package is private */
70
+ private : boolean ;
71
+ }
72
+
33
73
/** Get a package name + updater to use with updateRepo */
34
- function getUpdater ( ) : [ string , ( dir : string ) => void ] | undefined {
35
- if ( fs . existsSync ( "package.json" ) ) {
36
- const { name, version } = JSON . parse (
37
- fs . readFileSync ( "package.json" , { encoding : "utf-8" } )
74
+ async function getUpdater (
75
+ auto : Auto
76
+ ) : Promise < [ string , ( dir : string ) => void ] | undefined > {
77
+ // We are in a lerna monorepo so we should try to make updates for all of the
78
+ // packages in it. We assume that the thing we are updating is also a JS project
79
+ if ( isLernaMonorepo ( ) ) {
80
+ const { name } = readPackageJson ( ) ;
81
+ // Since we have already tagged the release we need to calculate from the previous tag
82
+ const lastRelease = await auto . git ! . getPreviousTagInBranch ( ) ;
83
+ const changedPackages : LernaPackage [ ] = JSON . parse (
84
+ execSync ( `lerna ls --json --since ${ lastRelease } ` , { encoding : "utf8" } )
38
85
) ;
39
86
40
87
return [
41
88
name ,
42
89
( dir ) => {
43
- const hasLock = fs . existsSync ( "yarn.lock" ) ;
44
- updateNpmPackage ( dir , name , version , hasLock ) ;
90
+ changedPackages . forEach ( ( p ) => {
91
+ if ( p . private ) {
92
+ return ;
93
+ }
94
+
95
+ updateJsProject ( dir , p . name , p . version ) ;
96
+ } ) ;
45
97
} ,
46
98
] ;
47
99
}
100
+
101
+ // We are in NPM package. We assume that the thing we are updating is also a JS project.
102
+ if ( isNpmPackage ( ) ) {
103
+ const { name, version } = readPackageJson ( ) ;
104
+ return [ name , ( dir ) => updateJsProject ( dir , name , version ) ] ;
105
+ }
48
106
}
49
107
50
108
const optionalOptions = t . interface ( {
@@ -102,14 +160,15 @@ export default class UpdateRepoPlugin implements IPlugin {
102
160
}
103
161
104
162
for await ( const config of this . options ) {
105
- await this . updateRepo ( newVersion , releaseNotes , config ) ;
163
+ await this . updateRepo ( auto , newVersion , releaseNotes , config ) ;
106
164
}
107
165
}
108
166
) ;
109
167
}
110
168
111
169
/** Open a pr with a dependency update */
112
170
private async updateRepo (
171
+ auto : Auto ,
113
172
newVersion : string ,
114
173
releaseNotes : string ,
115
174
config : UpdateRepoConfiguration
@@ -122,7 +181,7 @@ export default class UpdateRepoPlugin implements IPlugin {
122
181
) ;
123
182
}
124
183
125
- const updater = getUpdater ( ) ;
184
+ const updater = await getUpdater ( auto ) ;
126
185
127
186
if ( ! updater ) {
128
187
throw new Error (
0 commit comments