Skip to content

Commit f072244

Browse files
committed
feat(ng-dev): update target labels in renovate config
This commit enhances the release tool to dynamically adjust Renovate labels based on the current version. Example: angular/angular#61894
1 parent 64207a2 commit f072244

File tree

3 files changed

+110
-6
lines changed

3 files changed

+110
-6
lines changed

ng-dev/release/publish/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ ts_library(
88
visibility = ["//ng-dev:__subpackages__"],
99
deps = [
1010
"//ng-dev/commit-message",
11+
"//ng-dev/pr/common/labels",
1112
"//ng-dev/pr/merge",
1213
"//ng-dev/release/build",
1314
"//ng-dev/release/config",

ng-dev/release/publish/actions.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ import {Prompt} from '../../utils/prompt.js';
4444
import {glob} from 'fast-glob';
4545
import {PnpmVersioning} from './pnpm-versioning.js';
4646
import {Commit} from '../../utils/git/octokit-types.js';
47+
import {updateRenovateConfigTargetLabels} from './actions/renovate-config-updates.js';
48+
import {targetLabels} from '../../pr/common/labels/target.js';
4749

4850
/** Interface describing a Github repository. */
4951
export interface GithubRepo {
@@ -217,13 +219,27 @@ export abstract class ReleaseAction {
217219
}
218220

219221
// Commit message for the release point.
220-
const commitMessage = getCommitMessageForRelease(newVersion);
221222
const filesToCommit = [
222223
workspaceRelativePackageJsonPath,
223224
workspaceRelativeChangelogPath,
224225
...this.getAspectLockFiles(),
225226
];
226227

228+
if (newVersion.patch === 0 && !newVersion.prerelease) {
229+
// Switch the renovate labels for `target: rc` to `target: patch`
230+
const renovateConfigPath = await updateRenovateConfigTargetLabels(
231+
this.projectDir,
232+
targetLabels['TARGET_RC'].name,
233+
targetLabels['TARGET_PATCH'].name,
234+
);
235+
236+
if (renovateConfigPath) {
237+
filesToCommit.push(renovateConfigPath);
238+
}
239+
}
240+
241+
const commitMessage = getCommitMessageForRelease(newVersion);
242+
227243
// Create a release staging commit including changelog and version bump.
228244
await this.createCommit(commitMessage, filesToCommit);
229245

ng-dev/release/publish/actions/renovate-config-updates.ts

Lines changed: 92 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import {existsSync} from 'node:fs';
22
import {green, Log} from '../../../utils/logging.js';
33
import {join} from 'node:path';
44
import {writeFile, readFile} from 'node:fs/promises';
5+
import {targetLabels} from '../../../pr/common/labels/target.js';
56

67
/**
78
* Updates the `renovate.json` configuration file to include a new base branch.
9+
* It also updates specific target labels within the package rules.
810
*
9-
* @param projectDir - The project directory path.
11+
* @param projectDir - The path to the project directory.
1012
* @param newBranchName - The name of the new branch to add to the base branches list.
11-
* @returns A promise that resolves to an string containing the path to the modified `renovate.json` file,
12-
* or null if config updating is disabled.
13+
* @returns A promise that resolves to the path of the modified `renovate.json` file if updated,
14+
* or `null` if the file was not found or the `baseBranches` array has an unexpected format.
1315
*/
1416
export async function updateRenovateConfig(
1517
projectDir: string,
@@ -18,13 +20,13 @@ export async function updateRenovateConfig(
1820
const renovateConfigPath = join(projectDir, 'renovate.json');
1921
if (!existsSync(renovateConfigPath)) {
2022
Log.warn(` ✘ Skipped updating Renovate config as it was not found.`);
21-
2223
return null;
2324
}
2425

2526
const config = await readFile(renovateConfigPath, 'utf-8');
2627
const configJson = JSON.parse(config) as Record<string, unknown>;
2728
const baseBranches = configJson.baseBranches;
29+
2830
if (!Array.isArray(baseBranches) || baseBranches.length !== 2) {
2931
Log.warn(
3032
` ✘ Skipped updating Renovate config: "baseBranches" must contain exactly 2 branches.`,
@@ -34,8 +36,93 @@ export async function updateRenovateConfig(
3436
}
3537

3638
configJson.baseBranches = ['main', newBranchName];
39+
40+
updateRenovateTargetLabel(
41+
configJson,
42+
targetLabels['TARGET_PATCH'].name,
43+
targetLabels['TARGET_RC'].name,
44+
);
3745
await writeFile(renovateConfigPath, JSON.stringify(configJson, undefined, 2));
38-
Log.info(green(` ✓ Updated Renovate config.`));
3946

47+
Log.info(green(` ✓ Updated Renovate config.`));
4048
return renovateConfigPath;
4149
}
50+
51+
/**
52+
* Updates a specific target label in the `renovate.json` configuration file.
53+
* This function specifically targets and replaces one label with another within the `packageRules`.
54+
*
55+
* @param projectDir - The path to the project directory.
56+
* @param fromLabel - The label name to be replaced.
57+
* @param toLabel - The new label name to replace `fromLabel` with.
58+
* @returns A promise that resolves to the path of the modified `renovate.json` file if updated,
59+
* or `null` if the file was not found or the `baseBranches` array has an unexpected format.
60+
*/
61+
export async function updateRenovateConfigTargetLabels(
62+
projectDir: string,
63+
fromLabel: string,
64+
toLabel: string,
65+
): Promise<string | null> {
66+
const renovateConfigPath = join(projectDir, 'renovate.json');
67+
if (!existsSync(renovateConfigPath)) {
68+
Log.warn(` ✘ Skipped updating Renovate config as it was not found.`);
69+
70+
return null;
71+
}
72+
73+
const config = await readFile(renovateConfigPath, 'utf-8');
74+
const configJson = JSON.parse(config) as Record<string, unknown>;
75+
76+
// Check baseBranches just in case, though this function's primary focus is labels
77+
const baseBranches = configJson.baseBranches;
78+
if (!Array.isArray(baseBranches) || baseBranches.length !== 2) {
79+
Log.warn(
80+
` ✘ Skipped updating Renovate config: "baseBranches" must contain exactly 2 branches.`,
81+
);
82+
83+
return null;
84+
}
85+
86+
if (updateRenovateTargetLabel(configJson, fromLabel, toLabel)) {
87+
await writeFile(renovateConfigPath, JSON.stringify(configJson, undefined, 2));
88+
Log.info(green(` ✓ Updated target label in Renovate config.`));
89+
90+
return renovateConfigPath;
91+
} else {
92+
Log.info(green(` ✓ No changes to target labels in Renovate config.`));
93+
return null;
94+
}
95+
}
96+
97+
/**
98+
* Updates a specific target label within the `packageRules` of a Renovate configuration.
99+
*
100+
* @param configJson - The parsed JSON object of the Renovate configuration.
101+
* @param fromLabel - The label name to be replaced.
102+
* @param toLabel - The new label name to replace `fromLabel` with.
103+
* @returns `true` is the label has been updated, otherwise `false`.
104+
*/
105+
function updateRenovateTargetLabel(
106+
configJson: Record<string, unknown>,
107+
fromLabel: string,
108+
toLabel: string,
109+
): boolean {
110+
if (!Array.isArray(configJson.packageRules)) {
111+
return false;
112+
}
113+
114+
let updated = false;
115+
for (const rule of configJson.packageRules) {
116+
if (!Array.isArray(rule.addLabels)) {
117+
continue;
118+
}
119+
120+
const idx = (rule.addLabels as string[]).findIndex((x) => x === fromLabel);
121+
if (idx >= 0) {
122+
rule.addLabels[idx] = toLabel;
123+
updated = true;
124+
}
125+
}
126+
127+
return updated;
128+
}

0 commit comments

Comments
 (0)