Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@ones-design/coverage-report

Package Overview
Dependencies
Maintainers
0
Versions
25
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@ones-design/coverage-report - npm Package Compare versions

Comparing version 0.4.1-beta.0 to 0.5.0-beta.0

854

dist/index.js

@@ -1,9 +0,7 @@

'use strict';
const vendor = require('./vendor.js');
const fs = require('fs/promises');
const require$$0 = require('fs');
const require$$1 = require('path');
const require$$1$1 = require('https');
"use strict";
const vendor = require("./vendor.js");
const fs = require("fs/promises");
const require$$0 = require("fs");
const require$$1 = require("path");
const require$$1$1 = require("https");
const PRNotificationMustache = `

@@ -24,149 +22,144 @@ # ⚠️ 覆盖率下降警告

`;
/**
* key: 应该被替换的组件名
* value: 替换后的组件名
*/
const componentMap = {
Icon: 'Icon',
Action: 'Action',
Alert: 'Alert',
Hint: 'Alert',
Anchor: 'Anchor',
Avatar: 'Avatar',
BaseAvatar: 'Avatar',
MemberAvatar: 'Avatar',
getAvatarUrl: 'Avatar',
Badge: 'Badge',
Breadcrumb: 'Breadcrumb',
Button: 'Button',
Card: 'Card',
CardHeader: 'Card',
CardWrapper: 'Card',
LeftRightCardWrapper: 'Card',
Cascader: 'Cascader',
Checkbox: 'Checkbox',
BaseCheckbox: 'Checkbox',
NewCheckbox: 'Checkbox',
SquareCheckbox: 'Checkbox',
Col: 'Col',
Collapse: 'Collapse',
ConfigProvider: 'ConfigProvider',
Antd2LocaleProvider: 'ConfigProvider',
LocaleProvider: 'ConfigProvider',
DatePicker: 'DatePicker',
Calendar: 'DatePicker',
PopoverCalendar: 'DatePicker',
RangeCalendar: 'DatePicker',
RangePicker: 'DatePicker',
RcDatePicker: 'DatePicker',
wrapPicker: 'DatePicker',
DateRangeInput: 'DatePicker',
DateRangeInfoFragment: 'DatePicker',
Divider: 'Divider',
Drawer: 'Drawer',
Dropdown: 'Dropdown',
Empty: 'Empty',
EmptyRow: 'Empty',
Form: 'Form',
Highlight: 'Highlight',
Input: 'Input',
InputLinkify: 'Input',
Textarea: 'Input',
InputNumber: 'InputNumber',
AntInputNumber: 'InputNumber',
BaseNumberInput: 'InputNumber',
NumberInput: 'InputNumber',
Layout: 'Layout',
CommonDetailLayout: 'Layout',
CommonDetailLayoutWithMultiHead: 'Layout',
LayoutLeftRightResizable: 'Layout',
LeftNav: 'Layout',
LeftNavLink: 'Layout',
LeftNavList: 'Layout',
LeftNavHeaderITI: 'Layout',
LeftNavSection: 'Layout',
LayoutMainFlow: 'Layout',
LayoutMainFixed: 'Layout',
LayoutMainFixedFullGap: 'Layout',
LayoutMainFixedWide: 'Layout',
LayoutTopMainFull: 'Layout',
LayoutTopMainFlow: 'Layout',
LayoutTopMainFixed: 'Layout',
LayoutTopMainFixedCard: 'Layout',
LayoutTopMainFixedTab: 'Layout',
LayoutLeftMainFull: 'Layout',
LayoutLeftMainFlow: 'Layout',
LayoutLeftMainFixed: 'Layout',
LayoutLeftTopMainFixed: 'Layout',
LayoutLeftTopMainFlow: 'Layout',
List: 'List',
Loading: 'Loading',
LoadingAtCenterOfParent: 'Loading',
Menu: 'Menu',
Modal: 'Modal',
NavigatorMenu: 'NavigatorMenu',
notification: 'Notification',
Option: 'Option',
DropDownUserCell: 'Option',
Percent: 'Percent',
ProgressBar: 'Percent',
PopupConfirm: 'PopupConfirm',
Popover: 'Popover',
Progress: 'Progress',
Radio: 'Radio',
RadioGroup: 'Radio',
Result: 'Result',
Row: 'Row',
Select: 'Select',
EnhanceSelect: 'Select',
OptionGroupList: 'Select',
DropdownSelect: 'Select',
DropdownMultiSelect: 'Select',
DropdownSingleSelect: 'Select',
VirtualizeSelect: 'Select',
Skeleton: 'Skeleton',
Slider: 'Slider',
Space: 'Space',
Steps: 'Steps',
Switch: 'Switch',
RcSwitch: 'Switch',
Tabs: 'Tabs',
FoldableTabs: 'Tabs',
TextFoldableTabs: 'Tabs',
UrlFoldableTabs: 'Tabs',
Tag: 'Tag',
TimePicker: 'TimePicker',
toast: 'Toast',
message: 'Toast',
Tooltip: 'Tooltip',
TreeSelect: 'TreeSelect',
SelectAntTree: 'TreeSelect',
SelectTree: 'TreeSelect',
Typography: 'Typography',
ClickableLink: 'Typography',
Upload: '​Upload',
AvatarUploader: '​Upload',
Filter: 'Filter',
FilterEditor: 'Filter',
FilterMessage: 'Filter',
FilterMessages: 'Filter',
NewFilterEditor: 'Filter',
SimpleCustomTaskFilterEditor: 'Filter',
Guide: 'Guide',
Table: 'Table',
FilterableTable: 'Table',
InfiniteTable: 'Table',
SimpleTable: 'Table',
TaskList: 'Table',
VirtualTable: 'Table',
CanvasTable: 'CanvasTable',
Transfer: 'Transfer',
SelectMemberDialog: 'UserTransfer',
Tree: 'Tree',
importDepartmentTree: 'Tree',
importJQTreeWithReactNode: 'Tree',
importSelectJQTree: 'Tree',
User: 'UserSelect',
UserSelect: 'UserSelect'
Icon: "Icon",
Action: "Action",
Alert: "Alert",
Hint: "Alert",
Anchor: "Anchor",
Avatar: "Avatar",
BaseAvatar: "Avatar",
MemberAvatar: "Avatar",
getAvatarUrl: "Avatar",
Badge: "Badge",
Breadcrumb: "Breadcrumb",
Button: "Button",
Card: "Card",
CardHeader: "Card",
CardWrapper: "Card",
LeftRightCardWrapper: "Card",
Cascader: "Cascader",
Checkbox: "Checkbox",
BaseCheckbox: "Checkbox",
NewCheckbox: "Checkbox",
SquareCheckbox: "Checkbox",
Col: "Col",
Collapse: "Collapse",
ConfigProvider: "ConfigProvider",
Antd2LocaleProvider: "ConfigProvider",
LocaleProvider: "ConfigProvider",
DatePicker: "DatePicker",
Calendar: "DatePicker",
PopoverCalendar: "DatePicker",
RangeCalendar: "DatePicker",
RangePicker: "DatePicker",
RcDatePicker: "DatePicker",
wrapPicker: "DatePicker",
DateRangeInput: "DatePicker",
DateRangeInfoFragment: "DatePicker",
Divider: "Divider",
Drawer: "Drawer",
Dropdown: "Dropdown",
Empty: "Empty",
EmptyRow: "Empty",
Form: "Form",
Highlight: "Highlight",
Input: "Input",
InputLinkify: "Input",
Textarea: "Input",
InputNumber: "InputNumber",
AntInputNumber: "InputNumber",
BaseNumberInput: "InputNumber",
NumberInput: "InputNumber",
Layout: "Layout",
CommonDetailLayout: "Layout",
CommonDetailLayoutWithMultiHead: "Layout",
LayoutLeftRightResizable: "Layout",
LeftNav: "Layout",
LeftNavLink: "Layout",
LeftNavList: "Layout",
LeftNavHeaderITI: "Layout",
LeftNavSection: "Layout",
LayoutMainFlow: "Layout",
LayoutMainFixed: "Layout",
LayoutMainFixedFullGap: "Layout",
LayoutMainFixedWide: "Layout",
LayoutTopMainFull: "Layout",
LayoutTopMainFlow: "Layout",
LayoutTopMainFixed: "Layout",
LayoutTopMainFixedCard: "Layout",
LayoutTopMainFixedTab: "Layout",
LayoutLeftMainFull: "Layout",
LayoutLeftMainFlow: "Layout",
LayoutLeftMainFixed: "Layout",
LayoutLeftTopMainFixed: "Layout",
LayoutLeftTopMainFlow: "Layout",
List: "List",
Loading: "Loading",
LoadingAtCenterOfParent: "Loading",
Menu: "Menu",
Modal: "Modal",
NavigatorMenu: "NavigatorMenu",
notification: "Notification",
Option: "Option",
DropDownUserCell: "Option",
Percent: "Percent",
ProgressBar: "Percent",
PopupConfirm: "PopupConfirm",
Popover: "Popover",
Progress: "Progress",
Radio: "Radio",
RadioGroup: "Radio",
Result: "Result",
Row: "Row",
Select: "Select",
EnhanceSelect: "Select",
OptionGroupList: "Select",
DropdownSelect: "Select",
DropdownMultiSelect: "Select",
DropdownSingleSelect: "Select",
VirtualizeSelect: "Select",
Skeleton: "Skeleton",
Slider: "Slider",
Space: "Space",
Steps: "Steps",
Switch: "Switch",
RcSwitch: "Switch",
Tabs: "Tabs",
FoldableTabs: "Tabs",
TextFoldableTabs: "Tabs",
UrlFoldableTabs: "Tabs",
Tag: "Tag",
TimePicker: "TimePicker",
toast: "Toast",
message: "Toast",
Tooltip: "Tooltip",
TreeSelect: "TreeSelect",
SelectAntTree: "TreeSelect",
SelectTree: "TreeSelect",
Typography: "Typography",
ClickableLink: "Typography",
Upload: "​Upload",
AvatarUploader: "​Upload",
Filter: "Filter",
FilterEditor: "Filter",
FilterMessage: "Filter",
FilterMessages: "Filter",
NewFilterEditor: "Filter",
SimpleCustomTaskFilterEditor: "Filter",
Guide: "Guide",
Table: "Table",
FilterableTable: "Table",
InfiniteTable: "Table",
SimpleTable: "Table",
TaskList: "Table",
VirtualTable: "Table",
CanvasTable: "CanvasTable",
Transfer: "Transfer",
SelectMemberDialog: "UserTransfer",
Tree: "Tree",
importDepartmentTree: "Tree",
importJQTreeWithReactNode: "Tree",
importSelectJQTree: "Tree",
User: "UserSelect",
UserSelect: "UserSelect"
};

