/* eslint-disable no-await-in-loop */ /* eslint-disable no-console */ const chalk = require('chalk'); const jsdom = require('jsdom'); const jQuery = require('jquery'); const fetch = require('node-fetch'); const simpleGit = require('simple-git/promise'); const { JSDOM } = jsdom; const { window } = new JSDOM(); const { document } = new JSDOM('').window; global.document = document; const $ = jQuery(window); const QUERY_TITLE = '.gh-header-title .js-issue-title'; const QUERY_DESCRIPTION_LINES = '.comment-body table tbody tr'; const QUERY_AUTHOR = '.timeline-comment-header-text .author:first'; const MAINTAINERS = ['zombiej', 'zombieJ', 'afc163', 'chenshuai2144']; const fromVersion = process.argv[process.argv.length - 2]; const toVersion = process.argv[process.argv.length - 1]; const cwd = process.cwd(); const git = simpleGit(cwd); function getDescription(row = '') { return row .trim() .replace('🇺🇸 English', '') .replace('🇨🇳 Chinese', '') .trim(); } async function printLog() { if (!/\d+\.\d+\.\d+/.test(fromVersion)) { console.log( chalk.red( '🤪 Not pass validate tags. Please execute like `print-changelog.js 3.26.0 master` instead.', ), ); } const logs = await git.log({ from: fromVersion, to: toVersion }); let prList = []; for (let i = 0; i < logs.all.length; i += 1) { const { message, body, hash } = logs.all[i]; const text = `${message} ${body}`; const match = text.match(/#\d+/g); const prs = (match || []).map(pr => pr.slice(1)); const validatePRs = []; console.log( `[${i + 1}/${logs.all.length}]`, hash.slice(0, 6), '-', prs.length ? prs.map(pr => `#${pr}`).join(',') : '?', ); for (let j = 0; j < prs.length; j += 1) { const pr = prs[j]; // Use jquery to get full html page since it don't need auth token const res = await fetch(`https://github.com/ant-design/ant-design/pull/${pr}`); if (res.url.includes('/issues/')) { continue; } const html = await res.text(); const $html = $(html); const prTitle = $html .find(QUERY_TITLE) .text() .trim(); const prAuthor = $html .find(QUERY_AUTHOR) .text() .trim(); const prLines = $html.find(QUERY_DESCRIPTION_LINES); const lines = []; prLines.each(function getDesc() { lines.push( $(this) .text() .trim(), ); }); const english = getDescription(lines.find(line => line.includes('🇺🇸 English'))); const chinese = getDescription(lines.find(line => line.includes('🇨🇳 Chinese'))); validatePRs.push({ pr, hash, title: prTitle, author: prAuthor, english: english || chinese || prTitle, chinese: chinese || english || prTitle, }); } if (validatePRs.length === 1) { console.log(chalk.cyan(' - Match PR:', `#${validatePRs[0].pr}`)); prList = prList.concat(validatePRs); } else if (message.includes('docs:')) { console.log(chalk.cyan(' - Skip document!')); } else { console.log(chalk.yellow(' - Miss match!')); prList.push({ hash, title: message, }); } } console.log('\n', chalk.green('Done. Here is the log:')); function printPR(lang, postLang) { prList.forEach(entity => { const { pr, author, hash, title } = entity; if (pr) { const str = postLang(entity[lang]); let icon = ''; if (str.toLowerCase().includes('fix') || str.includes('修复')) { icon = '🐞'; } let authorText = ''; if (!MAINTAINERS.includes(author)) { authorText = ` [@${author}](https://github.com/${author})`; } console.log( `- ${icon} ${str}[#${pr}](https://github.com/ant-design/ant-design/pull/${pr})${authorText}`, ); } else { console.log( `🆘 Miss Match: ${title} -> https://github.com/ant-design/ant-design/commit/${hash}`, ); } }); } // Chinese console.log(chalk.yellow('Chinese changelog:')); printPR('chinese', chinese => (chinese[chinese.length - 1] === '。' ? chinese : `${chinese}。`)); console.log('\n-----\n'); // English console.log(chalk.yellow('English changelog:')); printPR('english', english => { english = english.trim(); if (english[english.length - 1] !== '.') { english = `${english}.`; } return `${english} `; }); } printLog(); /* eslint-enable */