@alauda/doom
Version:
Doctor Doom making docs.
126 lines (125 loc) • 4.45 kB
JavaScript
import { logger } from '@rspress/core';
import { render } from 'ejs';
import { ResponseError, xfetch } from 'x-fetch';
import { cyan, red } from 'yoctocolors';
import { isCI } from './utils.js';
const releaseCache = new Map();
const FIELD_MAPPER = {
zh: 'customfield_13800',
en: 'customfield_13801',
};
const issuesToListItems = (issues, lang, isMdx) => issues
.map((issue) => {
const description = ((FIELD_MAPPER[lang] && issue.fields[FIELD_MAPPER[lang]]) ||
issue.fields[FIELD_MAPPER.en])?.trim();
if (!description) {
return;
}
return {
type: 'listItem',
children: [
{
type: 'paragraph',
children: description
.split('\n')
.map((line) => ({ type: 'text', value: line }))
.reduce((acc, curr, index) => {
if (index === 0) {
acc.push(curr);
}
else {
acc.push(
// @ts-expect-error -- seems like a typing issue in mdast or TypeScript
isMdx
? { type: 'mdxJsxFlowElement', name: 'br' }
: { type: 'html', value: '<br>' }, curr);
}
return acc;
}, []),
},
],
};
})
.filter(Boolean);
const { JIRA_USERNAME, JIRA_PASSWORD } = process.env;
let warned = false;
const NO_ISSUE_MAPPER = {
zh: '此次发版无相关问题。',
en: 'No issues in this release.',
};
const resolveRelease_ = async (releaseTemplates, releaseQuery, isMdx) => {
const query = new URLSearchParams(releaseQuery);
const templateName = query.get('template');
if (!templateName) {
logger.error(`Release notes template not found for query \`${red(releaseQuery)}\``);
return;
}
const template = releaseTemplates[templateName];
if (!template) {
logger.error(`Release notes template \`${red(templateName)}\` not found`);
return;
}
let Authorization;
if (JIRA_USERNAME && JIRA_PASSWORD) {
Authorization = `Basic ${Buffer.from(`${JIRA_USERNAME}:${JIRA_PASSWORD}`).toString('base64')}`;
}
else {
if (warned) {
return;
}
warned = true;
const message = `\`${cyan('JIRA_USERNAME')}\` and \`${cyan('JIRA_PASSWORD')}\` environments must be set for fetching Jira issues`;
if (isCI) {
throw new Error(message);
}
logger.warn(message);
return;
}
const data = {};
for (const [key, value] of query.entries()) {
if (key === 'template') {
continue;
}
data[key] = value;
}
const jql = await render(template, data, { async: true });
logger.info(`Fetching release notes for query \`${cyan(releaseQuery)}\``);
let issues;
try {
;
({ issues } = await xfetch(`https://jira.alauda.cn/rest/api/2/search?${new URLSearchParams({ jql })}`, { headers: { Authorization } }));
}
catch (err) {
if (err instanceof ResponseError) {
const error = err;
logger.error(`Failed to fetch release notes for query \`${red(releaseQuery)}\` with status \`${error.response.status}\` and ${error.data ? `data ${JSON.stringify(error.data, null, 2)}` : `message \`${error.message}\``}`);
}
return;
}
return ['en', 'zh'].reduce((acc, lang) => Object.assign(acc, {
[lang]: issues.length
? {
type: 'list',
children: issuesToListItems(issues, lang, isMdx),
}
: {
type: 'paragraph',
children: [
{
type: 'text',
value: NO_ISSUE_MAPPER[lang] || NO_ISSUE_MAPPER.en,
},
],
},
}), {});
};
export const resolveRelease = async (releaseTemplates, releaseQuery, lang, isMdx) => {
if (releaseCache.has(releaseQuery)) {
const cached = await releaseCache.get(releaseQuery);
return cached?.[lang] ?? cached?.en;
}
const resolving = resolveRelease_(releaseTemplates, releaseQuery, isMdx);
releaseCache.set(releaseQuery, resolving);
const resolved = await resolving;
return resolved?.[lang] ?? resolved?.en;
};