@@ -15,12 +15,41 @@ let exitCode = 0;
15
15
let skipRestore = true ;
16
16
const s = prompts . spinner ( ) ;
17
17
18
+ function handleCancel ( ) {
19
+ prompts . cancel ( "Operation cancelled. Exiting setup - maybe another time? 👋" ) ;
20
+ process . exit ( 0 ) ;
21
+ }
22
+
18
23
function handlePromptCancel ( value ) {
19
24
if ( prompts . isCancel ( value ) ) {
20
- prompts . cancel (
21
- "Operation cancelled. Exiting setup - maybe another time? 👋"
22
- ) ;
23
- process . exit ( 0 ) ;
25
+ handleCancel ( ) ;
26
+ }
27
+ }
28
+
29
+ function skipSpinnerBlock ( blockText ) {
30
+ s . start ( chalk . gray ( "➖ " + blockText ) ) ;
31
+ s . stop ( chalk . gray ( "➖ " + blockText ) ) ;
32
+ }
33
+
34
+ function successSpinnerBlock ( blockText ) {
35
+ s . start ( chalk . green ( "✅ " + blockText ) ) ;
36
+ s . stop ( chalk . green ( "✅ " + blockText ) ) ;
37
+ }
38
+
39
+ async function withSpinner (
40
+ callback ,
41
+ { startText, successText, stopText, errorText }
42
+ ) {
43
+ s . start ( startText ) ;
44
+
45
+ try {
46
+ await callback ( ) ;
47
+
48
+ s . stop ( chalk . green ( "✅ " + successText ) ) ;
49
+ } catch ( error ) {
50
+ s . stop ( chalk . red ( "❌ " + stopText ) ) ;
51
+
52
+ throw new Error ( errorText , { cause : error } ) ;
24
53
}
25
54
}
26
55
50
79
51
80
skipRestore = values [ "skip-restore" ] ;
52
81
82
+ const skipApi = values [ "skip-api" ] ;
83
+ const skipUninstalls = values [ "skip-uninstalls" ] ;
84
+
85
+ /** @type {Octokit } */
86
+ let octokit ;
87
+
88
+ if ( skipApi ) {
89
+ skipSpinnerBlock ( `Skipping checking GitHub authentication.` ) ;
90
+ } else {
91
+ successSpinnerBlock ( `Checking GitHub authentication.` ) ;
92
+
93
+ await withSpinner (
94
+ async ( ) => {
95
+ await $ `gh auth status` ;
96
+ const auth = ( await $ `gh auth token` ) . stdout . trim ( ) ;
97
+
98
+ octokit = new Octokit ( { auth } ) ;
99
+ } ,
100
+ {
101
+ startText : `Fetching gh auth status...` ,
102
+ successText : `Fetched gh auth status.` ,
103
+ stopText : `Error fetching gh auth status.` ,
104
+ errorText : `Could not fetch github auth token. ` ,
105
+ }
106
+ ) ;
107
+ }
108
+
53
109
async function getDefaultSettings ( ) {
54
110
let gitRemoteFetch ;
55
111
try {
@@ -108,43 +164,91 @@ try {
108
164
return value ;
109
165
}
110
166
111
- const repository = await getPrefillOrPromptedValue (
112
- "repository" ,
113
- "What will the kebab-case name of the repository be?" ,
114
- defaultRepository
167
+ const owner = await getPrefillOrPromptedValue (
168
+ "owner" ,
169
+ "What owner or user will the repository be under?" ,
170
+ defaultOwner
171
+ ) ;
172
+
173
+ const repository = await ensureRepositoryExists (
174
+ await getPrefillOrPromptedValue (
175
+ "repository" ,
176
+ "What will the kebab-case name of the repository be?" ,
177
+ defaultRepository
178
+ )
115
179
) ;
116
180
181
+ async function ensureRepositoryExists ( repository ) {
182
+ if ( skipApi ) {
183
+ return repository ;
184
+ }
185
+
186
+ // We'll continuously pester the user for a repository
187
+ // until they bail, create a new one, or it exists.
188
+ while ( true ) {
189
+ // Because the Octokit SDK throws on 404s (😡),
190
+ // we try/catch to check whether the repo exists.
191
+ try {
192
+ await octokit . rest . repos . get ( {
193
+ owner,
194
+ repo : repository ,
195
+ } ) ;
196
+ return repository ;
197
+ } catch ( error ) {
198
+ if ( error . status !== 404 ) {
199
+ throw error ;
200
+ }
201
+ }
202
+
203
+ const selection = await prompts . select ( {
204
+ message : `Repository ${ repository } doesn't seem to exist under ${ owner } . What would you like to do?` ,
205
+ options : [
206
+ { label : "Bail out and maybe try again later" , value : "bail" } ,
207
+ { label : "Create a new repository" , value : "create" } ,
208
+ {
209
+ label : "Try again with a different repository" ,
210
+ value : "different" ,
211
+ } ,
212
+ ] ,
213
+ } ) ;
214
+
215
+ handlePromptCancel ( selection ) ;
216
+
217
+ switch ( selection ) {
218
+ case "bail" :
219
+ handleCancel ( ) ;
220
+ break ;
221
+
222
+ case "create" :
223
+ await octokit . rest . repos . createUsingTemplate ( {
224
+ name : repository ,
225
+ owner,
226
+ template_owner : "JoshuaKGoldberg" ,
227
+ template_repo : "template-typescript-node-package" ,
228
+ } ) ;
229
+ break ;
230
+
231
+ case "different" :
232
+ repository = await prompts . text ( {
233
+ message : `What would you like to call the repository?` ,
234
+ } ) ;
235
+ break ;
236
+ }
237
+ }
238
+ }
239
+
117
240
const title = await getPrefillOrPromptedValue (
118
241
"title" ,
119
242
"What will the Title Case title of the repository be?" ,
120
243
titleCase ( repository ) . replaceAll ( "-" , " " )
121
244
) ;
122
245
123
- const owner = await getPrefillOrPromptedValue (
124
- "owner" ,
125
- "What owner or user will the repository be under?" ,
126
- defaultOwner
127
- ) ;
128
-
129
246
const description = await getPrefillOrPromptedValue (
130
247
"description" ,
131
248
"How would you describe the new package?" ,
132
249
"A very lovely package. Hooray!"
133
250
) ;
134
251
135
- const skipApi = values [ "skip-api" ] ;
136
- const skipUninstalls = values [ "skip-uninstalls" ] ;
137
-
138
- const successSpinnerBlock = ( blockText ) => {
139
- s . start ( chalk . green ( "✅ " + blockText ) ) ;
140
- s . stop ( chalk . green ( "✅ " + blockText ) ) ;
141
- } ;
142
-
143
- const skipSpinnerBlock = ( blockText ) => {
144
- s . start ( chalk . gray ( "➖ " + blockText ) ) ;
145
- s . stop ( chalk . gray ( "➖ " + blockText ) ) ;
146
- } ;
147
-
148
252
successSpinnerBlock ( "Started hydrating package metadata locally." ) ;
149
253
150
254
async function readFileAsJSON ( filePath ) {
@@ -158,23 +262,6 @@ try {
158
262
}
159
263
}
160
264
161
- const withSpinner = async (
162
- callback ,
163
- { startText, successText, stopText, errorText }
164
- ) => {
165
- s . start ( startText ) ;
166
-
167
- try {
168
- await callback ( ) ;
169
-
170
- s . stop ( chalk . green ( "✅ " + successText ) ) ;
171
- } catch ( error ) {
172
- s . stop ( chalk . red ( "❌ " + stopText ) ) ;
173
-
174
- throw new Error ( errorText , { cause : error } ) ;
175
- }
176
- } ;
177
-
178
265
await withSpinner (
179
266
async ( ) => {
180
267
let user ;
@@ -410,28 +497,11 @@ try {
410
497
}
411
498
) ;
412
499
413
- if ( skipApi ) {
500
+ if ( ! octokit ) {
414
501
skipSpinnerBlock ( `Skipping API hydration.` ) ;
415
502
} else {
416
503
successSpinnerBlock ( `Starting API hydration.` ) ;
417
504
418
- let octokit ;
419
-
420
- await withSpinner (
421
- async ( ) => {
422
- await $ `gh auth status` ;
423
- const auth = ( await $ `gh auth token` ) . stdout . trim ( ) ;
424
-
425
- octokit = new Octokit ( { auth } ) ;
426
- } ,
427
- {
428
- startText : `Fetching gh auth status...` ,
429
- successText : `Fetched gh auth status.` ,
430
- stopText : `Error fetching gh auth status.` ,
431
- errorText : `Could not fetch github auth token. ` ,
432
- }
433
- ) ;
434
-
435
505
await withSpinner (
436
506
async ( ) => {
437
507
const existingLabels = JSON . parse (
0 commit comments