mirror of
https://github.com/renovatebot/renovate.git
synced 2026-11-01 02:00:10 +00:00
91e068f1fd
* ci(linter): add renovate/v8-ignore-reason rule
Flag coverage-ignore comments ("v8 ignore") that carry no justification.
Accepted forms: "-- reason" / "--- reason" (recommended) and the legacy
colon form "v8 ignore <kind>[ <count>]: reason", which is already
widespread in the codebase (29 sites). Bare "v8 ignore stop" markers are
exempt because the justification lives on the paired "start" marker. The
"v8 ignore next <N>" count form remains allowed; this rule only requires
a justification.
Registered as "warn" instead of "error": the repo currently has 119
reason-less v8 ignore comments, too many to fix mechanically in one PR,
so existing sites are left untouched and can be fixed incrementally.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* ci(linter): promote renovate/v8-ignore-reason to error
Record the empirical verdict on the contested "v8 ignore next <N>" count
semantics in the rule doc: verified against vitest 4 with
ast-v8-to-istanbul that the count is not honored - the ignore hint always
exempts exactly the next AST node regardless of N. Counts are therefore
inert and stay allowed; the rule keeps requiring only a justification.
Promoting to error so all remaining reason-less coverage-ignore comments
must be fixed; the burndown follows in subsequent commits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 1)
Give every reason-less "v8 ignore" comment outside the large platform
index files a site-specific justification explaining why the exempted
branch is untestable or defensive, as now required by the
renovate/v8-ignore-reason rule.
Also guard against a nullish comment.loc in the rule itself; the
merged-in stricter tools typechecking flagged the unguarded access.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* refactor: add justifications to coverage-ignore comments (batch 2)
Cover the five large platform index files (github, bitbucket,
bitbucket-server, codecommit, gitlab) with site-specific reasons on
every "v8 ignore" comment, completing the renovate/v8-ignore-reason
burndown. Two meaningless ignore hints inside commented-out CodeCommit
mergePr code are dropped instead of annotated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017RxHFNsSworLcv23xXk9Hk
* Apply suggestions from code review
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
* Update lib/util/regex.ts
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Michael Kriese <michael.kriese@gmx.de>
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
207 lines
5.3 KiB
TypeScript
207 lines
5.3 KiB
TypeScript
import { isNullOrUndefined, isPlainObject, isString } from '@sindresorhus/is';
|
|
import { dequal } from 'dequal';
|
|
import { DateTime } from 'luxon';
|
|
import { logger } from '../../../logger/index.ts';
|
|
import * as memCache from '../../../util/cache/memory/index.ts';
|
|
import { getCache } from '../../../util/cache/repository/index.ts';
|
|
import type { BitbucketServerHttp } from '../../../util/http/bitbucket-server.ts';
|
|
import { getQueryString } from '../../../util/url.ts';
|
|
import type { BbsPr, BbsPrCacheData, BbsRestPr } from './types.ts';
|
|
import { prInfo } from './utils.ts';
|
|
|
|
/* v8 ignore next -- one-off cache-schema migration shim, only runs against real legacy repo caches */
|
|
function migrateBitbucketServerCache(platform: unknown): void {
|
|
if (!isPlainObject(platform)) {
|
|
return;
|
|
}
|
|
|
|
if (!isPlainObject(platform.bitbucketServer)) {
|
|
return;
|
|
}
|
|
|
|
platform['bitbucket-server'] = platform.bitbucketServer;
|
|
delete platform.bitbucketServer;
|
|
}
|
|
|
|
export class BbsPrCache {
|
|
private cache: BbsPrCacheData;
|
|
private items: BbsPr[] = [];
|
|
private projectKey: string;
|
|
private repo: string;
|
|
private readonly ignorePrAuthor: boolean;
|
|
private author: string | null;
|
|
|
|
private constructor(
|
|
projectKey: string,
|
|
repo: string,
|
|
ignorePrAuthor: boolean,
|
|
author: string | null,
|
|
) {
|
|
this.projectKey = projectKey;
|
|
this.repo = repo;
|
|
this.ignorePrAuthor = ignorePrAuthor;
|
|
this.author = author;
|
|
const repoCache = getCache();
|
|
repoCache.platform ??= {};
|
|
migrateBitbucketServerCache(repoCache.platform);
|
|
repoCache.platform['bitbucket-server'] ??= {};
|
|
let pullRequestCache = repoCache.platform['bitbucket-server']
|
|
.pullRequestsCache as BbsPrCacheData;
|
|
if (
|
|
isNullOrUndefined(pullRequestCache) ||
|
|
pullRequestCache.author !== author
|
|
) {
|
|
pullRequestCache = {
|
|
items: {},
|
|
updatedDate: null,
|
|
author,
|
|
};
|
|
}
|
|
repoCache.platform['bitbucket-server'].pullRequestsCache = pullRequestCache;
|
|
this.cache = pullRequestCache;
|
|
this.updateItems();
|
|
}
|
|
|
|
private static async init(
|
|
http: BitbucketServerHttp,
|
|
projectKey: string,
|
|
repo: string,
|
|
ignorePrAuthor: boolean,
|
|
author: string | null,
|
|
): Promise<BbsPrCache> {
|
|
const res = new BbsPrCache(projectKey, repo, ignorePrAuthor, author);
|
|
const isSynced = memCache.get<true | undefined>('bbs-pr-cache-synced');
|
|
|
|
// v8 ignore next -- TODO: add test #40625
|
|
if (!isSynced) {
|
|
await res.sync(http);
|
|
memCache.set('bbs-pr-cache-synced', true);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
private getPrs(): BbsPr[] {
|
|
return this.items;
|
|
}
|
|
|
|
static async getPrs(
|
|
http: BitbucketServerHttp,
|
|
projectKey: string,
|
|
repo: string,
|
|
ignorePrAuthor: boolean,
|
|
author: string,
|
|
): Promise<BbsPr[]> {
|
|
const prCache = await BbsPrCache.init(
|
|
http,
|
|
projectKey,
|
|
repo,
|
|
ignorePrAuthor,
|
|
author,
|
|
);
|
|
return prCache.getPrs();
|
|
}
|
|
|
|
private setPr(item: BbsPr): void {
|
|
this.cache.items[item.number] = item;
|
|
this.updateItems();
|
|
}
|
|
|
|
static async setPr(
|
|
http: BitbucketServerHttp,
|
|
projectKey: string,
|
|
repo: string,
|
|
ignorePrAuthor: boolean,
|
|
author: string,
|
|
item: BbsPr,
|
|
): Promise<void> {
|
|
const prCache = await BbsPrCache.init(
|
|
http,
|
|
projectKey,
|
|
repo,
|
|
ignorePrAuthor,
|
|
author,
|
|
);
|
|
prCache.setPr(item);
|
|
}
|
|
|
|
private reconcile(rawItems: BbsRestPr[]): boolean {
|
|
logger.debug('reconciled');
|
|
const { items } = this.cache;
|
|
let { updatedDate } = this.cache;
|
|
const cacheTime = updatedDate ? DateTime.fromMillis(updatedDate) : null;
|
|
|
|
let needNextPage = true;
|
|
|
|
for (const rawItem of rawItems) {
|
|
const id = rawItem.id;
|
|
|
|
const newItem = prInfo(rawItem);
|
|
|
|
const oldItem = items[id];
|
|
if (dequal(oldItem, newItem)) {
|
|
needNextPage = false;
|
|
continue;
|
|
}
|
|
|
|
items[id] = newItem;
|
|
|
|
const itemTime = DateTime.fromMillis(rawItem.updatedDate);
|
|
if (!cacheTime || itemTime > cacheTime) {
|
|
updatedDate = rawItem.updatedDate;
|
|
}
|
|
}
|
|
|
|
this.cache.updatedDate = updatedDate;
|
|
|
|
return needNextPage;
|
|
}
|
|
|
|
private async sync(http: BitbucketServerHttp): Promise<BbsPrCache> {
|
|
const searchParams: Record<string, string> = {
|
|
state: 'ALL',
|
|
limit: this.items.length ? '20' : '100',
|
|
};
|
|
if (!this.ignorePrAuthor && isString(this.author)) {
|
|
searchParams['role.1'] = 'AUTHOR';
|
|
searchParams['username.1'] = this.author;
|
|
}
|
|
let query: string | null = getQueryString(searchParams);
|
|
|
|
while (query) {
|
|
const res = await http.getJsonUnchecked<{
|
|
nextPageStart: string;
|
|
values: BbsRestPr[];
|
|
}>(
|
|
`./rest/api/1.0/projects/${this.projectKey}/repos/${this.repo}/pull-requests?${query}`,
|
|
{
|
|
memCache: false,
|
|
},
|
|
);
|
|
|
|
const needNextPage = this.reconcile(res.body.values);
|
|
if (!needNextPage) {
|
|
break;
|
|
}
|
|
|
|
if (res.body.nextPageStart) {
|
|
searchParams.start = res.body.nextPageStart.toString();
|
|
} else {
|
|
query = null;
|
|
}
|
|
}
|
|
|
|
this.updateItems();
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* Ensure the pr cache starts with the most recent PRs.
|
|
* JavaScript ensures that the cache is sorted by PR number.
|
|
*/
|
|
private updateItems(): void {
|
|
this.items = Object.values(this.cache.items).reverse();
|
|
}
|
|
}
|