ssb-git-repo
Advanced tools
Comparing version 1.4.1 to 1.5.0
25
index.js
@@ -13,9 +13,10 @@ var ref = require('ssb-ref') | ||
} | ||
if (options.forks) { | ||
if (!ref.isMsg(options.forks)) | ||
throw new Error('Invalid repo ID: ' + options.forks) | ||
msg.forks = options.forks | ||
if (options.upstream) { | ||
var upstreamId = options.upstream.id | ||
if (!ref.isMsg(upstreamId)) | ||
throw new Error('Invalid repo ID: ' + upstreamId) | ||
msg.upstream = upstreamId | ||
} | ||
sbot.publish(msg, function (err, msg) { | ||
var repo = new Repo(sbot, msg.key, msg.value) | ||
var repo = new Repo(sbot, msg.key, msg.value, options.upstream) | ||
repo.synced = true | ||
@@ -31,2 +32,3 @@ if (options.live) | ||
if (!options) options = {} | ||
var msg | ||
@@ -41,5 +43,14 @@ if (typeof id == 'object') { | ||
function gotMsg(err, msg) { | ||
function gotMsg(err, _msg) { | ||
if (err) return cb(err) | ||
var repo = new Repo(sbot, id, msg) | ||
msg = _msg | ||
if (msg.content.upstream) | ||
exports.getRepo(sbot, msg.content.upstream, options, gotUpstream) | ||
else | ||
gotUpstream() | ||
} | ||
function gotUpstream(err, upstream) { | ||
if (err) return cb(err) | ||
var repo = new Repo(sbot, id, msg, upstream) | ||
repo._sync(options.live) | ||
@@ -46,0 +57,0 @@ cb(null, repo) |
184
lib/repo.js
@@ -11,5 +11,46 @@ var pull = require('pull-stream') | ||
var createSSBBlobHash = require('pull-hash/ext/ssb') | ||
var gitPack = require('pull-git-pack') | ||
var GitRepo = require('pull-git-repo') | ||
var Mentions = require('ssb-mentions') | ||
module.exports = Repo | ||
function until(condition) { | ||
return function (read) { | ||
return function (end, cb) { | ||
read(end, function (end, data) { | ||
if (end || data == condition) | ||
cb(end || true) | ||
else | ||
cb(null, data) | ||
}) | ||
} | ||
} | ||
} | ||
var issueUpdateRegex = /(?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?) +(?:issue +)?(%[A-Za-z0-9\/+]{43}=\.sha256)/g | ||
// msg id pattern from ssb-ref/index.js | ||
// close/fix pattern based on https://github.com/gitlabhq/gitlabhq/blob/c5ed929d33981d4af25c701087a4eaca1348cc1b/doc/customization/issue_closing.md | ||
function getIssueMentions(object) { | ||
var ids = {} | ||
var mentions = [] | ||
var text = object.title + '\n\n' + object.body | ||
issueUpdateRegex.lastIndex = 0 | ||
for (var m; m = issueUpdateRegex.exec(text); ) { | ||
var id = m[1] | ||
if (id in ids) continue | ||
if (ref.isLink(id)) { | ||
mentions.push({ | ||
link: id, | ||
open: false, | ||
object: object.id, | ||
label: object.title | ||
}) | ||
ids[id] = true | ||
} | ||
} | ||
return mentions | ||
} | ||
var emptyPackId = '&47hwmsDkBO4rXpJgiKY4dfJDoGB7oL/7wiimQsZL5wI=.sha256' | ||
@@ -26,6 +67,37 @@ var emptyIdxId = '&JuEIZDf1XX38OXLTVlS8HCSXCD073j2AQP7ejQbgepc=.sha256' | ||
function Repo(sbot, id, msg) { | ||
function getMentions(repo, pack, cb) { | ||
var done = multicb({ pluck: 1, spread: true }) | ||
var mentionsCb = done() | ||
// decode the pack and detect mentions | ||
pull( | ||
pull(pack, gitPack.decode({}, repo, done())), | ||
pull.asyncMap(function (obj, cb) { | ||
if (obj.type == 'commit') | ||
GitRepo.getCommitParsed(obj, cb) | ||
else if (obj.type == 'tag') | ||
GitRepo.getTagParsed(obj, cb) | ||
else | ||
pull(obj.read, pull.drain(null, cb)) | ||
}), | ||
pull.filter(Boolean), | ||
pull.map(function (obj) { | ||
var text = obj.title + '\n\n' + obj.body | ||
return Mentions(text).map(function (mention) { | ||
mention.object = obj.id | ||
mention.label = obj.title | ||
// TODO: add commit/tag title to mention? | ||
return mention | ||
}) | ||
}), | ||
pull.flatten(), | ||
pull.collect(mentionsCb) | ||
) | ||
done(cb) | ||
} | ||
function Repo(sbot, id, msg, upstream) { | ||
this.sbot = sbot | ||
this.id = id | ||
this.feed = msg.author | ||
this.upstream = upstream | ||
this._refs = {/* ref: sha1 */} | ||
@@ -40,5 +112,3 @@ this._objects = {/* sha1: {type, length, key} */} | ||
this._oldPacksPushable = pushable() | ||
this._newPacksPushable = pushable() | ||
this._oldPacks = cache(this._oldPacksPushable) | ||
this._newPacks = reverse(this._newPacksPushable) | ||
@@ -58,2 +128,9 @@ } | ||
Repo.prototype.getHead = function (cb) { | ||
if (this.head) | ||
cb(null, this.head) | ||
else | ||
this._headCbs.push(cb) | ||
} | ||
Repo.prototype._setHead = function (head) { | ||
@@ -209,3 +286,3 @@ this.head = head | ||
if (ended || end) return cb(ended || end) | ||
this._headCbs.push(function (err, ref) { | ||
this.getHead(function (err, ref) { | ||
ended = err || true | ||
@@ -257,2 +334,5 @@ cb(err, {name: 'HEAD', ref: ref}) | ||
this._oldPacksPushable = pushable() | ||
this._oldPacks = cache(this._oldPacksPushable) | ||
pull( | ||
@@ -362,3 +442,3 @@ this.sbot.links({ | ||
this._newPacks(), | ||
this._oldPacks() | ||
this._oldPacks ? this._oldPacks() : pull.empty() | ||
]) | ||
@@ -464,2 +544,5 @@ } | ||
var indexesCb = done() | ||
var mentionsCb = done() | ||
var issuesCb = done() | ||
var refsCb = done() | ||
@@ -470,8 +553,25 @@ pull( | ||
var done = multicb({ pluck: 1, spread: true }) | ||
pull(pack.pack, addSSBBlob(self.sbot, done())) | ||
var packCached = cache(pack.pack) | ||
// add the pack and the idx to ssb | ||
pull(packCached(), addSSBBlob(self.sbot, done())) | ||
pull(pack.idx, addSSBBlob(self.sbot, done())) | ||
done(function (err, packId, idxId) { | ||
if (err) cb(err) | ||
else if (packId == emptyPackId && idxId == emptyIdxId) cb() | ||
else cb(null, {pack: {link: packId}, idx: {link: idxId}}) | ||
if (err) return cb(err) | ||
if (packId == emptyPackId && idxId == emptyIdxId) return cb() | ||
// add the pack and idx before publishing the message, | ||
// so that decoding deltas in the pack works | ||
self._newPacksPushable.push({ | ||
packId: packId, | ||
idxId: idxId | ||
}) | ||
getMentions(self, packCached(), function (err, mentions) { | ||
if (err) return cb(err) | ||
cb(null, { | ||
pack: {link: packId}, | ||
idx: {link: idxId}, | ||
mentions: mentions | ||
}) | ||
}) | ||
}) | ||
@@ -483,12 +583,63 @@ }), | ||
indexesCb(err, combined.map(function (obj) { return obj.idx })) | ||
mentionsCb(err, [].concat.apply([], | ||
combined.map(function (obj) { return obj.mentions }))) | ||
// now that the packs are added to the repo, read the ref updates | ||
// and new commits | ||
if (readRefUpdates) | ||
Repo_readRefUpdates.call(self, readRefUpdates, gotRefUpdates) | ||
else | ||
gotRefUpdates() | ||
}) | ||
) | ||
if (readRefUpdates) | ||
Repo_readRefUpdates.call(this, readRefUpdates, done()) | ||
function gotRefUpdates(err, refUpdatesObj) { | ||
refsCb(err, refUpdatesObj) | ||
if (err) return | ||
// detect issue close commands in commit messages | ||
// read commit messages from last head to current head | ||
self.getHead(function (err, ref) { | ||
var newHead = refUpdatesObj[ref] | ||
if (!newHead) { | ||
// HEAD not updated | ||
return issuesCb(null, []) | ||
} | ||
done(function (err, packs, indexes, refUpdatesObj) { | ||
GitRepo(self).resolveRef(ref, function (err, oldHead) { | ||
if (err) return issuesCb(err) | ||
if (oldHead == newHead) | ||
return issuesCb(null, []) | ||
pull( | ||
GitRepo(self).readLog(newHead), | ||
until(oldHead), | ||
pull.asyncMap(self.getCommitParsed.bind(self)), | ||
pull.map(getIssueMentions), | ||
pull.flatten(), | ||
pull.collect(issuesCb) | ||
) | ||
}) | ||
}) | ||
} | ||
done(function (err, packs, indexes, mentions, issues, refUpdatesObj) { | ||
if (err) return cb(err) | ||
if (packs.length == 0 && indexes.length == 0) packs = indexes = undefined | ||
self.sbot.publish({ | ||
if (issues && mentions) { | ||
// deduplicate closed issues and issue mentions | ||
var closed = {} | ||
issues.forEach(function (issue) { | ||
if (issue.open === false) | ||
closed[[issue.link, issue.object]] = true | ||
}) | ||
mentions = mentions.filter(function (mention) { | ||
return !closed[[mention.link, mention.object]] | ||
}) | ||
} | ||
if (mentions.length == 0) mentions = undefined | ||
if (issues.length == 0) issues = undefined | ||
var msg = { | ||
type: 'git-update', | ||
@@ -498,4 +649,7 @@ repo: self.id, | ||
indexes: indexes, | ||
refs: refUpdatesObj | ||
}, function (err, msg) { | ||
refs: refUpdatesObj, | ||
mentions: mentions, | ||
issues: issues, | ||
} | ||
self.sbot.publish(msg, function (err, msg) { | ||
if (err) return cb(err) | ||
@@ -502,0 +656,0 @@ self._processNewMsg(msg.value.content) |
{ | ||
"name": "ssb-git-repo", | ||
"version": "1.4.1", | ||
"version": "1.5.0", | ||
"description": "git repos in secure-scuttlebutt", | ||
@@ -29,6 +29,7 @@ "main": "index.js", | ||
"pull-git-pack": "^0.1.2", | ||
"pull-git-repo": "^0.2.2", | ||
"pull-git-repo": "^0.3.0", | ||
"pull-hash": "^0.0.0", | ||
"pull-pushable": "^2.0.0", | ||
"pull-stream": "^3.1.0", | ||
"ssb-mentions": "^0.0.0", | ||
"ssb-ref": "^2.3.0" | ||
@@ -35,0 +36,0 @@ }, |
@@ -25,3 +25,4 @@ # ssb-git-repo | ||
- `sbot`: a [scuttlebot][] or [ssb-client][] object | ||
- `options.forks`: message ID of a repo of which this repo is considered a fork | ||
- `options.upstream` (`ssbGit.Repo`): upstream repo (of which | ||
the new repo will be a fork) | ||
- `options.live`: keep the repo updated as changes are pushed to it | ||
@@ -62,2 +63,6 @@ - `cb`: function called when the repo is created | ||
#### `repo.getHead(cb(err, head))` | ||
Get the repo's HEAD, i.e. the "default branch" ref, e.g. `"refs/heads/master" | ||
[abstract-pull-git-repo]: https://github.com/clehner/abstract-pull-git-repo | ||
@@ -64,0 +69,0 @@ [ssb-client]: https://github.com/ssbc/ssb-client |
@@ -6,2 +6,3 @@ var test = require('tape') | ||
var pull = require('pull-stream') | ||
var GitRepo = require('pull-git-repo') | ||
@@ -66,1 +67,18 @@ var createSbot = require('scuttlebot') | ||
}) | ||
test('fork a repo', function (t) { | ||
ssbGit.createRepo(sbot, {live: true}, function (err, upstream) { | ||
t.error(err, 'created upstream') | ||
var update = pullGitRepoTests.getUpdate(0) | ||
upstream.update(update.refs, update.objects, function (err) { | ||
t.error(err, 'pushed update to upstream') | ||
ssbGit.createRepo(sbot, { | ||
upstream: GitRepo(upstream) | ||
}, function (err, fork) { | ||
t.error(err, 'created fork') | ||
pullGitRepoTests.testObjectsAdded(t, GitRepo(fork), update.hashes) | ||
t.end() | ||
}) | ||
}) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
30342
863
121
11
+ Addedssb-mentions@^0.0.0
+ Addedpull-git-repo@0.3.2(transitive)
+ Addedpull-kvdiff@0.0.0(transitive)
+ Addedssb-mentions@0.0.0(transitive)
- Removedpull-git-repo@0.2.5(transitive)
Updatedpull-git-repo@^0.3.0