refactor(tools/sync-module-labels): move shared code into a shared helper (#42249)

As otherwise this leads to us importing the tool itself, which has a
top-level function that runs the tool.

As noted on a comment on #42012, this means that the tests are now
executing `gh` which isn't intended.

Co-authored-by: Claude Sonnet 4.6 <jamie.tanna+claude-code@mend.io>
This commit is contained in:
Jamie Tanna
2026-03-30 18:31:35 +01:00
committed by GitHub
parent 107fcfd3f3
commit e31dfd74e8
3 changed files with 123 additions and 115 deletions
+1 -1
View File
@@ -5,7 +5,7 @@ import {
formatMissingLabels,
getExpectedModuleLabels,
getMissingModuleLabels,
} from '../../tools/sync-module-labels.ts';
} from '../../tools/utils/sync-module-labels.ts';
describe('other/sync-module-labels', () => {
it('creates module labels with the expected metadata', () => {
+7 -114
View File
@@ -1,122 +1,15 @@
import { Command } from 'commander';
import { quote } from 'shlex';
import { init, logger } from '../lib/logger/index.ts';
import { getDatasourceList } from '../lib/modules/datasource/index.ts';
import { allManagersList } from '../lib/modules/manager/index.ts';
import { getPlatformList } from '../lib/modules/platform/index.ts';
import { exec } from './utils/exec.ts';
export type ModuleLabelKind = 'datasource' | 'manager' | 'platform';
export interface GitHubLabel {
color: string;
description: string;
name: string;
}
export interface CliOptions {
repo: string;
showCommands?: boolean;
}
import type { CliOptions, GitHubLabel } from './utils/sync-module-labels.ts';
import {
formatCreateLabelCommands,
formatMissingLabels,
getExpectedModuleLabels,
getMissingModuleLabels,
} from './utils/sync-module-labels.ts';
const defaultRepo = 'renovatebot/renovate';
const moduleLabelColor = 'C5DEF5';
export function getLabelDescription(
kind: ModuleLabelKind,
moduleId: string,
): string {
return `Related to the ${moduleId} ${kind}`;
}
export function createModuleLabel(
kind: ModuleLabelKind,
moduleId: string,
): GitHubLabel {
return {
color: moduleLabelColor,
description: getLabelDescription(kind, moduleId),
name: `${kind}:${moduleId}`,
};
}
function getSortedUnique(values: string[]): string[] {
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
export function getExpectedModuleLabels(): GitHubLabel[] {
const datasources = getSortedUnique(getDatasourceList()).map((datasource) =>
createModuleLabel('datasource', datasource),
);
const managers = getSortedUnique(allManagersList).map((manager) =>
createModuleLabel('manager', manager),
);
const platforms = getSortedUnique(getPlatformList()).map((platform) =>
createModuleLabel('platform', platform),
);
return [...datasources, ...managers, ...platforms].sort((left, right) =>
left.name.localeCompare(right.name),
);
}
export function getMissingModuleLabels(
expectedLabels: GitHubLabel[],
existingLabels: GitHubLabel[],
): GitHubLabel[] {
const existingNames = new Set(existingLabels.map((label) => label.name));
return expectedLabels.filter((label) => !existingNames.has(label.name));
}
export function formatMissingLabels(labels: GitHubLabel[]): string {
const sections: Record<ModuleLabelKind, string[]> = {
datasource: [],
manager: [],
platform: [],
};
for (const label of labels) {
const kind = label.name.split(':')[0] as ModuleLabelKind;
sections[kind].push(label.name);
}
const lines: string[] = [];
for (const kind of ['datasource', 'manager', 'platform'] as const) {
const names = sections[kind];
if (names.length === 0) {
continue;
}
lines.push(`${kind}s (${names.length}):`);
for (const name of names) {
lines.push(`- ${name}`);
}
}
return lines.join('\n');
}
export function getCreateLabelCommand(
repo: string,
label: GitHubLabel,
): string {
return (
`gh label create ${quote(label.name)} -R ${quote(repo)}` +
` --color ${quote(label.color)}` +
` --description ${quote(label.description)}`
);
}
export function formatCreateLabelCommands(
repo: string,
labels: GitHubLabel[],
): string {
return [...labels]
.sort((left, right) => left.name.localeCompare(right.name))
.map((label) => getCreateLabelCommand(repo, label))
.join('\n');
}
async function getRepoLabels(repo: string): Promise<GitHubLabel[]> {
const result = await exec('gh', [
+115
View File
@@ -0,0 +1,115 @@
import { quote } from 'shlex';
import { getDatasourceList } from '../../lib/modules/datasource/index.ts';
import { allManagersList } from '../../lib/modules/manager/index.ts';
import { getPlatformList } from '../../lib/modules/platform/index.ts';
export type ModuleLabelKind = 'datasource' | 'manager' | 'platform';
export interface GitHubLabel {
color: string;
description: string;
name: string;
}
export interface CliOptions {
repo: string;
showCommands?: boolean;
}
const moduleLabelColor = 'C5DEF5';
export function getLabelDescription(
kind: ModuleLabelKind,
moduleId: string,
): string {
return `Related to the ${moduleId} ${kind}`;
}
export function createModuleLabel(
kind: ModuleLabelKind,
moduleId: string,
): GitHubLabel {
return {
color: moduleLabelColor,
description: getLabelDescription(kind, moduleId),
name: `${kind}:${moduleId}`,
};
}
function getSortedUnique(values: string[]): string[] {
return [...new Set(values)].sort((left, right) => left.localeCompare(right));
}
export function getExpectedModuleLabels(): GitHubLabel[] {
const datasources = getSortedUnique(getDatasourceList()).map((datasource) =>
createModuleLabel('datasource', datasource),
);
const managers = getSortedUnique(allManagersList).map((manager) =>
createModuleLabel('manager', manager),
);
const platforms = getSortedUnique(getPlatformList()).map((platform) =>
createModuleLabel('platform', platform),
);
return [...datasources, ...managers, ...platforms].sort((left, right) =>
left.name.localeCompare(right.name),
);
}
export function getMissingModuleLabels(
expectedLabels: GitHubLabel[],
existingLabels: GitHubLabel[],
): GitHubLabel[] {
const existingNames = new Set(existingLabels.map((label) => label.name));
return expectedLabels.filter((label) => !existingNames.has(label.name));
}
export function formatMissingLabels(labels: GitHubLabel[]): string {
const sections: Record<ModuleLabelKind, string[]> = {
datasource: [],
manager: [],
platform: [],
};
for (const label of labels) {
const kind = label.name.split(':')[0] as ModuleLabelKind;
sections[kind].push(label.name);
}
const lines: string[] = [];
for (const kind of ['datasource', 'manager', 'platform'] as const) {
const names = sections[kind];
if (names.length === 0) {
continue;
}
lines.push(`${kind}s (${names.length}):`);
for (const name of names) {
lines.push(`- ${name}`);
}
}
return lines.join('\n');
}
export function getCreateLabelCommand(
repo: string,
label: GitHubLabel,
): string {
return (
`gh label create ${quote(label.name)} -R ${quote(repo)}` +
` --color ${quote(label.color)}` +
` --description ${quote(label.description)}`
);
}
export function formatCreateLabelCommands(
repo: string,
labels: GitHubLabel[],
): string {
return [...labels]
.sort((left, right) => left.name.localeCompare(right.name))
.map((label) => getCreateLabelCommand(repo, label))
.join('\n');
}