1
1
const semver = require ( 'semver' )
2
2
const log = require ( 'proc-log' )
3
3
const pacote = require ( 'pacote' )
4
+ const read = require ( 'read' )
5
+ const Table = require ( 'cli-table3' )
4
6
const { run, git, npm, pkg : cli , spawn } = require ( './util.js' )
5
7
6
8
const resetdeps = ( ) => npm ( 'run' , 'resetdeps' )
7
9
8
10
const op = ( ) => spawn ( 'op' , 'item' , 'get' , 'npm' , '--otp' , { out : true , ok : true } )
9
11
10
- const getVersion = async ( s ) => {
11
- const mani = await pacote . manifest ( s , { preferOnline : true } ) . catch ( ( ) => null )
12
- return mani ?. version
13
- }
14
- const getLatestMajor = async ( s ) => {
15
- const pack = await pacote . packument ( s , { preferOnline : true } ) . catch ( ( ) => null )
16
- return pack ?. [ 'dist-tags' ] ?. latest ? semver . major ( pack [ 'dist-tags' ] . latest ) : 0
17
- }
12
+ const getWorkspaceTag = async ( { name, version } ) => {
13
+ const { prerelease, major } = semver . parse ( version )
14
+ if ( prerelease . length ) {
15
+ return 'prerelease'
16
+ }
18
17
19
- const TAG = {
20
- cli : ( { version } ) => `next-${ semver . major ( version ) } ` ,
21
- workspace : async ( { name, version } ) => {
22
- const { prerelease, major } = semver . parse ( version )
23
- if ( prerelease . length ) {
24
- return 'prerelease'
25
- }
26
- if ( major >= await getLatestMajor ( name ) ) {
27
- return 'latest'
28
- }
29
- return 'backport'
30
- } ,
31
- }
18
+ const pack = await pacote . packument ( name , { preferOnline : true } ) . catch ( ( ) => null )
19
+
20
+ if ( ! pack ) {
21
+ // This might never happen but if we were to create a new workspace that has never
22
+ // been published before it should be set to latest right away.
23
+ return 'latest'
24
+ }
32
25
33
- const needsPublish = async ( { private, name, version } , { force, getTag } ) => {
34
- if ( private ) {
35
- return
26
+ if ( major >= semver . major ( pack [ 'dist-tags' ] . latest ) ) {
27
+ // if the major version we are publishing is greater than the major version
28
+ // of the latest dist-tag, then this should be latest too
29
+ return 'latest'
36
30
}
37
31
38
- const tag = await getTag ( { name, version } )
39
- if ( force || version !== await getVersion ( `${ name } @${ tag } ` ) ) {
40
- return tag
32
+ // Anything else is a backport
33
+ return 'backport'
34
+ }
35
+
36
+ const versionNotExists = async ( { name, version } ) => {
37
+ const spec = `${ name } @${ version } `
38
+ let exists
39
+ try {
40
+ await pacote . manifest ( spec , { preferOnline : true } )
41
+ exists = true // if it exists, no publish needed
42
+ } catch {
43
+ exists = false // otherwise its needs publishing
41
44
}
45
+ log . info ( `${ spec } exists=${ exists } ` )
46
+ return ! exists
42
47
}
43
48
44
- const getPublishes = async ( opts ) => {
45
- const publish = [ ]
49
+ const getPublishes = async ( { force } ) => {
50
+ const publishPackages = [ ]
51
+
52
+ for ( const { pkg } of await cli . mapWorkspaces ( { public : true } ) ) {
53
+ if ( force || await versionNotExists ( pkg ) ) {
54
+ publishPackages . push ( {
55
+ workspace : true ,
56
+ name : pkg . name ,
57
+ version : pkg . version ,
58
+ tag : await getWorkspaceTag ( pkg ) ,
59
+ } )
60
+ }
61
+ }
46
62
47
- for ( const { name, pkg } of await cli . mapWorkspaces ( ) ) {
48
- publish . push ( {
49
- workspace : name ,
50
- tag : await needsPublish ( pkg , { ...opts , getTag : TAG . workspace } ) ,
63
+ if ( force || await versionNotExists ( cli ) ) {
64
+ publishPackages . push ( {
65
+ name : cli . name ,
66
+ version : cli . version ,
67
+ tag : `next-${ semver . major ( cli . version ) } ` ,
51
68
} )
52
69
}
53
70
54
- publish . push ( {
55
- tag : await needsPublish ( cli , { ...opts , getTag : TAG . cli } ) ,
56
- } )
57
-
58
- return publish . filter ( p => p . tag )
71
+ return publishPackages
59
72
}
60
73
61
74
const main = async ( opts ) => {
@@ -64,12 +77,21 @@ const main = async (opts) => {
64
77
65
78
if ( ! publishes . length ) {
66
79
throw new Error (
67
- 'Nothing to publish, exiting. ' +
80
+ 'Nothing to publish, exiting.\n ' +
68
81
'All packages to publish should have their version bumped before running this script.'
69
82
)
70
83
}
71
84
72
- log . info ( 'publish' , '\n' + publishes . map ( JSON . stringify ) . join ( '\n' ) )
85
+ const table = new Table ( { head : [ 'name' , 'version' , 'tag' ] } )
86
+ for ( const publish of publishes ) {
87
+ table . push ( [ publish . name , publish . version , publish . tag ] )
88
+ }
89
+
90
+ const prompt = `Ready to publish the following packages:\n${ table . toString ( ) } \nOk to proceed? `
91
+ const confirm = await read ( { prompt, default : 'y' } )
92
+ if ( confirm . trim ( ) . toLowerCase ( ) . charAt ( 0 ) !== 'y' ) {
93
+ throw new Error ( 'Aborted' )
94
+ }
73
95
74
96
await git ( 'clean' , '-fd' )
75
97
await resetdeps ( )
@@ -87,8 +109,8 @@ const main = async (opts) => {
87
109
await npm ( 'install' , '-w' , 'docs' , '--ignore-scripts' , '--no-audit' , '--no-fund' )
88
110
await git . dirty ( )
89
111
90
- for ( const p of publishes ) {
91
- const workspace = p . workspace && `--workspace=${ p . workspace } `
112
+ for ( const publish of publishes ) {
113
+ const workspace = publish . workspace && `--workspace=${ publish . name } `
92
114
if ( packOnly ) {
93
115
await npm (
94
116
'pack' ,
@@ -99,7 +121,7 @@ const main = async (opts) => {
99
121
await npm (
100
122
'publish' ,
101
123
workspace ,
102
- `--tag=${ p . tag } ` ,
124
+ `--tag=${ publish . tag } ` ,
103
125
opts . dryRun && '--dry-run' ,
104
126
opts . otp && `--otp=${ opts . otp === 'op' ? await op ( ) : opts . otp } `
105
127
)
0 commit comments