Skip to content

Commit

Permalink
1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
blond committed Feb 25, 2016
1 parent 4b99e7b commit 1050506
Show file tree
Hide file tree
Showing 20 changed files with 593 additions and 9 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["nodejs-lts"]
}
2 changes: 1 addition & 1 deletion .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ insert_final_newline = true
indent_style = space
indent_size = 4

[*.{json,*rc}]
[*.{json,*rc,yml}]
indent_size = 2

[*.md]
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
node_modules
lib
coverage
.nyc_output
35 changes: 32 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
sudo: false

language: node_js
node_js:
- '5'
- '4'

matrix:
include:
- node_js: "4"
env: COVERALLS=1
- node_js: "5"

# This is a random private key used purely for testing.
before_script:
- echo -e "Host *\n\tStrictHostKeyChecking no\n" >> ~/.ssh/config
- echo -e "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkTcgXnHuqR0gbwegnr9Zxz4hTkjjV/SpgJNPJz7mo/HKNbx0rqjj1P0yGR053R9GSFFim2ut4NK9DPPUkQdyucw+DoLkYRHJmlJ4BNa9NTCD0sl+eSXO2969kZojCYSOgbmkCJx8mdgTwhzdgE/jhBrsY0hPE6pRTlU+H68/zeNdJUAIJf0LLXOm3hpTKLA19VICltl/j9VvBJpgRHdBylXEyL8HokYpjkQQk1ZXj3m7Nlo8yDdg4VcljOJWC+Xh8kxRMfK5x/VRVsYKCQXN5QlzKeqf7USRDUS/7mFoPUBW+d4kwKtGxRsWuIL2yeqzifZUTOgsh9+ZWAWxWffQZ your_email@example.com" > ~/.ssh/id_rsa.pub
- echo -e "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEA5E3IF5x7qkdIG8HoJ6/Wcc+IU5I41f0qYCTTyc+5qPxyjW8d\nK6o49T9MhkdOd0fRkhRYptrreDSvQzz1JEHcrnMPg6C5GERyZpSeATWvTUwg9LJf\nnklztvevZGaIwmEjoG5pAicfJnYE8Ic3YBP44Qa7GNITxOqUU5VPh+vP83jXSVAC\nCX9Cy1zpt4aUyiwNfVSApbZf4/VbwSaYER3QcpVxMi/B6JGKY5EEJNWV495uzZaP\nMg3YOFXJYziVgvl4fJMUTHyucf1UVbGCgkFzeUJcynqn+1EkQ1Ev+5haD1AVvneJ\nMCrRsUbFriC9snqs4n2VEzoLIffmVgFsVn30GQIDAQABAoIBAQDPQm2sQbti0mN8\nD4Uawl8D40v30n8WhUa7EbPTOmlqKAQ2sfDhex9KRbTLEmEBmImA/Eee8o9iCTIy\n8Fv8Fm6pUHt9G6Pti/XvemwW3Q3QNpSUkHqN0FDkgecQVqVBEb6uHo3mDm4RFINX\neOmkp30BjIK9/blEw1D0sFALLOEUPaDdPMwiXtFgqfrFSgpDET3TvQIwZ2LxxTm0\ncNmP3sCSlZHJNkZI4hBEWaaXR+V5/+C1qblDCo5blAWTcX3UzqrwUUJgFi6VnBuh\n7S9Q6+CEIU+4JRyWQNmY8YgZFaAp6IOr/kyfPxTP1+UEVVgcLn3WDYwfG9og0tmz\nfzlruAgBAoGBAPfz73Pey86tNZEanhJhbX8gVjzy2hvyhT0paHg0q/H6c1VWOtUH\nOwZ3Ns2xAZqJhlDqCHnQYSCZDly042U/theP4N8zo1APb4Yg4qdmXF9QE1+2M03r\nkS6138gU/CSCLf8pCYa6pA/GmsaXxloeJGLvT4fzOZRsVav80/92XHRhAoGBAOu2\nmKh4Gr1EjgN9QNbk9cQTSFDtlBEqO/0pTepvL73UvNp/BAn4iYZFU4WnklFVBSWc\nL84Sc732xU12TAbTTUsa6E7W29pS8u7zVTxlIdQIIU5pzDyU1pNNk2kpxzte5p3Y\nPDtniPFsoYLWoH0LpsKL93t2pLAj+IOkE6f3XBq5AoGAIKaYo5N1FxQr952frx/x\nQUpK0N/R5Ng8v18SiLG26rhmM5iVSrQXC7TrHI7wfR8a9tC6qP/NqnM9NuwC/bQ0\nEEo7/GhaWxKNRwZRkmWiSFLNGk9t1hbtGU+N1lUdFtmloPIQdRNiw0kN3JTj474Q\nYI7O1EItFORnK6yxZfR6HEECgYEA1CT7MGUoa8APsMRCXyaiq15Pb8bjxK8mXquW\nHLEFXuzhLCW1FORDoj0y9s/iuKC0iS0ROX8R/J7k5NrbgikbH8WP36UxKkYNr1IC\nHOFImPTYRSKjVsL+fIUNb1DSp3S6SsYbL7v3XJJQqtlQiDq8U8x1aQFXJ9C4EoLR\nzhKrKsECgYBtU/TSF/TATZY5XtrN9O+HX1Fbz70Ci8XgvioheVI2fezOcXPRzDcC\nOYPaCMNKA5E8gHdg4s0TN7uDvKTJ+KhSg2V7gZ39A28dHrJaRX7Nz4k6t2uEBjX9\na1JidpAIbJ+3w7+hj6L299tVZvS+Y/6Dz/uuEQGXfJg/l/5CCvQPsA==\n-----END RSA PRIVATE KEY-----" > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa*
- eval `ssh-agent -s`
- ssh-add ~/.ssh/id_rsa
- git config --global user.name travis
- git config --global user.email travis@locahost

after_success:
- if [ "x$COVERALLS" = "x1" ]; then npm run coveralls; fi

# It is necessary for nodegit
# https://github.com/nodegit/nodegit#getting-started
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++-4.9-dev
- gcc-4.9
- g++-4.9
107 changes: 107 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,120 @@ nodegit-clone
[david]: https://david-dm.org/blond/nodegit-clone
[dependency-img]: http://img.shields.io/david/blond/nodegit-clone.svg

Clone git repository with [nodegit](http://www.nodegit.org/).

Install
-------

```
$ npm install --save nodegit-clone
```

Usage
-----

```js
import clone from 'nodegit-clone';

clone('https://github.com/owner/repo')
.then(repo => {
// Access any repository methods here.
console.log(repo.path());
});

// path/to/repo/.git
```

API
---

### clone({ url, [localPath], [ghToken], [ssh] })

Returns a Promise, that resolves to instance of [Repository](http://www.nodegit.org/api/repository/).

#### url

Type: `string`

The URL to the repository.

**Note:** the following protocols are supported: `http`, `https`, `git` and `ssh`.

```js
clone('http://github.com/owner/repo');
clone('https://github.com/owner/repo');
clone('git://github.com/owner/repo.git');
clone('git@github.com:owner/repo.git');
```

#### localPath

Type: `string`

The Local path to store repository.

**Note:** if `localPath` is not specified then repository will be cloned to directory with repository name.

#### ghToken

Type: `string`

The GitHub personal OAuth token.

#### ssh

Type: `object`

The object with paths to ssh keys and passphrase.

GitHub Private Repositories
---------------------------

Before you can clone a repository, you'll need a GitHub OAuth application token. You can find more information on generating one here: [Creating an access token for command-line use](https://help.github.com/articles/creating-an-access-token-for-command-line-use/).

In this example we're going to clone one of our private test repositories from GitHub. This must be an https protocol URL for the clone to work.

```js
// Keep this value a secret. If you accidentally commit
// this key to a public GitHub repository they will immediately revoke it.
const GITHUB_TOKEN = '<GH_TOKEN>';

clone({
url: 'https://github.com/owner/private',
ghToken: GITHUB_TOKEN
});
```

SSH Keys
--------

Before you can clone a repository, you'll need SSH keys. You can find more information on generating them here: [Generating an SSH key](https://help.github.com/articles/generating-an-ssh-key/).

In this example we're going to clone one of our private test repositories. This must be an ssh protocol URL for the clone to work.

```js
clone({
url: 'git@github.com:owner/private.git',
ssh: {
publicKey: '/path/to/public-key',
privateKey: '/path/to/private-key'
}
});
```

For encrypted keys you should specify the `passphrase` option:

```js
clone({
url: 'git@github.com:owner/private.git',
ssh: {
publicKey: '/path/to/public-key',
privateKey: '/path/to/private-key',
passphrase: 'password'
}
});
```

License
-------

Expand Down
10 changes: 9 additions & 1 deletion appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
environment:
nodejs_version: "4"

clone_folder: c:\projects\nodegit-clone

# fix lineendings in Windows
init:
- git config --global core.autocrlf input
- git config --global user.name appveyor
- git config --global user.email appveyor@locahost

install:
- ps: Install-Product node $env:nodejs_version
- node --version
- npm --version
- npm install

test_script:
- npm run test
- npm run unit-test

build: "off"
52 changes: 48 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "nodegit-clone",
"version": "0.0.0",
"description": "Git clone with nodegit",
"version": "1.0.0",
"description": "Clone git repository with nodegit",
"license": "MIT",
"repository": "blond/nodegit-clone",
"author": "Andrew Abramov <mail@blond.im> (github.com/blond)",
Expand All @@ -11,7 +11,51 @@
"http",
"https",
"ssh",
"github"
"github",
"token"
]
],
"main": "lib/clone.js",
"files": [
"libs/**",
"index.js"
],
"dependencies": {
"is-ssh": "1.3.0",
"nodegit": "0.11.3",
"throw": "1.1.0"
},
"devDependencies": {
"ava": "0.12.0",
"babel-cli": "6.5.1",
"babel-eslint": "5.0.0",
"babel-preset-nodejs-lts": "1.2.1",
"babel-register": "6.5.2",
"coveralls": "2.11.6",
"es6-promisify": "3.0.0",
"eslint": "2.2.0",
"fs-extra": "0.26.5",
"nyc": "5.6.0",
"tempfile": "1.1.1"
},
"scripts": {
"test": "npm run lint && npm run cover",
"lint": "eslint .",
"unit-test": "ava",
"cover": "nyc ava",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"prepublish": "npm run clean && npm run compile",
"compile": "babel src -d lib",
"clean": "rm -rf lib/"
},
"ava": {
"files": [
"test/**/*.js",
"!test/fixtures/**",
"!test/utils/**"
],
"verbose": true,
"require": [
"babel-register"
]
}
}
54 changes: 54 additions & 0 deletions src/clone.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import os from 'os';

import git from 'nodegit';
import isSSH from 'is-ssh';

import init from './init';

/**
* Clones repository to `localPath`.
*
* @param {Object} opts Options or url of the repository.
* @param {String} opts.url The URL to the repository.
* @param {String} [opts.localPath] The Local path to store repository.
* @param {String} [opts.ghToken] The GitHub personal OAuth token.
* @param {Object} [opts.ssh] The object with paths to ssh keys and passphrase.
* @param {String} [opts.ssh.publicKey] The path to the public key of the credential.
* @param {String} [opts.ssh.privateKey] The path to the private key of the credential.
* @param {String} [opts.ssh.passphrase] The passphrase of the credential.
*
* @returns {Promise<Git.Repository>} A promise `Git.Repository` instance.
* @see [Git.Repository]{@link http://www.nodegit.org/api/repository/}
*/
export default function clone(opts) {
const { url, localPath, ghToken, ssh } = init(opts);

const cloneOpts = { fetchOpts: {} };
const callbacks = cloneOpts.fetchOpts.callbacks = {};

if (os.type() === 'Darwin'/* OS X */) {
// This is a required callback for OS X machines. There is a known issue
// with libgit2 being able to verify certificates from GitHub.
callbacks.certificateCheck = () => 1;
}

if (ghToken) {
callbacks.certificateCheck = () => 1;
callbacks.credentials = () => {
// In order to authorize the clone operation, we'll need to respond to a low-level callback
// that expects credentials to be passed.
// This function will respond back with the OAuth token.
return git.Cred.userpassPlaintextNew(ghToken, "x-oauth-basic");
};
} else if (ssh.publicKey || isSSH(url)) {
callbacks.credentials = (url, username) => {
// Forward user name to validate authentication.
return git.Cred.sshKeyFromAgent(username, ssh.publicKey, ssh.privateKey, ssh.passphrase);
};
}

// Convert NodeGit promise to ES Promise
return new Promise((resolve, reject) => {
git.Clone(url, localPath, cloneOpts).then(resolve, reject);
});
}
20 changes: 20 additions & 0 deletions src/init.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import path from 'path';
import thr from 'throw';

import repoName from './repo-name';

/**
* Initializes options.
*
* @param {Object} opts
* @returns {String}
*/
export default function init(opts={}) {
const {
url = (typeof opts === 'string') ? opts : thr('You should specify url to repository.'),
localPath = repoName(url),
ghToken, ssh={}
} = opts;

return { url, localPath: path.resolve(localPath), ghToken, ssh };
}
11 changes: 11 additions & 0 deletions src/repo-name.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import path from 'path';

/**
* Returns repository name.
*
* @param {String} url — url of the repository.
* @returns {String}
*/
export default function getRepoName(url) {
return path.basename(url, '.git');
}
45 changes: 45 additions & 0 deletions test/errors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import path from 'path';

import test from 'ava';
import fs from 'fs-extra';
import promisify from 'es6-promisify';

import clone from '../src/clone';
import tmpdirs from './utils/tmpdirs';

const outputFile = promisify(fs.outputFile);
const tmps = tmpdirs();
const tmpdir = tmps.tmpdir.bind(tmpdirs);

test.after('clear', () => tmps.clear());

test('should throw error if local store of repository already exists', t => {
const url = 'git://github.com/nodegit/fake.git';
const workdir = tmpdir();

return t.throws(
occupy(workdir).then(() => clone({ url: url, localPath: workdir }))
);
});

test('should throw error if repository does not exist', t => {
return t.throws(
clone({ url: 'git://github.com/nodegit/fake.git', localPath: tmpdir() })
);
});

test('should throw error if page does not exist', t => {
return t.throws(
clone({ url: 'http://github.com/nodegit/fake', localPath: tmpdir() })
);
});

/**
* @param {String} dir — path to dir.
* @returns {Promise}
*/
function occupy(dir) {
const filename = path.join(dir, 'some-file.txt');

return outputFile(filename, 'text');
}
Loading

0 comments on commit 1050506

Please sign in to comment.