UNPKG

4.12 kBJavaScriptView Raw
1var fs = require('fs')
2var u = require('./util')
3var multicb = require('multicb')
4var Mentions = require('ssb-mentions')
5
6function splitEnd(str) {
7 return str ? /(?:(.*?):)?(.*)/.exec(str).slice(1) : []
8}
9
10function mdLink(text, href) {
11 return !text || text == href ? href : '[' + text + '](' + href + ')'
12}
13
14function getRev(repo, branch, cb) {
15 var Repo = require('pull-git-repo')
16 Repo(repo).resolveRef(branch, function (err, rev) {
17 if (err && err.name === 'NotFoundError') err = null
18 cb(null, rev)
19 })
20}
21
22function formatGitLog(a, b) {
23 var range = a + '..' + b
24 try {
25 // https://github.com/github/hub/blob/master/git/git.go
26 return u.gitSync('log', '--no-color', '--cherry',
27 '--format=%h (%aN, %ar)%n%w(78,3,3)%s%n%+b', range)
28 } catch(e) {
29 return '`git log ' + range + '`'
30 }
31}
32
33module.exports = function pullRequest(argv) {
34 var head = splitEnd(argv.head || argv.h)
35 var headRepoId = u.getRemote(head[0] || u.getDefaultRemote())
36 var headBranch = head[1] || u.getCurrentBranch()
37 if (!headRepoId || !headBranch) throw 'unable to find head'
38
39 var text = argv.message || argv.m
40 var filename = argv.file || argv.F
41 if (text && filename)
42 throw 'only one of message and file option may be specified'
43 if (filename && !fs.existsSync(filename))
44 throw 'file ' + JSON.stringify(filename) + ' does not exist'
45
46 var base = splitEnd(argv.base || argv.b)
47 var baseRepoId = base[0]
48 var baseBranch = base[1]
49 if (baseRepoId) {
50 baseRepoId = u.getRemote(baseRepoId)
51 if (!baseRepoId) throw 'invalid base repo ' + JSON.stringify(base[0])
52 }
53
54 var ssbGit = require('ssb-git-repo')
55 var sbot
56 var done = multicb({pluck: 1, spread: true})
57 var gotFeed = done()
58 var gotHeadRepo = done()
59 var gotBaseRepo = done()
60 u.getSbot(argv, function (err, _sbot) {
61 if (err) throw err
62 sbot = _sbot
63 sbot.whoami(gotFeed)
64 ssbGit.getRepo(sbot, headRepoId, gotHeadRepo)
65 if (baseRepoId) ssbGit.getRepo(sbot, baseRepoId, gotBaseRepo)
66 else gotBaseRepo()
67 })
68
69 done(function (err, feed, headRepo, baseRepo) {
70 if (err) throw err
71 sbot.id = feed.id
72
73 // default base repo to upstream of head repo, or head repo
74 // default base branch to base repo's default branch
75 if (!baseRepo) {
76 if (headRepo.upstream) {
77 baseRepo = headRepo.upstream
78 } else {
79 baseRepo = headRepo
80 }
81 baseRepoId = baseRepo.id
82 }
83
84 if (baseBranch) next()
85 else baseRepo.getHead(function (err, ref) {
86 if (err) throw err
87 baseBranch = ref && ref.replace(/refs\/heads\//, '') || 'master'
88 next()
89 })
90
91 function next() {
92 if (text) gotText(text, doneEditing)
93 else if (filename) fs.readFile(filename, 'utf8', gotText)
94 else {
95 var done = multicb({pluck: 1, spread: true})
96 u.getName(sbot, [sbot.id, null], baseRepoId, done())
97 u.getName(sbot, [sbot.id, null], headRepoId, done())
98 getRev(baseRepo, baseBranch, done())
99 getRev(headRepo, headBranch, done())
100 done(editText)
101 }
102 }
103 })
104
105 function editText(err, baseRepoName, headRepoName, baseRev, headRev) {
106 if (err) throw err
107 var defaultText = 'Requesting a pull ' +
108 'to ' + mdLink(baseRepoName, baseRepoId) + ':' + baseBranch + '\n' +
109 'from ' + mdLink(headRepoName, headRepoId) + ':' + headBranch + '\n\n' +
110 'Write message text for this pull request.' +
111 (baseRev && headRev
112 ? '\n\nChanges:\n\n' + formatGitLog(baseRev, headRev)
113 : '')
114 u.editor('PULLREQ', defaultText, gotText, doneEditing)
115 }
116
117 function gotText(text, cb) {
118 if (!text) return cb('empty message: aborting')
119 var prSchemas = require('ssb-pull-requests/lib/schemas')
120 var value = prSchemas.new(baseRepoId, baseBranch,
121 headRepoId, headBranch, text)
122 var mentions = Mentions(text)
123 if (mentions.length) value.mentions = mentions
124 sbot.publish(value, function (err, msg) {
125 if (err) return cb(err)
126 console.log(JSON.stringify(msg, 0, 2))
127 cb(null)
128 })
129 }
130
131 function doneEditing(err) {
132 if (err) console.error(err)
133 sbot.close()
134 }
135}