eslint-metrics-uploader.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. const { google } = require('googleapis');
  20. const { SPREADSHEET_ID } = process.env;
  21. const SERVICE_ACCOUNT_KEY = JSON.parse(process.env.SERVICE_ACCOUNT_KEY);
  22. const auth = new google.auth.GoogleAuth({
  23. credentials: SERVICE_ACCOUNT_KEY,
  24. scopes: ['https://www.googleapis.com/auth/spreadsheets'],
  25. });
  26. const sheets = google.sheets({ version: 'v4', auth });
  27. const DATETIME = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
  28. async function writeToGoogleSheet(data, range, headers, append = false) {
  29. const request = {
  30. spreadsheetId: SPREADSHEET_ID,
  31. range,
  32. valueInputOption: 'USER_ENTERED',
  33. resource: { values: append ? data : [headers, ...data] },
  34. };
  35. const method = append ? 'append' : 'update';
  36. await sheets.spreadsheets.values[method](request);
  37. }
  38. // Process ESLint results and prepare data for Google Sheets
  39. module.exports = async results => {
  40. const enrichedRules = {
  41. 'react-prefer-function-component/react-prefer-function-component': {
  42. description: 'We prefer function components to class-based components',
  43. },
  44. 'react/jsx-filename-extension': {
  45. description:
  46. 'We prefer Typescript - all JSX files should be converted to TSX',
  47. },
  48. 'react/forbid-component-props': {
  49. description:
  50. 'We prefer Emotion for styling rather than `className` or `style` props',
  51. },
  52. // Ignore thie rule here - the messages in eslintrc_metrics.js are sufficient descriptions, broken down by file type.
  53. 'no-restricted-imports': {
  54. description:
  55. "This rule catches several things that shouldn't be used anymore. LESS, antD, etc. See individual occurrence messages for details",
  56. },
  57. 'no-console': {
  58. description:
  59. "We don't want a bunch of console noise, but you can use the `logger` from `@superset-ui/core` when there's a reason to.",
  60. },
  61. };
  62. // Consolidate data processing into a single loop for efficiency
  63. const metricsByRule = {};
  64. let occurrencesData = [];
  65. results.forEach(result => {
  66. result.messages.forEach(({ ruleId, line, column, message }) => {
  67. const ruleData = metricsByRule[ruleId] || { count: 0 };
  68. ruleData.count += 1;
  69. metricsByRule[ruleId] = ruleData;
  70. occurrencesData.push({
  71. rule: ruleId,
  72. message,
  73. file: result.filePath,
  74. line,
  75. column,
  76. ts: DATETIME,
  77. });
  78. });
  79. });
  80. // Transform data for Google Sheets
  81. const metricsData = Object.entries(metricsByRule).map(([rule, { count }]) => [
  82. 'ESLint',
  83. rule,
  84. enrichedRules[rule]?.description || 'N/A',
  85. `${count}`,
  86. DATETIME,
  87. ]);
  88. occurrencesData = occurrencesData.map(
  89. ({ rule, message, file, line, column }) => [
  90. rule,
  91. enrichedRules[rule]?.description || 'N/A',
  92. message,
  93. file,
  94. `${line}`,
  95. `${column}`,
  96. DATETIME,
  97. ],
  98. );
  99. const aggregatedHistoryHeaders = [
  100. 'Process',
  101. 'Rule',
  102. 'Description',
  103. 'Count',
  104. 'Timestamp',
  105. ];
  106. const eslintBacklogHeaders = [
  107. 'Rule',
  108. 'Rule Description',
  109. 'ESLint Message',
  110. 'File',
  111. 'Line',
  112. 'Column',
  113. 'Timestamp',
  114. ];
  115. try {
  116. await writeToGoogleSheet(
  117. metricsData,
  118. 'Aggregated History!A:E',
  119. aggregatedHistoryHeaders,
  120. true,
  121. );
  122. await writeToGoogleSheet(
  123. occurrencesData,
  124. 'ESLint Backlog!A:G',
  125. eslintBacklogHeaders,
  126. );
  127. } catch (error) {
  128. console.error('Error writing to Google Sheets:', error);
  129. }
  130. };