@@ -49,6 +49,37 @@ function settingsUrl(deployTarget: DeployTargetInfo) {
49
49
return `${ OBSERVABLE_UI_ORIGIN } projects/@${ deployTarget . workspace . login } /${ deployTarget . project . slug } ` ;
50
50
}
51
51
52
+ /**
53
+ * Returns the ownerName and repoName of the first GitHub remote (HTTPS or SSH)
54
+ * on the current repository, or null.
55
+ */
56
+ async function getGitHubRemote ( ) {
57
+ const remotes = ( await promisify ( exec ) ( "git remote -v" ) ) . stdout
58
+ . split ( "\n" )
59
+ . filter ( ( d ) => d )
60
+ . map ( ( d ) => {
61
+ const [ , url ] = d . split ( / \s / g) ;
62
+ if ( url . startsWith ( "https://github.com/" ) ) {
63
+ // HTTPS: https://github.com/observablehq/framework.git
64
+ const [ ownerName , repoName ] = new URL ( url ) . pathname
65
+ . slice ( 1 )
66
+ . replace ( / \. g i t $ / , "" )
67
+ . split ( "/" ) ;
68
+ return { ownerName, repoName} ;
69
+ } else if ( url . startsWith ( "[email protected] :" ) ) {
70
+ // SSH: git@github .com:observablehq/framework.git
71
+ const [ ownerName , repoName ] = url
72
+ . replace ( / ^ g i t @ g i t h u b .c o m : / , "" )
73
+ . replace ( / \. g i t $ / , "" )
74
+ . split ( "/" ) ;
75
+ return { ownerName, repoName} ;
76
+ }
77
+ } ) ;
78
+ const remote = remotes . find ( ( d ) => d && d . ownerName && d . repoName ) ;
79
+ if ( ! remote ) throw new CliError ( "No GitHub remote found." ) ;
80
+ return remote ?? null ;
81
+ }
82
+
52
83
export interface DeployOptions {
53
84
config : Config ;
54
85
deployConfigPath : string | undefined ;
@@ -246,28 +277,23 @@ class Deployer {
246
277
if ( deployTarget . create ) {
247
278
throw new Error ( "Incorrect deploy target state" ) ;
248
279
}
249
- // We only support cloud builds from the root directory so this ignores this.deployOptions.config.root
280
+ if ( ! deployTarget . project . build_environment_id ) {
281
+ // TODO: allow setting build environment from CLI
282
+ throw new CliError ( "No build environment configured." ) ;
283
+ }
284
+ // We only support cloud builds from the root directory so this ignores
285
+ // this.deployOptions.config.root
250
286
const isGit = existsSync ( ".git" ) ;
251
287
if ( ! isGit ) throw new CliError ( "Not at root of a git repository." ) ;
252
- const remotes = ( await promisify ( exec ) ( "git remote -v" , { cwd : this . deployOptions . config . root } ) ) . stdout
253
- . split ( "\n" )
254
- . filter ( ( d ) => d )
255
- . map ( ( d ) => d . split ( / \s / g) ) ;
256
- const gitHub = remotes . find ( ( [ , url ] ) => url . startsWith ( "https://github.com/" ) ) ;
257
- if ( ! gitHub ) throw new CliError ( "No GitHub remote found." ) ;
258
- // TODO: validate "Your branch is up to date" & "nothing to commit, working tree clean"
259
-
260
- if ( ! deployTarget . project . build_environment_id ) throw new CliError ( "No build environment configured." ) ;
261
- // TODO: allow setting build environment from CLI
262
-
263
- const [ ownerName , repoName ] = formatGitUrl ( gitHub [ 1 ] ) . split ( "/" ) ;
264
- const branch = ( await promisify ( exec ) ( "git rev-parse --abbrev-ref HEAD" , { cwd : this . deployOptions . config . root } ) )
265
- . stdout ;
266
288
289
+ const { ownerName, repoName} = await getGitHubRemote ( ) ;
290
+ const branch = ( await promisify ( exec ) ( "git rev-parse --abbrev-ref HEAD" ) ) . stdout ;
267
291
let localRepo = await this . apiClient . getGitHubRepository ( { ownerName, repoName} ) ;
268
292
269
293
// If a source repository has already been configured, check that it’s
270
- // accessible and matches the local repository and branch
294
+ // accessible and matches the local repository and branch.
295
+ // TODO: validate local/remote refs match, "Your branch is up to date",
296
+ // and "nothing to commit, working tree clean".
271
297
if ( deployTarget . project . source ) {
272
298
if ( localRepo && deployTarget . project . source . provider_id !== localRepo . provider_id ) {
273
299
throw new CliError (
@@ -283,7 +309,6 @@ class Deployer {
283
309
) } `
284
310
) ;
285
311
}
286
- // TODO: validate local/remote refs match
287
312
const remoteAuthedRepo = await this . apiClient . getGitHubRepository ( {
288
313
providerId : deployTarget . project . source . provider_id
289
314
} ) ;
@@ -295,7 +320,7 @@ class Deployer {
295
320
) } `
296
321
) ;
297
322
}
298
-
323
+
299
324
// Configured repo is OK; proceed
300
325
return ;
301
326
}
0 commit comments