@@ -176,61 +169,107 @@ const componentNames = Object.keys(componentMap);

Action: {
files: ['ones-web-common/packages/graph/src/scripts']
files: ["ones-web-common/packages/graph/src/scripts"]
},
Anchor: {
files: ['ones-ai-web-common/packages/editor/src/scripts/plugins/link/index.jsx']
files: ["ones-ai-web-common/packages/editor/src/scripts/plugins/link/index.jsx"]
},
Avatar: {
files: ['ones-ai-web-common/packages/unit/lib/common_topbar/topbar_right/index.tsx']
files: ["ones-ai-web-common/packages/unit/lib/common_topbar/topbar_right/index.tsx"]
},
Empty: {
files: ['ones-project-web/src/scripts/ui/views/task_view/task_list', 'ones-ai-web-common/packages/widgets/src/scripts/field_input/index.tsx', 'ones-ai-web-common/packages/components/src/scripts/team/confluence_import/features/migration/space-choose/spaces.tsx'],
packages: ['@ones-ai/components/src/scripts/ui/views/task_view/task_list/empty_task_list']
files: [
"ones-project-web/src/scripts/ui/views/task_view/task_list",
"ones-ai-web-common/packages/widgets/src/scripts/field_input/index.tsx",
"ones-ai-web-common/packages/components/src/scripts/team/confluence_import/features/migration/space-choose/spaces.tsx"
],
packages: ["@ones-ai/components/src/scripts/ui/views/task_view/task_list/empty_task_list"]
},
Filter: {
files: ['ones-project-web/src/scripts', 'ones-ai-web-common/packages/components/src/scripts/new_filter/filter_adapt_old_props', 'ones-ai-web-common/packages/plan/src/scripts/ui/views/manhour_report/components/topbar', 'ones-ai-web-common/packages/utils/lib/constraints_conf_helper/index.ts'],
packages: ['@ones-ai/components/src/scripts/new_filter', '@ones-ai/components/src/scripts/new_filter/filter']
files: [
"ones-project-web/src/scripts",
"ones-ai-web-common/packages/components/src/scripts/new_filter/filter_adapt_old_props",
"ones-ai-web-common/packages/plan/src/scripts/ui/views/manhour_report/components/topbar",
"ones-ai-web-common/packages/utils/lib/constraints_conf_helper/index.ts"
],
packages: [
"@ones-ai/components/src/scripts/new_filter",
"@ones-ai/components/src/scripts/new_filter/filter"
]
},
Input: {
files: ['ones-ai-web-common/packages/components/src/scripts/logs/message/item_message_editor/item_message_input.jsx']
files: [
"ones-ai-web-common/packages/components/src/scripts/logs/message/item_message_editor/item_message_input.jsx"
]
},
InputNumber: {
files: ['ones-project-web/src/scripts/ui/views/automation/field_components', 'ones-ai-web-common/packages/widgets/src/scripts/field_input'],
packages: ['@ones-ai/widgets']
files: [
"ones-project-web/src/scripts/ui/views/automation/field_components",
"ones-ai-web-common/packages/widgets/src/scripts/field_input"
],
packages: ["@ones-ai/widgets"]
},
Loading: {
files: ['ones-ai-web-common/packages/components/src/scripts/ui/views/task_list/components/task_group_list/index.tsx', 'ones-ai-web-common/packages/components/src/scripts/ui/views/task_view/task_list/static_table_list/index.tsx'],
packages: ['@ones-ai/components/src/scripts/ui/views/task_view/task_list/static_table_list/loading']
files: [
"ones-ai-web-common/packages/components/src/scripts/ui/views/task_list/components/task_group_list/index.tsx",
"ones-ai-web-common/packages/components/src/scripts/ui/views/task_view/task_list/static_table_list/index.tsx"
],
packages: [
"@ones-ai/components/src/scripts/ui/views/task_view/task_list/static_table_list/loading"
]
},
Modal: {
files: ['ones-ai-web-common/packages/components/src/scripts/ui/widgets/dialog']
files: ["ones-ai-web-common/packages/components/src/scripts/ui/widgets/dialog"]
},
PopupConfirm: {
files: ['ones-ai-web-common/packages/components/src/scripts/manhour/task_detail/grouped_manhour_panel_header/remaining_manhour_popover_confirm.jsx', 'ones-ai-web-common/packages/unit/lib/popover_progress_slider/popover_progress_slider.jsx']
files: [
"ones-ai-web-common/packages/components/src/scripts/manhour/task_detail/grouped_manhour_panel_header/remaining_manhour_popover_confirm.jsx",
"ones-ai-web-common/packages/unit/lib/popover_progress_slider/popover_progress_slider.jsx"
]
},
Radio: {
files: ['ones-project-web/src/scripts/ui/views/view/common_view_config_edit_form/index.jsx']
files: ["ones-project-web/src/scripts/ui/views/view/common_view_config_edit_form/index.jsx"]
},
Result: {
files: ['ones-project-web/src/scripts/ppm/scripts/ui/components/dep_dialogs']
files: ["ones-project-web/src/scripts/ppm/scripts/ui/components/dep_dialogs"]
},
Select: {
files: ['ones-ai-web-common/packages/components/src/scripts/form/issue_type_select/issue_type_select.tsx', 'ones-ai-web-common/packages/components/src/scripts/form/select_or_checkbox.tsx']
files: [
"ones-ai-web-common/packages/components/src/scripts/form/issue_type_select/issue_type_select.tsx",
"ones-ai-web-common/packages/components/src/scripts/form/select_or_checkbox.tsx"
]
},
Skeleton: {
files: ['ones-project-web/src/scripts/ui/components/project_list/view/view_layout.tsx', 'ones-ai-web-common/packages/components/src/scripts/team/user_group/member_table', 'ones-ai-web-common/packages/components/src/scripts/organization/org_oversea_subscription/components/order_change_modal']
files: [
"ones-project-web/src/scripts/ui/components/project_list/view/view_layout.tsx",
"ones-ai-web-common/packages/components/src/scripts/team/user_group/member_table",
"ones-ai-web-common/packages/components/src/scripts/organization/org_oversea_subscription/components/order_change_modal"
]
},
Table: {
files: ['ones-ai-web-common/packages/unit/lib/dashboard/card/special_chart_card/index.tsx', 'ones-ai-web-common/packages/widgets/node_modules/@ones-ai/fixed-data-table-2/examples/ContextExample.js']
files: [
"ones-ai-web-common/packages/unit/lib/dashboard/card/special_chart_card/index.tsx",
"ones-ai-web-common/packages/widgets/node_modules/@ones-ai/fixed-data-table-2/examples/ContextExample.js"
]
},
Tag: {
files: ['ones-ai-web-common/packages/components/src/scripts/third_party/components/common/index.tsx'],
packages: ['@ones-ai/components/src/scripts/third_party/components/common']
files: [
"ones-ai-web-common/packages/components/src/scripts/third_party/components/common/index.tsx"
],
packages: ["@ones-ai/components/src/scripts/third_party/components/common"]
},
UserSelect: {
files: ['ones-project-web/src/scripts/ui/views/automation/field_components/field_group.tsx', 'ones-project-web/src/scripts/ui/views/component/kanban/kanban_detail_card.tsx', 'ones-project-web/src/scripts/ui/views/task/task_field/task_field_source.ts', 'ones-ai-web-common/packages/dao/schemas.ts', 'ones-ai-web-common/packages/types/lib/graphql_models/manhour.ts'],
packages: ['@ones-ai/components/src/scripts/user']
files: [
"ones-project-web/src/scripts/ui/views/automation/field_components/field_group.tsx",
"ones-project-web/src/scripts/ui/views/component/kanban/kanban_detail_card.tsx",
"ones-project-web/src/scripts/ui/views/task/task_field/task_field_source.ts",
"ones-ai-web-common/packages/dao/schemas.ts",
"ones-ai-web-common/packages/types/lib/graphql_models/manhour.ts"
],
packages: ["@ones-ai/components/src/scripts/user"]
}
};
const ignorePath = ['node_modules', 'ones-ai-web-common/packages/onboarding', 'ones-ai-web-common/packages/wiz-editor/src/scripts/plugins'];
const ignorePath = [
"node_modules",
"ones-ai-web-common/packages/onboarding",
"ones-ai-web-common/packages/wiz-editor/src/scripts/plugins"
];
function getCoverage(paths) {

@@ -245,9 +284,6 @@ const components = {

const fullPath = require$$1.resolve(targetPath);
// [dirname, basename][]
const files = require$$0.statSync(fullPath).isDirectory() ? require$$0.readdirSync(fullPath).map(name => [fullPath, name]) : [[require$$1.dirname(fullPath), require$$1.basename(fullPath)]];
const files = require$$0.statSync(fullPath).isDirectory() ? require$$0.readdirSync(fullPath).map((name) => [fullPath, name]) : [[require$$1.dirname(fullPath), require$$1.basename(fullPath)]];
files.forEach(([dirname, name]) => {
const filePath = require$$1.join(dirname, name);
// 排除无须扫描的目录
if (ignorePath.some(path => filePath.includes(path))) {
if (ignorePath.some((path2) => filePath.includes(path2))) {
return;

@@ -260,18 +296,16 @@ }

if (stats.isFile() && /\.(ts|tsx|js|jsx)$/.test(name)) {
const data = require$$0.readFileSync(filePath, 'utf-8');
const data = require$$0.readFileSync(filePath, "utf-8");
const matchArray = [...data.matchAll(/^import +(?!type)([^'"]+) +from +['"]([^'"]*)['"]/gm)];
matchArray.forEach(item => {
item[1].replace(/[{}]/g, '').split(',').forEach(component => {
let name = component.trim().replace(/ .+/, '').replace(/\/\/ .*(\n|$)|\W/gs, '');
// 排除无须扫描的包
if (name === '' || /^react|^@ones-design\/icons/.test(item[2]) || !componentNames.includes(name) && !/^antd/.test(item[2])) {
matchArray.forEach((item) => {
item[1].replace(/[{}]/g, "").split(",").forEach((component) => {
let name2 = component.trim().replace(/ .+/, "").replace(/\/\/ .*(\n|$)|\W/gs, "");
if (name2 === "" || /^react|^@ones-design\/icons/.test(item[2]) || !componentNames.includes(name2) && !/^antd/.test(item[2])) {
return;
}
name = componentMap[name] ?? name;
if (invalidResult[name]?.files?.some(i => filePath.includes(i)) || invalidResult[name]?.packages?.some(i => i == item[2])) {
name2 = componentMap[name2] ?? name2;
if (invalidResult[name2]?.files?.some((i) => filePath.includes(i)) || invalidResult[name2]?.packages?.some((i) => i == item[2])) {
return;
}
if (!components[name]) {
components[name] = {
if (!components[name2]) {
components[name2] = {
new: 0,

@@ -284,13 +318,13 @@ old: 0,

if (/^@ones-design/.test(item[2])) {
components[name].new++;
components[name2].new++;
components.all.new++;
} else {
const relativePath = require$$1.relative(require$$1.resolve(), filePath);
if (!components[name].files[relativePath]) {
components[name].files[relativePath] = [];
if (!components[name2].files[relativePath]) {
components[name2].files[relativePath] = [];
}
if (!components[name].files[relativePath].includes(item[0])) {
components[name].files[relativePath].push(item[0]);
if (!components[name2].files[relativePath].includes(item[0])) {
components[name2].files[relativePath].push(item[0]);
}
components[name].old++;
components[name2].old++;
components.all.old++;

@@ -303,4 +337,4 @@ }

}
paths.filter(p => require$$0.existsSync(p)).forEach(dfs);
Object.keys(components).forEach(item => {
paths.filter((p) => require$$0.existsSync(p)).forEach(dfs);
Object.keys(components).forEach((item) => {
const coverage = components[item].new / (components[item].new + components[item].old);

@@ -312,3 +346,3 @@ components[item].coverage = Number.isNaN(coverage) ? 1 : coverage;

};
Object.keys(components).sort().sort((a, b) => components[a].coverage > components[b].coverage ? 1 : -1).forEach(item => {
Object.keys(components).sort().sort((a, b) => components[a].coverage > components[b].coverage ? 1 : -1).forEach((item) => {
sortedComponents[item] = components[item];

@@ -318,24 +352,14 @@ });

}
/* ==== Enum ==== */
let Status = /*#__PURE__*/function (Status) {
Status["improved"] = "improved";
Status["declined"] = "declined";
Status["unchanged"] = "unchanged";
return Status;
}({});
let StatusIcon = /*#__PURE__*/function (StatusIcon) {
StatusIcon["improved"] = "\uD83D\uDFE2";
StatusIcon["declined"] = "\uD83D\uDD34";
StatusIcon["unchanged"] = "\uD83D\uDD35";
return StatusIcon;
}({});
/* ==== Type ==== */
/**
* 根据 action.yml 中的输入参数定义类型
*/
var Status = /* @__PURE__ */ ((Status2) => {
Status2["improved"] = "improved";
Status2["declined"] = "declined";
Status2["unchanged"] = "unchanged";
return Status2;
})(Status || {});
var StatusIcon = /* @__PURE__ */ ((StatusIcon2) => {
StatusIcon2["improved"] = "🟢";
StatusIcon2["declined"] = "🔴";
StatusIcon2["unchanged"] = "🔵";
return StatusIcon2;
})(StatusIcon || {});
function getDiffCoverage(report, baselineReport) {

@@ -351,19 +375,18 @@ const diffCoverage = Object.entries(report).reduce((acc, [component, info]) => {

const trend = info.coverage - baselineInfo.coverage;
/**
* 以一段 import 代码为最小单位,比较两个文件的差异
*/
const diffList = Object.keys(info.files || {}).reduce((acc, file) => {
const headFile = info.files[file];
const baseFile = baselineInfo.files[file];
if (headFile?.length && !vendor.isEqual(headFile, baseFile)) {
const headCodeLines = vendor.difference(headFile, baseFile).flatMap(code => code.split(/\r|\n|\r\n/)).map(line => `+ ${line}`);
const baseCodeLines = vendor.difference(baseFile, headFile).flatMap(code => code.split(/\r|\n|\r\n/)).map(line => `- ${line}`);
acc.push({
file,
code: headCodeLines.concat(baseCodeLines).join('\n')
});
}
return acc;
}, []);
const diffList = Object.keys(info.files || {}).reduce(
(acc2, file) => {
const headFile = info.files[file];
const baseFile = baselineInfo.files[file];
if (headFile?.length && !vendor.isEqual(headFile, baseFile)) {
const headCodeLines = vendor.difference(headFile, baseFile).flatMap((code) => code.split(/\r|\n|\r\n/)).map((line) => `+ ${line}`);
const baseCodeLines = vendor.difference(baseFile, headFile).flatMap((code) => code.split(/\r|\n|\r\n/)).map((line) => `- ${line}`);
acc2.push({
file,
code: headCodeLines.concat(baseCodeLines).join("\n")
});
}
return acc2;
},
[]
);
acc[component] = {

@@ -379,7 +402,5 @@ head: info,

const sortedDiffCoverage = {
all: undefined
all: void 0
};
Object.keys(diffCoverage).sort().sort((a, b) => {
// 根据 trend 排序:
// 降低 》 提升 》 未变化
const trendA = diffCoverage[a].trend;

@@ -390,3 +411,3 @@ const trendB = diffCoverage[b].trend;

return trendA > trendB ? 1 : trendA < trendB ? -1 : 0;
}).forEach(component => {
}).forEach((component) => {
sortedDiffCoverage[component] = diffCoverage[component];

@@ -396,5 +417,4 @@ });

}
const getPull = async function getPull(prNumber) {
const gitHubToken = vendor.coreExports.getInput('github-token').trim();
const getPull = async function getPull2(prNumber) {
const gitHubToken = vendor.coreExports.getInput("github-token").trim();
try {

@@ -408,7 +428,10 @@ const octokit = vendor.getOctokit_1(gitHubToken);

});
vendor.coreExports.debug(`PR #${prNumber} data: \n` + JSON.stringify(response.data, null, 2));
vendor.coreExports.debug(`PR #${prNumber} data:
` + JSON.stringify(response.data, null, 2));
return response.data;
} catch (error) {
if (error instanceof vendor.RequestError && (error.status === 404 || error.status === 403)) {
vendor.coreExports.warning(`Couldn't fetch PR due to error:\n[${error.name}]\n${error.message}`);
vendor.coreExports.warning(`Couldn't fetch PR due to error:
[${error.name}]
${error.message}`);
}

@@ -420,57 +443,48 @@ throw error;

};
const checkout = async branch => {
await vendor.exec_2('git', ['checkout', branch]);
const checkout = async (branch) => {
await vendor.exec_2("git", ["checkout", branch]);
};
/**
* 发送企业微信通知,以 Markdown 格式发送,文档参考:
* @see https://developer.work.weixin.qq.com/document/path/91770#markdown%E7%B1%BB%E5%9E%8B
*/
async function sendNotification(token, message) {
return new Promise((resolve, reject) => {
const req = require$$1$1.request(`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${token}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
const req = require$$1$1.request(
`https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=${token}`,
{
method: "POST",
headers: {
"Content-Type": "application/json"
}
},
(res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
const payload = JSON.parse(data);
if (payload.errcode !== 0 || res.statusCode >= 400) {
reject(payload);
}
resolve(payload);
});
}
}, res => {
let data = '';
res.on('data', chunk => {
data += chunk;
});
res.on('end', () => {
const payload = JSON.parse(data);
if (payload.errcode !== 0 || res.statusCode >= 400) {
reject(payload);
}
resolve(payload);
});
});
req.on('error', e => {
);
req.on("error", (e) => {
reject(e);
});
req.write(JSON.stringify({
msgtype: 'markdown',
markdown: {
content: message
}
}));
req.write(
JSON.stringify({
msgtype: "markdown",
markdown: {
content: message
}
})
);
req.end();
});
}
/**
* 数字转换百分比
* @param percentage 0.xx
* @param symbol 是否带 + 符号
* @returns xx.xx%
*/
function toPercentage(percentage, symbol = false) {
const prefix = !symbol ? '' : percentage > 0 ? '+' : '';
const prefix = !symbol ? "" : percentage > 0 ? "+" : "";
return `${prefix}${(percentage * 100).toFixed(2)}%`;
}
// https://github.com/davelosert/vitest-coverage-report-action/blob/v2.1.1/src/writeSummaryToPR.ts
const COMMENT_MARKER = (markerPostfix = 'root') => `<!-- ones-design-coverage-report-marker-${markerPostfix} -->`;
const COMMENT_MARKER = (markerPostfix = "root") => `<!-- ones-design-coverage-report-marker-${markerPostfix} -->`;
const writeSummaryToPR = async ({

@@ -481,5 +495,7 @@ summary,

}) => {
const gitHubToken = vendor.coreExports.getInput('github-token').trim();
const gitHubToken = vendor.coreExports.getInput("github-token").trim();
const octokit = vendor.getOctokit_1(gitHubToken);
const commentBody = `${summary.stringify()}\n\n${COMMENT_MARKER(markerPostfix)}`;
const commentBody = `${summary.stringify()}
${COMMENT_MARKER(markerPostfix)}`;
const existingComment = await findCommentByBody(octokit, COMMENT_MARKER(markerPostfix), pr);

@@ -508,31 +524,21 @@ if (existingComment) {

});
for await (const {
data: comments
} of commentsIterator) {
const comment = comments.find(comment => comment.body?.includes(commentBodyIncludes));
for await (const { data: comments } of commentsIterator) {
const comment = comments.find((comment2) => comment2.body?.includes(commentBodyIncludes));
if (comment) return comment;
}
return undefined;
return void 0;
}
// 解析 GitHub Action input 参数
const options = new class {
#cache = Object.create(null);
#cache = /* @__PURE__ */ Object.create(null);
get paths() {
return this.#cache.paths ?? (this.#cache.paths = vendor.coreExports.getMultilineInput('paths', {
required: true
}));
return this.#cache.paths ?? (this.#cache.paths = vendor.coreExports.getMultilineInput("paths", { required: true }));
}
get mode() {
return this.#cache.mode ?? (this.#cache.mode = vendor.coreExports.getInput('mode', {
required: true
}));
return this.#cache.mode ?? (this.#cache.mode = vendor.coreExports.getInput("mode", { required: true }));
}
get prNumber() {
return this.#cache.prNumber ?? (this.#cache.prNumber = Number(vendor.coreExports.getInput('pr-number', {
required: this.mode === 'pr'
})));
return this.#cache.prNumber ?? (this.#cache.prNumber = Number(vendor.coreExports.getInput("pr-number", { required: this.mode === "pr" })));
}
get additionalNotification() {
return this.#cache.additionalNotification ?? (this.#cache.additionalNotification = vendor.coreExports.getInput('additional-notification', {
return this.#cache.additionalNotification ?? (this.#cache.additionalNotification = vendor.coreExports.getInput("additional-notification", {
required: false

@@ -542,13 +548,10 @@ }));

get workWechatToken() {
return this.#cache.workWechatToken ?? (this.#cache.workWechatToken = vendor.coreExports.getInput('work-wechat-token', {
required: false
}));
return this.#cache.workWechatToken ?? (this.#cache.workWechatToken = vendor.coreExports.getInput("work-wechat-token", { required: false }));
}
get artifactRetentionDays() {
return this.#cache.artifactRetentionDays ?? (this.#cache.artifactRetentionDays = Number(vendor.coreExports.getInput('artifact-retention-days', {
required: false
})));
return this.#cache.artifactRetentionDays ?? (this.#cache.artifactRetentionDays = Number(
vendor.coreExports.getInput("artifact-retention-days", { required: false })
));
}
}();
const PRSummaryTableMustache = `

@@ -667,46 +670,42 @@ <table>

`;
function getWorkflowURL() {
const {
owner,
repo
} = vendor.context.repo;
const {
runId
} = vendor.context;
const { owner, repo } = vendor.context.repo;
const { runId } = vendor.context;
return `${vendor.context.serverUrl}/${owner}/${repo}/actions/runs/${runId}`;
}
function getReportSummaryData(report) {
return Object.entries(report).reduce((acc, [component, info]) => {
acc.table.push({
status: StatusIcon[info.status],
component,
trend: toPercentage(info.trend, true),
percentage: toPercentage(info.head.coverage),
coveredAndTotal: `${info.head.new} / ${info.head.new + info.head.old}`,
basePercentage: toPercentage(info.base.coverage),
baseCoveredAndTotal: `${info.base.new} / ${info.base.new + info.base.old}`
});
acc.info.push({
component,
head: {
files: Object.entries(info.head?.files ?? {}).map(([file, code]) => ({
file,
code: code.join('\n')
}))
},
diffList: info.diffList
});
acc.pass = acc.pass && info.diffList.length === 0;
return acc;
}, {
pass: true,
table: [],
info: []
});
return Object.entries(report).reduce(
(acc, [component, info]) => {
acc.table.push({
status: StatusIcon[info.status],
component,
trend: toPercentage(info.trend, true),
percentage: toPercentage(info.head.coverage),
coveredAndTotal: `${info.head.new} / ${info.head.new + info.head.old}`,
basePercentage: toPercentage(info.base.coverage),
baseCoveredAndTotal: `${info.base.new} / ${info.base.new + info.base.old}`
});
acc.info.push({
component,
head: {
files: Object.entries(info.head?.files ?? {}).map(([file, code]) => ({
file,
code: code.join("\n")
}))
},
diffList: info.diffList
});
acc.pass = acc.pass && info.diffList.length === 0;
return acc;
},
{
pass: true,
table: [],
info: []
}
);
}
function getPRSummary(diffReport) {
const data = {
date: new Date(Date.now() + 8 * 60 * 60 * 1000).toLocaleString('zh-CN'),
date: new Date(Date.now() + 8 * 60 * 60 * 1e3).toLocaleString("zh-CN"),
workflowUrl: getWorkflowURL(),

@@ -716,3 +715,3 @@ runNumber: vendor.context.runNumber,

};
vendor.coreExports.debug('PR Summary Mustache Data:');
vendor.coreExports.debug("PR Summary Mustache Data:");
vendor.coreExports.debug(JSON.stringify(data, null, 2));

@@ -722,8 +721,7 @@ const view = vendor.mustache.render(PRSummaryMustache, data);

}
async function prMode(summary) {
vendor.coreExports.info('Getting pull-request info...');
vendor.coreExports.info("Getting pull-request info...");
const pr = await getPull(options.prNumber);
vendor.coreExports.info('Pull-request info got successfully.');
vendor.coreExports.info('Generating PR coverage report...');
vendor.coreExports.info("Pull-request info got successfully.");
vendor.coreExports.info("Generating PR coverage report...");
await checkout(pr.head.ref);

@@ -736,34 +734,33 @@ const allHeadReport = getCoverage(options.paths);

const view = getPRSummary(diffReport);
vendor.coreExports.info('PR coverage report generated successfully.');
vendor.coreExports.info('Writing pr-coverage-report.json...');
await fs.writeFile('pr-coverage-report.json', JSON.stringify(diffReport, null, 2));
vendor.coreExports.info('pr-coverage-report.json generated successfully.');
vendor.coreExports.info('Uploading pr-coverage-report.json to artifacts...');
await new vendor.artifact.DefaultArtifactClient().uploadArtifact('pr-coverage-report', ['pr-coverage-report.json'], '.', {
retentionDays: options.artifactRetentionDays
});
vendor.coreExports.info('pr-coverage-report.json uploaded successfully.');
vendor.coreExports.info("PR coverage report generated successfully.");
vendor.coreExports.info("Writing pr-coverage-report.json...");
await fs.writeFile("pr-coverage-report.json", JSON.stringify(diffReport, null, 2));
vendor.coreExports.info("pr-coverage-report.json generated successfully.");
vendor.coreExports.info("Uploading pr-coverage-report.json to artifacts...");
await new vendor.artifact.DefaultArtifactClient().uploadArtifact(
"pr-coverage-report",
["pr-coverage-report.json"],
".",
{ retentionDays: options.artifactRetentionDays }
);
vendor.coreExports.info("pr-coverage-report.json uploaded successfully.");
try {
vendor.coreExports.info('Writing report to pull-request...');
vendor.coreExports.info("Writing report to pull-request...");
summary.addRaw(view);
await writeSummaryToPR({
summary,
pr
});
vendor.coreExports.info('Report written successfully.');
await writeSummaryToPR({ summary, pr });
vendor.coreExports.info("Report written successfully.");
} catch (error) {
if (error instanceof vendor.RequestError && (error.status === 404 || error.status === 403)) {
vendor.coreExports.warning(`Couldn't write a comment to the pull-request. Please make sure your job has the permission 'pull-request: write'.
vendor.coreExports.warning(
`Couldn't write a comment to the pull-request. Please make sure your job has the permission 'pull-request: write'.
Original Error was: [${error.name}] - ${error.message}
`);
`
);
} else {
// Rethrow to handle it in the catch block of the run()-call.
throw error;
}
}
vendor.coreExports.info('Writing summary...');
vendor.coreExports.info("Writing summary...");
await summary.write();
vendor.coreExports.info('Summary written successfully.');
// 下降详情中包含文件列表的话,才发企业微信通知
vendor.coreExports.info("Summary written successfully.");
const declinedEntries = Object.entries(diffReport).filter(([component, info]) => {

@@ -773,7 +770,7 @@ return info.diffList.length > 0;

if (!declinedEntries.length) {
vendor.coreExports.info('No components with declined coverage, skipping sending notification.');
vendor.coreExports.info("No components with declined coverage, skipping sending notification.");
return;
}
vendor.coreExports.warning('There are some components with declined coverage.');
vendor.coreExports.info('Generating notification...');
vendor.coreExports.warning("There are some components with declined coverage.");
vendor.coreExports.info("Generating notification...");
const notificationData = {

@@ -791,3 +788,3 @@ additionalNotification: options.additionalNotification,

component,
color: info.status === 'declined' ? 'warning' : 'info',
color: info.status === "declined" ? "warning" : "info",
percentage: toPercentage(info.trend, true)

@@ -797,14 +794,13 @@ }))

const notificationView = vendor.mustache.render(PRNotificationMustache, notificationData);
vendor.coreExports.info('Notification generated successfully.');
vendor.coreExports.debug('Notification Mustache Data:');
vendor.coreExports.info("Notification generated successfully.");
vendor.coreExports.debug("Notification Mustache Data:");
vendor.coreExports.debug(JSON.stringify(notificationData, null, 2));
if (options.workWechatToken) {
vendor.coreExports.info('Sending notification to work wechat...');
vendor.coreExports.info("Sending notification to work wechat...");
await sendNotification(options.workWechatToken, notificationView);
vendor.coreExports.info('Notification sent successfully.');
vendor.coreExports.info("Notification sent successfully.");
} else {
vendor.coreExports.info('No work wechat token provided, skipping sending notification.');
vendor.coreExports.info("No work wechat token provided, skipping sending notification.");
}
}
const SingleNotificationMustache = `

@@ -822,3 +818,2 @@ # 覆盖率扫描结果

`;
const SingleSummaryTableMustache = `

@@ -879,6 +874,5 @@ <table>

`;
function getSingleSummary(report) {
const data = {
date: new Date(Date.now() + 8 * 60 * 60 * 1000).toLocaleString('zh-CN'),
date: new Date(Date.now() + 8 * 60 * 60 * 1e3).toLocaleString("zh-CN"),
workflowUrl: getWorkflowURL(),

@@ -899,31 +893,33 @@ runNumber: vendor.context.runNumber,

file,
code: code.join('\n')
code: code.join("\n")
}))
});
}
vendor.coreExports.debug('SingleSummaryMustache data:');
vendor.coreExports.debug("SingleSummaryMustache data:");
vendor.coreExports.debug(JSON.stringify(data, null, 2));
return vendor.mustache.render(SingleSummaryMustache, data);
}
async function singleMode(summary) {
vendor.coreExports.info('Generating single coverage report...');
vendor.coreExports.info("Generating single coverage report...");
const report = getCoverage(options.paths);
vendor.coreExports.info('Single coverage report generated successfully.');
vendor.coreExports.info('Writing coverage-report.json...');
await fs.writeFile('coverage-report.json', JSON.stringify(report, null, 2));
vendor.coreExports.info('coverage-report.json generated successfully.');
vendor.coreExports.info('Uploading coverage-report.json to artifacts...');
await new vendor.artifact.DefaultArtifactClient().uploadArtifact('coverage-report', ['coverage-report.json'], '.', {
retentionDays: options.artifactRetentionDays
});
vendor.coreExports.info('coverage-report.json uploaded successfully.');
vendor.coreExports.info('Generating summary...');
vendor.coreExports.info("Single coverage report generated successfully.");
vendor.coreExports.info("Writing coverage-report.json...");
await fs.writeFile("coverage-report.json", JSON.stringify(report, null, 2));
vendor.coreExports.info("coverage-report.json generated successfully.");
vendor.coreExports.info("Uploading coverage-report.json to artifacts...");
await new vendor.artifact.DefaultArtifactClient().uploadArtifact(
"coverage-report",
["coverage-report.json"],
".",
{ retentionDays: options.artifactRetentionDays }
);
vendor.coreExports.info("coverage-report.json uploaded successfully.");
vendor.coreExports.info("Generating summary...");
const view = getSingleSummary(report);
vendor.coreExports.info('Summary generated successfully.');
vendor.coreExports.info('Writing summary...');
vendor.coreExports.info("Summary generated successfully.");
vendor.coreExports.info("Writing summary...");
summary.addRaw(view);
await summary.write();
vendor.coreExports.info('Summary written successfully.');
vendor.coreExports.info('Generating notification...');
vendor.coreExports.info("Summary written successfully.");
vendor.coreExports.info("Generating notification...");
const data = {

@@ -936,3 +932,3 @@ additionalNotification: options.additionalNotification,

component,
color: info.coverage === 1 ? 'info' : 'warning',
color: info.coverage === 1 ? "info" : "warning",
percentage: toPercentage(info.coverage)

@@ -942,18 +938,16 @@ }))

const notificationView = vendor.mustache.render(SingleNotificationMustache, data);
vendor.coreExports.info('Notification generated successfully.');
vendor.coreExports.debug('Notification Mustache Data:');
vendor.coreExports.info("Notification generated successfully.");
vendor.coreExports.debug("Notification Mustache Data:");
vendor.coreExports.debug(JSON.stringify(data, null, 2));
if (options.workWechatToken) {
vendor.coreExports.info('Sending notification to work wechat...');
vendor.coreExports.info("Sending notification to work wechat...");
await sendNotification(options.workWechatToken, notificationView);
vendor.coreExports.info('Notification sent successfully.');
vendor.coreExports.info("Notification sent successfully.");
} else {
vendor.coreExports.info('No work wechat token provided, skipping sending notification.');
vendor.coreExports.info("No work wechat token provided, skipping sending notification.");
}
}
async function main() {
// WARNING: summary 是全局实例,传参只是为了更易理解与测试
const summary = vendor.coreExports.summary;
if (options.mode === 'pr') {
if (options.mode === "pr") {
await prMode(summary);

@@ -963,3 +957,3 @@ } else {

}
vendor.coreExports.info('Report generated successfully.');
vendor.coreExports.info("Report generated successfully.");
}

@@ -969,3 +963,3 @@ function errorHandler(err) {

vendor.coreExports.error(err.message);
vendor.coreExports.error(err.stack ?? '');
vendor.coreExports.error(err.stack ?? "");
vendor.coreExports.setFailed(err.message);

@@ -978,4 +972,4 @@ } else {

}
process.on('unhandledRejection', errorHandler);
process.on('uncaughtException', errorHandler);
process.on("unhandledRejection", errorHandler);
process.on("uncaughtException", errorHandler);
main();
{
"name": "@ones-design/coverage-report",
"version": "0.4.1-beta.0",
"version": "0.5.0-beta.0",
"description": "ONES Design Coverage Report Action",

@@ -47,3 +47,3 @@ "type": "commonjs",

},
"gitHead": "49c126b50109f6edc56f42502a35924ef6cfe98a"
"gitHead": "b3d535827932c182006837f4226f889b258b8910"
}

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc