Skip to content

Commit 92fabdf

Browse files
committed
rename project to git-http-mock-server
1 parent b235d65 commit 92fabdf

File tree

4 files changed

+144
-46
lines changed

4 files changed

+144
-46
lines changed

README.md

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,74 @@
1-
# karma-git-http-server-middleware
1+
# git-http-mock-server
22

3-
A karma middleware for '[git-http-backend](https://github.com/substack/git-http-backend)',
4-
originally inspired by '[git-http-server](https://github.com/bahamas10/node-git-http-server)'
3+
Clone and push to git repository test fixtures over HTTP.
4+
5+
## What it does
6+
7+
Given a directory of bare git repositories, `git-http-mock-server` will serve those repositories using the
8+
native `git-http-backend` process built into `git` (which needs to be installed on the machine).
9+
You can then run tests that clone or push to git repositories (regardless of whether Github is down)
10+
and you can run those tests in parallel without them interfering with each other.
11+
(It uses copy-on-write so that pushing to the repo doesn't actually alter the repo.)
12+
Because it uses `git-http-backend` git hooks (such as `hooks/update` and `hooks/post-receive`) are automatically supported.
13+
14+
It also supports HTTP Basic Auth password protection of repos so you can test how your code handles 401 errors.
515

616
## How to use
717

818
```sh
9-
npm install --save-dev karma-git-http-server-middleware
19+
npm install --save-dev git-http-mock-server
1020
```
1121

12-
In your `karma.config.js`, add:
22+
Now `cd` to a directory in which you have some bare git repos
23+
and run this server:
1324

25+
```sh
26+
> cd __fixtures__
27+
> ls
28+
test-repo1.git test-repo2.git imaginatively-named-repo.git
29+
> git-http-mock-server
1430
```
15-
beforeMiddleware: ['git-http-server'],
16-
gitHttpServer: {
17-
root: '__tests__/__fixtures__',
18-
route: 'git-server'
19-
},
31+
32+
Now clone away...
33+
```sh
34+
> git clone https://localhost:8174/imaginatively-named-repo.git
2035
```
2136

22-
Then in your JS code, you can reference git repos on disk via `http://localhost:9876/git-server/name-of-repo.git`.
37+
### Environment Variables
2338

24-
This is useful for testing `isomorphic-git` and applications built using it.
39+
- `GIT_HTTP_MOCK_SERVER_PORT` default is 8174 (to be compatible with [git-http-server](https://github.com/bahamas10/node-git-http-server))
40+
- `GIT_HTTP_MOCK_SERVER_ROUTE` default is `/`
41+
- `GIT_HTTP_MOCK_SERVER_ROOT` default is `process.cwd()`
2542

26-
## Examples
43+
### .htpasswd support
2744

28-
See <https://github.com/isomorphic-git/isomorphic-git/tree/master/__tests__>
45+
You can place an Apache-style `.htpasswd` file in a bare repo to protect it with Basic Authentication.
46+
47+
```sh
48+
> cd __fixtures__/test-repo1.git
49+
> htpasswd -cb .htpasswd testuser testpassword
50+
Adding password for user testuser.
51+
> cat .htpasswd
52+
testuser:$apr1$BRdvH4Mu$3HrpeyBrWiS88GcSPidgq/
53+
```
54+
55+
If you don't have `htpasswd` on your machine, you can use [htpasswd](https://npm.im/htpasswd) which is
56+
a cross-platform Node implementation of `htpasswd`.
2957

3058
## Dependencies
3159

32-
- [fixturez](https://github.com/thejameskyle/fixturez): Easily create and maintain test fixtures in the file system
33-
- [git-http-backend](https://github.com/substack/git-http-backend): serve a git repository over http
60+
- [basic-auth](https://ghub.io/basic-auth): node.js basic auth parser
61+
- [chalk](https://ghub.io/chalk): Terminal string styling done right
62+
- [fixturez](https://ghub.io/fixturez): Easily create and maintain test fixtures in the file system
63+
- [git-http-backend](https://ghub.io/git-http-backend): serve a git repository over http
64+
- [htpasswd-js](https://ghub.io/htpasswd-js): Pure JS htpasswd authentication
65+
66+
originally inspired by '[git-http-server](https://github.com/bahamas10/node-git-http-server)'
3467

3568
## License
3669

3770
MIT
3871

3972
## Changelog
4073

41-
1.0.0 - Initial release
42-
43-
2.0.0 - Copy repo on push (so repo stays untouched)
74+
1.0.0 - Initial release

bin.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/usr/bin/env node
2+
// Standalone server for use without karma!
3+
var http = require('http')
4+
var path = require('path')
5+
var factory = require('./middleware')
6+
7+
var config = {
8+
root: path.resolve(process.cwd(), process.env.GIT_HTTP_MOCK_SERVER_ROOT || '.'),
9+
glob: '*',
10+
route: process.env.GIT_HTTP_MOCK_SERVER_ROUTE || '/'
11+
}
12+
13+
var server = http.createServer(factory(config))
14+
server.listen(process.env.GIT_HTTP_MOCK_SERVER_PORT || 8174)

middleware.js

Lines changed: 68 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,104 @@
1-
var spawn = require('child_process').spawn;
2-
var path = require('path').posix;
3-
var url = require('url');
4-
var backend = require('git-http-backend');
5-
var fixturez = require('fixturez');
1+
var spawn = require('child_process').spawn
2+
var fs = require('fs')
3+
var path = require('path')
4+
var url = require('url')
5+
6+
var auth = require('basic-auth')
7+
var chalk = require('chalk')
8+
var fixturez = require('fixturez')
9+
var backend = require('git-http-backend')
10+
var htpasswd = require('htpasswd-js')
611

712
function factory (config) {
813
if (!config.root) throw new Error('Missing required "gitHttpServer.root" config option')
914
if (!config.route) throw new Error('Missing required "gitHttpServer.route" config option')
1015
if (!config.route.startsWith('/')) throw new Error('"gitHttpServer.route" must start with a "/"')
1116
// TODO: Make this configurable in karma.conf.js
12-
var f = fixturez(config.root, {root: process.cwd()})
17+
var f = fixturez(config.root, {root: process.cwd(), glob: config.glob})
1318

1419
function getGitDir (req) {
1520
var u = url.parse(req.url)
1621
if (u.pathname.startsWith(config.route)) {
1722
if (req.method === 'GET' && u.pathname.endsWith('/info/refs')) {
1823
let gitdir = u.pathname.replace(config.route, '').replace(/\/info\/refs$/, '').replace(/^\//, '')
19-
let fixtureName = path.basename(gitdir)
24+
let fixtureName = path.posix.basename(gitdir)
2025
return f.find(fixtureName)
2126
}
2227
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-git-upload-pack-request') {
2328
let gitdir = u.pathname.replace(config.route, '').replace(/\/git-upload-pack$/, '').replace(/^\//, '')
24-
let fixtureName = path.basename(gitdir)
29+
let fixtureName = path.posix.basename(gitdir)
2530
return f.find(fixtureName)
2631
}
2732
if (req.method === 'POST' && req.headers['content-type'] === 'application/x-git-receive-pack-request') {
2833
let gitdir = u.pathname.replace(config.route, '').replace(/\/git-receive-pack$/, '').replace(/^\//, '')
29-
let fixtureName = path.basename(gitdir)
34+
let fixtureName = path.posix.basename(gitdir)
3035
return f.copy(fixtureName)
3136
}
3237
}
3338
return null
3439
}
3540

36-
return function middleware (req, res, next) {
37-
var gitdir = getGitDir(req);
38-
if (gitdir == null) return next();
41+
return async function middleware (req, res, next) {
42+
if (!next) next = () => void(0)
43+
try {
44+
var gitdir = getGitDir(req)
45+
} catch (err) {
46+
res.statusCode = 404
47+
res.end(err.message + '\n')
48+
console.log(chalk.red('[git-http-server] 404 ' + req.url))
49+
return
50+
}
51+
if (gitdir == null) return next()
52+
53+
// Check for a .htaccess file
54+
let data = null
55+
try {
56+
data = fs.readFileSync(path.join(gitdir, '.htpasswd'), 'utf8')
57+
} catch (err) {
58+
// no .htaccess file, proceed without authentication
59+
}
60+
if (data) {
61+
// The previous line would have failed if there wasn't an .htaccess file, so
62+
// we must treat this as protected.
63+
let cred = auth.parse(req.headers['authorization'])
64+
if (cred === undefined) {
65+
res.statusCode = 401
66+
res.setHeader('WWW-Authenticate', 'Basic')
67+
res.end('Unauthorized' + '\n')
68+
console.log(chalk.red('[git-http-server] 401 ' + req.url))
69+
return
70+
}
71+
let valid = await htpasswd.authenticate({
72+
username: cred.name,
73+
password: cred.pass,
74+
data
75+
})
76+
if (!valid) {
77+
res.statusCode = 401
78+
res.setHeader('WWW-Authenticate', 'Basic')
79+
res.end('Bad credentials' + '\n')
80+
console.log(chalk.red('[git-http-server] 401 ' + req.url))
81+
return
82+
}
83+
}
3984

4085
req.pipe(backend(req.url, function (err, service) {
4186
if (err) {
42-
res.statusCode = 500;
43-
res.end(err + '\n');
44-
return;
87+
res.statusCode = 500
88+
res.end(err + '\n')
89+
console.log(chalk.red('[git-http-server] 500 ' + req.url))
90+
return
4591
}
4692

47-
res.setHeader('content-type', service.type);
48-
console.log('[git-http-server] ' + service.cmd + ' ' + service.args.concat(gitdir).join(' '))
49-
var ps = spawn(service.cmd, service.args.concat(gitdir));
50-
ps.stdout.pipe(service.createStream()).pipe(ps.stdin);
51-
})).pipe(res);
93+
res.setHeader('content-type', service.type)
94+
console.log(chalk.green('[git-http-server] 200 ' + req.url))
95+
// console.log('[git-http-server] ' + service.cmd + ' ' + service.args.concat(gitdir).join(' '))
96+
var ps = spawn(service.cmd, service.args.concat(gitdir))
97+
ps.stdout.pipe(service.createStream()).pipe(ps.stdin)
98+
})).pipe(res)
5299
}
53100
}
54101

55102
factory.$inject = ['config.gitHttpServer']
56103

57-
module.exports = factory
104+
module.exports = factory

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
{
2-
"name": "karma-git-http-server-middleware",
2+
"name": "git-http-mock-server",
33
"version": "0.0.0-development",
4-
"description": "A karma middleware for 'git-http-backend'",
4+
"description": "Clone and push to git repository test fixtures over HTTP.",
55
"main": "index.js",
6+
"bin": {
7+
"git-http-mock-server": "bin.js"
8+
},
69
"scripts": {
710
"test": "echo \"No tests\"",
811
"semantic-release": "semantic-release",
912
"travis-deploy-once": "travis-deploy-once"
1013
},
1114
"repository": {
1215
"type": "git",
13-
"url": "https://github.com/isomorphic-git/karma-git-http-server-middleware.git"
16+
"url": "https://github.com/isomorphic-git/git-http-mock-server.git"
1417
},
1518
"keywords": [
1619
"karma-plugin",
@@ -21,12 +24,15 @@
2124
"author": "William Hilton <wmhilton@gmail.com>",
2225
"license": "MIT",
2326
"bugs": {
24-
"url": "https://github.com/isomorphic-git/karma-git-http-server-middleware/issues"
27+
"url": "https://github.com/isomorphic-git/git-http-mock-server/issues"
2528
},
26-
"homepage": "https://github.com/isomorphic-git/karma-git-http-server-middleware#readme",
29+
"homepage": "https://github.com/isomorphic-git/git-http-mock-server#readme",
2730
"dependencies": {
31+
"basic-auth": "^2.0.0",
32+
"chalk": "^2.4.1",
2833
"fixturez": "^1.1.0",
29-
"git-http-backend": "^1.0.2"
34+
"git-http-backend": "^1.0.2",
35+
"htpasswd-js": "^1.0.2"
3036
},
3137
"devDependencies": {
3238
"semantic-release": "15.1.7",

0 commit comments

Comments
 (0)