| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- const Student = require("../models/student");
- const Database = require('../config/database');
- const Mysql = require('../config/mysql');
- const CsvReader = require("../config/csvReader");
- const StudentService = require("../services/studentService");
- const GitlabApi = require("../apis/gitlabClient");
- const JsonHandler = require("../config/jsonHandler");
- const StudentConstructor = require("../models/constructors/StudentConstructor");
- const GroupConstructor = require("../models/constructors/GroupConstructor");
- const GroupService = require("../services/groupService");
- class Analysis {
- async run() {
- try {
- /* // mysql 连接
- const mysql = await Mysql.connect();
- let [rows, fields] = await mysql.execute("select * from user limit 10");
- console.log(rows);
- mysql.end();
- */
- /* // mongo 连接
- await Database.asyncConnect();
- let data = await StudentService.getAll();
- console.log(data);
- Database.close();
- */
- await Database.asyncConnect();
- let filter = {
- group: 5
- };
- let data = await GroupService.findOne(filter);
- console.log(data);
- Database.close();
-
- } catch (errors) {
- console.error(errors);
- }
- }
- async getUserInfo() { // 集成所有用户信息
- let portal_user = await CsvReader.readFile(__dirname + '/portal_user.csv', data => {
- let { id, email, username, name, phone } = data;
- let emailReg = /^[0-9]+@s.ail\.nju\.edu\.cn$/;
- if (emailReg.test(email)) {
- username = email.split("@")[0];
- }
- return {
- userId: id, email, studentId: username, name, phone
- }
- });
- let devcloud_user = await CsvReader.readFile(__dirname + '/软工II小组名单.csv', data => {
- let { 组号, 姓名, 学号 } = data;
- return {
- groupId: 组号,
- name: 姓名,
- studentId: 学号
- }
- });
- portal_user.sort((a, b) => {
- if (a.studentId < b.studentId) return -1;
- else if (a.studentId == b.studentId) return 0;
- else return 1;
- });
- if (devcloud_user instanceof Array)
- devcloud_user.forEach((val, idx, arr) => {
- let info = this.findInfo(val, portal_user);
- if (info) {
- arr[idx].userId = info.userId;
- arr[idx].email = info.email;
- arr[idx].phone = info.phone;
- } else {
- console.log('cannot find', val);
- }
- });
- // await JsonHandler.writeSync(devcloud_user, __dirname + '/user_info.json');
- }
- async transformUserInfo() { // 改为小组形式展示用户
- let user_info = await JsonHandler.readSync(__dirname+'/user_info.json');
- let group_user_map = {};
- for(let user of user_info) {
- if(!group_user_map[user.groupId]) group_user_map[user.groupId] = [];
- group_user_map[user.groupId].push(user);
- }
- await JsonHandler.writeSync(group_user_map, __dirname+'/group_user_map.json');
- }
- async getProjectsByGroup() { // 按小组拿到项目
- let devcloud_user = await JsonHandler.readSync(__dirname + '/user_info.json');
- let group_project_info_map = {};
- for(let i=0;i<devcloud_user.length;i++) {
- // for (let i = 0; i < 5; i++) {
- if (!group_project_info_map[devcloud_user[i].groupId]) {
- group_project_info_map[devcloud_user[i].groupId] = [];
- }
- let proj_list = group_project_info_map[devcloud_user[i].groupId];
- let user_projects = await GitlabApi.getAllProjetsByUserId(devcloud_user[i].userId);
- if (proj_list.length === 0) proj_list = user_projects.res;
- else proj_list = this.getIntersection(proj_list, user_projects.res, "projectId");
- group_project_info_map[devcloud_user[i].groupId]=proj_list;
- console.log(i, " -- finish")
- }
- // console.log(group_project_info_map);
- // await JsonHandler.writeSync(group_project_info_map, __dirname + '/group_project_info_map.json');
- }
- async getCommitsByGroup() { // 按照小组拿到commit 记录
- let group_project_info_map = await JsonHandler.readSync(__dirname + '/group_project_info_map.json');
- let group_commits_map = {};
- for(let k of Object.keys(group_project_info_map)) {
- console.log("group -- ",k);
- if(!group_commits_map[k]) group_commits_map[k] = [];
- for(let project of group_project_info_map[k]) {
- console.log("project -- ",project.projectId);
- let commits = await GitlabApi.getCommitsByGitlabProjectId(project.projectId);
- group_commits_map[k].push(...commits.map((commit) => {
- let {id, message, committer_name, committer_email} = commit;
- return {id, message, committer_name, committer_email, projectId: project.projectId};
- }));
- }
- }
- // JsonHandler.writeSync(group_commits_map, __dirname + '/group_commits_map.json');
- // console.log(group_commits_map)
- }
- async getCommitsStatistics() { // 按小组生成最终的commit报告
- let group_commits_map = await JsonHandler.readSync(__dirname+'/group_commits_map.json');
- let group_user_map = await JsonHandler.readSync(__dirname+'/group_user_map.json')
- let group_user_commits_map = {};
- for(let k of Object.keys(group_commits_map)) {
- if(!group_user_commits_map[k]) group_user_commits_map[k] = {};
- let tmpMap = {};
- for(let commit of group_commits_map[k]) {
- if(!tmpMap[commit.committer_name]) tmpMap[commit.committer_name] = {
- count: 0,
- committer_email: commit.committer_email,
- commit_messages: []
- };
- tmpMap[commit.committer_name].count += 1;
- tmpMap[commit.committer_name].commit_messages.push(commit.message);
- }
- for(let committer_name of Object.keys(tmpMap)) {
- let user = this.findUserByCommitterName(committer_name, group_user_map[k]);
- if(user == null) user = this.findUserByCommitterEmail(tmpMap[committer_name].committer_email, group_user_map[k]);
- let user_identity = committer_name;
- if(user) {
- user_identity = user.studentId
- }
- // 根据 committer_name 从数据库拿到 "valid-commit-times","buglist-commit","feature-commit"
- const mysql = await Mysql.connect();
- let bug = await mysql.execute("select count(*) as count from `commit` where `gitlab_username` = ? and `related_type` = 'BUG_ID'", [committer_name]);
- let tree = await mysql.execute("select count(*) as count from `commit` where `gitlab_username` = ? and `related_type` = 'TREE_ID'", [committer_name]);
- mysql.end();
- group_user_commits_map[k][user_identity] = {
- 'commit-times': tmpMap[committer_name].count,
- 'commit-msg-overview': tmpMap[committer_name].commit_messages,
- 'buglist-commit': bug[0][0]['count'],
- 'feature-commit': tree[0][0]['count'],
- 'valid-commit-times': bug[0][0]['count'] + tree[0][0]['count']
- }
- }
- console.log(group_user_commits_map)
- await JsonHandler.writeSync(group_user_commits_map, __dirname+'/group_user_commits_map.json');
- }
- }
- async getPipelineStatistics() { // 按小组生成Pipeline报告
- // 警告: 理论上应该从项目出发统计Pipeline触发数,但是数据库中存在很多项目Pipeline被删除的情况,
- // 因此我直接统计一段时间内所有用户的Pipeline触发次数, 非本次项目的也可能会统计在内
- // (宁愿多取一点数据)
- // "pipeline": {
- // "pipeline-deploy":0,
- // "pipeline-pass":0,
- // "pipeline-failure":0
- // },
- let group_user_map = await JsonHandler.readSync(__dirname+'/group_user_map.json');
- let group_user_pipeline_map = {};
- let startTime = '2022-02-13 20:13:10';
- const mysql = await Mysql.connect();
- for(let k of Object.keys(group_user_map)) {
- if(!group_user_pipeline_map[k]) group_user_pipeline_map[k] = {};
- let user_list = group_user_map[k];
- for(let user of user_list) {
- group_user_pipeline_map[k][user.studentId] = {
- "pipeline-deploy":0,
- "pipeline-pass":0,
- "pipeline-failure":0
- };
- let [row] = await mysql.execute("select result,count(*) as count from pipeline_record where start_time > ? and user_id = ? group by result;", [startTime, user.userId]);
- for(let res of row) {
- if(res.result === '部署失败') {
- group_user_pipeline_map[k][user.studentId]["pipeline-failure"] += res.count;
- } else if(res.result === '部署成功') {
- group_user_pipeline_map[k][user.studentId]["pipeline-pass"] += res.count;
- }
- }
- group_user_pipeline_map[k][user.studentId]["pipeline-deploy"] =
- group_user_pipeline_map[k][user.studentId]["pipeline-pass"] +
- group_user_pipeline_map[k][user.studentId]["pipeline-failure"];
- }
- }
- mysql.end();
- // await JsonHandler.writeSync(group_user_pipeline_map, __dirname+'/group_user_pipeline_map.json');
- }
- async getInterfaceTestStatistics() { // 按小组生成接口测试报告
- // 由于依赖Pipeline, 所以也有上述问题
- let group_user_map = await JsonHandler.readSync(__dirname+'/group_user_map.json');
- let group_user_interface_test_map = {};
- let startTime = '2022-02-13 20:13:10';
- const mysql = await Mysql.connect();
- for(let k of Object.keys(group_user_map)) {
- if(!group_user_interface_test_map[k]) group_user_interface_test_map[k] = {};
- let user_list = group_user_map[k];
- for(let user of user_list) {
- let [row] = await mysql.execute("select count(*) as times, COALESCE(sum(success),0) as success, COALESCE(sum(failure),0) as failure from test_result where test_result.pipeline_record_id in (select id as pipe_record_id from pipeline_record where start_time > ? and user_id = ? ) ;", [startTime, user.userId]);
- // console.log(row[0]); // { times: 0, success: null, failure: null }
- row[0]['times'] = parseInt(row[0]['times']);
- row[0]['failure'] = parseInt(row[0]['failure']);
- row[0]['success'] = parseInt(row[0]['success']);
- group_user_interface_test_map[k][user.studentId] = {
- "interface-test-times": row[0]['times'],
- "interface-test-concurrency-count": row[0]['failure'] + row[0]['success'],
- "interface-test-concurrency-failure": row[0]['failure'],
- "interface-test-concurrency-pass": row[0]['success']
- };
- }
- }
- mysql.end();
- await JsonHandler.writeSync(group_user_interface_test_map, __dirname+'/group_user_interface_test_map.json');
- }
- async fromJsonToDatabase() { // 将上面生成的一系列json文件组合导入数据库
- // TODO
- const group_user_map = await JsonHandler.readSync(__dirname+'/group_user_map.json');
- const group_project_info_map = await JsonHandler.readSync(__dirname+'/group_project_info_map.json');
- const group_user_commits_map = await JsonHandler.readSync(__dirname+'/group_user_commits_map.json');
- const group_user_pipeline_map = await JsonHandler.readSync(__dirname+'/group_user_pipeline_map.json');
- const group_user_interface_test_map = await JsonHandler.readSync(__dirname+'/group_user_interface_test_map.json');
- // mongo 连接
- await Database.asyncConnect();
- const generateGroupMembers = function(g) {
- return group_user_map[g].map(item => {
- return {
- "userId": item.userId,
- "studentId":item.studentId,
- "name":item.name
- };
- });
- }
- const generateGroupCommit = function(g) {
- let raw = Object.entries(group_user_commits_map[g])
- .map(v => {
- v[1].identity = v[0];
- return v[1];
- });
- let res = raw.reduce((prev, cur) => {
- prev["commit-times"] += cur["commit-times"];
- prev["valid-commit-times"] += cur["valid-commit-times"];
- prev["buglist-commit"] += cur["buglist-commit"];
- prev["feature-commit"] += cur["feature-commit"];
- prev["commit-msg-overview"].push(...cur[["commit-msg-overview"]]);
- return prev;
- },{
- "commit-times": 0,
- "valid-commit-times": 0,
- "buglist-commit": 0,
- "feature-commit": 0,
- "commit-msg-overview": []
- });
- res["commit-contribution"] = raw.map(item => {
- return {
- "name": item.identity,
- "times": item["commit-times"],
- "proportion": res["commit-times"] === 0 ? 0 : (item["commit-times"] / res["commit-times"] * 100).toFixed(2)
- }
- });
- return res;
- }
- const generateGroupInterfaceTest = function(g) {
- let raw = Object.entries(group_user_interface_test_map[g])
- .map(v => {
- v[1].identity = v[0];
- return v[1];
- });
- let res = raw.reduce((prev, cur) => {
- prev["interface-test-times"] += cur["interface-test-times"];
- prev["interface-test-concurrency-count"] += cur["interface-test-concurrency-count"];
- prev["interface-test-concurrency-failure"] += cur["interface-test-concurrency-failure"];
- prev["interface-test-concurrency-pass"] += cur["interface-test-concurrency-pass"];
- return prev;
- },{
- "interface-test-times": 0,
- "interface-test-concurrency-count": 0,
- "interface-test-concurrency-failure": 0,
- "interface-test-concurrency-pass": 0
- });
- res["interface-test-contribution"] = raw.map(item => {
- return {
- "name": item.identity,
- "times": item["interface-test-times"],
- "proportion": res["interface-test-times"] === 0 ? 0 : (item["interface-test-times"] / res["interface-test-times"] * 100).toFixed(2)
- }
- });
- return res;
- }
- const generateGroupPipeline = function(g) {
- let raw = Object.entries(group_user_pipeline_map[g])
- .map(v => {
- v[1].identity = v[0];
- return v[1];
- });
- let res = raw.reduce((prev, cur) => {
- prev["pipeline-deploy"] += cur["pipeline-deploy"];
- prev["pipeline-pass"] += cur["pipeline-pass"];
- prev["pipeline-failure"] += cur["pipeline-failure"];
- return prev;
- },{
- "pipeline-deploy": 0,
- "pipeline-pass": 0,
- "pipeline-failure": 0,
- });
- res["pipeline-contribution"] = raw.map(item => {
- return {
- "name": item.identity,
- "times": item["pipeline-deploy"],
- "proportion": res["pipeline-deploy"] === 0 ? 0 : (item["pipeline-deploy"] / res["pipeline-deploy"] * 100).toFixed(2)
- }
- });
- return res;
- }
- for(let group of Object.keys(group_user_map)) {
- // 生成小组报告, 入库
- let projects = group_project_info_map[group];
- let members = generateGroupMembers(group);
- let group_commit = generateGroupCommit(group);
- let group_interface_test = generateGroupInterfaceTest(group);
- let group_pipeline = generateGroupPipeline(group);
- let groupInfo = new GroupConstructor(
- group,
- projects,
- members,
- group_commit,
- group_interface_test,
- group_pipeline
- );
- // console.log(groupInfo);
- GroupService.create(groupInfo);
- // for(let user of group_user_map[group]) { // 生成个人报告, 入库
- // let commit = group_user_commits_map[group][user.studentId];
- // if(commit == null) commit = {
- // "commit-times": 0,
- // "valid-commit-times": 0,
- // "buglist-commit": 0,
- // "feature-commit": 0,
- // "commit-msg-overview": []
- // };
- // let interface_test = group_user_interface_test_map[group][user.studentId];
- // let pipeline = group_user_pipeline_map_map[group][user.studentId];
- // let studentInfo = new StudentConstructor(
- // user.name,
- // user.userId,
- // user.studentId,
- // group,
- // user.email,
- // commit,
- // projects,
- // interface_test,
- // pipeline
- // );
- // // console.log(studentInfo)
- // StudentService.create(studentInfo);
- // }
- }
- }
- findUserByCommitterEmail(committer_email, user_list) { // 通过committer email找用户
- for(let user of user_list) {
- if(committer_email === user.email) return user;
- }
- return null;
- }
- findUserByCommitterName(committer_name, user_list) { // 通过committer name找用户
- for(let user of user_list) {
- if(committer_name === user.name || committer_name === user.studentId || committer_name === user.phone) return user;
- }
- return null;
- }
- findInfo(devUser, portalUsers) { // 在portalUser中找到devUser所对应的信息, 二分查找
- let l = 0, r = portalUsers.length - 1;
- while (l <= r) {
- let m = Math.floor((r - l) / 2) + l;
- if (portalUsers[m].studentId === devUser.studentId) {
- return portalUsers[m];
- } else if (portalUsers[m].studentId < devUser.studentId) {
- l = m + 1;
- } else {
- r = m - 1;
- }
- }
- return null;
- }
- getIntersection(arr_a, arr_b, key) { // 求两个数组的交集
- let res = [];
- arr_a.forEach(a => {
- arr_b.forEach(b => {
- if (a[key] === b[key]) {
- res.push(a);
- }
- })
- })
- return res;
- }
- }
- (new Analysis()).run().then(_ => {
- // process.exit(0);
- }).catch(err => {
- console.error(err);
- })
|