源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
// How much reading a pull request asks for. Review state is deliberately not
|
||||
// labelled here: GitHub already indexes review, check and draft state, so a
|
||||
// search qualifier answers "whose move is it" without a workflow keeping a
|
||||
// copy fresh. Pull request search has no size qualifier, which leaves reading
|
||||
// effort as the one axis a query cannot express.
|
||||
|
||||
const EFFORT_LABELS = ['effort/XS', 'effort/S', 'effort/M', 'effort/L', 'effort/XL'];
|
||||
|
||||
// Counted changes should track what a human actually reads. Lockfiles,
|
||||
// regenerated artifacts and binaries are verified by their own contracts, so
|
||||
// letting their line counts reach the tiers would inflate every pull request
|
||||
// that happens to touch one. A Rust dependency bump alone rewrites thousands
|
||||
// of Cargo.lock lines that nobody reviews line by line.
|
||||
const UNREAD_PATTERNS = [
|
||||
/(^|\/)(package-lock\.json|pnpm-lock\.yaml|yarn\.lock|Cargo\.lock|uv\.lock)$/,
|
||||
/(^|\/)THIRD_PARTY_(NOTICES|LICENSES)[^/]*$/,
|
||||
/\.generated\.[cm]?[jt]sx?$/,
|
||||
/\.snapshot\.json$/,
|
||||
/\.min\.(js|css)$/,
|
||||
/\.(png|jpe?g|gif|ico|webp|woff2?|ttf|sqlite|zip|gz|pdf)$/,
|
||||
];
|
||||
|
||||
// Tier boundaries are inclusive upper bounds on readable lines. Test code is
|
||||
// not discounted anywhere here; it is reviewed too.
|
||||
const EFFORT_TIERS = [
|
||||
{ label: 'effort/XS', maxLines: 10 },
|
||||
{ label: 'effort/S', maxLines: 100 },
|
||||
{ label: 'effort/M', maxLines: 500 },
|
||||
{ label: 'effort/L', maxLines: 1000 },
|
||||
{ label: 'effort/XL', maxLines: Number.POSITIVE_INFINITY },
|
||||
];
|
||||
|
||||
function isUnreadPath(path) {
|
||||
const normalized = String(path).replace(/\\/g, '/');
|
||||
return UNREAD_PATTERNS.some((pattern) => pattern.test(normalized));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<{filename: string, additions?: number, deletions?: number}>} files
|
||||
*/
|
||||
function countReadableLines(files = []) {
|
||||
return files.reduce((total, file) => {
|
||||
if (isUnreadPath(file.filename)) return total;
|
||||
return total + (file.additions ?? 0) + (file.deletions ?? 0);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<object>} files
|
||||
*/
|
||||
function classifyEffort(files = []) {
|
||||
const lines = countReadableLines(files);
|
||||
const tier = EFFORT_TIERS.find((candidate) => lines <= candidate.maxLines);
|
||||
return { label: tier.label, lines };
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<object>} files
|
||||
* @param {string[]} currentLabels
|
||||
*/
|
||||
export function planLabels(files = [], currentLabels = []) {
|
||||
const { label, lines } = classifyEffort(files);
|
||||
const current = new Set(currentLabels);
|
||||
|
||||
return {
|
||||
label,
|
||||
lines,
|
||||
addLabels: current.has(label) ? [] : [label],
|
||||
removeLabels: EFFORT_LABELS.filter((name) => name !== label && current.has(name)),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user