@jsenv/github-pull-request-filesize-impact v2.0.0-alpha.0
github-pull-request-filesize-impact
Monitor pull request impact on file sizes.
Table of contents
- Presentation
- Installation
- How it works
- generateSnapshotFile
- reportSizeImpactIntoGithubPullRequest
- Why merge
Presentation
@jsenv/github-pull-request-filesize-impact comment your pull request on github to see the impact of changes on specific file sizes.
The screenshot below shows how it is integrated to a github pull request.

The comment can be expanded to get more details.

Installation
npm install --save-dev @jsenv/github-pull-request-filesize-impactHow it works
In order to know a given pull request size impact two functions are needed: generateSnapshotFile and reportSizeImpactIntoGithubPullRequest.
generateSnapshotFile generates a .json file saving file size to compare them later. It must be runned twice:
- Once on pull request base branch
- Once on a state where pull request head has been merged into its base.
Then reportSizeImpactIntoGithubPullRequest can be called. It reads these two .json files, compare them and comment the pull request accordingly.
To configure this for your project check Configuration for Github workflow and Configuration outside Github workflow.
Configuration for GitHub workflow
You can see how this can be integrated in a GitHub workflow in .github/workflows/size-impact.yml
And also see several runs for this workflow at https://github.com/jsenv/jsenv-github-pull-request-filesize-impact/actions?workflow=size-impact
Fork issue
Using GitHub workflow has one drawback: When a fork opens a pull request the workflow fails. This is because the workflow is runned inside the forked repository. GITHUB_TOKEN from forked repository is not allowed to post comment inside main repository.
Check https://github.community/t5/GitHub-Actions/Token-permissions-for-forks-once-again/td-p/33839 for more information.
Configuration outside GitHub workflow
generateSnapshotFile needs to be runned twice in a given git state. To setup your git state check Configuration for Github workflow. The exact code is up to you according to your execution environment.
reportSizeImpactIntoGithubPullRequest needs special process.env values and throw if they are missing. These variables are available in a github workflow, when outside you must provide them manually. The code below shows what process.env values must be set.
import { reportSizeImpactIntoGithubPullRequest } from "@jsenv/github-pull-request-filesize-impact"
const githubToken = "github-personnal-access-token"
const githubRepository = "repository-owner/repository-name"
const pullRequestNumber = 1
const pullRequestRef = "pr-name"
process.env.GITHUB_EVENT_NAME = "pull_request"
process.env.GITHUB_REPOSITORY = githubRepository
process.env.GITHUB_REF = `refs/pull/${pullRequestNumber}/merge`
process.env.GITHUB_BASE_REF = "master"
process.env.GITHUB_HEAD_REF = pullRequestRef
process.env.GITHUB_TOKEN = githubToken
reportSizeImpactIntoGithubPullRequest({
projectDirectoryUrl: "file:///Users/directory",
})If you where inside travis you would write process.env.GITHUB_REPOSITORY = process.env.TRAVIS_REPO_SLUG. As documented in https://docs.travis-ci.com/user/environment-variables/#default-environment-variables
Also be sure githubToken has the right to read/write comments on issues.
generateSnapshotFile
generateSnapshotFile is an async function analysing file sizes per directory and saving the result into a json file.
import { generateSnapshotFile } from "@jsenv/github-pull-request-filesize-impact"
await generateSnapshotFile({
projectDirectoryUrl: "file:///directory",
trackingConfig: {
dist: {
"./dist/**/*.js": true,
},
},
snapshotFileRelativeUrl: "./size-snapshot.json",
})— source code at src/generateSnapshotFile.js.
projectDirectoryUrl
projectDirectoryUrl parameter is a string leading to your project root directory. This parameter is required.
logLevel
logLevel parameter controls verbosity of logs during the function execution.
The list of available logLevel values can be found on @jsenv/logger documentation
trackingConfig
trackingConfig parameter is an object used to configure group of files you want to track. This parameter is optional with a default value exported in src/jsenvTrackingConfig.js
trackingConfig keys are group names that will appear in the generated comment.
trackingConfig values are specifierMetaMap as documented in https://github.com/jsenv/jsenv-url-meta#normalizespecifiermetamap.
For every group you track there will be a corresponding line in the generated pull request comment as visible in docs/comment-example.md
For example you can create two groups like this:
const trackingConfig = {
whatever: {
"./dist/whatever/**/*.js": true,
},
dist: {
"./dist/**/*.js": true,
"./dist/whatever/**/*.js": false,
},
}And the generated comment will have two expandable section.
transformations
transformations parameter is an object used to transform files content before computing their size. This parameter is optional with a default value of { none: (buffer) => bufer }.
You can use this parameter to track file size after gzip compression.
import { generateSnapshotFile, none, gzip } from "@jsenv/github-pull-request-filesize-impact"
await generateSnapshotFile({
projectDirectoryUrl: "file:///directory",
transformations: { none, gzip },
})And the pull request comment now contains gzip size. Check docs/comment-example.md#introduce-gzip to see how it looks like.
You can enable none, gzip and brotli compression this way. transformations can be used to add custom transformations.
import { none, gzip } from "@jsenv/github-pull-request-filesize-impact"
const transformations = {
none,
trim: (buffer) => String(buffer).trim(),
}manifestFilePattern
manifestFilePattern parameter is a string controlling if a manifest json file will be taken into account when generating snapshot. The parameter also control the name of the manifest file. This parameter is optional with a default value of ./**/manifest.json.
Manifest where introduced by webpack in https://github.com/danethurber/webpack-manifest-plugin. There is the equivalent for rollup at https://github.com/shuizhongyueming/rollup-plugin-output-manifest.
The concept is to be able to remap generated file like file.4798774987w97er984798.js back to file.js.
Without this, comparison of directories accross branches would consider generated files as always new because of their dynamic names.
reportSizeImpactIntoGithubPullRequest
reportSizeImpactIntoGithubPullRequest is an async function comparing two directory snapshots and commenting a github pull request with the comparison result.
import { reportSizeImpactIntoGithubPullRequest } from "@jsenv/github-pull-request-filesize-impact"
await reportSizeImpactIntoGithubPullRequest({
projectDirectoryUrl: "file:///directory",
baseSnapshotFileRelativeUrl: "../snapshot.base.json",
headSnapshotFileRelativeUrl: "../snapshot.head.json",
logLevel: "info",
generatedByLink: true,
})— source code at src/reportSizeImpactIntoGithubPullRequest.js.
baseSnapshotFileRelativeUrl
baseSnapshotFileRelativeUrl parameter is a string leading to the base snapshot file. This parameter is required.
headSnapshotFileRelativeUrl
headSnapshotFileRelativeUrl parameter is a string leading to the head snapshot file. This parameter is required.
commentSections
commentSections parameter is an object controlling which comment sections are enabled and their order. This parameter is optionnal and enable groupImpact, fileByFileImpact and cacheImpact section in that order. Check docs/comment-example.md#basic-example to see the comment sections.
You can control sections order because it follow commentSections keys order. You can also control which section are enabled at all. For instance docs/comment-example.md#group-disabled-filebyfile-enabled-cache-disabled can be generated by passing commentSections below.
const commentSections = { fileByFileImpact: true }This parameter could be an array. Using an object was decided in case each section becomes configurable in the future.
generatedByLink
generatedByLink parameter controls if pull request comment contains a generated by message. This parameter is optionnal and enabled by default. This parameter allows someone to understand where the pull request message comes from.
formatSize
formatSize parameter controls the display of file size. This parameter is optionnal, the default value doing an english formatting of a number. Check source code if you want to pass a custom function.
Why merge
As documented in How it works generateSnapshotFile must be called in a state where the pull request is merged into its target. This part explains why it's needed.
To know impacts of a pull request changes on a given branch, these changes must be on the branch. To understand why we will simulate what happens starting from a git tree where:
- There is a
masterbranch mebranch is one commit ahead ofmasterotherbranch is one commit ahead ofmaster- A pull request wants to merge
meintomaster
In upcoming "schemas", a capital letter represent a commit.
Initial git tree
┌───D─── other (A+D)
│
───A─────── master (A)
│
└───B─── me (A+B)Now other gets merged into master
Git tree after merging other branch
┌───D───┐ other (A+D)
│ │
───A───────D─── master (A+D)
│
└───B──── me (A+B)Now we push a commit to me
Git tree after pushing into me branch
┌───D───┐ other (A+D)
│ │
───A───────D─── master (A+D)
│
└───B───E─── me (A+B+E)In this state:
meis 1 commit behindmasterand 2 commits aheadPull request wants to merge
B,Eand does not containD.- merging pull request means adding
B+Eintomaster. Master would becomeA+D+B+E.Depending how pull request gets merged order may differ but that's not important for this demonstration.
To compute the actual impact of merging me into master we must simulate the merge. Let's create a merge branch with this state.
Git tree after creating merge branch
┌───D───┐ other (A+D)
│ │
───A───────D──── master (A+D)
│ │
│ └───┬─── merge (A+D+B+E)
│ │
└───B───E───┘ me (A+B+E)If D changes overlaps with E changes, impact is analysed after these changes are merged.
Moreover D changes that are not in B or E are ignored thanks to diff between merge and master.
merge = A+D+B+E
master = A+D
merge - master = B+E6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago