From 214f43dd2f64a4390fc0aabfd2cedce8eb8a415d Mon Sep 17 00:00:00 2001 From: Nicola Molinari Date: Fri, 13 Aug 2021 17:03:22 +0200 Subject: [PATCH] feat: add script to check and update issue on TS migration status (#1986) * feat: add script to check and update issue on TS migration status * fix: percentage * refactor(scripts): render table with package name and location --- .github/workflows/ts-migration-check.yml | 42 +++++++ package.json | 2 + scripts/check-ts-migration.mjs | 141 +++++++++++++++++++++++ yarn.lock | 30 ++--- 4 files changed, 200 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/ts-migration-check.yml create mode 100755 scripts/check-ts-migration.mjs diff --git a/.github/workflows/ts-migration-check.yml b/.github/workflows/ts-migration-check.yml new file mode 100644 index 0000000000..a77e532fb2 --- /dev/null +++ b/.github/workflows/ts-migration-check.yml @@ -0,0 +1,42 @@ +name: TypeScript migration check + +# The event triggers are configured as following: +# - on branch main, trigger the workflow on every push +on: + push: + branches: + - main + +jobs: + build_lint_and_test: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Read .nvmrc + run: echo ::set-output name=NVMRC::$(cat .nvmrc) + id: nvm + + - name: Setup Node (uses version in .nvmrc) + uses: actions/setup-node@v2 + with: + node-version: "${{ steps.nvm.outputs.NVMRC }}" + + - name: Get yarn cache + id: yarn-cache + run: echo "::set-output name=dir::$(yarn cache dir)" + + - uses: actions/cache@v2 + with: + path: ${{ steps.yarn-cache.outputs.dir }} + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock', 'patches/*.patch') }} + restore-keys: | + ${{ runner.os }}-yarn- + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Checking TypeScript migration + run: ./scripts/check-ts-migration.mjs diff --git a/package.json b/package.json index f03c23994c..8a5e3471e8 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "@formatjs/cli": "4.2.30", "@formatjs/intl-relativetimeformat": "9.2.1", "@manypkg/cli": "0.18.0", + "@manypkg/get-packages": "1.1.1", "@percy/cli": "1.0.0-beta.63", "@percy/puppeteer": "2.0.0", "@preconstruct/cli": "2.1.0", @@ -111,6 +112,7 @@ "cross-env": "7.0.3", "eslint": "7.32.0", "eslint-formatter-pretty": "4.1.0", + "execa": "5.1.1", "formik": "^2.2.9", "glob": "7.1.7", "global": "4.4.0", diff --git a/scripts/check-ts-migration.mjs b/scripts/check-ts-migration.mjs new file mode 100755 index 0000000000..346dbf7b08 --- /dev/null +++ b/scripts/check-ts-migration.mjs @@ -0,0 +1,141 @@ +#!/usr/bin/env node + +import fs from 'fs'; +import path from 'path'; +import mri from 'mri'; +import execa from 'execa'; +import { getPackagesSync } from '@manypkg/get-packages'; + +const flags = mri(process.argv.slice(2), { alias: { help: ['h'] } }); + +if (flags.help) { + console.log(` + Usage: check-ts-migration [options] + + Displays help information. + + Options: + --dry-run (optional) Simulate a run, the generated content will be printed to stdout. + `); + process.exit(0); +} + +const issueTitle = 'TypeScript migration overview'; + +const dryRun = flags['dry-run'] ? true : false; + +const execute = async () => { + if (!dryRun) { + const result = await execa('gh', ['--version']); + if (result.failed) { + throw new Error( + 'Missing required binary "gh". Make sure it is installed.' + ); + } + } + + const workspacePackages = getPackagesSync(process.cwd()); + const publicPackages = workspacePackages.packages.filter( + (packageInfo) => !packageInfo.packageJson.private + ); + + const stats = publicPackages.reduce( + (stats, packageInfo) => { + const entryPointPath = path.join(packageInfo.dir, 'src/index.ts'); + const isTS = fs.existsSync(entryPointPath); + + return { + migrated: isTS ? stats.migrated + 1 : stats.migrated, + pending: isTS ? stats.pending : stats.pending + 1, + pendingPackages: [ + ...stats.pendingPackages, + isTS + ? null + : { + name: packageInfo.packageJson.name, + dir: path.relative(process.cwd(), packageInfo.dir), + }, + ].filter(Boolean), + }; + }, + { + migrated: 0, + pending: 0, + pendingPackages: [], + } + ); + + const percentageCompleted = Math.floor( + (stats.migrated * 100) / publicPackages.length + ); + + const statsMd = ` +## Progress + +![${percentageCompleted}%](https://progress-bar.dev/${percentageCompleted}) + +**${stats.migrated} out of ${ + publicPackages.length + } packages** have been migrated to TypeScript. + +## Pending migration + +The following **${ + stats.pending + } packages** have not been migrated to TypeScript yet: + +| Package | Location | +| --- | --- | +${stats.pendingPackages + .map( + (packageInfo) => + `| \`${packageInfo.name}\` | [${packageInfo.dir}](https://github.com/commercetools/ui-kit/tree/main/${packageInfo.dir}) |` + ) + .join('\n')} + `; + + if (dryRun) { + console.log(statsMd); + process.exit(0); + } + + // Push stats to repository + const resultGhIssueRaw = await execa('gh', [ + 'issue', + 'list', + '--search', + `"${issueTitle}"`, + '--json', + 'number', + ]); + const resultGhIssue = JSON.parse(resultGhIssueRaw.stdout); + + if (resultGhIssue.length === 0) { + // Create a new issue + await execa('gh', [ + 'issue', + 'create', + '--title', + issueTitle, + '--body', + statsMd, + ]); + } else { + const [issue] = resultGhIssue; + // Update existing issue + await execa('gh', [ + 'issue', + 'edit', + issue.number, + '--title', + `${issueTitle} (\`${percentageCompleted}%\` completed)`, + '--body', + statsMd, + ]); + } +}; + +execute().catch((error) => { + console.error(error.message || error); + process.exit(1); +}); diff --git a/yarn.lock b/yarn.lock index eb40e0158e..b02a5d0e17 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6107,6 +6107,21 @@ events@^3.2.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== +execa@5.1.1, execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + execa@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777" @@ -6133,21 +6148,6 @@ execa@^1.0.0: signal-exit "^3.0.0" strip-eof "^1.0.0" -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - execall@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45"