Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/docusaurus-utils/src/__tests__/urlUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,23 @@ describe('hasSSHProtocol', () => {
expect(hasSSHProtocol(url)).toBe(true);
});

it('recognizes implied SSH protocol without a user', () => {
expect(hasSSHProtocol('github.com:facebook/docusaurus.git')).toBe(true);
// An SSH config host alias, as used for several GitHub accounts
expect(hasSSHProtocol('github-work:facebook/docusaurus.git')).toBe(true);
});

it('recognizes implied SSH protocol with a path relative to a home directory', () => {
expect(hasSSHProtocol('git@example.com:~git/docusaurus.git')).toBe(true);
expect(hasSSHProtocol('example.com:~/docusaurus.git')).toBe(true);
});

it('does not recognize a Windows drive path', () => {
expect(hasSSHProtocol('C:/projects/docusaurus.git')).toBe(false);
expect(hasSSHProtocol('C:\\projects\\docusaurus.git')).toBe(false);
expect(hasSSHProtocol('C:projects/docusaurus.git')).toBe(false);
});

it('does not recognize HTTPS with credentials', () => {
const url = 'https://user:pass@github.com/facebook/docusaurus.git';
expect(hasSSHProtocol(url)).toBe(false);
Expand Down
16 changes: 13 additions & 3 deletions packages/docusaurus-utils/src/urlUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -314,14 +314,24 @@ export function buildHttpsUrl(
/**
* Whether the current URL is an SSH protocol. In addition to looking for
* `ssh:`, it will also allow protocol-less URLs like
* `git@github.com:facebook/docusaurus.git`.
* `git@github.com:facebook/docusaurus.git`, with or without the user part
* (`github.com:facebook/docusaurus.git`, or an SSH config host alias).
*/
export function hasSSHProtocol(sourceRepoUrl: string): boolean {
const url = URL.parse(sourceRepoUrl);
if (url === null) {
// Without "://", git reads `[user@]host:path` as an SCP-style address. When
// the user part is left out, URL.parse() takes the host for a URL scheme
// (`github.com:` is a valid one), so it is checked here as well.
if (url === null || !sourceRepoUrl.includes('://')) {
// Recognizes SCP-style addresses, implying SSH
// Example: git@github.com:facebook/docusaurus.git
return /^(?:[\w-]+@)?[\w.-]+:[\w./-]+/.test(sourceRepoUrl);
// Example: github.com:~user/docusaurus.git
// A Windows drive path like C:/repo or C:repo is not one: like git on
// Windows, a single-letter host is read as a drive letter.
return (
/^(?:[\w-]+@)?[\w.-]+:[\w./~-]+/.test(sourceRepoUrl) &&
!/^[a-z]:/i.test(sourceRepoUrl)
);
}
return url.protocol === 'ssh:';
}