UNPKG

4.15 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 if (argv._.length > 0) return require('./help')(argv)
35
36 var head = splitEnd(argv.head || argv.h)
37 var headRepoId = u.getRemote(head[0])
38 var headBranch = head[1] || u.getCurrentBranch()
39 if (!headRepoId || !headBranch) throw 'unable to find head'
40
41 var text = argv.message || argv.m
42 var filename = argv.file || argv.F
43 if (text && filename)
44 throw 'only one of message and file option may be specified'
45 if (filename && !fs.existsSync(filename))
46 throw 'file ' + JSON.stringify(filename) + ' does not exist'
47
48 var base = splitEnd(argv.base || argv.b)
49 var baseRepoId = base[0]
50 var baseBranch = base[1]
51 if (baseRepoId) {
52 baseRepoId = u.getRemote(baseRepoId)
53 if (!baseRepoId) throw 'invalid base repo ' + JSON.stringify(base[0])
54 }
55
56 var ssbGit = require('ssb-git-repo')
57 var sbot
58 var done = multicb({pluck: 1, spread: true})
59 var gotFeed = done()
60 var gotHeadRepo = done()
61 var gotBaseRepo = done()
62 u.getSbot(argv, function (err, _sbot) {
63 if (err) throw err
64 sbot = _sbot
65 sbot.whoami(gotFeed)
66 ssbGit.getRepo(sbot, headRepoId, gotHeadRepo)
67 if (baseRepoId) ssbGit.getRepo(sbot, baseRepoId, gotBaseRepo)
68 else gotBaseRepo()
69 })
70
71 done(function (err, feed, headRepo, baseRepo) {
72 if (err) throw err
73 sbot.id = feed.id
74
75 // default base repo to upstream of head repo, or head repo
76 // default base branch to base repo's default branch
77 if (!baseRepo) {
78 if (headRepo.upstream) {
79 baseRepo = headRepo.upstream
80 } else {
81 baseRepo = headRepo
82 }
83 baseRepoId = baseRepo.id
84 }
85
86 if (baseBranch) next()
87 else baseRepo.getHead(function (err, ref) {
88 if (err) throw err
89 baseBranch = ref && ref.replace(/refs\/heads\//, '') || 'master'
90 next()
91 })
92
93 function next() {
94 if (text) gotText(text, doneEditing)
95 else if (filename) fs.readFile(filename, 'utf8', gotText)
96 else {
97 var done = multicb({pluck: 1, spread: true})
98 u.getName(sbot, [sbot.id, null], baseRepoId, done())
99 u.getName(sbot, [sbot.id, null], headRepoId, done())
100 getRev(baseRepo, baseBranch, done())
101 getRev(headRepo, headBranch, done())
102 done(editText)
103 }
104 }
105 })
106
107 function editText(err, baseRepoName, headRepoName, baseRev, headRev) {
108 if (err) throw err
109 var defaultText = 'Requesting a pull ' +
110 'to ' + mdLink(baseRepoName, baseRepoId) + ':' + baseBranch + '\n' +
111 'from ' + mdLink(headRepoName, headRepoId) + ':' + headBranch + '\n\n' +
112 'Write message text for this pull request.' +
113 (baseRev && headRev
114 ? '\n\nChanges:\n\n' + formatGitLog(baseRev, headRev)
115 : '')
116 u.editor('PULLREQ', defaultText, gotText, doneEditing)
117 }
118
119 function gotText(text, cb) {
120 if (!text) return cb('empty message: aborting')
121 var prSchemas = require('ssb-pull-requests/lib/schemas')
122 var value = prSchemas.new(baseRepoId, baseBranch,
123 headRepoId, headBranch, text)
124 var mentions = Mentions(text)
125 if (mentions.length) value.mentions = mentions
126 sbot.publish(value, function (err, msg) {
127 if (err) return cb(err)
128 console.log(JSON.stringify(msg, 0, 2))
129 cb(null)
130 })
131 }
132
133 function doneEditing(err) {
134 if (err) console.error(err)
135 sbot.close()
136 }
137}