git-contributor
Version:
git contributor
192 lines (173 loc) • 5.25 kB
JavaScript
;
const _ = require('xutil');
const {
execSync
} = require('child_process');
const {
parse
} = require('url');
const path = require('path');
const httpclient = require('urllib');
const pkg = require('../package');
const gitLog2MailList = () => {
const logs = execSync('git log --pretty="%an <%ae>"').toString();
const list = logs.split(/\n/g).reverse();
return _.uniq(list)
.filter(item => item.length)
.map(item => {
return item.split(/\s+/g).pop();
});
};
const getInfoFromGithub = maillist => {
const api = 'https://api.github.com/search/users?q=';
const tasks = maillist.map(email => {
const uri = `${api}${encodeURIComponent(email + ' in:email type:user')}`;
const options = {
dataType: 'json',
headers: {
'user-agent': Date.now()
},
timeout: 30E3
};
if (process.env.OAUTH_TOKEN) {
options.headers['Authorization'] = `token ${process.env.OAUTH_TOKEN}`;
}
return httpclient.request(uri, options).then(res => res.data);
});
return Promise.all(tasks).then(list => {
return list.map(item => {
if (item && item.total_count === 1) {
return item.items[0];
}
});
});
};
const getInfoFromGithubNewAPI = info => {
// https://docs.github.com/en/rest/reference/repos#list-repository-contributors get top 100 contributors
const uri = `https://api.github.com/repos/${info.groupName}/${info.repoName}/contributors?per_page=100`;
const options = {
dataType: 'json',
headers: {
'user-agent': Date.now()
},
timeout: 30000
};
if (process.env.OAUTH_TOKEN) {
options.headers['Authorization'] = `token ${process.env.OAUTH_TOKEN}`;
}
return httpclient.request(uri, options).then(res => res.data);
};
const format = list => {
return list.filter(item => item).map(item => {
return {
login: item.login,
avatar_url: item.avatar_url,
html_url: item.html_url
};
});
};
const getRepoInfo = async (url) => {
// git@github.com:xudafeng/git-contributor.git
// https://github.com/xudafeng/git-contributor
if (url.slice(0, 4) === 'git@') {
url = url
.replace(':', '/')
.replace('git@', 'http://');
}
url = url
.replace(/\.git$/g, '');
const obj = parse(url);
const arr = obj.pathname.split('/');
return {
groupName: arr[1],
repoName: arr[2]
};
};
exports.getAuthor = async (options = {}) => {
const cwd = path.resolve(options.cwd || process.cwd());
const pointGithubRepoUrl = options.url;
const originPkg = path.join(cwd, 'package.json');
const dotGitDir = path.join(cwd, '.git');
if (_.isExistedFile(originPkg)) {
try {
const pkg = require(originPkg);
if (pkg.repository && pkg.repository.url) {
const info = await getRepoInfo(pkg.repository.url);
const infoList = await getInfoFromGithubNewAPI(info);
return format(infoList);
}
} catch (e) {
}
} else if (pointGithubRepoUrl) {
const info = await getRepoInfo(pointGithubRepoUrl);
const infoList = await getInfoFromGithubNewAPI(info);
return format(infoList);
}
if (!_.isExistedDir(dotGitDir)) {
return [];
}
const mailList = gitLog2MailList();
const infoList = await getInfoFromGithub(_.uniq(mailList));
return format(infoList);
};
const ifHasZh = (readMeContext) => {
let count = 0;
readMeContext.split('').forEach(char => {
if (/[\u4e00-\u9fa5]/.test(char)) count++;
});
return count / readMeContext.length >= 0.1;
};
exports.genMarkDown = (list, readMeContext = '') => {
const startToken = '<!-- GITCONTRIBUTOR_START -->';
const endToken = '<!-- GITCONTRIBUTOR_END -->';
const contentFirstLine = [''];
const lineMax = 6;
const contentFirstLineData = list.splice(0, lineMax);
contentFirstLineData.map((item, key) => {
contentFirstLine.push(`[<img src="${item.avatar_url}" width="100px;"/><br/><sub><b>${item.login}</b></sub>](${item.html_url})<br/>`);
});
contentFirstLine.push('');
const contentRemaining = [];
list.map((item, key) => {
contentRemaining.push(`[<img src="${item.avatar_url}" width="100px;"/><br/><sub><b>${item.login}</b></sub>](${item.html_url})<br/>`);
});
const genLine = (number) => {
const r = [];
while (number--) {
r.push(' :---: ');
}
return r;
};
const genLinesOfN = (content, n) => {
const result = [];
while (content.length > n) {
let line = ['', ...content.splice(0, n), ''].join('|');
result.push(line);
}
result.push(content.join('|'));
return result;
};
const isZH = ifHasZh(readMeContext);
const contributorTitle = isZH ? '贡献者' : 'Contributors';
const footer = isZH ?
`[git-contributor 说明](${pkg.homepage}),自动生成时间:\`${_.moment()}\`。` :
`This project follows the git-contributor [spec](${pkg.homepage}), auto updated at \`${_.moment()}\`.`;
const res = [
startToken,
'',
`## ${contributorTitle}`,
'',
contentFirstLine.join('|'),
`|${genLine(contentFirstLineData.length).join('|')}|`,
...genLinesOfN(contentRemaining, lineMax),
'',
footer,
'',
endToken
];
return {
content: res.join('\n'),
startToken,
endToken
};
};