From 00a8c23ef4bc12b37ddbc00ba9ae4357b7727d69 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Tue, 20 May 2025 11:52:35 +0200 Subject: [PATCH 01/16] ensure benchmarkBaseDir is taken into account --- src/write.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/write.ts b/src/write.ts index 43e7492d..21d04164 100644 --- a/src/write.ts +++ b/src/write.ts @@ -108,16 +108,22 @@ function getComparePathAndSha(): [string, string] | undefined { return [comparePath, sha]; } -async function getPrevBench(benchName: string, config: Config): Promise { +async function getPrevBench(config: Config): Promise { // TODO: error handling const comparePathAndSha = getComparePathAndSha(); if (!comparePathAndSha) { return null; } + let benchmarkBaseDir = './'; + + const { githubToken, skipFetchGhPages, ghRepository, basePath, name } = config; + if (githubToken && !skipFetchGhPages && ghRepository) { + benchmarkBaseDir = './benchmark-data-repository'; + } const [comparePath, compareSha] = comparePathAndSha; - const data = await loadDataJson(path.join(config.basePath, comparePath)); + const data = await loadDataJson(path.join(benchmarkBaseDir, basePath, comparePath)); - const suite = data.entries[benchName]; + const suite = data.entries[name]; if (suite === undefined) { return null; @@ -632,7 +638,7 @@ async function writeBenchmarkToGitHubPages(bench: Benchmark, config: Config) { } try { await writeBenchmarkToGitHubPagesWithRetry(bench, config, 10); - return; + return await getPrevBench(config); } catch (e) { console.warn(e); throw e; @@ -678,8 +684,7 @@ export async function writeBenchmark(bench: Benchmark, config: Config) { prevBench = await writeBenchmarkToExternalJson(bench, externalDataJsonPath, config); } else { console.log('Writing to GitHub Pages'); - prevBench = await getPrevBench(name, config); - await writeBenchmarkToGitHubPages(bench, config); + prevBench = await writeBenchmarkToGitHubPages(bench, config); } // Put this after `git push` for reducing possibility to get conflict on push. Since sending From 46637f482d62585aa23d15a8a87aeb6e8d18d7a8 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 10:40:55 +0200 Subject: [PATCH 02/16] add tests and test data for base path with ghRepository --- .../data-dir/original_data.json | 2 +- .../data-dir/pr/original_data.json | 23 ++++++ test/write.spec.ts | 79 +++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 test/data/write/benchmark-data-repository/data-dir/pr/original_data.json diff --git a/test/data/write/benchmark-data-repository/data-dir/original_data.json b/test/data/write/benchmark-data-repository/data-dir/original_data.json index 271fc949..e0ce3b2b 100644 --- a/test/data/write/benchmark-data-repository/data-dir/original_data.json +++ b/test/data/write/benchmark-data-repository/data-dir/original_data.json @@ -16,7 +16,7 @@ }, "date": 1574927127603, "tool": "cargo", - "benches": [{ "name": "bench_fib_10", "range": "± 20", "unit": "ns/iter", "value": 100 }] + "benches": [{ "name": "bench_fib_10", "range": "± 20", "unit": "ns/iter", "value": 100, "os": "ubuntu-latest" }] } ] } diff --git a/test/data/write/benchmark-data-repository/data-dir/pr/original_data.json b/test/data/write/benchmark-data-repository/data-dir/pr/original_data.json new file mode 100644 index 00000000..d9d7bae0 --- /dev/null +++ b/test/data/write/benchmark-data-repository/data-dir/pr/original_data.json @@ -0,0 +1,23 @@ +{ + "lastUpdate": 1574927128603, + "repoUrl": "https://github.com/user/repo", + "entries": { + "Test benchmark": [ + { + "commit": { + "author": { "email": "dummy@example.com", "name": "User", "username": "user" }, + "committer": { "email": "dummy@example.com", "name": "User", "username": "user" }, + "distinct": false, + "id": "pr commit id", + "message": "dummy message", + "timestamp": "dummy stamp", + "tree_id": "dummy tree id", + "url": "https://github.com/user/repo/commit/pr commit id" + }, + "date": 1574927127604, + "tool": "cargo", + "benches": [{ "name": "bench_fib_10", "range": "± 20", "unit": "ns/iter", "value": 500, "os": "ubuntu-latest" }] + } + ] + } +} diff --git a/test/write.spec.ts b/test/write.spec.ts index 9e64bfe9..472994fd 100644 --- a/test/write.spec.ts +++ b/test/write.spec.ts @@ -920,6 +920,7 @@ describe.each(['https://github.com', 'https://github.enterprise.corp'])('writeBe path.join('with-index-html', 'data.json'), path.join('benchmark-data-repository', 'data-dir', 'data.json'), path.join('benchmark-data-repository', 'data-dir', 'listing.json'), + path.join('benchmark-data-repository', 'data-dir', 'pr', '10.json'), path.join('benchmark-data-repository', 'data-dir', 'refs'), path.join('benchmark-data-repository', 'data-dir', 'index.html'), path.join('benchmark-data-repository', 'new-data-dir'), @@ -1369,6 +1370,57 @@ describe.each(['https://github.com', 'https://github.enterprise.corp'])('writeBe `This comment was automatically generated by [workflow](${serverUrl}/user/repo/actions?query=workflow%3AWorkflow%20name) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).`, ], }, + { + it: 'raises an alert when exceeding threshold 2.0 for push event with gh repository and base path', + config: { ...defaultCfg, ghRepository: 'https://github.com/user/other-repo' }, + added: { + commit: commit('current commit id'), + date: lastUpdate, + benches: [bench('bench_fib_10', 500), bench('bench_fib_20', 25000)], // Exceeds 2.0 threshold + bigger_is_better: false, + }, + gitServerUrl: serverUrl, + gitHistory: gitHistory(), + expectedDataBaseDirectory: 'benchmark-data-repository', + error: [ + '# :warning: **Performance Alert** :warning:', + '', + "Possible performance regression was detected for benchmark **'Test benchmark'**.", + 'Benchmark result of this commit is worse than the previous benchmark result exceeding threshold `2`.', + '', + '| Benchmark suite | Current: current commit id | Previous: prev commit id | Ratio |', + '|-|-|-|-|', + '| `bench_fib_10` | `500` ns/iter (`± 20`) | `100` ns/iter (`± 20`) | `5` |', + '', + `This comment was automatically generated by [workflow](${serverUrl}/user/repo/actions?query=workflow%3AWorkflow%20name) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).`, + ], + }, + { + it: 'raises an alert when exceeding threshold 2.0 for merge group event with gh repository and base path', + config: { ...defaultCfg, ghRepository: 'https://github.com/user/other-repo' }, + payloadType: PayloadType.MergeGroup, + added: { + commit: commit('current commit id'), + date: lastUpdate, + benches: [bench('bench_fib_10', 500), bench('bench_fib_20', 25000)], // Exceeds 2.0 threshold + bigger_is_better: false, + }, + gitServerUrl: serverUrl, + gitHistory: gitHistory(), + expectedDataBaseDirectory: 'benchmark-data-repository', + error: [ + '# :warning: **Performance Alert** :warning:', + '', + "Possible performance regression was detected for benchmark **'Test benchmark'**.", + 'Benchmark result of this commit is worse than the previous benchmark result exceeding threshold `2`.', + '', + '| Benchmark suite | Current: current commit id | Previous: prev commit id | Ratio |', + '|-|-|-|-|', + '| `bench_fib_10` | `500` ns/iter (`± 20`) | `100` ns/iter (`± 20`) | `5` |', + '', + `This comment was automatically generated by [workflow](${serverUrl}/user/repo/actions?query=workflow%3AWorkflow%20name) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).`, + ], + }, { it: 'raises an alert when exceeding threshold 2.0 for merge group event', config: defaultCfg, @@ -1419,6 +1471,32 @@ describe.each(['https://github.com', 'https://github.enterprise.corp'])('writeBe `This comment was automatically generated by [workflow](${serverUrl}/user/repo/actions?query=workflow%3AWorkflow%20name) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).`, ], }, + { + it: 'raises an alert when exceeding threshold 2.0 for pull request event with gh-repository and base path', + config: { ...defaultCfg, ghRepository: 'https://github.com/user/other-repo' }, + payloadType: PayloadType.PullRequest, + added: { + commit: commit('current commit id'), + date: lastUpdate, + benches: [bench('bench_fib_10', 500), bench('bench_fib_20', 25000)], // Exceeds 2.0 threshold + bigger_is_better: false, + }, + gitServerUrl: serverUrl, + gitHistory: gitHistory(), + expectedDataBaseDirectory: 'benchmark-data-repository', + error: [ + '# :warning: **Performance Alert** :warning:', + '', + "Possible performance regression was detected for benchmark **'Test benchmark'**.", + 'Benchmark result of this commit is worse than the previous benchmark result exceeding threshold `2`.', + '', + '| Benchmark suite | Current: current commit id | Previous: prev commit id | Ratio |', + '|-|-|-|-|', + '| `bench_fib_10` | `500` ns/iter (`± 20`) | `100` ns/iter (`± 20`) | `5` |', + '', + `This comment was automatically generated by [workflow](${serverUrl}/user/repo/actions?query=workflow%3AWorkflow%20name) using [github-action-benchmark](https://github.com/marketplace/actions/continuous-benchmark).`, + ], + }, { it: 'writes data for pull request event', config: defaultCfg, @@ -1455,6 +1533,7 @@ describe.each(['https://github.com', 'https://github.enterprise.corp'])('writeBe const originalDataJson = path.join(dataDirPath, 'original_data.json'); const indexHtml = path.join(dataDirPath, 'index.html'); + // copy data to append to/compare against if (await isFile(originalDataJson)) { await fs.mkdir(path.dirname(dataJs), { recursive: true }); await fs.copyFile(originalDataJson, dataJs); From 8647a85df8734346162c2eff08632e1882c8efc6 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 10:48:52 +0200 Subject: [PATCH 03/16] return `prevBench` from `writeBenchmarkToGitHubPages()` --- src/write.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/write.ts b/src/write.ts index 21d04164..126d991f 100644 --- a/src/write.ts +++ b/src/write.ts @@ -108,18 +108,13 @@ function getComparePathAndSha(): [string, string] | undefined { return [comparePath, sha]; } -async function getPrevBench(config: Config): Promise { +async function getPrevBench(benchmarkBaseDir: string, config: Config): Promise { // TODO: error handling const comparePathAndSha = getComparePathAndSha(); if (!comparePathAndSha) { return null; } - let benchmarkBaseDir = './'; - - const { githubToken, skipFetchGhPages, ghRepository, basePath, name } = config; - if (githubToken && !skipFetchGhPages && ghRepository) { - benchmarkBaseDir = './benchmark-data-repository'; - } + const { basePath, name } = config; const [comparePath, compareSha] = comparePathAndSha; const data = await loadDataJson(path.join(benchmarkBaseDir, basePath, comparePath)); @@ -498,7 +493,11 @@ function isRemoteRejectedError(err: unknown): err is Error { return false; } -async function writeBenchmarkToGitHubPagesWithRetry(bench: Benchmark, config: Config, retry: number) { +async function writeBenchmarkToGitHubPagesWithRetry( + bench: Benchmark, + config: Config, + retry: number, +): Promise { const { name, ghPagesBranch, @@ -552,6 +551,7 @@ async function writeBenchmarkToGitHubPagesWithRetry(bench: Benchmark, config: Co githubToken: !!githubToken, }); } + const prevBench = await getPrevBench(benchmarkBaseDir, config); // `benchmarkDataDirPath` is an absolute path at this stage, // so we need to convert it to relative to be able to prepend the `benchmarkBaseDir` @@ -561,7 +561,7 @@ async function writeBenchmarkToGitHubPagesWithRetry(bench: Benchmark, config: Co // sometimes we don't want to push the benchmark data (e.g. on the merge queue). // in this case, skip the below. console.warn('No data path could be built'); - return; + return prevBench; } let dataRelativePath = getDataPath(dataEntry); @@ -612,8 +612,7 @@ async function writeBenchmarkToGitHubPagesWithRetry(bench: Benchmark, config: Co core.warning( `Retrying to generate a commit and push to remote ${ghPagesBranch} with retry count ${retry}...`, ); - await writeBenchmarkToGitHubPagesWithRetry(bench, config, retry - 1); // Recursively retry - return; + return await writeBenchmarkToGitHubPagesWithRetry(bench, config, retry - 1); // Recursively retry } else { core.warning(`Failed to add benchmark data to '${name}' data: ${JSON.stringify(bench)}`); throw new Error( @@ -626,9 +625,11 @@ async function writeBenchmarkToGitHubPagesWithRetry(bench: Benchmark, config: Co `Auto-push to ${ghPagesBranch} is skipped because it requires both 'github-token' and 'auto-push' inputs`, ); } + + return prevBench; } -async function writeBenchmarkToGitHubPages(bench: Benchmark, config: Config) { +async function writeBenchmarkToGitHubPages(bench: Benchmark, config: Config): Promise { const { ghPagesBranch, skipFetchGhPages, ghRepository, githubToken } = config; if (!ghRepository) { if (!skipFetchGhPages) { @@ -637,8 +638,7 @@ async function writeBenchmarkToGitHubPages(bench: Benchmark, config: Config) { await git.cmd([], 'switch', ghPagesBranch); } try { - await writeBenchmarkToGitHubPagesWithRetry(bench, config, 10); - return await getPrevBench(config); + return await writeBenchmarkToGitHubPagesWithRetry(bench, config, 10); } catch (e) { console.warn(e); throw e; From e5d6fac60a98942b33f659920a8aa3f7574148a1 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 10:50:21 +0200 Subject: [PATCH 04/16] rename `benchmarkBaseDir` to `benchmarkRepoDir` --- src/write.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/write.ts b/src/write.ts index 126d991f..6ba24e43 100644 --- a/src/write.ts +++ b/src/write.ts @@ -108,7 +108,7 @@ function getComparePathAndSha(): [string, string] | undefined { return [comparePath, sha]; } -async function getPrevBench(benchmarkBaseDir: string, config: Config): Promise { +async function getPrevBench(benchmarkRepoDir: string, config: Config): Promise { // TODO: error handling const comparePathAndSha = getComparePathAndSha(); if (!comparePathAndSha) { @@ -116,7 +116,7 @@ async function getPrevBench(benchmarkBaseDir: string, config: Config): Promise { - await io.rmRF(benchmarkBaseDir); + await io.rmRF(benchmarkRepoDir); }); - extraGitArguments = [`--work-tree=${benchmarkBaseDir}`, `--git-dir=${benchmarkBaseDir}/.git`]; + extraGitArguments = [`--work-tree=${benchmarkRepoDir}`, `--git-dir=${benchmarkRepoDir}/.git`]; await git.checkout(ghPagesBranch, extraGitArguments); } else if (!skipFetchGhPages && (isPrivateRepo === false || githubToken)) { await git.pull(githubToken, ghPagesBranch); @@ -551,10 +551,10 @@ async function writeBenchmarkToGitHubPagesWithRetry( githubToken: !!githubToken, }); } - const prevBench = await getPrevBench(benchmarkBaseDir, config); + const prevBench = await getPrevBench(benchmarkRepoDir, config); // `benchmarkDataDirPath` is an absolute path at this stage, - // so we need to convert it to relative to be able to prepend the `benchmarkBaseDir` + // so we need to convert it to relative to be able to prepend the `benchmarkRepoDir` const dataEntry = getDataEntry(); if (!dataEntry) { @@ -566,7 +566,7 @@ async function writeBenchmarkToGitHubPagesWithRetry( let dataRelativePath = getDataPath(dataEntry); dataRelativePath = path.join(basePath, dataRelativePath); - const dataPath = path.join(benchmarkBaseDir, dataRelativePath); + const dataPath = path.join(benchmarkRepoDir, dataRelativePath); await io.mkdirP(path.dirname(dataPath)); @@ -577,13 +577,13 @@ async function writeBenchmarkToGitHubPagesWithRetry( // handle the listing const listingPath = path.join(basePath, 'listing.json'); - const listing = await loadListing(benchmarkBaseDir, listingPath); + const listing = await loadListing(benchmarkRepoDir, listingPath); - await updateAndStoreListing(benchmarkBaseDir, listingPath, listing, dataEntry); + await updateAndStoreListing(benchmarkRepoDir, listingPath, listing, dataEntry); await git.cmd(extraGitArguments, 'add', listingPath); await git.cmd(extraGitArguments, 'add', dataRelativePath); - await addIndexHtmlIfNeeded(extraGitArguments, benchmarkBaseDir, path.join(basePath, 'index.html')); + await addIndexHtmlIfNeeded(extraGitArguments, benchmarkRepoDir, path.join(basePath, 'index.html')); await git.cmd(extraGitArguments, 'commit', '-m', `add ${name} benchmark result for ${bench.commit.id}`); if (githubToken && autoPush) { From 98f5e9de8308bb8d7ae18f24c55ce582f5b3fa25 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 11:39:48 +0200 Subject: [PATCH 05/16] checklist select and deselect all --- src/default_index.html | 74 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 69 insertions(+), 5 deletions(-) diff --git a/src/default_index.html b/src/default_index.html index 50fce36f..dc3e3f27 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -68,10 +68,19 @@ display: flex; gap: 25px; } + .checklist { + padding-right: 10px; + } .checklist-title { font-weight: bold; text-align: center; } + .select-all { + background: grey; + color: white; + margin-right: 2px; + width: 100%; + } .benchmark-set { margin: 8px 0; width: 100%; @@ -393,8 +402,36 @@ elem.setAttribute(key.replace(' ', ''), value); }); } + function updateSelectAllStatus(add, selectAll, max) { + let numSelected = selectAll.getAttribute('num-selected'); + numSelected = numSelected ? Number(numSelected) : 0; + numSelected = numSelected ? numSelected : 0; + + if (add) { + numSelected += 1; + } else if (!add && numSelected === 0) { + numSelected = 0; + } else { + numSelected -= 1; + } + + selectAll.setAttribute('num-selected', numSelected); + + // set the state + if (numSelected === 0) { + selectAll.checked = false; + selectAll.indeterminate = false; + } else if (numSelected === max) { + selectAll.checked = true; + selectAll.indeterminate = false; + } else { + selectAll.checked = false; + selectAll.indeterminate = true; + } + } function setChartHiddenStatus(hide, key, value) { + value = value ? value : 'undefined'; const charts = document.getElementsByClassName('benchmark-graphs'); const filteredCharts = Array.from(charts).filter((chart) => { const chartValue = chart.getAttribute(key.replace(' ', '')); @@ -448,7 +485,37 @@ title.textContent = key; checklist.appendChild(title); + // select all / deselect all + const selectAllWrapper = document.createElement('div'); + selectAllWrapper.className = 'select-all'; + + const selectAll = document.createElement('input'); + selectAll.setAttribute('id', `${key}-select-all`); + selectAll.setAttribute('type', 'checkbox'); + const checkboxId = `${key}-select-all-checkbox`; + const selectAllLabel = document.createElement('label'); + selectAllLabel.setAttribute('for', checkboxId); + selectAllLabel.textContent = 'select all'; + selectAllWrapper.appendChild(selectAll); + selectAllWrapper.appendChild(selectAllLabel); + checklist.appendChild(selectAllWrapper); + + selectAll.addEventListener('change', function () { + values.forEach((value) => { + const checkbox = document.getElementById(`${key}-${value}`); + checkbox.checked = this.checked; + + // hide the chart + setChartHiddenStatus(!this.checked, key, value); + }); + const numSelected = this.checked ? values.length : 0; + selectAll.setAttribute('num-selected', numSelected); + }); + values.forEach((value) => { + // select all + updateSelectAllStatus(true, selectAll, values.length); + // generate the filter interface from the unique values const wrapper = document.createElement('div'); wrapper.className = 'checklist-entry'; @@ -476,11 +543,8 @@ checkBox.addEventListener('change', function () { const key = this.getAttribute('key'); const value = this.getAttribute('value'); - if (this.checked) { - setChartHiddenStatus(false, key, value); - } else { - setChartHiddenStatus(true, key, value); - } + setChartHiddenStatus(!this.checked, key, value); + updateSelectAllStatus(this.checked, selectAll, values.length); }); wrapper.appendChild(checkBox); wrapper.appendChild(label); From 83e39cb9dc53e1b23f568e2eab88c2cf36324dec Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 12:07:42 +0200 Subject: [PATCH 06/16] reorganize filter interface creation code --- src/default_index.html | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/default_index.html b/src/default_index.html index dc3e3f27..219faa13 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -461,20 +461,19 @@ }); } - function getUniqueValuesForKey(groupKeys, groupBy) { + function getUniqueValuesByKey(groupKeys, groupBy) { // get the unique values for each group const uniqueValues = {}; groupBy.forEach((key) => { - const keys = groupKeys.map((k) => k[key]); - const set = [...new Set(keys)]; - uniqueValues[key] = set; + uniqueValues[key] = [...new Set(groupKeys.map((k) => k[key]))]; }); return uniqueValues; } - function createFilterInterface(elem, groupKeys, groupBy) { + function createFilterInterface(elem, uniqueValues) { + const fragment = document.createDocumentFragment(); + elem.className = 'filter-interface'; - const uniqueValues = getUniqueValuesForKey(groupKeys, groupBy); Object.entries(uniqueValues).forEach(([key, values]) => { const checklist = document.createElement('div'); @@ -552,8 +551,9 @@ checklist.appendChild(wrapper); }); - elem.appendChild(checklist); + fragment.appendChild(checklist); }); + elem.appendChild(fragment); } function populateRefPrDropdown(refsOpt, prsOpt) { const refs = refsOpt ? refsOpt : []; @@ -671,7 +671,8 @@ const groupKeys = Object.keys(groupedData).map((keyString) => parseKey(keyString, groupBy)); // create the interface at the top of the page for filtering - createFilterInterface(filterElem, groupKeys, groupBy); + const uniqueValues = getUniqueValuesByKey(groupKeys, groupBy); + createFilterInterface(filterElem, uniqueValues); // create a chart for each group Object.entries(groupedData).forEach(([groupKeyString, filteredTraces]) => { From 6913a214744f47cc08ca0f345fe8224461ce2221 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 12:31:07 +0200 Subject: [PATCH 07/16] convert numbers for comparison --- src/default_index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/default_index.html b/src/default_index.html index 219faa13..829bf92d 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -432,6 +432,7 @@ function setChartHiddenStatus(hide, key, value) { value = value ? value : 'undefined'; + value = typeof value === 'number' ? value.toString() : value; const charts = document.getElementsByClassName('benchmark-graphs'); const filteredCharts = Array.from(charts).filter((chart) => { const chartValue = chart.getAttribute(key.replace(' ', '')); From ec9b97638bf30a282229d53f51c5a6115d742f57 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 12:42:59 +0200 Subject: [PATCH 08/16] display the number of charts shown --- src/default_index.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/default_index.html b/src/default_index.html index 829bf92d..6702b1d9 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -128,6 +128,8 @@
+ Number of charts displayed: +
@@ -430,6 +432,11 @@ } } + function updateNumShown(numShown) { + const elem = document.getElementById('num-charts-shown'); + elem.textContent = numShown; + } + function setChartHiddenStatus(hide, key, value) { value = value ? value : 'undefined'; value = typeof value === 'number' ? value.toString() : value; @@ -460,6 +467,13 @@ } chart.setAttribute('hidden-by', hiddenBy); }); + + // update number of charts hidden + const numShown = Array.from(charts).filter((chart) => { + return chart.style.getPropertyValue('display') !== 'none'; + }).length; + + updateNumShown(numShown); } function getUniqueValuesByKey(groupKeys, groupBy) { @@ -675,6 +689,7 @@ const uniqueValues = getUniqueValuesByKey(groupKeys, groupBy); createFilterInterface(filterElem, uniqueValues); + let numShown = 0; // create a chart for each group Object.entries(groupedData).forEach(([groupKeyString, filteredTraces]) => { // build the title @@ -688,11 +703,14 @@ const chartElem = chartFilteredTraces(setElem, title, filteredTraces); if (chartElem) { addAttributesToChartElement(chartElem, groupKey); + numShown += 1; } }); main.appendChild(filterElem); main.appendChild(setElem); + + updateNumShown(numShown); } async function checkFileAvailable(url) { const response = await fetch(url, { method: 'HEAD' }).catch((e) => { From 1e1cd6e22c4775c5988d0e5d6373154a7c865e44 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 13:08:45 +0200 Subject: [PATCH 09/16] add button to clear all filters --- src/default_index.html | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/default_index.html b/src/default_index.html index 6702b1d9..5c909061 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -130,6 +130,7 @@
Number of charts displayed:
+
@@ -488,7 +489,31 @@ function createFilterInterface(elem, uniqueValues) { const fragment = document.createDocumentFragment(); - elem.className = 'filter-interface'; + // button to clear all filters + const clearFilters = document.getElementById('clear-filters-btn-div'); + clearFilters.innerHTML = ''; + const btn = document.createElement('button'); + btn.setAttribute('id', 'clear-filters-btn'); + btn.textContent = 'Clear all filters'; + btn.disabled = true; + btn.addEventListener('click', function () { + Object.entries(uniqueValues).forEach(([key, values]) => { + values.forEach((value) => { + const checkbox = document.getElementById(`${key}-${value}`); + checkbox.checked = true; + const hidden = false; + + // hide the chart + setChartHiddenStatus(hidden, key, value); + }); + const numSelected = values.length; + const selectAll = document.getElementById(`${key}-select-all`); + selectAll.setAttribute('num-selected', numSelected); + selectAll.checked = true; + selectAll.indeterminate = false; + }); + }); + clearFilters.appendChild(btn); Object.entries(uniqueValues).forEach(([key, values]) => { const checklist = document.createElement('div'); @@ -518,9 +543,15 @@ values.forEach((value) => { const checkbox = document.getElementById(`${key}-${value}`); checkbox.checked = this.checked; + const hidden = !this.checked; // hide the chart - setChartHiddenStatus(!this.checked, key, value); + setChartHiddenStatus(hidden, key, value); + + // enable clear filters button + if (hidden) { + btn.disabled = false; + } }); const numSelected = this.checked ? values.length : 0; selectAll.setAttribute('num-selected', numSelected); From 9f9fc180991dca9a6224bece99d4ece196588915 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 13:47:54 +0200 Subject: [PATCH 10/16] use different commits for different parts of CI check --- .github/workflows/test-fail.yml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml index 843bf7fd..a43d6163 100644 --- a/.github/workflows/test-fail.yml +++ b/.github/workflows/test-fail.yml @@ -3,11 +3,14 @@ on: workflow_dispatch: pull_request: jobs: - run-action-exceed-threshold: + setup: runs-on: ubuntu-latest steps: # run the test using the local action in repo - uses: actions/checkout@v4 + with: + # use last commit from main as basis for comparison + ref: main - name: "build" run: | npm install @@ -22,6 +25,18 @@ jobs: gh-pages-branch: gh-pages-test group-by: 'os' schema: 'name,os' + +jobs: + check: + needs: [setup] + runs-on: ubuntu-latest + steps: + # run the test using the local action in repo + - uses: actions/checkout@v4 + - name: "build" + run: | + npm install + npm run build - uses: ./ # local action in repo # Then add the data from part 2, which represents # more than a 200% increase. @@ -35,11 +50,12 @@ jobs: schema: 'name,os' fail-on-alert: true alert-threshold: 200% + # ensure that the above job fails check-action-fails-on-exceed-threshold: if: ${{ always() }} runs-on: ubuntu-latest - needs: [run-action-exceed-threshold] + needs: [check] steps: - name: Successful - expected failure but job exited successfully if: ${{ !(contains(needs.*.result, 'failure')) }} From 13b0ab795e35806daeef7d779d5b2e32026ce367 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Wed, 21 May 2025 13:51:41 +0200 Subject: [PATCH 11/16] remove duplicate `jobs` key --- .github/workflows/test-fail.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml index a43d6163..80ac3b18 100644 --- a/.github/workflows/test-fail.yml +++ b/.github/workflows/test-fail.yml @@ -26,7 +26,6 @@ jobs: group-by: 'os' schema: 'name,os' -jobs: check: needs: [setup] runs-on: ubuntu-latest From 60e136fa58dd54471ed86325e42faf7293008b9a Mon Sep 17 00:00:00 2001 From: wysiwys Date: Thu, 22 May 2025 09:10:24 +0200 Subject: [PATCH 12/16] write data to json for base_ref --- .github/workflows/test-fail.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml index 80ac3b18..2c92bb3a 100644 --- a/.github/workflows/test-fail.yml +++ b/.github/workflows/test-fail.yml @@ -2,6 +2,7 @@ name: Test that the action fails if benchmark increase exceeds threshold on: workflow_dispatch: pull_request: + jobs: setup: runs-on: ubuntu-latest @@ -9,8 +10,8 @@ jobs: # run the test using the local action in repo - uses: actions/checkout@v4 with: - # use last commit from main as basis for comparison - ref: main + # use base ref for comparison + ref: ${{ GITHUB_BASE_REF }} - name: "build" run: | npm install @@ -25,6 +26,7 @@ jobs: gh-pages-branch: gh-pages-test group-by: 'os' schema: 'name,os' + external-data-json-path: refs/heads/${{ GITHUB_BASE_REF }}.json check: needs: [setup] From 93257ae088af0384bdf67e46278dba849c0f5288 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Thu, 22 May 2025 09:11:47 +0200 Subject: [PATCH 13/16] fix syntax --- .github/workflows/test-fail.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml index 2c92bb3a..2efdf7e4 100644 --- a/.github/workflows/test-fail.yml +++ b/.github/workflows/test-fail.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v4 with: # use base ref for comparison - ref: ${{ GITHUB_BASE_REF }} + ref: ${{ $GITHUB_BASE_REF }} - name: "build" run: | npm install @@ -26,7 +26,7 @@ jobs: gh-pages-branch: gh-pages-test group-by: 'os' schema: 'name,os' - external-data-json-path: refs/heads/${{ GITHUB_BASE_REF }}.json + external-data-json-path: refs/heads/${{ $GITHUB_BASE_REF }}.json check: needs: [setup] From 462de22a85176263acaf833a1018a1582e7cf865 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Thu, 22 May 2025 09:13:30 +0200 Subject: [PATCH 14/16] get base ref via `github` --- .github/workflows/test-fail.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml index 2efdf7e4..68548d3a 100644 --- a/.github/workflows/test-fail.yml +++ b/.github/workflows/test-fail.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v4 with: # use base ref for comparison - ref: ${{ $GITHUB_BASE_REF }} + ref: ${{ github.base_ref }} - name: "build" run: | npm install @@ -26,7 +26,7 @@ jobs: gh-pages-branch: gh-pages-test group-by: 'os' schema: 'name,os' - external-data-json-path: refs/heads/${{ $GITHUB_BASE_REF }}.json + external-data-json-path: refs/heads/${{ github.base_ref }}.json check: needs: [setup] From ce6430553766822de5c1fa7732354ee6cc88e5f2 Mon Sep 17 00:00:00 2001 From: wysiwys Date: Thu, 22 May 2025 12:15:13 +0200 Subject: [PATCH 15/16] remove workflow --- .github/workflows/test-fail.yml | 66 --------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 .github/workflows/test-fail.yml diff --git a/.github/workflows/test-fail.yml b/.github/workflows/test-fail.yml deleted file mode 100644 index 68548d3a..00000000 --- a/.github/workflows/test-fail.yml +++ /dev/null @@ -1,66 +0,0 @@ -name: Test that the action fails if benchmark increase exceeds threshold -on: - workflow_dispatch: - pull_request: - -jobs: - setup: - runs-on: ubuntu-latest - steps: - # run the test using the local action in repo - - uses: actions/checkout@v4 - with: - # use base ref for comparison - ref: ${{ github.base_ref }} - - name: "build" - run: | - npm install - npm run build - - uses: ./ # local action in repo - # First add the data from part 1 - with: - name: 'Test fail if exceed threshold' - input-data-path: ./test/data/extract/testFailPart1.json - github-token: ${{ secrets.GITHUB_TOKEN }} - auto-push: true - gh-pages-branch: gh-pages-test - group-by: 'os' - schema: 'name,os' - external-data-json-path: refs/heads/${{ github.base_ref }}.json - - check: - needs: [setup] - runs-on: ubuntu-latest - steps: - # run the test using the local action in repo - - uses: actions/checkout@v4 - - name: "build" - run: | - npm install - npm run build - - uses: ./ # local action in repo - # Then add the data from part 2, which represents - # more than a 200% increase. - with: - name: 'Test fail if exceed threshold' - input-data-path: ./test/data/extract/testFailPart2.json - github-token: ${{ secrets.GITHUB_TOKEN }} - auto-push: true - gh-pages-branch: gh-pages-test - group-by: 'os' - schema: 'name,os' - fail-on-alert: true - alert-threshold: 200% - - # ensure that the above job fails - check-action-fails-on-exceed-threshold: - if: ${{ always() }} - runs-on: ubuntu-latest - needs: [check] - steps: - - name: Successful - expected failure but job exited successfully - if: ${{ !(contains(needs.*.result, 'failure')) }} - run: exit 1 - - name: Failing - expected failure - if: ${{ (contains(needs.*.result, 'failure')) }} - run: exit 0 From 54b727194f1632e589f4085e4d621b08c6db890b Mon Sep 17 00:00:00 2001 From: wysiwys Date: Thu, 22 May 2025 14:16:46 +0200 Subject: [PATCH 16/16] move comment above function signature --- src/default_index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/default_index.html b/src/default_index.html index 5c909061..a6f54efe 100644 --- a/src/default_index.html +++ b/src/default_index.html @@ -477,8 +477,8 @@ updateNumShown(numShown); } + // get the unique values for each group function getUniqueValuesByKey(groupKeys, groupBy) { - // get the unique values for each group const uniqueValues = {}; groupBy.forEach((key) => { uniqueValues[key] = [...new Set(groupKeys.map((k) => k[key]))];