diff --git a/.gitignore b/.gitignore index 7149dbabc1..47e76b6d37 100644 --- a/.gitignore +++ b/.gitignore @@ -159,4 +159,7 @@ e2e-test-report/ # VS Code backing up svg files *svg.bkp -*svg.dtmp \ No newline at end of file +*svg.dtmp + +# Scripts +plugins-report.html \ No newline at end of file diff --git a/package.json b/package.json index bad49ab55f..595a6ff78f 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "build:api-reports": "yarn build:api-reports:only --tsc", "build:api-reports:only": "backstage-repo-tools api-reports --allow-warnings 'packages/core-components,plugins/+(catalog|catalog-import|git-release-manager|jenkins|kubernetes)' -o ae-wrong-input-file-type --validate-release-tags", "build:api-docs": "LANG=en_EN yarn build:api-reports --docs", + "build:plugins-report": "node ./scripts/build-plugins-report", "tsc": "tsc", "tsc:full": "backstage-cli repo clean && tsc --skipLibCheck false --incremental false", "clean": "backstage-cli repo clean", @@ -83,6 +84,7 @@ "lint-staged": "^13.0.0", "minimist": "^1.2.5", "node-gyp": "^9.4.0", + "open": "^7.2.1", "prettier": "^2.2.1", "semver": "^7.5.3", "shx": "^0.3.2", diff --git a/scripts/build-plugins-report.js b/scripts/build-plugins-report.js new file mode 100755 index 0000000000..185562cda8 --- /dev/null +++ b/scripts/build-plugins-report.js @@ -0,0 +1,150 @@ +#!/usr/bin/env node +/* + * Copyright 2023 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const fs = require('fs-extra'); +const path = require('path'); +const open = require('open'); +const { execFile: execFileCb } = require('child_process'); +const { promisify } = require('util'); + +const execFile = promisify(execFileCb); + +const rootDirectory = path.resolve(__dirname, '..'); + +async function run(command, ...args) { + const { stdout, stderr } = await execFile(command, args, { + cwd: rootDirectory, + }); + + if (stderr) { + console.error(stderr); + } + + return stdout.trim(); +} + +function generateHtmlReport(rows) { + const thead = `${rows[0].map(cell => `${cell}`).join('')}`; + + const tbody = rows + .slice(1) + .map(row => `${row.map(cell => `${cell}`).join('')}`) + .join(''); + + return ` + + + Backstage Plugins Report + + + + + ${thead} + ${tbody} +
+ + + `; +} + +const PLUGIN_ROLES = ['frontend-plugin', 'backend-plugin']; + +async function main() { + const pluginsDirectory = path.resolve(rootDirectory, 'plugins'); + + const directoryNames = fs + .readdirSync(pluginsDirectory, { withFileTypes: true }) + .filter(dirent => dirent.isDirectory()) + .map(dirent => dirent.name); + + const tableRows = [['Plugin', 'Author', 'Message', 'Date']]; + + for (const directoryName of directoryNames) { + console.log(`🔎 Reading data for ${directoryName}`); + + const directoryPath = path.resolve(pluginsDirectory, directoryName); + + const packageJson = await fs.readJson( + path.resolve(directoryPath, 'package.json'), + ); + + const plugin = PLUGIN_ROLES.includes(packageJson?.backstage?.role ?? ''); + + if (!plugin) continue; + + let data; + let skip = 0; + const maxCount = 10; + while (!data && skip <= 100) { + const output = await run( + 'git', + 'log', + 'origin/master', + `--skip=${skip}`, + `--max-count=${maxCount}`, + '--format=%an;%s;%as', + directoryPath, + ); + + data = output.split('\n').find(commit => { + // exclude merge commits + if (commit.includes('Merge pull request #')) { + return false; + } + + // exclude commits authored by a bot + if ( + commit.startsWith('renovate[bot]') || + commit.startsWith('github-actions[bot]') + ) { + return false; + } + + return true; + }); + + skip += 10; + } + + if (data) { + tableRows.push([directoryName, ...data.split(';')]); + } else { + console.log(`⚠️ No data found for ${directoryName}`); + } + } + + const file = 'plugins-report.html'; + + console.log(`📊 Generating plugins report...`); + + fs.writeFile(file, generateHtmlReport(tableRows), err => { + if (err) throw err; + }); + + console.log(`📄 Opening ${file} file...`); + + open(file); +} + +main(process.argv.slice(2)).catch(error => { + console.error(error.stack || error); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index 3659fce669..2d03125f54 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34349,7 +34349,7 @@ __metadata: languageName: node linkType: hard -"open@npm:^7.4.2": +"open@npm:^7.2.1, open@npm:^7.4.2": version: 7.4.2 resolution: "open@npm:7.4.2" dependencies: @@ -38468,6 +38468,7 @@ __metadata: lint-staged: ^13.0.0 minimist: ^1.2.5 node-gyp: ^9.4.0 + open: ^7.2.1 prettier: ^2.2.1 semver: ^7.5.3 shx: ^0.3.2