mirror of
https://github.com/esphome/esphome.git
synced 2026-07-10 08:55:36 +00:00
[ci] Exclude test changes from small-pr/medium-pr size labels (#17172)
This commit is contained in:
@@ -147,19 +147,9 @@ async function detectCoreChanges(changedFiles) {
|
||||
}
|
||||
|
||||
// Strategy: PR size detection
|
||||
async function detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD) {
|
||||
async function detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD) {
|
||||
const labels = new Set();
|
||||
|
||||
if (totalChanges <= SMALL_PR_THRESHOLD) {
|
||||
labels.add('small-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
if (totalChanges <= MEDIUM_PR_THRESHOLD) {
|
||||
labels.add('medium-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
const testAdditions = prFiles
|
||||
.filter(file => file.filename.startsWith('tests/'))
|
||||
.reduce((sum, file) => sum + (file.additions || 0), 0);
|
||||
@@ -167,7 +157,24 @@ async function detectPRSize(prFiles, totalAdditions, totalDeletions, totalChange
|
||||
.filter(file => file.filename.startsWith('tests/'))
|
||||
.reduce((sum, file) => sum + (file.deletions || 0), 0);
|
||||
|
||||
const nonTestChanges = (totalAdditions - testAdditions) - (totalDeletions - testDeletions);
|
||||
const nonTestAdditions = totalAdditions - testAdditions;
|
||||
const nonTestDeletions = totalDeletions - testDeletions;
|
||||
|
||||
// small/medium count churn (additions + deletions) so a balanced refactor isn't undersized.
|
||||
const nonTestChurn = nonTestAdditions + nonTestDeletions;
|
||||
|
||||
if (nonTestChurn <= SMALL_PR_THRESHOLD) {
|
||||
labels.add('small-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
if (nonTestChurn <= MEDIUM_PR_THRESHOLD) {
|
||||
labels.add('medium-pr');
|
||||
return labels;
|
||||
}
|
||||
|
||||
// too-big uses net line delta (additions - deletions), matching the review message in reviews.js.
|
||||
const nonTestChanges = nonTestAdditions - nonTestDeletions;
|
||||
|
||||
// Don't add too-big if mega-pr label is already present
|
||||
if (nonTestChanges > TOO_BIG_THRESHOLD && !isMegaPR) {
|
||||
|
||||
@@ -123,7 +123,7 @@ module.exports = async ({ github, context }) => {
|
||||
detectNewComponents(github, context, prFiles),
|
||||
detectNewPlatforms(github, context, prFiles, apiData),
|
||||
detectCoreChanges(changedFiles),
|
||||
detectPRSize(prFiles, totalAdditions, totalDeletions, totalChanges, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
|
||||
detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL_PR_THRESHOLD, MEDIUM_PR_THRESHOLD, TOO_BIG_THRESHOLD),
|
||||
detectDashboardChanges(changedFiles),
|
||||
detectGitHubActionsChanges(changedFiles),
|
||||
detectCodeOwner(github, context, changedFiles),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const { describe, it } = require('node:test');
|
||||
const assert = require('node:assert/strict');
|
||||
const { detectNewPlatforms, detectNewComponents } = require('../detectors');
|
||||
const { detectNewPlatforms, detectNewComponents, detectPRSize } = require('../detectors');
|
||||
|
||||
// Minimal GitHub API mock — only repos.getContent is called by detectNewPlatforms/detectNewComponents
|
||||
// to check for CONFIG_SCHEMA in newly added files.
|
||||
@@ -145,3 +145,79 @@ describe('detectNewComponents', () => {
|
||||
assert.equal(result.labels.size, 0);
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// detectPRSize
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('detectPRSize', () => {
|
||||
const SMALL = 30;
|
||||
const MEDIUM = 100;
|
||||
const TOO_BIG = 1000;
|
||||
|
||||
function size(prFiles, isMegaPR = false) {
|
||||
const totalAdditions = prFiles.reduce((sum, file) => sum + (file.additions || 0), 0);
|
||||
const totalDeletions = prFiles.reduce((sum, file) => sum + (file.deletions || 0), 0);
|
||||
return detectPRSize(prFiles, totalAdditions, totalDeletions, isMegaPR, SMALL, MEDIUM, TOO_BIG);
|
||||
}
|
||||
|
||||
it('counts only non-test changes toward small-pr', async () => {
|
||||
// 10 source + 5000 test lines -> non-test churn of 10 is still small.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 10, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('small-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('counts additions and deletions as churn (not net delta)', async () => {
|
||||
// A balanced refactor (40 added, 40 removed) is 80 lines of churn -> medium, not small.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 40, deletions: 40 },
|
||||
]);
|
||||
assert.ok(labels.has('medium-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('labels medium-pr when non-test changes exceed small threshold', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 60, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('medium-pr'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('uses net delta (not churn) for too-big', async () => {
|
||||
// 600 added + 600 removed: 1200 churn (above too-big) but 0 net delta -> not too-big.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 600, deletions: 600 },
|
||||
]);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
|
||||
it('labels too-big when non-test changes exceed the big threshold', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 2000, deletions: 0 },
|
||||
{ filename: 'tests/components/foo/test.esp32-idf.yaml', additions: 5000, deletions: 0 },
|
||||
]);
|
||||
assert.ok(labels.has('too-big'));
|
||||
assert.equal(labels.size, 1);
|
||||
});
|
||||
|
||||
it('does not label too-big when mega-pr is set', async () => {
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 2000, deletions: 0 },
|
||||
], true);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
|
||||
it('produces no size label for a large mega-pr in the gap above medium', async () => {
|
||||
// Non-test changes land between MEDIUM and TOO_BIG: not small/medium, and mega-pr suppresses too-big.
|
||||
const labels = await size([
|
||||
{ filename: 'esphome/components/foo/foo.cpp', additions: 500, deletions: 0 },
|
||||
], true);
|
||||
assert.equal(labels.size, 0);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user