From b5032650c5a7b43ce905801041600c43ffa69d1f Mon Sep 17 00:00:00 2001 From: Mark <129744061+markw-deriv@users.noreply.github.com> Date: Mon, 20 May 2024 08:58:46 +0100 Subject: [PATCH] [TRAH-3259]: chore: add comment to pull requests with bundle size information (#15172) --- .github/actions/analyze/action.yml | 90 ++++++++++++++-- .github/actions/analyze/compareReports.js | 122 ++++++++++++++++++++++ .github/workflows/analyze.yml | 5 + 3 files changed, 210 insertions(+), 7 deletions(-) create mode 100644 .github/actions/analyze/compareReports.js diff --git a/.github/actions/analyze/action.yml b/.github/actions/analyze/action.yml index 9f9cb7dcf729..cc1c0ad37c3f 100644 --- a/.github/actions/analyze/action.yml +++ b/.github/actions/analyze/action.yml @@ -27,6 +27,9 @@ inputs: DATADOG_SESSION_SAMPLE_RATE: description: 'Datadog session sample rate' required: false + GITHUB_TOKEN: + description: 'Github token for downloading artifacts' + required: true GD_API_KEY: description: 'Google drive api key' required: false @@ -58,6 +61,54 @@ inputs: runs: using: composite steps: + + - name: Get latest commit hash from master + id: latest_commit + shell: bash + run: | + git fetch origin master + latest_commit=$(git rev-parse origin/master) + echo "latest_commit=$latest_commit" >> $GITHUB_OUTPUT + + - name: Check if previous artifact exists + env: + LATEST_COMMIT: ${{ steps.latest_commit.outputs.latest_commit }} + id: artifact_check + shell: bash + run: | + ARTIFACT_EXISTS=$(curl -s -H "Authorization: Bearer ${{ github.token }}" "https://api.github.com/repos/${{ github.repository }}/actions/artifacts?name=reports-$LATEST_COMMIT" | jq '.total_count' | awk '{print $1}') + if [[ $ARTIFACT_EXISTS -gt 0 ]]; then + echo "artifact_exists=true" >> $GITHUB_OUTPUT + else + echo "artifact_exists=false" >> $GITHUB_OUTPUT + fi + + - name: Get artifact URL + id: get_artifact_url + env: + GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} + LATEST_COMMIT: ${{ steps.latest_commit.outputs.latest_commit }} + shell: bash + run: | + ARTIFACT_URL=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" \ + "https://api.github.com/repos/${{ github.repository }}/actions/artifacts?name=reports-${LATEST_COMMIT}" | \ + jq -r '.artifacts[0].archive_download_url') + echo "artifact_url=$ARTIFACT_URL" >> $GITHUB_OUTPUT + + - name: Download artifact + if: steps.get_artifact_url.outputs.artifact_url != 'null' + env: + ARTIFACT_URL: ${{ steps.get_artifact_url.outputs.artifact_url }} + GITHUB_TOKEN: ${{ inputs.GITHUB_TOKEN }} + shell: bash + run: | + curl -L -H "Authorization: Bearer $GITHUB_TOKEN" \ + "$ARTIFACT_URL" \ + -o artifact.zip + unzip artifact.zip -d old + cd old + unzip reports.zip + - name: Analyze all packages env: NODE_ENV: ${{ inputs.NODE_ENV }} @@ -78,17 +129,42 @@ runs: REF_NAME: ${{ inputs.REF_NAME }} REMOTE_CONFIG_URL: ${{ inputs.REMOTE_CONFIG_URL }} NODE_OPTIONS: "--max_old_space_size=4096" - run: npm run build:prod && npm run analyze:stats shell: bash + run: npm run build:prod && npm run analyze:stats && npm run analyze:build - - name: Zip all stats.json files + - name: Compare report to master + id: diff + if: steps.get_artifact_url.outputs.artifact_url != 'null' + shell: bash run: | - zip -r stats.zip packages/*/stats.json + DIFF_OUTPUT=$(node .github/workflows/compareReports.js) + echo "diff_output<> $GITHUB_OUTPUT + echo "$DIFF_OUTPUT" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + + - name: Comment on PR with Diff Output + if: github.event_name == 'pull_request' && steps.get_artifact_url.outputs.artifact_url != 'null' + uses: actions/github-script@v5 + env: + DIFF_OUTPUT: ${{ steps.diff.outputs.diff_output }} + with: + script: | + const diffOutput = process.env.DIFF_OUTPUT; + github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + body: `${diffOutput}` + }); + + - name: Zip all report.json files shell: bash + run: | + zip -r reports.zip packages/*/report.json - - name: Upload stats.zip + - name: Upload reports.zip uses: actions/upload-artifact@v4 with: - name: stats-${{ github.sha }} - path: stats.zip - retention-days: 1 + name: reports-${{ github.sha }} + path: reports.zip + retention-days: 5 diff --git a/.github/actions/analyze/compareReports.js b/.github/actions/analyze/compareReports.js new file mode 100644 index 000000000000..e6a69d5c112d --- /dev/null +++ b/.github/actions/analyze/compareReports.js @@ -0,0 +1,122 @@ +const fs = require('fs'); +const path = require('path'); + +function roundUpToDecimals(num, decimals) { + const factor = Math.pow(10, decimals); + return Math.ceil(num * factor) / factor; +} + +function readJsonFile(filePath) { + if (fs.existsSync(filePath)) { + const data = fs.readFileSync(filePath, 'utf-8'); + return JSON.parse(data); + } + return null; +} + +function calculateDiff(oldSize, newSize) { + return newSize - oldSize; +} + +function calculatePercentage(oldSize, newSize) { + if (oldSize === 0) { + return newSize === 0 ? 0 : 100; + } + return ((newSize - oldSize) / oldSize) * 100; +} + +function formatSize(size, roundUp) { + if (size === null) { + return '-'; + } + + const formattedSize = roundUp ? roundUpToDecimals(size / 1024, 2) + 'kb' : (size / 1024).toFixed(2) + 'kb'; + return formattedSize; +} + +const packagesDir = './packages'; +const oldPackagesDir = './old/packages'; +const packages = [...new Set([...fs.readdirSync(packagesDir), ...fs.readdirSync(oldPackagesDir)])]; + +let tableRows = ''; + +for (const pkg of packages) { + const oldReport = readJsonFile(path.join(oldPackagesDir, pkg, 'report.json')); + const newReport = readJsonFile(path.join(packagesDir, pkg, 'report.json')); + + const oldSize = oldReport ? oldReport[0].gzipSize : null; + const newSize = newReport ? newReport[0].gzipSize : null; + let diff = oldSize && newSize ? calculateDiff(oldSize, newSize) : null; + + if (oldSize === null) { + diff = newSize; + } + + if (newSize === null) { + diff = oldSize; + } + + let diffText = '-'; + + if (diff !== 0) { + diffText = diff < 0 ? '-' : '+' + formatSize(diff, true); + } else { + diffText = '+0kb'; + } + + let percentage = oldSize && newSize ? calculatePercentage(oldSize, newSize) : null; + + if (oldSize === null) { + percentage = 100; + } + + if (newSize === null) { + percentage = -100; + } + + let percentageText = '-'; + let percentageEmoji; + + if (percentage === 0) { + percentageEmoji = ''; + } else if (percentage < 0) { + percentageEmoji = '🟢'; // green for decrease + } else if (percentage >= 0 && percentage <= 5) { + percentageEmoji = '🟡'; // yellow for small increase + } else { + percentageEmoji = '🔴'; // red for larger increase + } + + if (percentage !== 0) { + percentageText = percentage.toFixed(2) + '%'; + } else { + percentageText = '0%'; + } + + tableRows += ` + + ${pkg} + ${formatSize(oldSize)} + ${formatSize(newSize)} + ${diffText} + ${percentageText} ${percentageEmoji} + + `.trim(); +} + +console.log( + ` + + + + + + + + + + ${tableRows} + +
packageoldnewdiffpercentage
+`.trim() +); diff --git a/.github/workflows/analyze.yml b/.github/workflows/analyze.yml index f6d6da369b75..63f0ad23b366 100644 --- a/.github/workflows/analyze.yml +++ b/.github/workflows/analyze.yml @@ -7,11 +7,15 @@ on: branches: - master + jobs: build_and_test: name: Analyze Bundle runs-on: Runner_16cores_Deriv-app environment: Preview + permissions: + contents: read + pull-requests: write steps: - name: Checkout uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 @@ -31,6 +35,7 @@ jobs: DATADOG_SESSION_REPLAY_SAMPLE_RATE: ${{ vars.DATADOG_SESSION_REPLAY_SAMPLE_RATE }} DATADOG_SESSION_SAMPLE_RATE: ${{ vars.DATADOG_SESSION_SAMPLE_RATE }} DATADOG_SESSION_SAMPLE_RATE_LOGS: ${{ vars.DATADOG_SESSION_SAMPLE_RATE_LOGS }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GD_API_KEY: ${{ secrets.GD_API_KEY }} GD_APP_ID: ${{ secrets.GD_APP_ID }} GD_CLIENT_ID: ${{ secrets.GD_CLIENT_ID }}