Skip to content

Commit

Permalink
feat(fetch, push, clone, pull): add autoTranslateSSH param (#946)
Browse files Browse the repository at this point in the history
  • Loading branch information
billiegoose committed Dec 4, 2019
1 parent 495f294 commit 661f74e
Show file tree
Hide file tree
Showing 10 changed files with 131 additions and 5 deletions.
3 changes: 3 additions & 0 deletions __tests__/__fixtures__/test-fetch-cors.git/config
Expand Up @@ -7,5 +7,8 @@
[remote "origin"]
url = https://github.com/isomorphic-git/isomorphic-git
fetch = +refs/heads/*:refs/remotes/origin/*
[remote "ssh"]
url = git@github.com:isomorphic-git/isomorphic-git.git
fetch = +refs/heads/*:refs/remotes/origin/*
[http]
corsProxy = http://localhost:9999
70 changes: 70 additions & 0 deletions __tests__/test-fetch.js
Expand Up @@ -73,6 +73,76 @@ describe('fetch', () => {
expect(shallow === '86ec153c7b48e02f92930d07542680f60d104d31\n').toBe(true)
})

it('throws UnknownTransportError if using shorter scp-like syntax', async () => {
const { gitdir } = await makeFixture('test-fetch-cors')
await config({
gitdir,
path: 'http.corsProxy',
value: `http://${localhost}:9999`
})
// Test
let err = null
try {
await fetch({
gitdir,
depth: 1,
singleBranch: true,
remote: 'ssh',
ref: 'test-branch-shallow-clone'
})
} catch (e) {
err = e
}
expect(err).toBeDefined()
expect(err.code).toEqual(E.UnknownTransportError)
})

it('shallow fetch using autoTranslateSSH param (from Github)', async () => {
const { fs, gitdir } = await makeFixture('test-fetch-cors')
await config({
gitdir,
path: 'http.corsProxy',
value: `http://${localhost}:9999`
})
// Test
await fetch({
gitdir,
depth: 1,
singleBranch: true,
remote: 'ssh',
ref: 'test-branch-shallow-clone',
autoTranslateSSH: true
})
expect(await fs.exists(`${gitdir}/shallow`)).toBe(true)
const shallow = (await fs.read(`${gitdir}/shallow`)).toString('utf8')
expect(shallow === '92e7b4123fbf135f5ffa9b6fe2ec78d07bbc353e\n').toBe(true)
})

it('shallow fetch using autoTranslateSSH config (from Github)', async () => {
const { fs, gitdir } = await makeFixture('test-fetch-cors')
await config({
gitdir,
path: 'http.corsProxy',
value: `http://${localhost}:9999`
})
await config({
gitdir,
path: 'isomorphic-git.autoTranslateSSH',
value: true
})
// Test
await fetch({
gitdir,
depth: 1,
singleBranch: true,
remote: 'ssh',
ref: 'test-branch-shallow-clone'
})
expect(await fs.exists(`${gitdir}/shallow`)).toBe(true)
const shallow = (await fs.read(`${gitdir}/shallow`)).toString('utf8')
expect(shallow === '92e7b4123fbf135f5ffa9b6fe2ec78d07bbc353e\n').toBe(true)
})

it('shallow fetch since (from Github)', async () => {
const { fs, gitdir } = await makeFixture('test-fetch-cors')
await config({
Expand Down
5 changes: 4 additions & 1 deletion src/commands/clone.js
Expand Up @@ -37,6 +37,7 @@ import { init } from './init.js'
* @param {object} [args.headers = {}] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
* @param {import('events').EventEmitter} [args.emitter] - [deprecated] Overrides the emitter set via the ['emitter' plugin](./plugin_emitter.md)
* @param {string} [args.emitterPrefix = ''] - Scope emitted events by prepending `emitterPrefix` to the event name
* @param {boolean} [args.autoTranslateSSH] - Attempt to automatically translate SSH remotes into HTTP equivalents
*
* @returns {Promise<void>} Resolves successfully when clone completes
*
Expand Down Expand Up @@ -79,6 +80,7 @@ export async function clone ({
noCheckout = false,
noTags = false,
headers = {},
autoTranslateSSH = false,
// @ts-ignore
onprogress
}) {
Expand Down Expand Up @@ -133,7 +135,8 @@ export async function clone ({
relative,
singleBranch,
headers,
tags: !noTags
tags: !noTags,
autoTranslateSSH
})
if (fetchHead === null) return
ref = ref || defaultBranch
Expand Down
18 changes: 16 additions & 2 deletions src/commands/fetch.js
Expand Up @@ -17,6 +17,7 @@ import { join } from '../utils/join.js'
import { pkg } from '../utils/pkg.js'
import { cores } from '../utils/plugins.js'
import { splitLines } from '../utils/splitLines.js'
import { translateSSHtoHTTP } from '../utils/translateSSHtoHTTP.js'
import { parseUploadPackResponse } from '../wire/parseUploadPackResponse.js'
import { writeUploadPackRequest } from '../wire/writeUploadPackRequest.js'

Expand Down Expand Up @@ -63,6 +64,7 @@ import { config } from './config'
* @param {object} [args.headers] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
* @param {boolean} [args.prune] - Delete local remote-tracking branches that are not present on the remote
* @param {boolean} [args.pruneTags] - Prune local tags that don’t exist on the remote, and force-update those tags that differ
* @param {boolean} [args.autoTranslateSSH] - Attempt to automatically translate SSH remotes into HTTP equivalents
* @param {import('events').EventEmitter} [args.emitter] - [deprecated] Overrides the emitter set via the ['emitter' plugin](./plugin_emitter.md).
* @param {string} [args.emitterPrefix = ''] - Scope emitted events by prepending `emitterPrefix` to the event name.
*
Expand Down Expand Up @@ -113,6 +115,7 @@ export async function fetch ({
headers = {},
prune = false,
pruneTags = false,
autoTranslateSSH = false,
// @ts-ignore
onprogress // deprecated
}) {
Expand Down Expand Up @@ -147,7 +150,8 @@ export async function fetch ({
singleBranch,
headers,
prune,
pruneTags
pruneTags,
autoTranslateSSH
})
if (response === null) {
return {
Expand Down Expand Up @@ -238,7 +242,8 @@ async function fetchPackfile ({
singleBranch,
headers,
prune,
pruneTags
pruneTags,
autoTranslateSSH
}) {
const fs = new FileSystem(_fs)
// Sanity checks
Expand All @@ -257,6 +262,15 @@ async function fetchPackfile ({
path: `remote.${remote}.url`
})
}

// Try to convert SSH URLs to HTTPS ones
if (
autoTranslateSSH ||
(await config({ fs, gitdir, path: `isomorphic-git.autoTranslateSSH` }))
) {
url = translateSSHtoHTTP(url)
}

if (corsProxy === undefined) {
corsProxy = await config({ fs, gitdir, path: 'http.corsProxy' })
}
Expand Down
5 changes: 4 additions & 1 deletion src/commands/pull.js
Expand Up @@ -36,6 +36,7 @@ import { merge } from './merge'
* @param {Object} [args.author] - passed to [commit](commit.md) when creating a merge commit
* @param {Object} [args.committer] - passed to [commit](commit.md) when creating a merge commit
* @param {string} [args.signingKey] - passed to [commit](commit.md) when creating a merge commit
* @param {boolean} [args.autoTranslateSSH] - Attempt to automatically translate SSH remotes into HTTP equivalents
* @param {boolean} [args.fast = false] - use fastCheckout instead of regular checkout
*
* @returns {Promise<void>} Resolves successfully when pull operation completes
Expand Down Expand Up @@ -73,6 +74,7 @@ export async function pull ({
author,
committer,
signingKey,
autoTranslateSSH = false,
fast = false
}) {
try {
Expand Down Expand Up @@ -102,7 +104,8 @@ export async function pull ({
token,
oauth2format,
singleBranch,
headers
headers,
autoTranslateSSH
})
// Merge the remote tracking branch into the local one.
await merge({
Expand Down
14 changes: 13 additions & 1 deletion src/commands/push.js
Expand Up @@ -10,6 +10,7 @@ import { join } from '../utils/join.js'
import { pkg } from '../utils/pkg.js'
import { cores } from '../utils/plugins.js'
import { splitLines } from '../utils/splitLines.js'
import { translateSSHtoHTTP } from '../utils/translateSSHtoHTTP.js'
import { parseReceivePackResponse } from '../wire/parseReceivePackResponse.js'
import { writeReceivePackRequest } from '../wire/writeReceivePackRequest.js'

Expand Down Expand Up @@ -61,6 +62,7 @@ import { pack } from './pack.js'
* @param {string} [args.token] - See the [Authentication](./authentication.html) documentation
* @param {string} [args.oauth2format] - See the [Authentication](./authentication.html) documentation
* @param {object} [args.headers] - Additional headers to include in HTTP requests, similar to git's `extraHeader` config
* @param {boolean} [args.autoTranslateSSH] - Attempt to automatically translate SSH remotes into HTTP equivalents
* @param {import('events').EventEmitter} [args.emitter] - [deprecated] Overrides the emitter set via the ['emitter' plugin](./plugin_emitter.md).
* @param {string} [args.emitterPrefix = ''] - Scope emitted events by prepending `emitterPrefix` to the event name.
*
Expand Down Expand Up @@ -99,14 +101,24 @@ export async function push ({
password = authPassword,
token,
oauth2format,
headers = {}
headers = {},
autoTranslateSSH = false
}) {
try {
const fs = new FileSystem(_fs)
// TODO: Figure out how pushing tags works. (This only works for branches.)
if (url === undefined) {
url = await config({ fs, gitdir, path: `remote.${remote}.url` })
}

// Try to convert SSH URLs to HTTPS ones
if (
autoTranslateSSH ||
(await config({ fs, gitdir, path: `isomorphic-git.autoTranslateSSH` }))
) {
url = translateSSHtoHTTP(url)
}

if (corsProxy === undefined) {
corsProxy = await config({ fs, gitdir, path: 'http.corsProxy' })
}
Expand Down
4 changes: 4 additions & 0 deletions src/index.d.ts
Expand Up @@ -317,6 +317,7 @@ export function clone(args: WorkDir & GitDir & {
noCheckout?: boolean;
noTags?: boolean;
headers?: { [key: string]: string };
autoTranslateSSH?: boolean;
}): Promise<void>;

export function commit(args: GitDir & {
Expand Down Expand Up @@ -432,6 +433,7 @@ export function fetch(args: GitDir & {
prune?: boolean;
pruneTags?: boolean;
headers?: { [key: string]: string };
autoTranslateSSH?: boolean;
}): Promise<FetchResponse>;

export function findRoot(args: {
Expand Down Expand Up @@ -568,6 +570,7 @@ export function pull(args: WorkDir & GitDir & {
headers?: { [key: string]: string };
emitter?: EventEmitter;
emitterPrefix?: string;
autoTranslateSSH?: boolean;
author?: {
name?: string;
email?: string;
Expand Down Expand Up @@ -601,6 +604,7 @@ export function push(args: GitDir & {
headers?: { [key: string]: string };
emitter?: EventEmitter;
emitterPrefix?: string;
autoTranslateSSH?: boolean;
}): Promise<PushResponse>;

export function readObject(args: GitDir & {
Expand Down
7 changes: 7 additions & 0 deletions src/managers/GitRemoteManager.js
Expand Up @@ -3,6 +3,13 @@ import { E, GitError } from '../models/GitError.js'
import { GitRemoteHTTP } from './GitRemoteHTTP'

function parseRemoteUrl ({ url }) {
// the stupid "shorter scp-like syntax"
if (url.startsWith('git@')) {
return {
transport: 'ssh',
address: url
}
}
const matches = url.match(/(\w+)(:\/\/|::)(.*)/)
if (matches === null) return
/*
Expand Down
3 changes: 3 additions & 0 deletions src/models/GitConfig.js
Expand Up @@ -26,6 +26,9 @@ const schema = {
symlinks: bool,
ignorecase: bool,
bigFileThreshold: num
},
'isomorphic-git': {
autoTranslateSSH: bool
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/utils/translateSSHtoHTTP.js
@@ -0,0 +1,7 @@
export function translateSSHtoHTTP (url) {
// handle "shorter scp-like syntax"
url = url.replace(/^git@([^:]+):/, 'https://$1/')
// handle proper SSH URLs
url = url.replace(/^ssh:\/\//, 'https://')
return url
}

0 comments on commit 661f74e

Please sign in to comment.