-
Notifications
You must be signed in to change notification settings - Fork 63
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #881 from ZeLonewolf/zlw-enhanced-stats
Move PR preview to Checks tab and add statistics
- Loading branch information
Showing
6 changed files
with
384 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,12 +12,31 @@ permissions: | |
pages: write | ||
pull-requests: write | ||
id-token: write | ||
checks: write | ||
concurrency: preview-${{ github.ref }} | ||
jobs: | ||
deploy-preview: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Checkout 🛎️ | ||
- name: Checkout Main Branch 🛎️ | ||
uses: actions/checkout@v3 | ||
with: | ||
ref: main | ||
- name: Install and Build Main Branch 🔧 | ||
run: | | ||
npm ci --include=dev | ||
npm run build | ||
npm run style | ||
npm run shields | ||
cp src/configs/config.aws.js src/config.js | ||
- name: Capture main branch usage statistics | ||
id: main-stats | ||
run: | | ||
MAIN_STATS=$(node scripts/stats.js -j) | ||
echo "MAIN_STATS<<EOF" >> $GITHUB_ENV | ||
echo -e "$MAIN_STATS" >> $GITHUB_ENV | ||
echo "EOF" >> $GITHUB_ENV | ||
- name: Checkout PR Branch 🛎️ | ||
uses: actions/checkout@v3 | ||
- name: Use Node.js 18.16.1 | ||
uses: actions/setup-node@v3 | ||
|
@@ -42,6 +61,30 @@ jobs: | |
npm run style | ||
npm run shields | ||
cp src/configs/config.aws.js src/config.js | ||
- name: Capture PR branch usage statistics | ||
id: pr-stats | ||
run: | | ||
PR_STATS=$(node scripts/stats.js -j) | ||
echo "PR_STATS<<EOF" >> $GITHUB_ENV | ||
echo -e "$PR_STATS" >> $GITHUB_ENV | ||
echo "EOF" >> $GITHUB_ENV | ||
- name: Compare Stats | ||
id: compare-stats | ||
run: | | ||
mkdir stats | ||
echo '${{ env.MAIN_STATS }}' | ||
echo '${{ env.PR_STATS }}' | ||
npm exec ts-node scripts/stats_compare '${{ env.MAIN_STATS }}' '${{ env.PR_STATS }}' > stats/stats-difference.md | ||
- name: Print Stats to GitHub Checks | ||
uses: LouisBrunner/[email protected] | ||
if: always() | ||
with: | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
name: Performance Metrics | ||
conclusion: neutral | ||
output: | | ||
{"summary":"Style size changes introduced by this PR"} | ||
output_text_description_file: stats/stats-difference.md | ||
- name: Upload Build artifact | ||
uses: actions/upload-artifact@v3 | ||
with: | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
name: Generate PR Preview Check | ||
on: | ||
pull_request: | ||
branches: [main] | ||
types: | ||
- opened | ||
- reopened | ||
- synchronize | ||
workflow_dispatch: | ||
permissions: | ||
checks: write | ||
jobs: | ||
deploy-preview: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Wait for PR Preview Upload (1x Sprite) | ||
uses: cygnetdigital/[email protected] | ||
with: | ||
url: "https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/sprites/sprite.png" | ||
responseCode: "200" | ||
timeout: 120000 | ||
interval: 500 | ||
- name: Wait for PR Preview Upload (2x Sprite) | ||
uses: cygnetdigital/[email protected] | ||
with: | ||
url: "https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/sprites/[email protected]" | ||
responseCode: "200" | ||
timeout: 120000 | ||
interval: 500 | ||
- name: Generate Preview text | ||
run: | | ||
echo "## PR Preview: | ||
* [Map](https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/) | ||
* [Shield Test](https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/shieldtest.html) | ||
* [style.json](https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/style.json) | ||
* [shields.json](https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/shields.json) | ||
* [taginfo.json](https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/taginfo.json) | ||
## Sprite Sheets: | ||
<img src="https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/sprites/sprite.png" /> | ||
<img src="https://preview.ourmap.us/pr/${{ github.event.pull_request.number }}/sprites/[email protected]" /> | ||
" > pr_preview.md | ||
- name: Print Preview Links to GitHub Checks | ||
uses: LouisBrunner/[email protected] | ||
if: always() | ||
with: | ||
token: ${{ secrets.GITHUB_TOKEN }} | ||
name: PR Preview | ||
conclusion: neutral | ||
output: | | ||
{"summary":"Preview map changes introduced by this PR"} | ||
output_text_description_file: pr_preview.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,20 +72,3 @@ jobs: | |
AWS_REGION: ${{ secrets.AWS_REGION }} | ||
SOURCE_DIR: "./dist" | ||
DEST_DIR: pr/${{ env.PR_NUM }} | ||
- name: Comment Pull Request | ||
uses: thollander/[email protected] | ||
with: | ||
message: | | ||
PR Preview: | ||
* [Map](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/) | ||
* [Shield Test](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/shieldtest.html) | ||
* [style.json](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/style.json) | ||
* [shields.json](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/shields.json) | ||
* [taginfo.json](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/taginfo.json) | ||
Sprite Sheets: | ||
![Sprites 1x](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/sprites/sprite.png) | ||
![Sprites 2x](https://preview.ourmap.us/pr/${{ env.PR_NUM }}/sprites/[email protected]) | ||
comment_tag: pr_preview | ||
pr_number: ${{ env.PR_NUM }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
/** | ||
* Calculates the difference between two objects by comparing their properties. | ||
* If a property value is an object, it recursively calls itself to calculate the difference. | ||
* Positive numbers for a property means that property is greater in object2 than object1. | ||
* @param {Object|null} object1 - The first object to compare. | ||
* @param {Object|null} object2 - The second object to compare. | ||
* @returns {Object} - An object containing the differences between object2 and object1. | ||
*/ | ||
export function calculateDifference( | ||
object1: object | null, | ||
object2: object | null | ||
): object { | ||
// If one object exists and the other doesn't, return the difference | ||
if (object1 === null && object2 !== null) { | ||
return object2; | ||
} else if (object2 === null && object1 !== null) { | ||
return negate(object1); | ||
} | ||
|
||
const difference = {}; | ||
|
||
// Iterate through each property in object1 | ||
for (const key in object1) { | ||
if (typeof object1[key] === "object" && typeof object2![key] === "object") { | ||
// Recursively calculate the difference for nested objects | ||
difference[key] = calculateDifference(object1[key], object2![key]); | ||
} else if ( | ||
typeof object1[key] === "number" && | ||
typeof object2![key] === "number" | ||
) { | ||
// Calculate the difference for numeric properties | ||
difference[key] = object2![key] - object1[key]; | ||
} else { | ||
// If the property exists in object1 but not in object2, include it in the result | ||
difference[key] = negate(object1![key]); | ||
} | ||
} | ||
|
||
// Include properties that exist in object2 but not in object1 | ||
for (const key in object2!) { | ||
if (!(key in object1!)) { | ||
difference[key] = object2[key]; | ||
} | ||
} | ||
|
||
return difference; | ||
} | ||
|
||
/** | ||
* Negate all numeric properties of this object. | ||
* @param {Object} object - The object to process. | ||
*/ | ||
function negate(object: object) { | ||
if (typeof object === "number") { | ||
return -object; | ||
} | ||
|
||
// Create a new object to store the result | ||
const result = {}; | ||
|
||
for (const key in object) { | ||
if (typeof object[key] === "object" && object[key] !== null) { | ||
// If the property value is an object (and not null), recursively process it | ||
result[key] = negate(object[key]); | ||
} else if (typeof object[key] === "number") { | ||
// If the property value is a number, multiply it by the multiplier | ||
result[key] = -object[key]; | ||
} | ||
} | ||
|
||
return result; | ||
} | ||
|
||
// "| | main | this PR | change | % change |", | ||
export type ComparedStats = { | ||
name: string; | ||
beforeValue: number | null; | ||
afterValue: number | null; | ||
change: number; | ||
pctChange: number | null; | ||
}; | ||
|
||
export function statsComparisonRow( | ||
name: string, | ||
val1: number | null, | ||
val2: number | null, | ||
change: number | ||
): ComparedStats { | ||
let pctChange: number | null; | ||
|
||
if (val1 !== null) { | ||
if (val2 !== null) { | ||
pctChange = change / val1; | ||
} else { | ||
pctChange = -1; | ||
} | ||
} else { | ||
pctChange = null; | ||
} | ||
|
||
return { | ||
name, | ||
beforeValue: val1, | ||
afterValue: val2, | ||
change, | ||
pctChange, | ||
}; | ||
} | ||
|
||
const pctFormat: Intl.NumberFormatOptions = { | ||
style: "percent", | ||
minimumFractionDigits: 1, | ||
maximumFractionDigits: 1, | ||
signDisplay: "exceptZero", | ||
}; | ||
|
||
function naLocString(val: number | null) { | ||
return val !== null ? val.toLocaleString("en") : "N/A"; | ||
} | ||
|
||
/** | ||
* produce a markdown row of statistics comparison | ||
*/ | ||
export function mdStringValues(stats: ComparedStats): string[] { | ||
const beforeValueStr = naLocString(stats.beforeValue); | ||
const afterValueStr = naLocString(stats.afterValue); | ||
const changeStr = naLocString(stats.change); | ||
const pctChangeStr = | ||
stats.pctChange !== null | ||
? stats.pctChange.toLocaleString("en", pctFormat) | ||
: "N/A"; | ||
|
||
return [stats.name, beforeValueStr, afterValueStr, changeStr, pctChangeStr]; | ||
} | ||
|
||
export function mdCompareRow( | ||
name: string, | ||
val1: number | null, | ||
val2: number | null, | ||
change: number | ||
): string { | ||
return mdStringValues(statsComparisonRow(name, val1, val2, change)).join( | ||
" | " | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import { calculateDifference, mdCompareRow } from "./object_compare"; | ||
|
||
const stats1 = JSON.parse(process.argv[2]); | ||
const stats2 = JSON.parse(process.argv[3]); | ||
|
||
const difference = calculateDifference(stats1, stats2); | ||
|
||
const diffHeaderRow = [ | ||
"| | main | this PR | change | % change |", | ||
"|-----------|--------------:|-------------:|----------------:|----------------:|", | ||
]; | ||
|
||
/** | ||
* Show comparison of overall aggregate statistics between this PR and previous | ||
*/ | ||
|
||
const layersRow = mdCompareRow( | ||
"Layers", | ||
stats1.layerCount, | ||
stats2.layerCount, | ||
difference.layerCount | ||
); | ||
|
||
const sizeRow = mdCompareRow( | ||
"Size (b)", | ||
stats1.styleSize, | ||
stats2.styleSize, | ||
difference.styleSize | ||
); | ||
|
||
printTable("Style size statistics", [layersRow, sizeRow]); | ||
|
||
/** | ||
* Show comparison of the number of layers in each group before and after | ||
*/ | ||
|
||
const layerCountChangeRows = []; | ||
|
||
for (const layer in difference.layerGroup) { | ||
layerCountChangeRows.push( | ||
mdCompareRow( | ||
layer, | ||
stats1.layerGroup[layer]?.layerCount, | ||
stats2.layerGroup[layer]?.layerCount, | ||
difference.layerGroup[layer]?.layerCount | ||
) | ||
); | ||
} | ||
|
||
printTable("Layer count comparison", layerCountChangeRows); | ||
|
||
/** | ||
* Show comparison of the aggregate size of layers in each group before and after | ||
*/ | ||
|
||
const layerSizeChangeRows = []; | ||
|
||
for (const layer in difference.layerGroup) { | ||
layerSizeChangeRows.push( | ||
mdCompareRow( | ||
layer, | ||
stats1.layerGroup[layer]?.size, | ||
stats2.layerGroup[layer]?.size, | ||
difference.layerGroup[layer]?.size | ||
) | ||
); | ||
} | ||
|
||
printTable("Layer size comparison", layerSizeChangeRows); | ||
|
||
function printTable(headingText, rows) { | ||
const table = [...diffHeaderRow, ...rows].join("\n"); | ||
const text = ` | ||
## ${headingText} | ||
${table} | ||
`; | ||
|
||
console.log(text); | ||
} |
Oops, something went wrong.