Skip to content

Commit 759bfac

Browse files
committed
Get file committer info.
1 parent 706f586 commit 759bfac

File tree

3 files changed

+75
-47
lines changed

3 files changed

+75
-47
lines changed

src/controller/git/repos/index.js

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const FS = require('fs-extra')
44
const Models = require('../../../../conf/sequelize');
55
const { readFile } = require('../../../utils/fsExtra');
66

7-
const { getFiles, repoFilesSort, getEntrysInfo, getEntrysCommit } = require('./util');
7+
const { getFiles, repoFilesSort, getEntrysInfo, getFilesCommitInfo, getFileCommit } = require('./util');
88

99
module.exports = {
1010
created: async (ctx) => {
@@ -131,10 +131,11 @@ module.exports = {
131131
const entry = await tree.getEntry(filePath);
132132
porps.id = entry.oid();
133133
porps.ref = reqRef.name();
134-
135-
const blob = await entry.getBlob()
134+
const commit = await getFileCommit(currentRepoPath, filePath, ref);
135+
const blob = await entry.getBlob();
136136
ctx.body = {
137137
...porps,
138+
...commit,
138139
content: blob.toString(),
139140
parsePath: PATH.parse(filePath),
140141
path: filePath,
@@ -146,6 +147,7 @@ module.exports = {
146147
blob.free();
147148
tree.free();
148149
} catch (err) {
150+
console.log('err:', err);
149151
ctx.response.status = err.statusCode || err.status || 500;
150152
ctx.body = { message: err.message, ...err }
151153
}
@@ -257,18 +259,14 @@ module.exports = {
257259
commit = await commit.walk(recursive);
258260
const treeArray = await getFiles(commit, recursive);
259261
const oldTree = [...treeArray];
260-
// 读取默认目录中的 README.md 文件内容
261-
let readme = treeArray.filter(item => item.type === 'blob' && /readme.md$/.test(item.path.toLocaleLowerCase()));
262-
if (readme && readme.length > 0) {
263-
readme = readme[0];
264-
const blob = await readme.entry.getBlob();
265-
body.readmeContent = await blob.toString();
266-
}
262+
// 目录文件排序
267263
let treeCommit = repoFilesSort([...oldTree]);
268-
// 获取
264+
// 获取 个文件的信息
269265
treeCommit = await getEntrysInfo(treeCommit, gitRepo, currentRepoPath);
270266
// 获取每个文件的 Commit 信息,性能低下暂不做处理
271267
// treeCommit = await getEntrysCommit(treeCommit, gitRepo, body.sha);
268+
// 性能显著提高
269+
treeCommit = await getFilesCommitInfo(currentRepoPath, branch, treeCommit);
272270
body.tree = treeCommit;
273271
ctx.body = body;
274272
} catch (err) {

src/controller/git/repos/util.js

Lines changed: 65 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
const nodegit = require('nodegit');
2-
const path = require('path');
2+
const promisify = require('util').promisify;
3+
const exec = promisify(require('child_process').exec);
34

45
// https://www.nodegit.org/api/object/#TYPE
56
// Object.TYPE.ANY -2
@@ -15,7 +16,7 @@ const path = require('path');
1516

1617
/**
1718
* Nodegit entries 获取目录
18-
* @param {Object} treeWalker
19+
* @param {Object} treeWalker
1920
* @param {Boolean} [recursive=false] 以广度优先顺序递归地遍历树。
2021
*/
2122
exports.getFiles = (treeWalker, recursive = false) => {
@@ -67,7 +68,7 @@ exports.getFiles = (treeWalker, recursive = false) => {
6768
* 2. 文件夹,排在第二位
6869
* 3. 隐藏文件,排第三位
6970
* 4. 文件,排第四位
70-
* @param {Array} tree
71+
* @param {Array} tree
7172
*/
7273
exports.repoFilesSort = (tree = []) => {
7374
const hiddenFolder = tree.filter(_item => /^\./.test(_item.name) && /^(tree|commit)$/.test(_item.type));
@@ -100,8 +101,68 @@ exports.getEntrysInfo = (tree = [], repo) => {
100101
});
101102
}
102103

104+
/**
105+
* 获取所有文件,对应在Tree下面最新的提交信息
106+
*
107+
* @param {String} repoPath 仓库路径
108+
* @param {String} branch 仓当前 ref
109+
* @param {Array} data 目录数组
110+
*/
111+
exports.getFilesCommitInfo = async (repoPath, branch, data) => {
112+
return Promise.all(data.map(async (item) => {
113+
const props = { ...item };
114+
const commit = await this.getFileCommit(repoPath, item.path, branch);
115+
props.message = commit.message;
116+
props.treehash = commit.hash;
117+
props.committer = commit.committer;
118+
return props;
119+
})).catch((err) => {
120+
throw new Error(`Can't get commit, ${err}`);
121+
});;
122+
}
123+
124+
/**
125+
* 获取某个路径的提交信息
126+
* 输出内容:https://git-scm.com/docs/git-log#_pretty_formats
127+
* 输出commit的总数:git rev-list --all --count
128+
* 通过hash查看内容:git --no-pager show 5b9cf7 --summary --pretty="%H"
129+
*
130+
* @param {String} repoPath 仓地址
131+
* @param {String} relPath 文件在仓中的路径
132+
* @param {String} ref ref ?= master
133+
*/
134+
exports.getFileCommit = async (repoPath, relPath, ref = "master") => {
135+
try {
136+
const format = '\n=>[hash]:%H\n=>[parentHashes]:%P\n=>[shortHash]:%h\n=>[treeHash]:%T\n=>[author-name]:%an\n=>[author-email]:%ae\n=>[author-relativedate]:%ar\n=>[author-timestamp]:%at\n=>[committer-name]:%cn\n=>[committer-email]:%ce\n=>[committer-relativedate]:%cr\n=>[committer-timestamp]:%ct\n=>[message]:%s';
137+
const { stdout } = await exec(`git rev-list --pretty="${format}" --max-count=1 ${ref} -- ${relPath}`, {
138+
cwd: repoPath,
139+
});
140+
const data = {};
141+
stdout.split('\n=>').forEach((item) => {
142+
if (/^\[/.test(item)) {
143+
let key = item.match(/[^\[]([^\[]*)(?=\]\:)/ig);
144+
const value = item.replace(/^\[.*\]:/, '');
145+
if (key.length > 0 && value) {
146+
key = key[0];
147+
if (key && key.includes('-')) {
148+
key = key.split('-');
149+
if (!data[key[0]]) data[key[0]] = {};
150+
data[key[0]][key[1]] = value;
151+
} else {
152+
data[key] = value;
153+
}
154+
}
155+
}
156+
});
157+
return data;
158+
} catch (error) {
159+
throw new Error(`Can't get commit, ${error}`);
160+
}
161+
}
162+
103163
/**
104164
* 获取每个问文件的 hash 和 message
165+
* [弃用]: 在大仓库下性能低下
105166
* https://github.com/nodegit/nodegit/issues/1174
106167
* @param {Array} tree 每个文件的JSON对象
107168
* @param {Object} repo Nodegit 仓对象
@@ -157,39 +218,8 @@ exports.getEntrysCommit = (tree = [], repo, firstCommitOnMasterSha) => {
157218
props.sha = sha;
158219
}
159220

160-
// if (item.path && (item.type === 'commit' || item.type === 'blob')) {
161-
// // https://github.com/nodegit/nodegit/issues/220
162-
// // 获取单个文件的提交
163-
// const walker = await repo.createRevWalk();
164-
// walker.push(firstCommitOnMasterSha);
165-
// walker.sorting(nodegit.Revwalk.SORT.Time);
166-
// const history = await walker.fileHistoryWalk(item.path, 500);
167-
// history.forEach((entry, index) => {
168-
// const commit = entry.commit;
169-
// if (index === 0) {
170-
// props.author = {};
171-
// props.author.name = commit.author().name();
172-
// props.author.email = commit.author().email();
173-
// props.message = commit.message();
174-
// props.sha = commit.sha();
175-
// props.time = commit.time();
176-
// }
177-
// });
178-
// }
179-
180-
// if (item.path === 'conf' && item.type === 'tree') {
181-
// const treeEntrys = await repo.getTree(item.id);
182-
// const treeEntry = treeEntrys.entryByIndex(0);
183-
// const refreshIndex = await repo.refreshIndex();
184-
// const indexEntryFolder = refreshIndex.getByPath(treeEntry.path());
185-
// }
186-
187-
// const blob = await nodegit.Blob.lookup(repo, item.id);
188-
// // const rawsize = await blob.rawsize()
189-
// // const content = await blob.content()
190-
// // const owner = await blob.owner();
191221
return props;
192222
})).catch((err) => {
193223
console.log('err:getEntrysCommit:', err);
194224
});
195-
}
225+
}

src/routes/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ module.exports = (app) => {
2323
app.use(require('./git/raw').routes());
2424
app.use(require('./git/repos').routes());
2525
app.use(require('./git/namespaces').routes());
26-
}
26+
}

0 commit comments

Comments
 (0)