Advertisement
Guest User

Untitled

a guest
Feb 21st, 2018
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import fs = require('fs');
  2. import path = require('path');
  3. import child_process = require("child_process");
  4.  
  5. type Author = {
  6.     displayNames: string[];
  7.     preferedName?: string;
  8.     emails: string[];
  9. };
  10.  
  11. type AuthorMap = { [s: string]: Author };
  12.  
  13. type Command = {
  14.     (...arg: string[]): void;
  15.     description?: string;
  16. };
  17.  
  18. const mailMapPath = path.resolve("../.mailmap");
  19. const authorsPath = path.resolve("../AUTHORS.md");
  20.  
  21. function getKnownAuthors(): Author[] {
  22.     const segmentRegExp = /\s?([^<]+)\s+<([^>]+)>/g;
  23.     const preferedNameRegeExp = /\s?#\s?([^#]+)$/;
  24.     const knownAuthors: Author[] = [];
  25.  
  26.     if (!fs.existsSync(mailMapPath)) {
  27.         throw new Error(`Could not load known users form .mailmap file at: ${mailMapPath}`);
  28.     }
  29.  
  30.     const mailMap = fs.readFileSync(mailMapPath).toString();
  31.  
  32.     for (const line of mailMap.split("\r\n")) {
  33.         const author: Author = { displayNames: [], emails: [] };
  34.         let match: RegExpMatchArray | null;
  35.  
  36.         while (match = segmentRegExp.exec(line)) {
  37.             author.displayNames.push(match[1]);
  38.             author.emails.push(match[2]);
  39.         }
  40.         if (match = preferedNameRegeExp.exec(line)) {
  41.             author.preferedName = match[1];
  42.         }
  43.         if (!author.emails) continue;
  44.         knownAuthors.push(author);
  45.         if (line.indexOf("#") > 0 && !author.preferedName) {
  46.             throw new Error("Could not match prefered name for: " + line);
  47.         }
  48.         // console.log("===> line: " + line);
  49.         // console.log(JSON.stringify(author, undefined, 2));
  50.     }
  51.     return knownAuthors;
  52. }
  53.  
  54. function getAuthorName(author: Author) {
  55.     return author.preferedName || author.displayNames[0];
  56. }
  57.  
  58. function getKnownAuthorMaps() {
  59.     const knownAuthors = getKnownAuthors();
  60.     const authorsByName: AuthorMap = {};
  61.     const authorsByEmail: AuthorMap = {};
  62.     knownAuthors.forEach(author => {
  63.         author.displayNames.forEach(n => authorsByName[n] = author);
  64.         author.emails.forEach(e => authorsByEmail[e.toLocaleLowerCase()] = author);
  65.     });
  66.     return {
  67.         knownAuthors,
  68.         authorsByName,
  69.         authorsByEmail
  70.     };
  71. }
  72.  
  73. function deduplicate<T>(array: T[]): T[] {
  74.     let result: T[] = []
  75.     if (array) {
  76.         for (const item of array) {
  77.             if (result.indexOf(item) < 0) {
  78.                 result.push(item);
  79.             }
  80.         }
  81.     }
  82.     return result;
  83. }
  84.  
  85. function log(s: string) {
  86.     console.log(`   ${s}`);
  87. }
  88.  
  89. function sortAuthors(a: string, b: string) {
  90.     if (a.charAt(0) === "@") a = a.substr(1);
  91.     if (b.charAt(0) === "@") b = b.substr(1);
  92.     if (a.toLocaleLowerCase() < b.toLocaleLowerCase()) {
  93.         return -1;
  94.     }
  95.     else {
  96.         return 1;
  97.     }
  98. }
  99.  
  100. namespace Commands {
  101.     export const writeAuthors: Command = function () {
  102.         const output = deduplicate(getKnownAuthors().map(getAuthorName).filter(a => !!a)).sort(sortAuthors).join("\r\n* ");
  103.         fs.writeFileSync(authorsPath, "TypeScript is authored by:\r\n* " + output);
  104.     };
  105.     writeAuthors.description = "Write known authors to AUTHORS.md file.";
  106.  
  107.     export const listKnownAuthors: Command = function () {
  108.         deduplicate(getKnownAuthors().map(getAuthorName)).filter(a => !!a).sort(sortAuthors).forEach(log);
  109.     };
  110.     listKnownAuthors.description = "List known authors as listed in .mailmap file.";
  111.  
  112.     export const listAuthors: Command = function (...specs:string[]) {
  113.         const cmd = "git shortlog -se " + specs.join(" ");
  114.         console.log(cmd);
  115.         const outputRegExp = /\d+\s+([^<]+)<([^>]+)>/;
  116.         const tty = process.platform === 'win32' ? 'CON' : '/dev/tty';
  117.         const authors: { name: string, email: string, knownAuthor?: Author }[] = [];
  118.         child_process.exec(`${cmd} < ${tty}`, { cwd: path.resolve("../") }, function (error, stdout, stderr) {
  119.             if (error) {
  120.                 console.log(stderr.toString());
  121.             }
  122.             else {
  123.                 const output = stdout.toString();
  124.                 const lines = output.split("\n");
  125.                 lines.forEach(line => {
  126.                     if (line) {
  127.                         let match: RegExpExecArray | null;
  128.                         if (match = outputRegExp.exec(line)) {
  129.                             authors.push({ name: match[1], email: match[2] });
  130.                         }
  131.                         else {
  132.                             throw new Error("Could not parse output: " + line);
  133.                         }
  134.                     }
  135.                 });
  136.  
  137.                 const maps = getKnownAuthorMaps();
  138.  
  139.                 const lookupAuthor = function ({name, email}: { name: string, email: string }) {
  140.                     return maps.authorsByEmail[email.toLocaleLowerCase()] || maps.authorsByName[name];
  141.                 };
  142.  
  143.                 const knownAuthors = authors
  144.                     .map(lookupAuthor)
  145.                     .filter(a => !!a)
  146.                     .map(getAuthorName);
  147.                 const unknownAuthors = authors
  148.                     .filter(a => !lookupAuthor(a))
  149.                     .map(a => `${a.name} <${a.email}>`);
  150.  
  151.                 if (knownAuthors.length) {
  152.                     console.log("\r\n");
  153.                     console.log("Found known authors: ");
  154.                     console.log("=====================");
  155.                     deduplicate(knownAuthors).sort(sortAuthors).forEach(log);
  156.                 }
  157.  
  158.                 if (unknownAuthors.length) {
  159.                     console.log("\r\n");
  160.                     console.log("Found unknown authors: ");
  161.                     console.log("=====================");
  162.                     deduplicate(unknownAuthors).sort(sortAuthors).forEach(log);
  163.                 }
  164.             }
  165.         });
  166.     };
  167.     listAuthors.description = "List known and unknown authors for a given spec, e.g. 'node authors.js listAuthors origin/release-2.6..origin/release-2.7'";
  168. }
  169.  
  170. var args = process.argv.slice(2);
  171. if (args.length < 1) {
  172.     console.log('Usage: node authors.js [command]');
  173.     console.log('List of commands: ');
  174.     Object.keys(Commands).forEach(k => console.log(`     ${k}: ${(Commands as any)[k]['description']}`));
  175. } else {
  176.     var cmd: Function = (Commands as any)[args[0]];
  177.     if (cmd === undefined) {
  178.         console.log('Unknown command ' + args[1]);
  179.     } else {
  180.         cmd.apply(undefined, args.slice(1));
  181.     }
  182. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement